feat(gvg): 组建期

This commit is contained in:
luying
2023-01-05 19:18:56 +08:00
parent 94c69089ac
commit 03fa74f3d1
50 changed files with 10354 additions and 38 deletions

View File

@@ -170,4 +170,8 @@ export const PUSH_ROUTE = {
LADDER_RANK_UPDATE: 'onLadderRankUpdate',
GROUP_SHOP_UPDATE: 'onGroupShopUpdate',
HIDDEN_DATA: 'onHiddenData',
LEAGUE_APPLY: 'onLeagueApply', // 当联军收到军团申请
LEAGUE_KICK: 'onKickedByLeague', // 当被踢出
LEAGUE_DISSMISS: 'onLeagueDismiss', // 当联军解散
LEAGUE_ABDICATE: 'onLeagueAbdicate', // 当被转让盟主
}

View File

@@ -0,0 +1,34 @@
export enum GVG_PERIOD {
TEAM = 1, // 组建期
PREPARE = 2, // 备战期
BATTLE = 3, // 战斗器
}
export enum LEAGUE_AUTH {
LEADER = 1, // 盟主
SUB_LEADER = 2, // 副盟主
MEMBER = 3, // 平民
}
export enum GVG_SERVER_TYPE {
NO = 0, // 刚开服根本不能参加的时候
SINGLE = 1, // 单服
MULTI = 2, // 跨服
}
export enum GVG_APPLY_TYPE {
ALL = 0,
APPLY = 1, // 军团向联军申请
INVITE = 2, // 联军向军团邀请
}
export enum LEAGUE_MANAGE_TYPE {
HANDLE_APPLY = 1, // 处理申请
INVITE = 2, // 邀请军团
KICK = 3, // 踢出军团
QUIT = 4, // 主动退出
DISSMISS = 5, // 解散联军
ABDICATE = 6, // 转让
BE_ABDICATED = 7, // 被转让
SET_INFO = 8, // 设置信息
}

View File

@@ -54,6 +54,7 @@ export const COUNTER = {
RACE_ACTIVITY: { name: 'raceAct', def: 1 },
HIDDEN_DATA: { name: 'hiddendata', def: 1 },
ARTIFACT_ID: { name: 'artid', def: 1 },
GVG_CONFIG: { name: 'gvg', def: 1 },
};
export const DEFAULT_HEROES = [19, 53,];
@@ -565,6 +566,7 @@ export const FILENAME = {
DIC_ARTIFACT_QUALITY_PLAN: 'dic_zyz_artifactQualityPlan',
DIC_ARTIFACT_QUALITY: 'dic_zyz_artifactQuality',
DIC_ARTIFACT_SEID: 'dic_zyz_artifactSeid',
DIC_GVG_PERIOD: 'dic_zyz_GVGPeriod',
}
export const WAR_RELATE_TABLES = [

View File

@@ -10,5 +10,6 @@ export * from './constModules/chatConst';
export * from './constModules/httpConst';
export * from './constModules/auctionConst';
export * from './constModules/mailConst';
export * from './constModules/gvgConst';
export * from './statusCode';
export * from './dataName';

View File

@@ -287,6 +287,25 @@ export const STATUS = {
LADDER_RANK_ERR: { code: 21208, simStr: '不可连战比排名自己高的玩家' },
LADDER_SWEEP_TIMES_OVER: { code: 21209, simStr: '连战次数过多' },
// GVG相关
GVG_HAS_NO_AUTH: { code: 21300, simStr: '您的权限不足' },
GVG_NOT_TEAM_PERIOD: { code: 21301, simStr: '您只能在组建期创建联军' },
GVG_TEAM_SERVER_TYPE_ERR: { code: 21302, simStr: '单服玩法不需要联军' },
GVG_LEAGUE_HAS_EXIST: { code: 21303, simStr: '联军已存在' },
GVG_NO_SERVER_TYPE: { code: 21304, simStr: '服务器开服一周后开放玩法' },
LEAGUE_IS_GUILD_MAX: { code: 21305, simStr: '该联军军团数已满' },
GVG_LEAGUE_NOT_EXIST: { code: 21306, simStr: '联军不存在' },
TARGET_GUILD_HAS_LEAGUE: { code: 21307, simStr: '对方已加入其他联军' },
TARGET_GUILD_NOT_FOUND: { code: 21308, simStr: '未找到该军团' },
GUILD_NOT_APPLY: { code: 21309, simStr: '对方军团未申请' },
GUILD_LV_NOT_ENOUGH: { code: 31310, simStr: '军团等级不足' },
GVG_CANNOUT_KICK_SELF_GUILD: { code: 31311, simStr: '不可踢走自己的军团' },
GUILD_HAS_QUIT: { code: 31312, simStr: '军团已经退出联军了' },
GVG_CANNOT_QUIT_OTHER_GUILD: { code: 31313, simStr: '只能主动退出自己的军团' },
LEAGUE_CODE_ERR: { code: 31314, simStr: '不能解散其他联军' },
GVG_HE_HAS_NO_AUTH: { code: 21300, simStr: '对方权限不足' },
LEAGUE_NAME_DUP: { code: 21301, simStr: '联军名重复' },
// 通用 30000 - 30099
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },
ROLE_MATERIAL_NOT_ENOUGH: { code: 30001, simStr: '材料数量不足' },
@@ -572,6 +591,7 @@ export const STATUS = {
GM_HIDDEN_CANNOT_INIT: { code: 60030, simStr: '已初始化过' },
GM_ACTIVITY_TIME_ERR: { code: 60031, simStr: '时间不可有重叠' },
GM_USER_TYPE_ERR: { code: 60032, simStr: '您不可使用账号密码登录,请从专属后台点击链接进入' },
GM_GVG_TIME_ERR: { code: 60033, simStr: '时间配置错误' },
// 支付相关状态 70000 - 79999
NO_PRODUCT_ID: { code: 70001, simStr: '无效商品' },
NO_PAY_TYPE: { code: 70002, simStr: '无效支付类型' },

48
shared/db/GVGConfig.ts Normal file
View File

@@ -0,0 +1,48 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { CounterModel } from './Counter';
import { COUNTER } from '../consts';
@index({ configId: -1 })
export default class GVGConfig extends BaseModel {
@prop({ required: true, default: 1 })
configId: number; // 配置唯一id
@prop({ required: true })
teamTime: number; // 组建期开始
@prop({ required: true })
prepareTime: number; // 准备期开始
@prop({ required: true })
battleTime: number; // 激战期开始
@prop({ required: true })
scheduleTime: number; // 下次定时任务时间
public static async createNewConfig(teamTime: number, prepareTime: number, battleTime: number, scheduleTime: number) {
const configId = await CounterModel.getNewCounter(COUNTER.GVG_CONFIG);
const result: GVGConfigType = await GVGConfigModel.findOneAndUpdate({ configId }, { $set: { teamTime, prepareTime, battleTime, scheduleTime } }, { upsert: true, new: true }).lean();
return result;
}
public static async findConfig() {
let configId = await CounterModel.getCounter(COUNTER.GVG_CONFIG);
const result: GVGConfigType = await GVGConfigModel.findOne({ configId }, { _id: 0 }).lean();
return result;
}
public static async updateConfig(configId: number, teamTime: number, prepareTime: number, battleTime: number, scheduleTime: number) {
const result: GVGConfigType = await GVGConfigModel.findOneAndUpdate({ configId }, { $set: { teamTime, prepareTime, battleTime, scheduleTime } }, { new: true }).lean();
return result;
}
}
export const GVGConfigModel = getModelForClass(GVGConfig);
export interface GVGConfigType extends Pick<DocumentType<GVGConfig>, keyof GVGConfig> {
id: number;
};
export type GVGConfigUpdate = Partial<GVGConfigType>; // 将所有字段变成可选项

195
shared/db/GVGLeague.ts Normal file
View File

@@ -0,0 +1,195 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import Role, { RoleType } from '../db/Role';
import { genCode } from '../pubUtils/util';
import { GuildType } from './Guild';
import { LEAGUE_AUTH } from '../consts';
class Member {
@prop({ required: true })
roleId: string;
@prop({ required: true })
auth: number;
}
@index({ leagueCode: 1, status: 1 })
@index({ guildCodes: 1, status: 1 })
@index({ 'members.roleId': 1, status: 1 })
export default class GVGLeague extends BaseModel {
@prop({ required: true })
leagueCode: string; // 唯一id
@prop({ required: true, type: String })
guildCodes: string[]; // 包含军团
@prop({ required: true, ref: () => Role, type: mongoose.Schema.Types.ObjectId })
leader: Ref<Role>;
@prop({ required: true, default: '' })
name: string; // 名称
@prop({ required: true, default: 1 })
icon: number; // 图标
@prop({ required: true, default: '' })
notice: string; // 公告
@prop({ required: true, default: 0 })
guildCnt: number; // 军团数量
@prop({ required: true, default: 0 })
memberCnt: number; // 玩家人数
@prop({ required: true, default: 0 })
leagueCe: number; // 联军总战力
@prop({ required: true, default: false })
isAuto: boolean; // 是否是自动创建的
@prop({ required: true, default: 1 })
status: number; // 1-健在 0-解散
@prop({ required: true, default: 1 })
type: number; // 1-单服 2-跨服
@prop({ required: true, default: 1 })
serverId: number; // 服务器id
@prop({ required: true, default: [], type: Member, _id: false })
members: Member[];
public static async checkName(name: string) {
const result = await GVGLeagueModel.exists({ name, status: 1 });
return result;
}
public static async createLeague(guild: GuildType, params: GVGLeagueUpdate) {
const { code, name, memberCnt, leader, guildCe, members } = guild;
const doc = new GVGLeagueModel();
const leagueCode = genCode(6);
let _leader = <RoleType>leader;
let _members = members.map(roleId => ({ roleId, auth: _leader.roleId == roleId? LEAGUE_AUTH.LEADER: LEAGUE_AUTH.MEMBER }));
const update = Object.assign(doc.toJSON(), { guildCodes: [code], name: `${name}联军`, guildCnt: 1, memberCnt, isAuto: true, leagueCe: guildCe, leader: _leader?._id, members: _members, leagueCode }, params);
delete update._id;
const result: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ guildCodes: code, status: 1 }, { $setOnInsert: update }, { upsert: true, new: true })
.select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 })
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.lean();
return result;
}
public static async findLeagueByGuild(guildCode: string) {
const league: GVGLeagueType = await GVGLeagueModel.findOne({ guildCodes: guildCode, status: 1 })
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.lean();
return league
}
public static async findByCondition(type: number, serverIds: number[], page: number, name: string) {
let query = {
status: 1, type, serverId: { $in: serverIds }
};
if(name) {
query['name'] = { $regex: new RegExp(name, 'i') };
}
const league: GVGLeagueType[] = await GVGLeagueModel.find(query)
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.skip((page - 1) * 30).limit(30)
.lean();
return league
}
public static async findByCode(leagueCode: string) {
const league: GVGLeagueType = await GVGLeagueModel.findOne({ leagueCode, status: 1 })
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.lean();
return league
}
public static async findByCodes(leagueCodes: string[]) {
const leagues: GVGLeagueType[] = await GVGLeagueModel.find({ leagueCode: { $in: leagueCodes }, status: 1 })
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.lean();
return leagues
}
public static async joinGuild(leagueCode: string, guild: GuildType) {
const { code, memberCnt, leader, guildCe, members } = guild;
let _leader = <RoleType>leader;
let _members = members.map(roleId => ({ roleId, auth: _leader.roleId == roleId? LEAGUE_AUTH.SUB_LEADER: LEAGUE_AUTH.MEMBER }));
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 },
{ $push: { guildCodes: code, members: { $each: _members } }, $inc: { guildCnt: 1, memberCnt: memberCnt, leagueCe: guildCe }
}, { new: true }).lean();
return league
}
public static async findAllLeague() {
const leagues: { leagueCode: string, memberCnt: number }[] = await GVGLeagueModel.aggregate([
{ $match: { status: 1 } },
{ $project: { leagueCode: 1, memberCnt: 1 } }
]);
return leagues;
}
public static async quitGuild(leagueCode: string, guild: GuildType) {
const { code, memberCnt, members, guildCe } = guild;
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 },
{ $pull: { guildCodes: code, members: { roleId: { $in: members } } }, $inc: { guildCnt: -1, memberCnt: -memberCnt, leagueCe: -guildCe }
}, { new: true }).lean();
return league
}
public static async dismiss(leagueCode: string) {
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $set: { status: 0 }}, { new: true }).lean();
return league
}
public static async abdicate(leagueCode: string, fromRoleId: string, toRoleId: string, leader: string) {
let league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': fromRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.SUB_LEADER }}, { new: true }).lean();
league = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': toRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.LEADER, leader }}, { new: true }).lean();
return league
}
public static async setInfo(leagueCode: string, name: string, notice: string, icon: number) {
let updateInfo: GVGLeagueUpdate = {};
if(name != undefined) updateInfo.name = name;
if(notice != undefined) updateInfo.notice = notice;
if(icon != undefined) updateInfo.icon = icon;
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $set: updateInfo }, { new: true }).lean();
return league;
}
public static async updateCe(roleId: string, incCe: number) {
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ 'members.roleId': roleId, status: 1 }, { $inc: { leagueCe: incCe } }, { new: true }).lean();
return league;
}
public static async joinMember(leagueCode: string, roleId: string, ce: number) {
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $push: { members: { roleId, auth: LEAGUE_AUTH.MEMBER } }, $inc: { memberCnt: 1, leagueCe: ce } }, { new: true }).lean();
return league;
}
public static async quitMember(leagueCode: string, roleId: string, ce: number) {
const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $pull: { members: { roleId } }, $inc: { memberCnt: -1, leagueCe: -ce } }, { new: true }).lean();
return league;
}
public static async abdicateGuild(leagueCode: string, fromRoleId: string, toRoleId: string, leader: string) {
let league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': fromRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.MEMBER }}).lean();
const member = league.members.find(cur => cur.roleId == fromRoleId);
const updateInfo = { 'members.$.auth': member?.auth };
if(member?.auth == LEAGUE_AUTH.LEADER) updateInfo['leader'] = leader;
league = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': toRoleId }, { $set: updateInfo }, { new: true }).lean();
return league
}
}
export const GVGLeagueModel = getModelForClass(GVGLeague);
export interface GVGLeagueType extends Pick<DocumentType<GVGLeague>, keyof GVGLeague> {
id: number;
};
export type GVGLeagueUpdate = Partial<GVGLeagueType>; // 将所有字段变成可选项

104
shared/db/GVGLeagueApply.ts Normal file
View File

@@ -0,0 +1,104 @@
import BaseModel from './BaseModel';
import { getModelForClass, prop, DocumentType, index, Ref } from '@typegoose/typegoose';
import GVGLeague, { GVGLeagueType } from './GVGLeague';
import Guild, { GuildType } from './Guild';
import { GVG_APPLY_TYPE } from '../consts';
@index({ leagueCode: 1, guildCode: 1, type: 1 })
export default class GVGLeagueApply extends BaseModel {
@prop({ required: true })
leagueCode: string; // 发起的联军 or 收到申请的联军
@prop({ required: true })
league: Ref<GVGLeague>;
@prop({ required: true })
guildCode: string; // 受邀的军团 or 发出申请的联军
@prop({ required: true })
guild: Ref<Guild>;
@prop({ required: true })
type: number; // 类型 1-邀请 2-申请
public static async findApplyFromGuild(guildCode: string) {
const result: GVGLeagueApplyType[] = await GVGLeagueApplyModel.find({ guildCode, type: GVG_APPLY_TYPE.APPLY }).lean();
return result;
}
public static async checkApply(leagueCode: string, guildCode: string, type: GVG_APPLY_TYPE) {
console.log('####', leagueCode, guildCode, type)
const result = await GVGLeagueApplyModel.exists({ guildCode, leagueCode,
type: type == GVG_APPLY_TYPE.ALL? { $in: [GVG_APPLY_TYPE.APPLY, GVG_APPLY_TYPE.INVITE] }: type
});
return result;
}
public static async createApply(league: GVGLeagueType, guild: GuildType, type: number) {
const result: GVGLeagueApplyType = await GVGLeagueApplyModel.findOneAndUpdate({ leagueCode: league.leagueCode, guildCode: guild.code, type }, { $set: { league: league._id, guild: guild._id, }}, { new: true, upsert: true })
.lean();
return result;
}
public static async findApplyFromLeague(leagueCode: string) {
const result: GVGLeagueApplyType[] = await GVGLeagueApplyModel.find({ leagueCode, type: GVG_APPLY_TYPE.APPLY })
.select({ _id: 0, guild: 1, guildCode: 1 })
.populate({
path: 'guild',
select: 'code icon name lv memberCnt leader guildCe +serverId',
model: 'Guild',
populate: {
path: 'leader',
select: 'roleName',
model: 'Role'
}
})
.lean();
return result;
}
public static async findInviteFromLeague(leagueCode: string) {
const result: GVGLeagueApplyType[] = await GVGLeagueApplyModel.find({ leagueCode, type: GVG_APPLY_TYPE.INVITE }).lean();
return result;
}
public static async findInviteFromGuild(guildCode: string) {
const result: GVGLeagueApplyType[] = await GVGLeagueApplyModel.find({ guildCode, type: GVG_APPLY_TYPE.INVITE })
.select({ _id: 0, guild: 1, guildCode: 1 })
.populate({
path: 'league',
// select: 'code icon name lv memberCnt leader guildCe +serverId',
model: 'GVGLeague',
populate: {
path: 'leader',
select: 'roleName',
model: 'Role'
}
})
.lean();
return result;
}
public static async deleteApply(guildCode: string, leagueCode: string) {
const n = await GVGLeagueApplyModel.deleteMany({ guildCode, leagueCode, type: GVG_APPLY_TYPE.APPLY });
return n;
}
public static async deleteAllGuildApply(guildCode: string) {
const n = await GVGLeagueApplyModel.deleteMany({ guildCode, type: GVG_APPLY_TYPE.APPLY });
return n;
}
public static async deleteInvite(guildCode: string, leagueCode: string) {
const n = await GVGLeagueApplyModel.deleteMany({ guildCode, leagueCode, type: GVG_APPLY_TYPE.INVITE });
return n;
}
}
export const GVGLeagueApplyModel = getModelForClass(GVGLeagueApply);
export interface GVGLeagueApplyType extends Pick<DocumentType<GVGLeagueApply>, keyof GVGLeagueApply> {
id: number;
};
export type GVGLeagueApplyUpdate = Partial<GVGLeagueApplyType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,82 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, } from '@typegoose/typegoose';
class Tech {
@prop({ required: true, default: 0 })
id: number;
@prop({ required: true, default: 0 })
progress: number; // 贡献
@prop({ required: true, default: 0 })
status: number; // 0-已解锁 1-已激活
}
class DonateRec {
@prop({ required: true, default: 0 })
roleId: string;
@prop({ required: true, default: 0 })
time: number;
@prop({ required: true, default: 0 })
count: number;
}
class Resource {
@prop({ required: true, default: 0 })
food: number; // 粮食
@prop({ required: true, default: 0 })
mineral: number; // 矿物
@prop({ required: true, default: 0 })
wood: number; // 木堆
}
@index({ leagueCode: 1, configId: 1 })
export default class GVGLeaguePrepare extends BaseModel {
@prop({ required: true })
configId: number; // 赛期配置id
@prop({ required: true })
leagueCode: string; // 联军
@prop({ required: true, default: 1 })
lv: number; // 等级
@prop({ required: true, default: 0 })
maxMemberCnt: number; // 进入备战期初始玩家人数
@prop({ required: true, default: 0 })
producerCnt: number; // 选择内政人数
@prop({ required: true, default: 0 })
fighterCnt: number; // 选择外政人数
@prop({ required: true, default: [], type: Tech, _id: false })
tech: Tech[]; // 千机阁
@prop({ required: true, default: [], type: DonateRec, _id: false })
donateRec: DonateRec[]; // 捐献记录
@prop({ required: true, default: {food: 0, mineral: 0, wood: 0}, type: Resource, _id: false })
resources: Resource
public static async initData(configId: number, leagueCode: string, maxMemberCnt: number) {
const doc = new GVGLeaguePrepareModel();
const update = Object.assign(doc.toJSON(), { maxMemberCnt });
delete update._id;
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $setOnInsert: update }, { upsert: true, new: true })
.select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 }).lean();
return result;
}
public static async findByLeague(configId: number, leagueCode: string) {
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOne({ configId, leagueCode }).lean();
return result;
}
}
export const GVGLeaguePrepareModel = getModelForClass(GVGLeaguePrepare);
export interface GVGLeaguePrepareType extends Pick<DocumentType<GVGLeaguePrepare>, keyof GVGLeaguePrepare> {
id: number;
};
export type GVGLeaguePrepareUpdate = Partial<GVGLeaguePrepareType>; // 将所有字段变成可选项

View File

@@ -0,0 +1,41 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
/**
* 服务器分战区
*/
@index({ time: -1, serverId: -1 })
export default class GVGServerGroup extends BaseModel {
@prop({ required: true, default: 1 })
serverId: number; // 服务器id
@prop({ required: true, default: 1 })
groupId: number; // 战区id
@prop({ required: true, default: 0 })
time: number; // 生效时间
public static async findByTime(time: number) {
const serverGroup: { serverId: number, groupId: number }[] = await GVGServerGroupModel.aggregate([
{ $match: { time: { $lte: time } } },
{ $sort: { time: -1 } },
{ $group: { _id: "$id", serverId: { $first: "$serverId" }, groupId: { $first: "$groupId" }, time: { $first: "$time" }} },
{ $sort: { _id: -1 } },
{ $project: { _id: 0, id: "$_id", serverId: "$serverId", groupId: "$groupId", time: "$time" } }
]);
return serverGroup;
}
public static async updateByServerId(serverId: number, groupId: number, time: number) {
const result: GVGServerGroupType = await GVGServerGroupModel.findOneAndUpdate({ serverId, time }, { $set: { groupId } }, { new: true, upsert: true }).lean();
return result
}
}
export let GVGServerGroupModel = getModelForClass(GVGServerGroup);
export interface GVGServerGroupType extends Pick<DocumentType<GVGServerGroup>, keyof GVGServerGroup> {
id: number;
};
export type GVGServerGroupUpdate = Partial<GVGServerGroupType>; // 将所有字段变成可选项

81
shared/db/GVGUserData.ts Normal file
View File

@@ -0,0 +1,81 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, } from '@typegoose/typegoose';
class ActiveRec {
@prop({ required: true, default: 1 })
id: number; // 1-内政令消耗 2-征战令消耗 3-科技树捐献
@prop({ required: true, default: 0 })
count: number;
@prop({ required: true, default: 0 })
time: number;
}
class Box {
@prop({ required: true, default: 0 })
score: number; // 宝箱积分
@prop({ required: true, default: [], type: Number })
received: number[]; // 领取记录
}
@index({ leagueCode: 1, roleId: 1, configId: 1, status: 1 })
export default class GVGUserData extends BaseModel {
@prop({ required: true })
roleId: string; // 玩家
@prop({ required: true })
configId: number; // 赛季信息
@prop({ required: true })
leagueCode: string; // 所属联军
@prop({ required: true, default: 0 })
job: number; // 职能 1-贤臣 2-猛将
// 备战期
@prop({ required: true, default: 0 })
active: number; // 活跃度
@prop({ required: true, default: 0, type: ActiveRec, _id: false })
activeRec: ActiveRec[]; // 活跃度记录
@prop({ required: true, default: 0 })
receivedLv: number; // 领取到的等级奖励
@prop({ required: true, default: 0 })
receiveCurrencyTime: number; // 领取内政令&征战令时间
@prop({ required: true, default: { score: 0, received: []}, type: Box, _id: false })
box: Box;
@prop({ required: true, default: 0 })
sendFightRewardTime: number; // 发送征战奖励的时间
// 激战期
@prop({ required: true, default: 0 })
battleStatus: number; // 1-被挑战中 0-可被挑战
@prop({ required: true, default: 0 })
area: number; // 所处区域 1-进攻北站 2-混战 3-据点 4-防守备战
@prop({ required: true, default: 0 })
protectTime: number; // 保护期
public static async findByRole(configId: number, leagueCode: string, roleId: string) {
const result: GVGUserDataType = await GVGUserDataModel.findOneAndUpdate({ configId, leagueCode, roleId }, {}, { new: true, upsert: true}).lean();
return result;
}
public static async findByRoles(configId: number, leagueCode: string, roleIds: string[]) {
const result: GVGUserDataType[] = await GVGUserDataModel.find({ configId, leagueCode, roleId: { $in: roleIds } }).lean();
return result;
}
}
export const GVGUserDataModel = getModelForClass(GVGUserData);
export interface GVGUserDataType extends Pick<DocumentType<GVGUserData>, keyof GVGUserData> {
id: number;
};
export type GVGUserDataUpdate = Partial<GVGUserDataType>; // 将所有字段变成可选项

37
shared/db/GVGUserItem.ts Normal file
View File

@@ -0,0 +1,37 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, } from '@typegoose/typegoose';
import { nowSeconds } from '../pubUtils/timeUtil';
@index({ leagueCode: 1, roleId: 1, configId: 1, status: 1 })
export default class GVGUserItem extends BaseModel {
@prop({ required: true })
roleId: string; // 玩家
@prop({ required: true })
leagueCode: string; // 联军id
@prop({ required: true })
configId: number; // 赛期
@prop({ required: true })
id: number; // 道具: 包括 种子、铲子、斧子
@prop({ required: true, default: 0 })
count: number; // 数量
@prop({ required: true, default: 0 })
expireTime: number;
public static async findByRole(configId: number, leagueCode: string, roleId: string) {
const result: GVGUserItemType[] = await GVGUserItemModel.find({ configId, leagueCode, roleId, expireTime: { $gte: nowSeconds() } }, { _id: 0 }).lean();
return result;
}
}
export const GVGUserItemModel = getModelForClass(GVGUserItem);
export interface GVGUserItemType extends Pick<DocumentType<GVGUserItem>, keyof GVGUserItem> {
id: number;
};
export type GVGUserItemUpdate = Partial<GVGUserItemType>; // 将所有字段变成可选项

41
shared/db/GVGUserTask.ts Normal file
View File

@@ -0,0 +1,41 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, } from '@typegoose/typegoose';
import { getZeroPointD } from '../pubUtils/timeUtil';
@index({ leagueCode: 1, roleId: 1, configId: 1, status: 1 })
export default class GVGUserTask extends BaseModel {
@prop({ required: true, default: '' })
roleId: string; // 玩家
@prop({ required: true, default: '' })
leagueCode: string; // 联军id
@prop({ required: true, default: 0 })
configId: number; // 赛期
@prop({ required: true, default: 0 })
id: number; // 任务id
@prop({ required: true, default: 0 })
count: number; // 1-已达成
@prop({ required: true, default: 0 })
status: number; // 1-未领取 2-已领取
@prop({ required: true, default: 0 })
createTime: number; // 1-未领取 2-已领取
public static async findByRole(configId: number, leagueCode: string, roleId: string) {
let today = getZeroPointD();
const result: GVGUserTaskType[] = await GVGUserTaskModel.find({ configId, leagueCode, roleId, createdAt: { $gte: today } }, { _id: 0, id: 1, count: 1, status: 1 }).lean();
return result;
}
}
export const GVGUserTaskModel = getModelForClass(GVGUserTask);
export interface GVGUserTaskType extends Pick<DocumentType<GVGUserTask>, keyof GVGUserTask> {
id: number;
};
export type GVGUserTaskUpdate = Partial<GVGUserTaskType>; // 将所有字段变成可选项

View File

@@ -111,6 +111,9 @@ export default class Guild extends BaseModel {
@prop({ required: true })
sdkMark: boolean; // 37sdk标记有问题
@prop({ required: true, default: '' })
leagueCode: string; // 参与联军
public static async createGuild(params: { guildCode: string, name: string, icon: number, notice: string }, role: RoleType, serverId: number) {
const doc = new GuildModel();
const update = Object.assign(doc.toJSON(), params, { leader: role._id, members: [role.roleId], guildCe: role.ce, serverId, lvUpdateTime: nowSeconds() });
@@ -175,7 +178,7 @@ export default class Guild extends BaseModel {
if(serverId) condition.serverId = serverId;
const result: GuildType = await GuildModel.findOne(condition)
.select(select)
.populate('leader', {roleId: 1, roleName: 1, frame: 1, head: 1, spine: 1, frames: 1, heads: 1, spines: 1, lv: 1, quitTime: 1, ce: 1, title: 1, _id: 0}, 'Role')
.populate('leader', {roleId: 1, roleName: 1, frame: 1, head: 1, spine: 1, frames: 1, heads: 1, spines: 1, lv: 1, quitTime: 1, ce: 1, title: 1}, 'Role')
.lean({ getters: true, virtuals: true });
return result;
}
@@ -315,6 +318,41 @@ export default class Guild extends BaseModel {
const result = await GuildModel.count(searchObj);
return result;
}
public static async joinLeague(guildCode: string, leagueCode: string) {
const result: GuildType = await GuildModel.findOneAndUpdate({ code: guildCode }, { $set: { leagueCode } }, { new: true }).lean();
return result
}
public static async findGuildsForGVG(page: number, name: string, serverIds: number[]) {
let query: any = { status: GUILD_STATUS.RUNNING, lv: { $gte: 3 }, leagueCode: '', serverId: { $in: serverIds } };
if(name) {
query['name'] = { $regex: new RegExp(name, 'i') }
}
const result: GuildType[] = await GuildModel.find(query)
.populate('leader', { roleId: 1, roleName: 1, _id: 0 }, 'Role')
.skip((page - 1) * 30).limit(30)
.lean();
return result;
}
public static async findByCodes(codes: string[]) {
const result: GuildType[] = await GuildModel.find({ status: GUILD_STATUS.RUNNING, code: { $in: codes } })
.select('+serverId')
.populate('leader', { roleId: 1, roleName: 1, _id: 0 }, 'Role')
.lean();
return result;
}
public static async quitFromLeague(guildCode: string, leagueCode: string, select = null) {
const result: GuildType = await GuildModel.findOneAndUpdate({ code: guildCode, leagueCode }, { $set: { leagueCode: '' } }, { new: true }).select(select).lean();
return result;
}
public static async dissmissLeague(leagueCode: string) {
const result: GuildType = await GuildModel.findOneAndUpdate({ leagueCode }, { $set: { leagueCode: '' }}).lean();
return result;
}
}
export const GuildModel = getModelForClass(Guild);

View File

@@ -0,0 +1,224 @@
import { RoleType } from "../../db/Role";
import { GVGLeagueType } from "../../db/GVGLeague";
import { GVGLeaguePrepareType } from "../../db/GVGLeaguePrepare";
import { GVGUserDataType } from "../../db/GVGUserData";
import { GuildType } from "../../db/Guild";
class LeagueLeaderInfo {
name: string; // 盟主名
serverId: number; // 盟主所处小区
serverName: number; // 盟主所处小区名
constructor(leader: RoleType, serverNames: any) {
this.name = leader.roleName;
this.serverId = leader.serverId;
this.serverName = serverNames[this.serverId];
}
}
class GVGItem {
id: number;
count: number;
expireTime: number; // 过期时间
}
class LeaguePlayerData {
auth: number = 3; // 我的权限 1-盟主 2-副盟主 3-平民
job: number = 0; // 我的职能1-贤臣 2-猛将 0-未选择
canPrepare: boolean = false; // 是否可以使用整备期模块,组建期过后加入的玩家,当天的整备模块不可参与
canChooseJob: boolean = true; // 是否可以选择职能,团内选择职业的人数达到最大人数了,已经不可再选职位了
items: GVGItem[] = []; // 持有的道具,包括两种令、战功和种子
// 奖励相关
receivedLv: number = 0; // 奖励领到几级
tasks: GVGTask[] = []; // 如果没有达成的任务就不放在这个数组里面
}
class LeagueResource {
food: number = 0; // 粮食
mineral: number = 0; // 矿物
wood: number = 0; // 木堆
}
class GVGTask {
id: number; // 任务id
count: number;
status: number; // 状态 0-未领取 1-已领取
}
export class GVGMainData {
configId: number = 0; // 赛期
period: number = 1; // 当前是什么期 1-组建期 2-备战期 3-激战期
countdownTime: number = 0; // 这个周期结束时间10位时间戳单位秒
type: number = 1; // 1-单服 2-跨服
hasLeague: boolean = false; // 是否拥有联军
// 左侧联军信息
leagueCode: string; // 联军唯一code
leader: LeagueLeaderInfo;
name: string; // 联军名
icon: number; // 图标
lv: number; // 联军等级
notice: string; // 公告
guildCnt: number; // 军团数量
memberCnt: number; // 玩家人数
teamCnt: number; // 里面的玩家的队伍数 TODO
leagueCe: number; // 联军内所有人总战力
// 个人信息
myInfo: LeaguePlayerData = new LeaguePlayerData();
// 激战期相关,城池背景
cities: number[] = []; // 占领的城池id
// 内政相关
resources: LeagueResource = new LeagueResource(); // 联盟的物资
activeTech: number[] = []; // 已激活了的科技树的id
sumTime: number = 0; // 今日贡献结算时间 10位时间戳
constructor(configId: number, period: number, countdownTime: number, type: number) {
this.configId = configId;
this.period = period;
this.countdownTime = countdownTime;
this.type = type;
}
setLeague(league: GVGLeagueType, serverNames: any) {
if(!league) return;
this.hasLeague = true;
let leader = <RoleType>league.leader;
this.leader = new LeagueLeaderInfo(leader, serverNames);
this.name = league.name;
this.icon = league.icon;
this.notice = league.notice;
this.guildCnt = league.guildCnt;
this.memberCnt = league.memberCnt;
this.leagueCe = league.leagueCe;
}
setLeagueParpare(leaguePrepare: GVGLeaguePrepareType) {
if(!leaguePrepare) return;
this.lv = leaguePrepare.lv;
this.resources = leaguePrepare.resources;
this.activeTech = leaguePrepare.tech.filter(cur => cur.status == 1).map(cur => cur.id);
}
setPlayerInfo(userData: GVGUserDataType, auth: number, canPrepare: boolean, canChooseJob: boolean, items: GVGItem[], tasks: GVGTask[]) {
this.myInfo.auth = auth;
this.myInfo.canPrepare = canPrepare;
this.myInfo.canChooseJob = canChooseJob;
this.myInfo.items = items;
if(userData) {
this.myInfo.job = userData?.job||0;
this.myInfo.receivedLv = userData?.receivedLv||0;
}
this.myInfo.tasks = tasks;
}
}
export class LeagueListInfo {
leagueCode: string; // 联军唯一id
name: string; // 联军名
icon: number; // icon
memberCnt: number; // 玩家人数
guildCnt: number; // 组成军团名
leaderName: string; // 大将军的姓名
leaderServerName: string; // 大将军所处小区名
leagueCe: number; // 联军战力
hasApply: boolean = false; // 是否申请过了
constructor(league: GVGLeagueType, serverNames: any) {
if(!league) return;
this.leagueCode = league.leagueCode;
this.name = league.name;
this.icon = league.icon;
this.memberCnt = league.memberCnt;
this.guildCnt = league.guildCnt;
this.leaderName = (<RoleType>league.leader).roleName;
this.leaderServerName = serverNames[(<RoleType>league.leader).serverId];
this.leagueCe = league.leagueCe;
}
setHasApply(hasApply: boolean) {
this.hasApply = hasApply;
}
}
export class LeagueSimpleInfo extends LeagueListInfo {
notice: string; // 公共
cities: number[] = []; // 占领的城池
constructor(league: GVGLeagueType, serverNames: any) {
super(league, serverNames);
if(!league) return;
this.notice = league.notice;
}
setCities(cities: number[]) {
this.cities = cities;
}
}
export class LeagueGuildInfo {
guildCode: string; // 军团唯一id
name: string; // 军团名
serverName: string; // 区服名
lv: number; // 军团等级
memberCnt: number; // 人数
leaderName: string; // 大将军的姓名
guildCe: number; // 军团战力
hasInvited: boolean; // 是否邀请过了
constructor(guild: GuildType, serverNames: any) {
if(!guild) return;
this.guildCode = guild.code;
this.name = guild.name;
this.serverName = serverNames[guild.serverId];
this.lv = guild.lv;
this.memberCnt = guild.memberCnt;
let leader = <RoleType>guild.leader;
this.leaderName = leader.roleName;
this.guildCe = guild.guildCe;
}
setHasInvited(hasInvited: boolean) {
this.hasInvited = hasInvited;
}
}
export class LeagueMemberListInfo {
roleId: string; // 玩家id
roleName: string; // 玩家名
lv: number; // 玩家等级
head: number; // 玩家头像
frame: number; // 玩家相框
guildName: string; // 所处军团名
serverName: string; // 所处小区名
job: number = 0; // 官职 1-贤臣 2-猛将
auth: number = 0; // 官职
active: number = 0; // 活跃
ce: number; // 玩家战力
isOnline: boolean; // 是否在线
quitTime: number; // 离线时间
constructor(role: RoleType, serverNames: any) {
if(!role) return;
this.roleId = role.roleId;
this.roleName = role.roleName;
this.lv = role.lv;
this.head = role.head;
this.frame = role.frame;
this.guildName = role.guildName;
this.serverName = serverNames[role.serverId];
this.ce = role.ce;
this.quitTime = role.quitTime;
this.isOnline = role.quitTime == role.loginTime;
}
setByUserData(data: GVGUserDataType) {
if(!data) return;
this.active = data.active;
this.job = data.job;
}
setAuth(auth: number) {
this.auth = auth;
}
}

View File

@@ -118,6 +118,7 @@ import { dicArtifactSeid, loadArtifactSeid } from "./dictionary/DicArtifactSeid"
import { DicArtifact } from "./dictionary/DicArtifact";
import { DicArtifactQuality } from "./dictionary/DicArtifactQuality";
import { dicGiftPackagePlan, loadGiftPackagePlan } from "./dictionary/DicGiftPackagePlan";
import { dicGVGPeriod, loadGVGPeriod } from './dictionary/DicGVGPeriod';
export const gameData = {
daily: dicDaily,
@@ -295,6 +296,7 @@ export const gameData = {
artifactQualityPlan: dicArtifactQualityPlan,
artifactSeid: dicArtifactSeid,
artifactByGroupAndQuality: dicArtifactsByGroup,
gvgPeriod: dicGVGPeriod,
};
// 在此提供一些原先在gamedata中提供的方法以便更方便获取gameData数据
@@ -1262,6 +1264,7 @@ function loadDatas() {
loadArtifactQuality();
loadArtifactQualityPlan();
loadArtifactSeid();
loadGVGPeriod();
}
// 重载dicParam

View File

@@ -0,0 +1,42 @@
// GVG周期表
import { FILENAME } from '../../consts'
import { parseNumberList, readFileAndParse } from '../util'
export interface DicGVGPeriod {
// 1-组建期 2-备战期 3-激战期
readonly periodType: number;
// 星期几 1-7
readonly day: number[];
// 星期几 1-7
readonly startDay: number;
// HH:mm, 组建期备战期填05:00。激战期填20:40
readonly startHour: number;
readonly startMinute: number;
readonly startSecond: number;
// HH:mm组建期填截止创建联军时间备战期填22:00激战期填21:40
readonly endHour: number;
readonly endMinute: number;
readonly endSecond: number;
}
export const dicGVGPeriod = new Map<number, DicGVGPeriod>();
export function loadGVGPeriod() {
dicGVGPeriod.clear();
let arr = readFileAndParse(FILENAME.DIC_GVG_PERIOD);
arr.forEach(o => {
o.day = parseNumberList(o.day);
o.startDay = o.day[0];
let startTime = o.startTime.split(':');
o.startHour = parseInt(startTime[0]);
o.startMinute = parseInt(startTime[1]);
o.startSecond = parseInt(startTime[2]);
let endTime = o.endTime.split(':');
o.endHour = parseInt(endTime[0]);
o.endMinute = parseInt(endTime[1]);
o.endSecond = parseInt(endTime[2]);
dicGVGPeriod.set(o.periodType, o);
});
arr = undefined;
}

View File

@@ -1,21 +1,22 @@
import { REFRESH_TIME, TIME_OUTPUT_TYPE, SHOP_REFRESH_TYPE } from '../consts';
import { isDebugTime } from './sdkUtil';
export const WEEK_TO_MS = 7 * 24 * 60 * 60 * 1000;
export const WEEK_TO_SECOND = 7 * 24 * 60 * 60;
export const DAY_TO_HOUR = 24;
export const DAY_TO_SECOND = 24 * 60 * 60;
export const DAY_TO_MS = 24 * 60 * 60 * 1000;
export const HOUR_TO_MINUTE = 60;
export const HOUR_TO_SECOND = 60 * 60;
export const HOUR_TO_MS = 60 * 60 * 1000;
export const MINUTE_TO_MS = 60 * 1000;
export const SECOND_TO_MS = 1000;
/**
* 时间
* @class
*/
class Time {
WEEK_TO_MS = 7 * 24 * 60 * 60 * 1000;
DAY_TO_HOUR = 24;
DAY_TO_SECOND = 24 * 60 * 60;
DAY_TO_MS = 24 * 60 * 60 * 1000;
HOUR_TO_MINUTE = 60;
HOUR_TO_SECOND = 60 * 60;
HOUR_TO_MS = 60 * 60 * 1000;
MINUTE_TO_MS = 60 * 1000;
SECOND_TO_MS = 1000;
now: Date; // 当前时间
time: Date; // 处理时间原料
outputType: number; // 输出格式
@@ -106,7 +107,7 @@ class Time {
if(time >= t) {
return t;
} else {
return new Date(t.getTime() - this.DAY_TO_MS);
return new Date(t.getTime() - DAY_TO_MS);
}
}
@@ -187,7 +188,7 @@ class Time {
let cur = this._getDayZeroPoint(curDate);
let pre = this._getDayZeroPoint(preDate);
return Math.floor((cur.getTime() - pre.getTime()) / this.DAY_TO_MS)
return Math.floor((cur.getTime() - pre.getTime()) / DAY_TO_MS)
}
/**
@@ -256,7 +257,7 @@ class Time {
if(this.time >= t) {
return this._returnResult(t);
} else {
return this._returnResult(t.getTime() - this.WEEK_TO_MS);
return this._returnResult(t.getTime() - WEEK_TO_MS);
}
}
@@ -287,10 +288,10 @@ class Time {
public getBeforeDayWithHour(day: number = 0, hour = REFRESH_TIME, minute = 0, seconds = 0) {
let t = this._setHour(this.time.getTime(), hour, minute, seconds);
if(this.time >= t) {
let timestamp = t.getTime() - day * this.DAY_TO_MS;
let timestamp = t.getTime() - day * DAY_TO_MS;
return this._returnResult(timestamp);
} else {
let timestamp = t.getTime() - (day + 1) * this.DAY_TO_MS;
let timestamp = t.getTime() - (day + 1) * DAY_TO_MS;
return this._returnResult(timestamp);
}
}
@@ -306,10 +307,10 @@ class Time {
let t = this._setHour(this.time.getTime(), hour, minute, seconds, 0);
// console.log(t.getTime(), this.time.getTime());
if(this.time.getTime() > t.getTime()) {
let timestamp = t.getTime() + (day + 1) * this.DAY_TO_MS;
let timestamp = t.getTime() + (day + 1) * DAY_TO_MS;
return this._returnResult(timestamp);
} else {
let timestamp = t.getTime() + day * this.DAY_TO_MS;
let timestamp = t.getTime() + day * DAY_TO_MS;
return this._returnResult(timestamp);
}
}
@@ -323,7 +324,7 @@ class Time {
*/
public getBeforeDayAndSetHour(day: number = 0, hour = REFRESH_TIME, minute = 0, seconds = 0) {
let t = this._setHour(this.time.getTime(), hour, minute, seconds);
let timestamp = t.getTime() - day * this.DAY_TO_MS;
let timestamp = t.getTime() - day * DAY_TO_MS;
return this._returnResult(timestamp);
}
@@ -336,7 +337,7 @@ class Time {
*/
public getAfterDayAndSetHour(day: number = 0, hour = REFRESH_TIME, minute = 0, seconds = 0) {
let t = this._setHour(this.time.getTime(), hour, minute, seconds);
let timestamp = t.getTime() + day * this.DAY_TO_MS;
let timestamp = t.getTime() + day * DAY_TO_MS;
return this._returnResult(timestamp);
}
@@ -345,7 +346,7 @@ class Time {
* @param day 几天前
*/
public getBeforeDay(day: number) {
let timestamp = this.time.getTime() - day * this.DAY_TO_MS;
let timestamp = this.time.getTime() - day * DAY_TO_MS;
return this._returnResult(timestamp);
}
@@ -354,7 +355,7 @@ class Time {
* @param day 几天后
*/
public getAfterDay(day: number) {
let timestamp = this.time.getTime() + day * this.DAY_TO_MS;
let timestamp = this.time.getTime() + day * DAY_TO_MS;
return this._returnResult(timestamp);
}
@@ -363,7 +364,7 @@ class Time {
* @param hour 几小时前
*/
public getBeforeHour(hour: number) {
let timestamp = this.time.getTime() - hour * this.HOUR_TO_MS;
let timestamp = this.time.getTime() - hour * HOUR_TO_MS;
return this._returnResult(timestamp);
}
@@ -372,7 +373,7 @@ class Time {
* @param hour 几分钟前
*/
public getBeforeMinute(minute: number) {
let timestamp = this.time.getTime() - minute * this.MINUTE_TO_MS;
let timestamp = this.time.getTime() - minute * MINUTE_TO_MS;
return this._returnResult(timestamp);
}
@@ -393,7 +394,7 @@ class Time {
public getAfterDayByGap(preDate: Date, day: number) {
let gap = this._getDayGap(preDate, this.time);
let n = Math.floor(gap / day);
return this._returnResult(preDate.getTime() + n * day * this.DAY_TO_MS);
return this._returnResult(preDate.getTime() + n * day * DAY_TO_MS);
}
/**
@@ -401,7 +402,7 @@ class Time {
* @param day day天以内
*/
public checkDay(day: number = 1) {
if (this.time.getTime() - this.now.getTime() <= day * this.DAY_TO_MS) {
if (this.time.getTime() - this.now.getTime() <= day * DAY_TO_MS) {
return true;
}
return false;

View File

@@ -922,5 +922,19 @@
"name": "更新隐藏数据",
"module": "sys",
"type": "update"
},
{
"id": 133,
"api": "gm.gmHandler.updateGVGServerGroup",
"name": "更新GVG战区分配",
"module": "sys",
"type": "update"
},
{
"id": 134,
"api": "gm.gmHandler.updateGVGConfig",
"name": "更新GVG时间",
"module": "sys",
"type": "update"
}
]

View File

@@ -0,0 +1,86 @@
[
{
"id": 1,
"Type": 1,
"boxPoint": 100000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 2,
"Type": 1,
"boxPoint": 150000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 3,
"Type": 1,
"boxPoint": 200000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 4,
"Type": 1,
"boxPoint": 250000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 5,
"Type": 1,
"boxPoint": 300000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 6,
"Type": 1,
"boxPoint": 350000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 7,
"Type": 2,
"boxPoint": 50000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 8,
"Type": 2,
"boxPoint": 100000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 9,
"Type": 2,
"boxPoint": 150000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 10,
"Type": 2,
"boxPoint": 200000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 11,
"Type": 2,
"boxPoint": 250000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
},
{
"id": 12,
"Type": 2,
"boxPoint": 300000,
"boxReward": "31002&500",
"boxLeagueReward": "12&500"
}
]

View File

@@ -0,0 +1,197 @@
[
{
"id": 1,
"name": "小麦",
"type": 1,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "10&1",
"value": 100,
"reward": "31002&5000",
"leagueReward": "12&100"
},
{
"id": 2,
"name": "玉米",
"type": 1,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&100",
"leagueConsume": "10&1",
"value": 150,
"reward": "31002&5001",
"leagueReward": "12&150"
},
{
"id": 3,
"name": "水稻",
"type": 1,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&200",
"leagueConsume": "10&1",
"value": 200,
"reward": "31002&5002",
"leagueReward": "12&150"
},
{
"id": 4,
"name": "普通铲子",
"type": 2,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "10&2",
"value": 15,
"reward": "31002&5003",
"leagueReward": "12&200"
},
{
"id": 5,
"name": "中级铲子",
"type": 2,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&100",
"leagueConsume": "10&2",
"value": 20,
"reward": "31002&5004",
"leagueReward": "12&300"
},
{
"id": 6,
"name": "高级铲子",
"type": 2,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&200",
"leagueConsume": "10&2",
"value": 30,
"reward": "31002&5005",
"leagueReward": "12&300"
},
{
"id": 7,
"name": "石斧",
"type": 3,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "10&2",
"value": 25,
"reward": "31002&5006",
"leagueReward": "12&200"
},
{
"id": 8,
"name": "铜斧",
"type": 3,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&100",
"leagueConsume": "10&2",
"value": 30,
"reward": "31002&5007",
"leagueReward": "12&300"
},
{
"id": 9,
"name": "铁斧",
"type": 3,
"refreshType": 1,
"image_id": "&",
"info": "&",
"consume": "31002&200",
"leagueConsume": "10&2",
"value": 40,
"reward": "31002&5008",
"leagueReward": "12&300"
},
{
"id": 10,
"name": "内政令",
"type": 4,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
},
{
"id": 11,
"name": "征战令",
"type": 4,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
},
{
"id": 12,
"name": "战功",
"type": 5,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
},
{
"id": 13,
"name": "复活令",
"type": 6,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
},
{
"id": 14,
"name": "匕首",
"type": 6,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
},
{
"id": 15,
"name": "箭塔",
"type": 6,
"refreshType": 2,
"image_id": "&",
"info": "&",
"consume": "&",
"leagueConsume": "&",
"value": 0,
"reward": "&",
"leagueReward": "&"
}
]

View File

@@ -0,0 +1,82 @@
[
{
"id": 1,
"lv": 1,
"food": 2000,
"mineral": 1000,
"wood": 1000,
"reward": "31002&500|31001&10000"
},
{
"id": 2,
"lv": 2,
"food": 2200,
"mineral": 1100,
"wood": 1100,
"reward": "31002&500|31001&10000"
},
{
"id": 3,
"lv": 3,
"food": 2400,
"mineral": 1200,
"wood": 1200,
"reward": "31002&500|31001&10000"
},
{
"id": 4,
"lv": 4,
"food": 2600,
"mineral": 1300,
"wood": 1300,
"reward": "31002&500|31001&10000"
},
{
"id": 5,
"lv": 5,
"food": 2800,
"mineral": 1400,
"wood": 1400,
"reward": "31002&500|31001&10000"
},
{
"id": 6,
"lv": 6,
"food": 3000,
"mineral": 1500,
"wood": 1500,
"reward": "31002&500|31001&10000"
},
{
"id": 7,
"lv": 7,
"food": 3200,
"mineral": 1600,
"wood": 1600,
"reward": "31002&500|31001&10000"
},
{
"id": 8,
"lv": 8,
"food": 3400,
"mineral": 1700,
"wood": 1700,
"reward": "31002&500|31001&10000"
},
{
"id": 9,
"lv": 9,
"food": 3600,
"mineral": 1800,
"wood": 1800,
"reward": "31002&500|31001&10000"
},
{
"id": 10,
"lv": 10,
"food": 3800,
"mineral": 1900,
"wood": 1900,
"reward": "31002&500|31001&10000"
}
]

View File

@@ -0,0 +1,20 @@
[
{
"periodType": 1,
"day": "7&",
"startTime": "05:00:00",
"endTime": "05:00:00"
},
{
"periodType": 2,
"day": "1&2&3&4&5",
"startTime": "05:00:00",
"endTime": "22:00:00"
},
{
"periodType": 3,
"day": "6&",
"startTime": "20:40:00",
"endTime": "21:40:00"
}
]

View File

@@ -0,0 +1,332 @@
[
{
"id": 1,
"name": "1级农庄",
"lv": 1,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "1&3",
"value": "10",
"sum": 100
},
{
"id": 2,
"name": "2级农庄",
"lv": 2,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "1&5",
"value": "120",
"sum": 100
},
{
"id": 3,
"name": "3级农庄",
"lv": 3,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "1&6",
"value": "130",
"sum": 100
},
{
"id": 4,
"name": "4级农庄",
"lv": 4,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "2&6",
"value": "140",
"sum": 100
},
{
"id": 5,
"name": "5级农庄",
"lv": 5,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "2&10",
"value": "150",
"sum": 100
},
{
"id": 6,
"name": "6级农庄",
"lv": 6,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "2&12",
"value": "160",
"sum": 100
},
{
"id": 7,
"name": "7级农庄",
"lv": 7,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "3&6",
"value": "170",
"sum": 100
},
{
"id": 8,
"name": "8级农庄",
"lv": 8,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "3&10",
"value": "180",
"sum": 100
},
{
"id": 9,
"name": "9级农庄",
"lv": 9,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "3&12",
"value": "190",
"sum": 100
},
{
"id": 10,
"name": "10级农庄",
"lv": 10,
"type": 1,
"limit": "X名武将X星",
"limitType": 1,
"limitParams": "5&12",
"value": "1100",
"sum": 100
},
{
"id": 11,
"name": "1级矿山",
"lv": 1,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&1",
"value": "11001021505315010",
"sum": 200
},
{
"id": 12,
"name": "2级矿山",
"lv": 2,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&2",
"value": "11001021505315010",
"sum": 200
},
{
"id": 13,
"name": "3级矿山",
"lv": 3,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&3",
"value": "11001021505315010",
"sum": 200
},
{
"id": 14,
"name": "4级矿山",
"lv": 4,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&4",
"value": "11001021505315010",
"sum": 200
},
{
"id": 15,
"name": "5级矿山",
"lv": 5,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&5",
"value": "11001021505315010",
"sum": 200
},
{
"id": 16,
"name": "6级矿山",
"lv": 6,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "1&6",
"value": "11001021505315010",
"sum": 200
},
{
"id": 17,
"name": "7级矿山",
"lv": 7,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "4&3",
"value": "11001021505315010",
"sum": 200
},
{
"id": 18,
"name": "8级矿山",
"lv": 8,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "4&4",
"value": "11001021505315010",
"sum": 200
},
{
"id": 19,
"name": "9级矿山",
"lv": 9,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "4&5",
"value": "11001021505315010",
"sum": 200
},
{
"id": 20,
"name": "10级矿山",
"lv": 10,
"type": 2,
"limit": "X件装备X星",
"limitType": 2,
"limitParams": "4&6",
"value": "215010320010415010",
"sum": 200
},
{
"id": 21,
"name": "1级木堆",
"lv": 1,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 100000,
"value": "3100",
"sum": 100
},
{
"id": 22,
"name": "2级木堆",
"lv": 2,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 200000,
"value": "3150",
"sum": 100
},
{
"id": 23,
"name": "3级木堆",
"lv": 3,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 300000,
"value": "3200",
"sum": 100
},
{
"id": 24,
"name": "4级木堆",
"lv": 4,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 400000,
"value": "3250",
"sum": 100
},
{
"id": 25,
"name": "5级木堆",
"lv": 5,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 500000,
"value": "3300",
"sum": 100
},
{
"id": 26,
"name": "6级木堆",
"lv": 6,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 600000,
"value": "3350",
"sum": 100
},
{
"id": 27,
"name": "7级木堆",
"lv": 7,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 700000,
"value": "3400",
"sum": 100
},
{
"id": 28,
"name": "8级木堆",
"lv": 8,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 800000,
"value": "3450",
"sum": 100
},
{
"id": 29,
"name": "9级木堆",
"lv": 9,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 900000,
"value": "3500",
"sum": 100
},
{
"id": 30,
"name": "10级木堆",
"lv": 10,
"type": 3,
"limit": "最强6人战力达XXXX",
"limitType": 3,
"limitParams": 1000000,
"value": "3600",
"sum": 100
}
]

View File

@@ -0,0 +1,110 @@
[
{
"id": 1,
"name": "贤臣1",
"content": "资源产量提升5%",
"type": 1,
"param": "5&",
"nodeSort": 1,
"levelSeid": 0,
"levelLimit": 1,
"prepositionId": "&",
"consume": "12&5000"
},
{
"id": 2,
"name": "猛将1",
"content": "征战中原联军成员攻击提升5%",
"type": 2,
"param": "&",
"nodeSort": 1,
"levelSeid": "1001&",
"levelLimit": 1,
"prepositionId": "&",
"consume": "12&5000"
},
{
"id": 3,
"name": "贤臣2",
"content": "资源产量提升10%",
"type": 1,
"param": "10&",
"nodeSort": 2,
"levelSeid": 0,
"levelLimit": 2,
"prepositionId": "1&",
"consume": "12&5000"
},
{
"id": 4,
"name": "猛将2",
"content": "征战中原联军成员攻击提升10%",
"type": 2,
"param": "&",
"nodeSort": 2,
"levelSeid": "1001&",
"levelLimit": 2,
"prepositionId": "2&",
"consume": "12&5000"
},
{
"id": 5,
"name": "激战1",
"content": "激战期时联军成员攻击提升2%",
"type": 3,
"param": "&",
"nodeSort": 3,
"levelSeid": "1001&",
"levelLimit": 2,
"prepositionId": "3&|4&",
"consume": "12&5000"
},
{
"id": 6,
"name": "激战2",
"content": "激战期时联军成员攻击提升5%",
"type": 3,
"param": "&",
"nodeSort": 4,
"levelSeid": "1001&",
"levelLimit": 4,
"prepositionId": "5&",
"consume": "12&5000"
},
{
"id": 7,
"name": "复活1",
"content": "激战期时联军成员复活cd减少30s",
"type": 4,
"param": "30&",
"nodeSort": 5,
"levelSeid": 0,
"levelLimit": 4,
"prepositionId": "6&",
"consume": "12&5000"
},
{
"id": 8,
"name": "箭塔1",
"content": "联军中随机20名成员获得箭塔箭塔每10s给该位置所有敌军减5点耐久箭头耐久为50点",
"type": 5,
"param": "10&5&50",
"nodeSort": 6,
"levelSeid": 0,
"levelLimit": 6,
"prepositionId": "7&",
"consume": "12&5000"
},
{
"id": 9,
"name": "攻城车1",
"content": "联军中随机20名成员获得攻城车使用攻城车道具可击杀1名敌军",
"type": 6,
"param": "20&",
"nodeSort": 6,
"levelSeid": 0,
"levelLimit": 6,
"prepositionId": "7&",
"consume": "12&5000"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
[
{
"id": 1,
"rankMin": 1,
"rankMax": 2,
"rankReward": "31002&800",
"rankLeagueReward": "12&800"
},
{
"id": 2,
"rankMin": 2,
"rankMax": 3,
"rankReward": "31002&700",
"rankLeagueReward": "12&700"
},
{
"id": 3,
"rankMin": 3,
"rankMax": 5,
"rankReward": "31002&600",
"rankLeagueReward": "12&600"
},
{
"id": 4,
"rankMin": 5,
"rankMax": 10,
"rankReward": "31002&500",
"rankLeagueReward": "12&500"
},
{
"id": 5,
"rankMin": 10,
"rankMax": 50,
"rankReward": "31002&400",
"rankLeagueReward": "12&400"
},
{
"id": 6,
"rankMin": 50,
"rankMax": 60,
"rankReward": "31002&300",
"rankLeagueReward": "12&300"
},
{
"id": 7,
"rankMin": 60,
"rankMax": 70,
"rankReward": "31002&200",
"rankLeagueReward": "12&200"
},
{
"id": 8,
"rankMin": 70,
"rankMax": 80,
"rankReward": "31002&150",
"rankLeagueReward": "12&150"
},
{
"id": 9,
"rankMin": 80,
"rankMax": 100,
"rankReward": "31002&100",
"rankLeagueReward": "12&100"
},
{
"id": 10,
"rankMin": 100,
"rankMax": 0,
"rankReward": "31002&50",
"rankLeagueReward": "12&50"
}
]

View File

@@ -0,0 +1,67 @@
[
{
"id": 1,
"rankMin": 0,
"rankMax": 10,
"rangeBeforeFrom": 0,
"rangeBeforeTo": 0,
"rangeBeforeNum": 0,
"rangeAfterFrom": 0,
"rangeAfterTo": 0,
"rangeAfterNum": 0,
"topChallengeFrom": 1,
"topChallengeTo": 10
},
{
"id": 2,
"rankMin": 10,
"rankMax": 50,
"rangeBeforeFrom": 10,
"rangeBeforeTo": -1,
"rangeBeforeNum": 20,
"rangeAfterFrom": 0,
"rangeAfterTo": 0,
"rangeAfterNum": 0,
"topChallengeFrom": 1,
"topChallengeTo": 10
},
{
"id": 3,
"rankMin": 50,
"rankMax": 150,
"rangeBeforeFrom": 5,
"rangeBeforeTo": 50,
"rangeBeforeNum": 20,
"rangeAfterFrom": 50,
"rangeAfterTo": -1,
"rangeAfterNum": 5,
"topChallengeFrom": 1,
"topChallengeTo": 5
},
{
"id": 4,
"rankMin": 150,
"rankMax": 250,
"rangeBeforeFrom": 50,
"rangeBeforeTo": 150,
"rangeBeforeNum": 25,
"rangeAfterFrom": 150,
"rangeAfterTo": -1,
"rangeAfterNum": 5,
"topChallengeFrom": 0,
"topChallengeTo": 0
},
{
"id": 5,
"rankMin": 250,
"rankMax": -1,
"rangeBeforeFrom": 150,
"rangeBeforeTo": 250,
"rangeBeforeNum": 30,
"rangeAfterFrom": 0,
"rangeAfterTo": 0,
"rangeAfterNum": 0,
"topChallengeFrom": 0,
"topChallengeTo": 0
}
]

View File

@@ -0,0 +1,123 @@
[
{
"id": 1,
"vestigeId": 1,
"name": "齐都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "2&1000",
"content": "枪兵",
"position": "&"
},
{
"id": 2,
"vestigeId": 2,
"name": "楚都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "6&1000",
"content": "策士",
"position": "&"
},
{
"id": 3,
"vestigeId": 3,
"name": "燕都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "5&1000",
"content": "游侠",
"position": "&"
},
{
"id": 4,
"vestigeId": 4,
"name": "韩都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "4&1000",
"content": "弓兵",
"position": "&"
},
{
"id": 5,
"vestigeId": 5,
"name": "赵都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "3&1000",
"content": "骑兵",
"position": "&"
},
{
"id": 6,
"vestigeId": 6,
"name": "魏都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "1&1000",
"content": "步兵",
"position": "&"
},
{
"id": 7,
"vestigeId": 7,
"name": "山巅帝陵",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "1&1000",
"content": "魏国",
"position": "&"
},
{
"id": 8,
"vestigeId": 8,
"name": "崖底河泽",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "2&1000",
"content": "吴国",
"position": "&"
},
{
"id": 9,
"vestigeId": 9,
"name": "深山迷林",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "3&1000",
"content": "蜀国",
"position": "&"
},
{
"id": 10,
"vestigeId": 10,
"name": "桃源古村",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "4&1000",
"content": "群雄",
"position": "&"
},
{
"id": 11,
"vestigeId": 11,
"name": "鹿鸣幽谷",
"mapType": "1&2",
"imageName": "&",
"additionType": 3,
"additionValue": "2&1000",
"content": "女性",
"position": "&"
}
]

View File

@@ -33,6 +33,6 @@
"DEBUG_TIME": 1,
"CHECK_WORD": 1,
"CAN_PAY": 1,
"SKIP_ENCODE": 0,
"SKIP_ENCODE": 1,
"NEED_REBATE": 0
}