// GVGTeam 数据库表,存储 GVG 队伍信息 import BaseModel from "./BaseModel"; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { genCode } from "../pubUtils/util"; import { nowSeconds } from "../pubUtils/timeUtil"; import { EXTERIOR, GVG } from "../pubUtils/dicParam"; import { DicGVGAreaPoint } from "../pubUtils/dictionary/DicGVGAreaPoint"; import { InitTeamParam, SaveTeamUpdateParam } from "../domain/gvgField/gvgDb"; import { GVGHeroInfo } from "../domain/dbGeneral"; import { GVG_CATAPULT } from "../consts"; @index({ roleId: 1, index: 1 }) @index({ teamCode: 1 }) @index({ cityId: 1, leagueId: 1 }) export default class GVGTeam extends BaseModel { @prop({ required: true }) configId: number; // 赛季,每赛季在enterCity的时候检测,如果不一样就更新durability那些东西 @prop({ required: true }) roleId: string; // 玩家id @prop({ required: true }) roleName: string; // 玩家名 @prop({ required: true }) serverId: number; // 小区id @prop({ required: true }) teamCode: string; // 玩家队伍唯一标识 @prop({ required: true }) index: number; // 队伍id,1-3,玩家的第几个队伍 @prop({ required: true }) leagueCode: string; // 联军 @prop({ required: true }) leagueName: string; // 联军 @prop({ required: true }) guildCode: string; // 军团 @prop({ required: false }) areaId: number; @prop({ required: false }) cityId: number; @prop({ required: false }) pointId: number; @prop({ required: true }) head: number; // 头像 @prop({ required: true }) spine: number; // 形象 @prop({ required: true }) frame: number; // 相框 @prop({ required: true, default: 0 }) durability: number; // 耐久 @prop({ required: true, default: 0 }) maxDurability: number; // 耐久 @prop({ required: true, default: 0 }) restartTime: number; // 修整期倒计时 @prop({ required: true, default: 0 }) attackTime: number; // 进攻冷却时间 @prop({ required: true, default: 0 }) lockTime: number; // 正在被进攻中 @prop({ required: true, default: 0 }) lockTeamCode: string; // 正在被这支队伍进攻中 @prop({ required: true, default: 0 }) fromAreaId: number; // 从那个区域移动 @prop({ required: true, default: 0 }) startMoveTime: number; @prop({ required: true, default: 0 }) moveCdTime: number; // 移动冷却时间 @prop({ required: true, default: 0 }) stopMoveTime: number; // 移动时间 @prop({ required: true, default: 0 }) defenseTime: number; // 防守保护时间 @prop({ required: true, default: 0 }) battleScore: number; // 积分 @prop({ required: true, default: 0 }) settleScore: number; // 积分 @prop({ required: true, type: () => GVGHeroInfo, _id: false }) lineup: GVGHeroInfo[]; @prop({ required: true }) lineupCe: number; @prop({ required: true }) groupKey: string; // 战区 @prop({ required: true, default: false }) isRobot: boolean; // 是否是机器人 @prop({ required: true, default: false }) captapultAtk: number; // 投石车的攻击力 @prop({ required: true, default: false }) isCatapult: boolean; // 是否是投石车 @prop({ required: true, default: false }) isBroken: boolean; // 机器人是否被击破,如果没有被击破,那么这个位置上就还是机器人,如果被击破了,这个位置就空出给玩家 originPointId: number; curTeamBreak: boolean; // 创建队伍 public static async saveTeam(roleId: string, index: number, updateParam: SaveTeamUpdateParam, initParam: InitTeamParam) { const doc = new GVGTeamModel(); const teamCode = genCode(8); const insert = Object.assign(doc.toJSON(), { ...initParam, teamCode }); delete insert.lineup; const team: GVGTeamType | null = await GVGTeamModel.findOneAndUpdate({ roleId, index }, { $setOnInsert: insert, $set: updateParam }, { upsert: true, new: true }).lean(); return team; } // 玩家切换城池更新队伍信息 public static async enterCity(roleId: string, cityId: number, areaId: number, groupKey: string) { let teams = await GVGTeamModel.findByRole(roleId, '-_id') let result: GVGTeamType[] = []; for(let targetTeam of teams) { let team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode: targetTeam.teamCode }, { $set: { cityId, areaId, fromAreaId: areaId, pointId: 0, groupKey } }, { new: true }).lean(); result.push(team); } return result; } // 离开队伍 public static async leaveCity(roleId: string) { let res = await GVGTeamModel.updateMany({ roleId }, { $set: { cityId: 0, areaId: 0, pointId: 0 } }); return !!res["ok"]; } // 查找角色队伍数 public static async getTeamCntByRole(roleId: string) { const teams: GVGTeamType[] = await GVGTeamModel.find({ roleId }).select('teamCode').lean(); return teams.length; } // 获取我的编队 public static async findByRole(roleId: string, select = '') { const teams: GVGTeamType[] = await GVGTeamModel.find({ roleId }).select(select).lean(); return teams; } // 获取我的编队 public static async findByRoleAndIndex(roleId: string, index: number, select = '') { const teams: GVGTeamType = await GVGTeamModel.findOne({ roleId, index }).select(select).lean(); return teams; } // 获取某个玩家的某个的编队 public static async findMyTeamByCode(roleId: string, teamCode: string, select = '') { const res: GVGTeamType = await GVGTeamModel.findOne({ roleId, teamCode }).select(select).lean(); return res; } // 获取编队 public static async findByCode(teamCode: string, select = '') { const res: GVGTeamType = await GVGTeamModel.findOne({ teamCode }).select(select).lean(); return res; } // 移动 public static async startMove(teamCode: string, areaId: number, fromAreaId: number) { const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, fromAreaId, stopMoveTime: nowSeconds() + GVG.GVG_DEFAULT_MOVE_CD, moveCdTime: nowSeconds() + GVG.GVG_DEFAULT_MOVE_CD } }, { new: true }).lean(); return res; } public static async stopMove(teamCode: string, areaId: number) { const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, stopMoveTime: nowSeconds() } }, { new: true }).lean(); return res; } // 查询挑战和防守的编队 public static async findBattleTeams(teamCode: string, oppoTeamCode: string) { const teams: GVGTeamType[] = await GVGTeamModel.find({ teamCode: { $in: [ teamCode, oppoTeamCode ] } }).lean(); let attackTeam: GVGTeamType = null, defenseTeam: GVGTeamType = null; for(let team of teams) { if(team.teamCode == teamCode) attackTeam = team; if(team.teamCode == oppoTeamCode) defenseTeam = team; } return { attackTeam, defenseTeam } } // 每赛季初刷新自己的耐久等东西 public static async refreshByConfig(roleId: string, updateArr: GVGTeamUpdate[]) { await GVGTeamModel.bulkWrite(updateArr.map(obj => { return { updateOne: { filter: { roleId, teamCode: obj.teamCode }, update: { $set: obj } } } })); return await GVGTeamModel.findByRole(roleId, '-_id'); } public static async findRobotTeams(groupKey: string, cityId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ groupKey, cityId, isRobot: true }).lean(); return team; } // 每赛季初刷新机器人 public static async initRobots(configId: number, groupKey: string, cityId: number, dicPoints: DicGVGAreaPoint[]) { await GVGTeamModel.bulkWrite(dicPoints.map(({ pointId, areaId, name, head, spine, ce, durability }) => { return { updateOne: { filter: { groupKey, cityId, areaId, pointId }, update: { $setOnInsert: { teamCode: genCode(8), maxDurability: durability, roleName: name, head, spine, frame: EXTERIOR.EXTERIOR_FACECASE, lineupCe: ce, isRobot: true, isBroken: false, startMoveTime: 0, stopMoveTime: 0, guildCode: '', leagueCode: '', leagueName: '', fromAreaId: areaId, }, $set: { configId, durability } }, upsert: true } } })); return await this.findRobotTeams(groupKey, cityId); } public static async findCatapultTeams(groupKey: string, cityId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ groupKey, cityId, isRobot: true, isCatapult: true }).lean(); return team; } // 生成投石车 public static async initCatapult(configId: number, groupKey: string, cityId: number, leagueCode: string, leagueName: string, areaIds: number[], atk: number, durability: number) { await GVGTeamModel.bulkWrite(areaIds.map(areaId => { return { updateOne: { filter: { groupKey, cityId, areaId }, update: { $setOnInsert: { teamCode: genCode(8), maxDurability: durability, captapultAtk: atk, leagueCode, leagueName, roleName: GVG.GVG_CATAPULT_NAME, head: GVG.GVG_CATAPULT_HEAD, spine: GVG.GVG_CATAPULT_SPINE, frame: EXTERIOR.EXTERIOR_FACECASE, lineupCe: GVG.GVG_CATAPULT_CE, isRobot: true, isCatapult: true, fromAreaId: areaId, isBroken: false, startMoveTime: 0, stopMoveTime: 0, guildCode: '', pointId: 0, roleId: GVG_CATAPULT }, $set: { configId, durability } }, upsert: true } } })); return await this.findCatapultTeams(groupKey, cityId); } // 攻击方攻击cd public static async battleStartLockAttack(teamCode: string) { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { attackTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD } }, { new: true }).lean(); return team; } // 防守方锁定cd public static async battleStartLockDefense(teamCode: string, lockTeamCode: string) { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { lockTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD, lockTeamCode } }, { new: true }).lean(); return team; } // 占领积分点 public static async settlePoint(teamCode: string, pointId: number) { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { pointId } }, { new: true }).lean(); return team; } // 结算挑战方 public static async battleEndAttack(teamCode: string, hpInc: number, rebirthAreaId: number, reviveCd: number) { let team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $inc: { durability: hpInc } }, { new: true }).lean(); if(team.durability <= 0) { let originPointId = team.pointId; team = await GVGTeamModel.teamBreak(teamCode, team.isRobot, team.maxDurability, rebirthAreaId, team.areaId, reviveCd); team.originPointId = originPointId; } return team; } // 结算防守方 public static async battleEndDefense(teamCode: string, hpInc: number, rebirthAreaId: number, reviveCd: number) { let team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { defenseTime: nowSeconds() + GVG.GVG_DEFAULT_DEFENSE_CD, lockTime: 0, lockTeamCode: '' }, $inc: { durability: hpInc } }, { new: true }).lean(); if(team.durability <= 0) { let originPointId = team.pointId; team = await GVGTeamModel.teamBreak(teamCode, team.isRobot, team.maxDurability, rebirthAreaId, team.areaId, reviveCd); team.originPointId = originPointId; } return team; } // 队伍进入修整器 public static async teamBreak(teamCode: string, isRobot: boolean, maxDurability: number, areaId: number, fromAreaId: number, reviveCd: number) { if(!isRobot) { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { restartTime: nowSeconds() - reviveCd, stopMoveTime: nowSeconds(), areaId, fromAreaId, durability: maxDurability } }, { new: true }).lean(); team.curTeamBreak = true; return team; } else { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { fromAreaId, durability: 0, isBroken: true } }, { new: true }).lean(); team.curTeamBreak = true; return team; } } public static async findByAreaId(groupKey: string, cityId: number, areaId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ groupKey, cityId, areaId, stopMoveTime: { $lte: nowSeconds() }, isBroken: false }).lean(); return team; } public static async findByConfigId(configId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ configId, cityId: { $gt: 0 } }).lean(); return team; } // 这个编队上是否已经有队伍了 public static async checkPoint(configId: number, groupKey: string, pointId: number) { return await GVGTeamModel.exists({ configId, groupKey, pointId, isBroken: false }); } // 投石车伤害 public static async attackByCatapult(teamCodes: string[], inc: number, rebirthAreaId: number) { await GVGTeamModel.updateMany({ teamCode: { $in: teamCodes } }, { $inc: { durability: -inc } }); let brokenTeams: GVGTeamType[] = await GVGTeamModel.find({ teamCode: { $in: teamCodes }, durability: { $lte: 0 } }).lean(); if(brokenTeams.length > 0) { await GVGTeamModel.bulkWrite(brokenTeams.map(({ teamCode, maxDurability }) => { return { updateOne: { filter: { teamCode }, update: { $set: { areaId: rebirthAreaId, pointId: 0, durability: maxDurability } }}} })); } let teams: GVGTeamType[] = await GVGTeamModel.find({ teamCode: { $in: teamCodes } }).lean(); return teams.map(team => { let originTeam = brokenTeams.find(origin => origin.teamCode == team.teamCode); if(originTeam) { team.originPointId = originTeam.originPointId; team.curTeamBreak = originTeam.curTeamBreak; } return team }) } // 加积分 public static async addScore(teamCode: string, battleScore: number, settleScore: number) { let team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $inc: { battleScore, settleScore } }, { new: true }).lean(); return team; } // 复活 public static async reviveTeam(teamCode: string) { let team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { restartTime: 0 } }, { new: true }).lean(); return team; } } export const GVGTeamModel = getModelForClass(GVGTeam); export interface GVGTeamType extends Pick, keyof GVGTeam> { id: number; }; export type GVGTeamUpdate = Partial; // 将所有字段变成可选项