From df8032cb06bea12a013b498b92e99ef2853d818f Mon Sep 17 00:00:00 2001 From: luying Date: Fri, 15 Jul 2022 21:13:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8D=E5=B0=86=E6=93=82=E5=8F=B0=EF=BC=9A?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=AF=B9=E6=89=8B=E8=AF=A6=E7=BB=86=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E7=BB=93=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servers/battle/handler/ladderHandler.ts | 112 ++++++++++++++---- game-server/app/services/ladderService.ts | 25 +++- game-server/app/services/timeTaskService.ts | 6 +- shared/consts/constModules/battleConst.ts | 2 - shared/consts/constModules/sysConst.ts | 1 + shared/consts/statusCode.ts | 4 + shared/db/LadderMatch.ts | 34 +++++- shared/db/LadderMatchRec.ts | 37 +++++- shared/domain/battleField/ladder.ts | 110 ++++++++++++++++- 9 files changed, 292 insertions(+), 39 deletions(-) diff --git a/game-server/app/servers/battle/handler/ladderHandler.ts b/game-server/app/servers/battle/handler/ladderHandler.ts index b18ce2ef2..bd13236fc 100644 --- a/game-server/app/servers/battle/handler/ladderHandler.ts +++ b/game-server/app/servers/battle/handler/ladderHandler.ts @@ -1,18 +1,20 @@ import { Application, BackendSession, pinus, HandlerService, } from 'pinus'; -import { uniq, findWhere, findIndex, pick } from 'underscore'; -import { gameData, getDicLadderMatchByMyRank, getPvpBoxBySeasonNumAndIndex } from '../../../pubUtils/data'; -import { RoleModel, RoleType } from '../../../db/Role'; +import { pick } from 'underscore'; +import { gameData } from '../../../pubUtils/data'; import { STATUS } from '../../../consts/statusCode'; -import { resResult, genCode, checkRoleIsRobot, robotIdComBack } from '../../../pubUtils/util'; +import { resResult } from '../../../pubUtils/util'; import { LadderMatchModel, LadderUpdateInter } from '../../../db/LadderMatch'; -import { checkRank, generateInitRecInfo, getBuyCntCost, getLadderData, getLadderOppStatus, refreshLadderDaily, refreshLadderEnemies } from '../../../services/ladderService'; -import { LadderDataReturn, LadderDefense, LadderDefenseHero, LadderOppLineupReturn, LadderOppPlayerInfo } from '../../../domain/battleField/ladder'; +import { battleEndWhenChange, checkRank, generateInitRecInfo, getBuyCntCost, getLadderData, getLadderOppStatus, refreshLadderDaily, refreshLadderEnemies } from '../../../services/ladderService'; +import { LadderDataReturn, LadderDefense, LadderDefenseHero, LadderOppDetailReturn, LadderOppLineupReturn, LadderOppPlayerHeroInfo, LadderOppPlayerReturn } from '../../../domain/battleField/ladder'; import { LadderMatchRecModel } from '../../../db/LadderMatchRec'; -import { HeroModel, HeroType } from '../../../db/Hero'; +import { HeroModel } from '../../../db/Hero'; import { LADDER } from '../../../pubUtils/dicParam'; import { handleCost } from '../../../services/role/rewardService'; -import { ITEM_CHANGE_REASON, LADDER_CHECK_STOP_TIME, LADDER_OPP_STATUS, LADDER_STATUS } from '../../../consts'; +import { ITEM_CHANGE_REASON, LADDER_OPP_STATUS, LADDER_STATUS, REDIS_KEY } from '../../../consts'; +import { getHeroesAttributes } from '../../../services/playerCeService'; +import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; +import { Rank } from '../../../services/rankService'; export default function (app: Application) { new HandlerService(app, {}); @@ -62,7 +64,7 @@ export class LadderHandler { let serverId = session.get('serverId'); let { roleId: targetRoleId, rank, myRank } = msg; // 检查双方排名等,不行的刷新对手回去 - let ladderData = await LadderMatchModel.findByRoleIdAndInclude(roleId); + let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); let { status, isRobot, hisLadderData } = await getLadderOppStatus(ladderData, targetRoleId, myRank, rank); @@ -73,6 +75,20 @@ export class LadderHandler { }); } + // 刷新次数 + let refOppObj = refreshLadderDaily(ladderData); + let update: LadderUpdateInter = {}; + if(refOppObj.shouldRefOpp) { + update = { ...refOppObj }; + } + + if(refOppObj.challengeCnt + 1 > LADDER.LADDER_CHALLENGE_FREE_TIMES + refOppObj.buyCnt) { + return resResult(STATUS.LADDER_CHALLENGE_CNT_MAX); + } + update.challengeCnt = refOppObj.challengeCnt + 1; + ladderData = await LadderMatchModel.updateByRoleIdAndInclude(roleId, update); + + // 创建ladderMatchRec,发行battleCode let attackInfo = generateInitRecInfo(false, false, ladderData.rank, ladderData); let defenseInfo = generateInitRecInfo(isRobot, true, rank, hisLadderData); @@ -82,7 +98,9 @@ export class LadderHandler { pinus.app.rpc.systimer.systimerRemote.setLadderCountDown.broadcast(rec.battleCode, rec.checkTime, LADDER_STATUS.CHECK); return resResult(STATUS.SUCCESS, { - time: rec.checkTime + LADDER_CHECK_STOP_TIME, + status, + challengeCnt: ladderData.challengeCnt, + time: rec.checkTime + LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN, battleCode: rec.battleCode }); } @@ -105,11 +123,27 @@ export class LadderHandler { let roleId = session.get('roleId'); let { battleCode } = msg; + let rec = await LadderMatchRecModel.findByBattleCode(battleCode); + if(!rec || rec.roleId1 != roleId) return resResult(STATUS.LADDER_REC_NOT_FOUND); + if(rec.status == LADDER_STATUS.COMPLETE || rec.status == LADDER_STATUS.NO) return resResult(STATUS.LADDER_REC_STATUS_IS_COMPLETE); + // 判断是机器人还是真人 + let isRobot = rec.defenseInfo.isRobot; + let dicLadderDifficultRatio = gameData.ladderDifficultRatio.get(rec.defenseInfo.oldRank); + let result = new LadderOppDetailReturn(rec); + if(isRobot) { + result.setByRobot(dicLadderDifficultRatio); + } else { + let hisLadderData = await LadderMatchModel.findByRoleIdAndInclude(rec.roleId2); + let dicWarJson = gameData.warJson.get(dicLadderDifficultRatio.gkId) + result.setByPlayer(hisLadderData, dicWarJson); + let attrByHid = await getHeroesAttributes(rec.roleId2); + for(let [hid, attribute] of attrByHid) { + result.setAttribute(hid, attribute.getAttributesToString()); + } + } - // 真人根据ladderMatch的defense,和warId对应的出兵表生成heroes - - return resResult(STATUS.SUCCESS); + return resResult(STATUS.SUCCESS, result); } // 6. 布完阵开始挑战 @@ -117,31 +151,63 @@ export class LadderHandler { let roleId = session.get('roleId'); let { battleCode, heroes } = msg; - // 检查挑战次数 - // 取消 chooseOpp 的倒计时 - // 更新ladderMatchRec状态,记录下出阵时候玩家选择的顺序 - // 开始倒计时,当时间到了还没battleEnd的时候算失败并发通知 + let rec = await LadderMatchRecModel.findByBattleCode(battleCode); + if(!rec || rec.roleId1 != roleId) return resResult(STATUS.LADDER_REC_NOT_FOUND); + if(rec.status != LADDER_STATUS.CHECK) return resResult(STATUS.LADDER_REC_STATUS_ERR); - return resResult(STATUS.SUCCESS) + let { isOK, heroes: dbHeroes } = await checkBattleHeroesByHid(roleId, heroes.map(cur => cur.actorId)); + if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); + + let attackHeroes = dbHeroes.map(hero => { + let heroInfo = new LadderOppPlayerHeroInfo(); + heroInfo.setByDefenseHero(hero); + return heroInfo; + }); + + rec = await LadderMatchRecModel.startBattle(battleCode, attackHeroes); + pinus.app.rpc.systimer.systimerRemote.setLadderCountDown.broadcast(rec.battleCode, rec.battleTime, LADDER_STATUS.BATTLE); + + return resResult(STATUS.SUCCESS, { + time: rec.battleTime + LADDER.LADDER_BATTLE_COUNTDOWN, + battleCode: rec.battleCode + }) } // 7. 挑战结算 async battleEnd(msg: { battleCode: string, isSuccess: boolean }, session: BackendSession) { let roleId = session.get('roleId'); + let serverId = session.get('serverId'); let { battleCode, isSuccess } = msg; + let rec = await LadderMatchRecModel.findByBattleCode(battleCode); + if(!rec || rec.roleId1 != roleId) return resResult(STATUS.LADDER_REC_NOT_FOUND); + if(rec.status != LADDER_STATUS.BATTLE) return resResult(STATUS.LADDER_REC_STATUS_ERR); + + let ladderData = await LadderMatchModel.findByRoleId(roleId); + if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); + // 取消 checkBattle 的倒计时 + pinus.app.rpc.systimer.systimerRemote.cancelLadderCountDown.broadcast(battleCode); + let result = new LadderDataReturn(); // 交换双方排名, transaction - // 更新redis + let { isChange, atkLadderMatch, defLadderMatch } = await LadderMatchModel.changeRank(isSuccess, rec.attackInfo, rec.defenseInfo); - // 更新ladderMatchRec状态,并记录信息 + if(isChange) { + let oppPlayers = await battleEndWhenChange(atkLadderMatch); + await battleEndWhenChange(defLadderMatch); + result.setOppPlayers(oppPlayers); + rec = await LadderMatchRecModel.battleEnd(battleCode, isSuccess, atkLadderMatch.rank, defLadderMatch? defLadderMatch.rank: rec.attackInfo.oldRank); + } else { + rec = await LadderMatchRecModel.battleEnd(battleCode, isSuccess); + } - // 刷新双方的对手并发通知 - // 扣挑战次数 + ladderData = await LadderMatchModel.updateByRoleId(roleId, { historyRank: atkLadderMatch.rank < ladderData.historyRank? atkLadderMatch.rank: ladderData.historyRank, locked: 0 }); + + result.setLadderData(ladderData, rec); // 获取奖励 - return resResult(STATUS.SUCCESS) + return resResult(STATUS.SUCCESS, result) } // 8. 战5次(扫荡) diff --git a/game-server/app/services/ladderService.ts b/game-server/app/services/ladderService.ts index 2adc48638..d71e0ed01 100644 --- a/game-server/app/services/ladderService.ts +++ b/game-server/app/services/ladderService.ts @@ -18,7 +18,7 @@ export function refreshLadderDaily(ladderData: LadderMatchType) { let curTime = new Date(); let shouldRefOpp = shouldRefresh(refDaily, curTime); if (shouldRefOpp) { - refOppCnt = 0; buyCnt = 0; challengeCnt =0; refDaily = curTime; + refOppCnt = 0; buyCnt = 0; challengeCnt = 0; refDaily = curTime; } return { shouldRefOpp, @@ -176,7 +176,10 @@ function isOver(isBefore: boolean, myRank: number, range: number, result: number export function checkRank(myRank: number, targetRank: number) { let dicLadderMatch = getDicLadderMatchByMyRank(myRank); - if(!dicLadderMatch && myRank != 0 && targetRank != 3001) return false; + if(!dicLadderMatch) { + if(myRank == 0 && targetRank == 3001) return true; + return false + } if(myRank < targetRank) { // 向后打 if(myRank + dicLadderMatch.rangeAfterMax < targetRank) return false; } else { // 向前打 @@ -263,3 +266,21 @@ export async function ladderTimeout(battleCode: string, status: LADDER_STATUS) { await sendMessageToUserWithSuc(rec.roleId1, PUSH_ROUTE.LADDER_BATTLE_STOP, { battleCode }); } } + +export async function battleEndWhenChange(ladderMatch: LadderMatchType) { + if(!ladderMatch) return; + + // 更新redis + let r = new Rank(REDIS_KEY.LADDER, { serverId: ladderMatch.serverId }); + console.log('##### ladderMatch.roleId', ladderMatch.roleId) + r.setRankWithRoleInfo(ladderMatch.roleId, ladderMatch.rank, 0); + + // 刷新对手 + let oppPlayers = await refreshLadderEnemies(ladderMatch); + await sendMessageToUserWithSuc(ladderMatch.roleId, PUSH_ROUTE.LADDER_RANK_UPDATE, { + oldRank: ladderMatch.oldRank, + newRank: ladderMatch.rank, + oppPlayers + }); + return oppPlayers +} \ No newline at end of file diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index 5152e0699..50fc8a3c0 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -5,7 +5,7 @@ import { nowSeconds, getTimeFun, getSeconds } from '../pubUtils/timeUtil'; import { getTodayGuildActivity, gameData } from '../pubUtils/data'; import { pvpSeasonEnd } from './pvpService'; import { getAllOnlineRoles, getAllServers, delGuildActivityRank, getServerCreateTime } from './redisService'; -import { GUILD_ACTIVITY_TYPE, REFRESH_TIME, COUNTER, AUCTION_TIME, GM_MAIL_TYPE, SERVER_TIMER, ACTIVITY_TYPE, PUSH_ROUTE, STATUS, LADDER_STATUS, LADDER_CHECK_STOP_TIME, LADDER_BATTLE_STOP_TIME, LADDER_SERVER_GAP_TIME } from '../consts'; +import { GUILD_ACTIVITY_TYPE, REFRESH_TIME, COUNTER, AUCTION_TIME, GM_MAIL_TYPE, SERVER_TIMER, ACTIVITY_TYPE, PUSH_ROUTE, STATUS, LADDER_STATUS, LADDER_SERVER_GAP_TIME } from '../consts'; import { pinus } from 'pinus'; import { settleGuildWeekly } from './guildService'; import { SendMailFun, sendMailsByGmMail, } from './mailService'; @@ -17,7 +17,7 @@ import { createNewServer, initMarquee } from './gmService'; import moment = require('moment'); import { CounterModel } from '../db/Counter'; import { reportOneOnline } from './authenticateService'; -import { PVP } from '../pubUtils/dicParam'; +import { LADDER, PVP } from '../pubUtils/dicParam'; import { fetch37Words } from './sdkService'; import { GMMailModel, GMMailType } from '../db/GMMail'; import { Maintenance, ServerlistModel, ServerlistType } from '../db/Serverlist'; @@ -739,7 +739,7 @@ async function setTakeRankSnapshotSchedule(activityId: number, serverId: number, // —————————————— 名将擂台 start —————————————— // export async function setLadderCountDown(battleCode: string, time: number, status: LADDER_STATUS) { - let endTime = time + (status == LADDER_STATUS.CHECK? LADDER_CHECK_STOP_TIME: LADDER_BATTLE_STOP_TIME) + LADDER_SERVER_GAP_TIME; + let endTime = time + (status == LADDER_STATUS.CHECK? LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN: LADDER.LADDER_BATTLE_COUNTDOWN) + LADDER_SERVER_GAP_TIME; scheduleJob(`ladder${battleCode}`, endTime * 1000, async () => { await ladderTimeout(battleCode, status); }) diff --git a/shared/consts/constModules/battleConst.ts b/shared/consts/constModules/battleConst.ts index 937bcad09..767dda78d 100644 --- a/shared/consts/constModules/battleConst.ts +++ b/shared/consts/constModules/battleConst.ts @@ -165,8 +165,6 @@ export enum LADDER_STATUS { COMPLETE = 3, // 战斗结束 } -export const LADDER_CHECK_STOP_TIME = 2 * 60; -export const LADDER_BATTLE_STOP_TIME = 5 * 60; export const LADDER_SERVER_GAP_TIME = 5; // 服务器比客户端晚5秒 export enum LADDER_OPP_STATUS { diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 813bbbd8b..fd8dc5dc0 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -382,6 +382,7 @@ export const KEY_TO_COMPOSE_FIELD = new Map([ [REDIS_KEY.PVP_RANK, COMPOSE_FIELD_TYPE.ROLE], [REDIS_KEY.GUILD_FUND, COMPOSE_FIELD_TYPE.GUILD], [REDIS_KEY.SUM_CE_SNAPSHOT, COMPOSE_FIELD_TYPE.ROLE], + [REDIS_KEY.LADDER, COMPOSE_FIELD_TYPE.ROLE], ]); diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index b10cbcced..9846e491c 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -263,6 +263,10 @@ export const STATUS = { LADDER_BUY_MAX: { code: 21201, simStr: '名将擂台购买次数达到上限' }, LADDER_RANK_ERROR: { code: 21202, simStr: '该排名玩家不可挑战' }, LADDER_REFRESH_CNT_MAX: { code: 21203, simStr: '刷新次数达到上限' }, + LADDER_REC_NOT_FOUND: { code: 21204, simStr: '未找到该条记录' }, + LADDER_REC_STATUS_IS_COMPLETE: { code: 21205, simStr: '该战斗已结束' }, + LADDER_CHALLENGE_CNT_MAX: { code: 21206, simStr: '挑战次数已达上限' }, + LADDER_REC_STATUS_ERR: { code: 21207, simStr: '战斗状态错误' }, // 通用 30000 - 30099 DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' }, diff --git a/shared/db/LadderMatch.ts b/shared/db/LadderMatch.ts index ab7f1d09e..e3533d6f1 100644 --- a/shared/db/LadderMatch.ts +++ b/shared/db/LadderMatch.ts @@ -1,6 +1,6 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose'; -import { LadderDefense, LadderOppPlayerInDB } from '../domain/battleField/ladder'; +import { LadderDefense, LadderOppPlayerInDB, LadderOppPlayerInfo } from '../domain/battleField/ladder'; import Role from './Role'; @index({ roleId: 1 }) @@ -14,6 +14,8 @@ export default class LadderMatch extends BaseModel { @prop({ required: true, default: 0 }) rank: number; // 排名 @prop({ required: true, default: 0 }) + oldRank: number; // 交换前排名 + @prop({ required: true, default: 0 }) historyRank: number; // 历史最高排名 @prop({ required: true, default: 0 }) @@ -66,10 +68,17 @@ export default class LadderMatch extends BaseModel { return defense; } + public static async updateByRoleIdAndInclude(roleId: string, params: LadderUpdateInter) { + const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: params}, { new: true }) + .populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt') + .populate('defense.hero', 'hid skinId quality star colorStar lv') + .lean(); + return defense; + } public static async findAll(serverId: number) { let result: LadderMatchType[] = [], latestTime = new Date(); while(latestTime) { - let ladderMatch = await LadderMatchModel.find({ serverId, rank: { $gt: 0 }, createdAt: { $lt: latestTime } }) + let ladderMatch = await LadderMatchModel.find({ serverId, rank: { $gt: 0, $lte: 3000 }, createdAt: { $lt: latestTime } }) .sort({ createdAt: -1 }) .populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt') .limit(1000); @@ -83,6 +92,27 @@ export default class LadderMatch extends BaseModel { const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId, rank, locked: 0 }, { $set: { locked: 1 }}, { new: true }).lean(); return defense; } + + public static async changeRank(isSuccess: boolean, attackInfo: LadderOppPlayerInfo, defenseInfo: LadderOppPlayerInfo) { + // TODO transaction + let atkLadderMatch: LadderMatchType, defLadderMatch: LadderMatchType, isChange = false; + if(defenseInfo.isRobot) { + atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean(); + if(isSuccess && atkLadderMatch && atkLadderMatch.rank > defenseInfo.oldRank) { + atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defenseInfo.oldRank, oldRank: atkLadderMatch.rank } }, { new: true }).lean(); + isChange = true; + } + } else { + atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean(); + defLadderMatch = await LadderMatchModel.findOne({ roleId: defenseInfo.roleId }).lean(); + if(isSuccess && atkLadderMatch && defLadderMatch && atkLadderMatch.rank > defLadderMatch.rank) { + atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defLadderMatch.rank, oldRank: atkLadderMatch.rank } }, { new: true }).lean(); + defLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: defenseInfo.roleId }, { $set: { rank: atkLadderMatch.rank, oldRank: defLadderMatch.rank } }, { new: true }).lean(); + isChange = true; + } + } + return { isChange, atkLadderMatch, defLadderMatch } + } } export const LadderMatchModel = getModelForClass(LadderMatch); diff --git a/shared/db/LadderMatchRec.ts b/shared/db/LadderMatchRec.ts index 7aef04d44..057235c7d 100644 --- a/shared/db/LadderMatchRec.ts +++ b/shared/db/LadderMatchRec.ts @@ -5,7 +5,7 @@ import { Defense, Attack, LineupCe, OppPlayer, HeroScore, } from '../domain/batt import { CounterModel } from './Counter'; import { COUNTER, LADDER_STATUS } from '../consts'; import { EXTERIOR, PVP } from '../pubUtils/dicParam'; -import { LadderDefense, LadderOppPlayerInfo } from '../domain/battleField/ladder'; +import { LadderDefense, LadderOppPlayerInfo, LadderOppPlayerHeroInfo } from '../domain/battleField/ladder'; import { genCode } from '../pubUtils/util'; import { nowSeconds } from '../pubUtils/timeUtil'; @@ -56,12 +56,41 @@ export default class LadderMatchRec extends BaseModel { } public static async timeout(battleCode: string) { - const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.COMPLETE, timeout: true } }).lean(); + const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.COMPLETE, timeout: true } }, { new: true }).lean(); return result; } public static async giveup(battleCode: string) { - const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.NO } }).lean(); + const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.NO } }, { new: true }).lean(); + return result; + } + + public static async findByBattleCode(battleCode: string, select: string = '') { + const result: LadderMatchRecType = await LadderMatchRecModel.findOne({ battleCode }).select(select).lean(); + return result; + } + + public static async startBattle(battleCode: string, attackHeroes: LadderOppPlayerHeroInfo[]) { + const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { + $set: { status: LADDER_STATUS.BATTLE, battleTime: nowSeconds(), 'attackInfo.heroes': attackHeroes } + }, { new: true }).lean(); + return result; + } + + public static async battleEnd(battleCode: string, isSuccess: boolean, atkNewRank?: number, defNewRank?: number) { + let update: LadderMatchRecUpdate = { status: LADDER_STATUS.COMPLETE, endTime: nowSeconds() }; + if(isSuccess) { + update['attackInfo.isSuccess'] = true; + update['defenseInfo.isSuccess'] = false; + } + if(atkNewRank != undefined && defNewRank != undefined) { + update['attackInfo.rank'] = atkNewRank; + update['attackInfo.oldRank'] = defNewRank; + update['defenseInfo.rank'] = defNewRank; + update['defenseInfo.oldRank'] = atkNewRank; + } + + const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: update }, { new: true }).lean(); return result; } } @@ -69,4 +98,4 @@ export default class LadderMatchRec extends BaseModel { export const LadderMatchRecModel = getModelForClass(LadderMatchRec); export interface LadderMatchRecType extends Pick, keyof LadderMatchRec> { }; -export type pvpUpdateInter = Partial; \ No newline at end of file +export type LadderMatchRecUpdate = Partial; \ No newline at end of file diff --git a/shared/domain/battleField/ladder.ts b/shared/domain/battleField/ladder.ts index 0c9858c57..2daa992a4 100644 --- a/shared/domain/battleField/ladder.ts +++ b/shared/domain/battleField/ladder.ts @@ -1,5 +1,5 @@ import { mongoose, prop, Ref } from "@typegoose/typegoose"; -import { LADDER_BATTLE_STOP_TIME, LADDER_CHECK_STOP_TIME, LADDER_STATUS } from "../../consts"; +import { LADDER_STATUS } from "../../consts"; import Hero, { HeroType } from '../../db/Hero'; import { LadderMatchType } from "../../db/LadderMatch"; import { LadderMatchRecType } from "../../db/LadderMatchRec"; @@ -137,6 +137,7 @@ export class LadderOppPlayerInfo { this.lv = role.lv; this.isSuccess = isSuccess; this.heroes = heroes; + this.isRobot = false; } initByRobot(dicLadderDifficultRatio: DicLadderDifficultRatio, heroes: LadderOppPlayerHeroInfo[], isSuccess: boolean) { @@ -149,7 +150,9 @@ export class LadderOppPlayerInfo { this.lv = dicLadderDifficultRatio.level; this.isSuccess = isSuccess; this.heroes = heroes; + this.isRobot = true; } + } // defense字段 接口返回 @@ -245,9 +248,9 @@ export class LadderDataReturn { if(ladderRec) { this.status = ladderRec.status; if(this.status == LADDER_STATUS.BATTLE) { - this.time = ladderRec.battleTime + LADDER_BATTLE_STOP_TIME; + this.time = ladderRec.battleTime + LADDER.LADDER_BATTLE_COUNTDOWN; } else if (this.status == LADDER_STATUS.CHECK) { - this.time = ladderRec.checkTime + LADDER_CHECK_STOP_TIME; + this.time = ladderRec.checkTime + LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN; } } } @@ -307,4 +310,105 @@ export class LadderOppLineupReturn { this.heroes.push(hero); } } +} + +// getOppData接口的返回 +export class LadderOppDetailHeroReturn { + actorId: number = 0; // 武将id + skinId: number = 0; // 皮肤id,fashions表的heroId + actorName: string = ''; // 武将名 + dataId: number = 0; // 出兵表唯一id + relation: number = 0; // 地方还是我方 + dirction: number = 0; // 方向 + outIndex: number = 0; // 玩家设置的出场顺序,即order字段 + x: number = 0; // 战场x坐标 + y: number = 0; // 战场y坐标 + var: number = 0; // 变量 + lv: number = 0; // 等级 + hide: number = 0; // 是否隐藏 + initial_ai: number = 0; // ai类型 + attribute: string = ''; // 武将属性,格式 id&val|id&val|...,这里的次级属性都是没有除1000的值 + star: number = 0; // 星级 + colorStar: number = 0; // 彩星 + quality: number = 0; // 品质 + skill: string = ''; // 技能 + seid: string = ''; // 技能 + spine: string = ''; // 动画 + + constructor(warJson: DicWarJson, defensHero: LadderDefenseHero) { + this.dataId = warJson.actorId; + this.relation = warJson.relation; + this.dirction = warJson.dirction; + this.x = warJson.x; + this.y = warJson.y; + this.var = warJson.var; + this.hide = warJson.hide; + + if(defensHero) { + this.outIndex = defensHero.order; + this.initial_ai = defensHero.ai; + let hero = defensHero.hero; + if(hero) { + this.actorId = hero.hid; + this.skinId = hero.skinId; + this.actorName = hero.hName; + this.lv = hero.lv; + } + } + } + + setAttribute(attribute: string) { + this.attribute = attribute; + } +} + +// getOppData接口的返回 +export class LadderOppDetailReturn { + battleCode: string = ''; + roleId: string = ''; + status: LADDER_STATUS = LADDER_STATUS.NO; + time: number = 0; + isRobot: boolean = false; + title: number = 1; + warId: number = 0; + heroes: LadderOppDetailHeroReturn[] = []; + + constructor(ladderRec: LadderMatchRecType) { + this.battleCode = ladderRec.battleCode; + this.roleId = ladderRec.roleId2; + this.status = ladderRec.status; + if(this.status == LADDER_STATUS.BATTLE) { + this.time = ladderRec.battleTime + LADDER.LADDER_BATTLE_COUNTDOWN; + } else if (this.status == LADDER_STATUS.CHECK) { + this.time = ladderRec.checkTime + LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN; + } + } + + setByPlayer(ladderMatch: LadderMatchType, warJsons: DicWarJson[]) { + this.isRobot = false; + let role = ladderMatch.role; + this.title = role.title; + if(ladderMatch.defense) { + this.warId = ladderMatch.defense.warId; + let heroes = ladderMatch.defense.heroes||[]; + for(let hero of heroes) { + let warJson = warJsons.find(cur => cur.dataId == hero.dataId); + if(warJson) { + let obj = new LadderOppDetailHeroReturn(warJson, hero); + this.heroes.push(obj); + } + } + } + } + + setByRobot(dicLadderDifficultRatio: DicLadderDifficultRatio) { + this.isRobot = true; + this.roleId = `robot${dicLadderDifficultRatio.rank}`; + this.warId = dicLadderDifficultRatio.gkId; + } + + setAttribute(hid: number, attribute: string) { + let hero = this.heroes.find(cur => cur.actorId == hid); + if(hero) hero.setAttribute(attribute); + } } \ No newline at end of file