import { Application, BackendSession, pinus, HandlerService, } from 'pinus'; import { isArray, pick } from 'underscore'; import { gameData } from '../../../pubUtils/data'; import { STATUS } from '../../../consts/statusCode'; import { resResult } from '../../../pubUtils/util'; import { LadderMatchModel, LadderUpdateInter } from '../../../db/LadderMatch'; import { battleEndWhenChange, checkRank, generateInitRecInfo, generateOppPlayers, getBuyCntCost, getLadderData, getLadderEnemies, getLadderOppDetailData, getLadderOppStatus, getNumberArr, ladderBattleEndReward, refreshLadderDaily, refreshLadderEnemies, sendLadderDailyReward, uniqueArr } from '../../../services/ladderService'; import { LadderDataReturn, LadderDefense, LadderDefenseHero, LadderOppDetailReturn, LadderOppLineupReturn, LadderOppPlayerHeroInfo, LadderOppPlayerReturn } from '../../../domain/battleField/ladder'; import { LadderMatchRecModel } from '../../../db/LadderMatchRec'; import { HeroModel } from '../../../db/Hero'; import { LADDER } from '../../../pubUtils/dicParam'; import { handleCost } from '../../../services/role/rewardService'; import { DEBUG_MAGIC_WORD, ITEM_CHANGE_REASON, LADDER_OPP_STATUS, LADDER_STATUS, REDIS_KEY } from '../../../consts'; import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { ServerlistModel } from '../../../db/Serverlist'; import { saveLadderDefCeByData } from '../../../services/redisService'; import { pushLadderTopChangeMsg } from '../../../services/sysChatService'; import { checkTaskInLadderEnd, checkTaskInLadderStart, checkTaskInLadderSweep } from '../../../services/task/taskService'; import { BattleRecordModel } from '../../../db/BattleRecord'; export default function (app: Application) { new HandlerService(app, {}); return new LadderHandler(app); } export class LadderHandler { constructor(private app: Application) { } // 1. 获取主界面 async getData(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let result = await getLadderData(roleId, true) return resResult(STATUS.SUCCESS, result); } // 2. 获取对手阵容信息 async getOppLineup(msg: { roleId: string, rank: number }, session: BackendSession) { let roleId: string = session.get('roleId'); let { roleId: targetRoleId, rank } = msg; let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData || !ladderData.defense) return resResult(STATUS.LADDER_NOT_OPEN); let isRobot = targetRoleId.startsWith('robot'); let result = new LadderOppLineupReturn(); result.setMyRank(ladderData.rank); if(isRobot) { let dicLadderDifficultRatio = gameData.ladderDifficultRatio.get(rank); let dicWar = gameData.war.get(dicLadderDifficultRatio.gkId); let dicWarJson = gameData.warJson.get(dicWar.dispatchJsonId); result.setRobot(dicLadderDifficultRatio, dicWarJson); } else { let hisLadderData = await LadderMatchModel.findByRoleIdAndInclude(targetRoleId); result.setPlayer(hisLadderData); } return resResult(STATUS.SUCCESS, result); } // 3. 点击挑战 async chooseOpp(msg: { roleId: string, rank: number, myRank: number }, session: BackendSession) { let roleId = session.get('roleId'); let serverId = session.get('serverId'); let sid = session.get('sid'); let { roleId: targetRoleId, rank, myRank } = msg; // 检查双方排名等,不行的刷新对手回去 let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData || !ladderData.defense) return resResult(STATUS.LADDER_NOT_OPEN); if(!checkRank(myRank, rank)) return resResult(STATUS.LADDER_RANK_ERROR); let { status, isRobot, hisLadderData } = await getLadderOppStatus(ladderData, targetRoleId, myRank, rank); if(status != LADDER_OPP_STATUS.BATTLE) { // await LadderMatchModel.unlock(serverId, targetRoleId); let oppPlayers = await refreshLadderEnemies(ladderData); return resResult(STATUS.SUCCESS, { status, oppPlayers }); } // 刷新次数 let refOppObj = refreshLadderDaily(ladderData); let update: LadderUpdateInter = {}; if(refOppObj.shouldRefOpp) { update = { ...refOppObj }; } if(refOppObj.challengeCnt + 1 > LADDER.LADDER_CHALLENGE_FREE_TIMES + refOppObj.buyCnt) { await LadderMatchModel.unlock(serverId, targetRoleId); 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); let rec = await LadderMatchRecModel.createRec(serverId, roleId, targetRoleId, hisLadderData?.defense, attackInfo, defenseInfo); // 倒计时,倒计时结束没有check设为失败并发失败通知 pinus.app.rpc.systimer.systimerRemote.setLadderCountDown.broadcast(rec.battleCode, rec.checkTime, LADDER_STATUS.CHECK); let result = await getLadderOppDetailData(rec); await checkTaskInLadderStart(serverId, roleId, sid); return resResult(STATUS.SUCCESS, { status, challengeCnt: ladderData.challengeCnt, ...result }); } // 4. 出战撤退 async giveupCheck(msg: { battleCode: string }, session: BackendSession) { let roleId = session.get('roleId'); let { battleCode } = msg; // 更新ladderMatchRec let rec = await LadderMatchRecModel.giveup(roleId, battleCode); if(rec) { pinus.app.rpc.systimer.systimerRemote.cancelLadderCountDown.broadcast(rec.battleCode); if(rec.defenseInfo && !rec.defenseInfo.isRobot) await LadderMatchModel.unlock(rec.serverId, rec.defenseInfo.roleId); } return resResult(STATUS.SUCCESS, { status: 0, time: 0 }); } // 5. 获取对手具体战场数据 async getOppData(msg: { battleCode: string }, session: BackendSession) { 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 result = await getLadderOppDetailData(rec); return resResult(STATUS.SUCCESS, result); } // 6. 布完阵开始挑战 async checkBattle(msg: { battleCode: string, battleId: number, heroes: { actorId: number, order: number }[] }, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleId'); let { battleId, battleCode, heroes } = msg; 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); 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; }); let warInfo = gameData.war.get(battleId); await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { roleId, roleName, battleId, status: 0, warName: warInfo?.gk_name, warType: warInfo?.warType, } }); 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: Math.floor(rec.battleTime/1000) + LADDER.LADDER_BATTLE_COUNTDOWN, battleCode: rec.battleCode }) } // 7. 挑战结算 async battleEnd(msg: { battleCode: string, isSuccess: boolean }, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let serverId = session.get('serverId'); let sid = session.get('sid'); 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 rank = rec.defenseInfo.oldRank; let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData || !ladderData.defense) return resResult(STATUS.LADDER_NOT_OPEN); // 取消 checkBattle 的倒计时 pinus.app.rpc.systimer.systimerRemote.cancelLadderCountDown.broadcast(battleCode); let result = new LadderDataReturn(); // 交换双方排名, transaction let { isChange, atkLadderMatch, defLadderMatch, endTime } = await LadderMatchModel.changeRank(isSuccess, rec.attackInfo, rec.defenseInfo); if(isChange) { let oppPlayers = await battleEndWhenChange(atkLadderMatch, defLadderMatch, true); result.setOppPlayers(oppPlayers); rec = await LadderMatchRecModel.battleEnd(battleCode, isSuccess, endTime, atkLadderMatch.rank, defLadderMatch? defLadderMatch.rank: rec.attackInfo.oldRank); if(atkLadderMatch.rank == 1) { pushLadderTopChangeMsg(roleId, roleName, serverId); } } else { rec = await LadderMatchRecModel.battleEnd(battleCode, isSuccess, endTime); let oppPlayers = await getLadderEnemies(atkLadderMatch); result.setOppPlayers(oppPlayers); } await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { status: isSuccess? 1: 2 } }); if(defLadderMatch) { await LadderMatchModel.unlock(defLadderMatch.serverId, defLadderMatch.roleId); } let historyRank = ladderData.historyRank; ladderData = await LadderMatchModel.updateByRoleId(roleId, { historyRank: (historyRank > atkLadderMatch.rank || historyRank == 0)? atkLadderMatch.rank: historyRank }); result.setLadderData(ladderData, rec); // 获取奖励 let { battleGoods, breakGoods } = await ladderBattleEndReward(roleId, roleName, sid, rank, isSuccess, historyRank, 1); await checkTaskInLadderEnd(serverId, roleId, sid, isSuccess, historyRank, atkLadderMatch.rank); return resResult(STATUS.SUCCESS, {...pick(result, ['rank', 'historyRank', 'challengeCnt','status', 'time', 'oppPlayers']), battleGoods, breakGoods}); } // 8. 战5次(扫荡) async battleSweep(msg: { roleId: string, rank: number, count: number }, session: BackendSession) { let serverId = session.get('serverId'); let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let { roleId: targetRoleId, rank, count } = msg; if(count > LADDER.LADDER_INITIAL_CHALLENGE_TIMES) { return resResult(STATUS.LADDER_SWEEP_TIMES_OVER); } let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData || !ladderData.defense) return resResult(STATUS.LADDER_NOT_OPEN); if(ladderData.rank >= rank) return resResult(STATUS.LADDER_RANK_ERR); // 刷新次数 let refOppObj = refreshLadderDaily(ladderData); let update: LadderUpdateInter = {}; if(refOppObj.shouldRefOpp) { update = { ...refOppObj }; } if(refOppObj.challengeCnt + count > LADDER.LADDER_CHALLENGE_FREE_TIMES + refOppObj.buyCnt) { return resResult(STATUS.LADDER_CHALLENGE_CNT_MAX); } update.challengeCnt = refOppObj.challengeCnt + count; ladderData = await LadderMatchModel.updateByRoleIdAndInclude(roleId, update); // 获取奖励 let { battleGoods } = await ladderBattleEndReward(roleId, roleName, sid, rank, true, rank, count); await checkTaskInLadderSweep(serverId, roleId, sid, count) return resResult(STATUS.SUCCESS, { challengeCnt: ladderData.challengeCnt, battleGoods }); } // 9. 设置防守阵容 async saveDefense(msg: { warId: number, heroes: { actorId: number, ai: number, dataId: number, order: number }[] }, session: BackendSession) { let { warId, heroes } = msg; let roleId = session.get('roleId'); let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); let hids: number[] = heroes.map(cur => cur.actorId); let dbHeroes = await HeroModel.findByHidRange(hids, roleId, '_id hid ce', true); let defenseHeroes = heroes.map(cur => { let dbHero = dbHeroes.find(ccur => ccur.hid == cur.actorId); return dbHero && new LadderDefenseHero(cur, dbHero._id, dbHero.ce); }).filter(cur => cur); let defense = new LadderDefense(defenseHeroes, warId); ladderData = await LadderMatchModel.updateByRoleId(roleId, { defense }); // 返回 let result = new LadderDataReturn(); result.setLadderData(ladderData); await saveLadderDefCeByData(roleId, ladderData); return resResult(STATUS.SUCCESS, pick(result, 'defense')); } // 10. 刷新对手 async refreshOppPlayers(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let sid = session.get('sid'); let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData || !ladderData.defense) return resResult(STATUS.LADDER_NOT_OPEN); let update: LadderUpdateInter = {}; // 刷新次数 let refOppObj = refreshLadderDaily(ladderData); if(refOppObj.shouldRefOpp) { update = { ...refOppObj }; } if(refOppObj.refOppCnt + 1 > LADDER.LADDER_REFRESH_TIMES) { return resResult(STATUS.LADDER_REFRESH_CNT_MAX); } update.refOppCnt = refOppObj.refOppCnt + 1; let oppPlayers = await refreshLadderEnemies(ladderData, update); // 返回 return resResult(STATUS.SUCCESS, { refOppCnt: update.refOppCnt, oppPlayers }); } // 11. 购买次数 async buyCnt(msg: { count: number }, session: BackendSession) { let { count } = msg; let roleId = session.get('roleId'); let sid = session.get('sid'); let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); let update: LadderUpdateInter = {}; // 刷新次数 let refOppObj = refreshLadderDaily(ladderData); if(refOppObj.shouldRefOpp) { update = { ...refOppObj }; } if(refOppObj.buyCnt + count > LADDER.LADDER_CHALLENGE_COST_TIMES) { return resResult(STATUS.LADDER_BUY_MAX); } let consumes = getBuyCntCost(refOppObj.buyCnt, count); if(!consumes) return resResult(STATUS.LADDER_BUY_MAX); let consumeResult = await handleCost(roleId, sid, consumes||[], ITEM_CHANGE_REASON.LADDER_BUY_CNT); if(!consumeResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); update.buyCnt = refOppObj.buyCnt + count; ladderData = await LadderMatchModel.updateByRoleId(roleId, update); // 返回 let result = new LadderDataReturn(); result.setLadderData(ladderData); return resResult(STATUS.SUCCESS, pick(result, ['buyCnt', 'challengeCnt'])); } // 12. 获取战报信息 async getRec(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let list = await LadderMatchRecModel.findRec(roleId); return resResult(STATUS.SUCCESS, { list }); } // debug接口 // 重置挑战次数 & 购买次数 async resetCnt(msg: { magicWord: string }, session: BackendSession) { const { magicWord } = msg; if (magicWord !== DEBUG_MAGIC_WORD) { return resResult(STATUS.TOKEN_ERR); } let roleId = session.get('roleId'); let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); await LadderMatchModel.updateByRoleId(roleId, { refDaily: new Date(Date.now() - 86400000) }); return resResult(STATUS.SUCCESS); } async setMyRank(msg: { magicWord: string, rank: number }, session: BackendSession) { const { magicWord, rank } = msg; if (magicWord !== DEBUG_MAGIC_WORD) { return resResult(STATUS.TOKEN_ERR); } let roleId = session.get('roleId'); let atkLadderMatch = await LadderMatchModel.findByRoleId(roleId); if(!atkLadderMatch || !atkLadderMatch.defense) return resResult(STATUS.LADDER_NOT_OPEN); let myRank = atkLadderMatch.rank; let defLadderMatch = await LadderMatchModel.findByRank(rank); if(defLadderMatch) { atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: { rank, oldRank: myRank, historyRank: rank } }, { new: true }).lean(); defLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: defLadderMatch.roleId }, { $set: { rank: myRank, oldRank: rank } }, { new: true }).lean(); } else { atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: { rank, oldRank: atkLadderMatch.rank, historyRank: rank } }, { new: true }).lean(); } await battleEndWhenChange(atkLadderMatch, defLadderMatch, true); return resResult(STATUS.SUCCESS); } async setMyOpp(msg: { magicWord: string, oppRanks: number[] }, session: BackendSession) { const { magicWord, oppRanks } = msg; if (magicWord !== DEBUG_MAGIC_WORD) { return resResult(STATUS.WRONG_PARMS); } if(!isArray(oppRanks) || oppRanks.length <= 0) return resResult(STATUS.WRONG_PARMS); let roleId = session.get('roleId'); let serverId = session.get('serverId'); let ladderData = await LadderMatchModel.findByRoleId(roleId); if(!ladderData) return resResult(STATUS.LADDER_NOT_OPEN); let topTen = getNumberArr(1, 10); let ranks = [...topTen, ...oppRanks]; let newRanks = uniqueArr(ranks.sort((a, b) => a - b)); await generateOppPlayers(newRanks, serverId, roleId); return resResult(STATUS.SUCCESS); } async sendDailyReward(msg: { magicWord: string }, session: BackendSession) { const { magicWord } = msg; if (magicWord !== DEBUG_MAGIC_WORD) { return resResult(STATUS.TOKEN_ERR); } let servers = await ServerlistModel.findByEnv(pinus.app.get('env')); for(let { serverId } of servers) { await sendLadderDailyReward(serverId); } return resResult(STATUS.SUCCESS) } }