import { Application, BackendSession, pinus } from 'pinus'; import { uniq, findWhere, findIndex } from 'underscore'; import { gameData, getPvpBoxs, getPLvByScore } from '../../../pubUtils/data'; import { refreshEnemies, getEnemies, getLvByScore, defaultHeroes, comsumeChallengeCnt, refresh, findPvpDefByRoleId, checkRoleIsRobot, getRefOppCnt, findPvpDefAllByRoleId, generPVPOppRecInfo, generMyRecInfo, robotIdComBack } from '../../../services/pvpService'; import { RoleModel, RoleType } from '../../../db/Role'; import { STATUS } from '../../../consts/statusCode'; import { resResult, genCode } from '../../../pubUtils/util'; import { PvpDefenseModel, OppPlayers } from '../../../db/PvpDefense'; import { pvpEndParamInter } from '../../../pubUtils/interface'; import { PlayerDetail, PlayerDetailHero } from '../../../domain/battleField/guild'; import { PVP_HERO_POS, PVP_HERO_ORDER, REDIS_KEY, LINEUP_NUM, TASK_TYPE } from '../../../consts'; import { PVP } from '../../../pubUtils/dicParam'; import { addItems } from '../../../services/rewardService'; import { HeroModel } from '../../../db/Hero'; import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { BattleRecordModel } from '../../../db/BattleRecord'; import { PvpRecordModel } from '../../../db/PvpRecord'; import { handleCost } from '../../../services/rewardService'; import { nowSeconds, getSeconds } from '../../../pubUtils/timeUtil'; import { setPvpSeasonResult, resetPvpWarId, resetPvpSeasonTime } from '../../../services/timeTaskService'; import { PvpSeasonResultModel } from '../../../db/PvpSeasonResult'; import { PvpHistoryOppModel, PvpHistoryOppType } from '../../../db/PvpHistoryOpp'; import { SystemConfigModel } from '../../../db/SystemConfig'; import { Rank } from '../../../services/rankService'; import { checkActivityTask, checkTask, checkTaskInPvpEnd } from '../../../services/taskService'; export default function (app: Application) { return new PvpHandler(app); } export class PvpHandler { constructor(private app: Application) { } async addRoleScore(msg: { heroScores: Array<{ hid: number, score: number }> }, session: BackendSession) { let { heroScores: addHeroScores } = msg; let roleId = session.get('roleId'); let sid = session.get('sid'); const funcs: number[] = session.get('funcs'); let { heroScores, hisScore } = await PvpDefenseModel.findByRoleId(roleId); let score = 0; for (let { hid, score: heroScore } of addHeroScores) { if (heroScore < 0) continue; let index = findIndex(heroScores, { hid }); if (index != -1) { heroScores[index].score = heroScore; } else { heroScores.push({ hid, score: heroScore }); } } for (let heroScore of heroScores) { score += heroScore.score; } if (score < 0) { score = 0; } if (hisScore < score) { hisScore = score; } let pLv = getPLvByScore(score); let pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { score, hisScore, pLv, heroScores }); let roleName = session.get('roleName'); const role = await RoleModel.findByRoleId(roleId); // 加入排行榜 let r = new Rank(REDIS_KEY.PVP_RANK, {}); await r.setRankWithRoleInfo(roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), role); // 任务 await checkTask(roleId, sid, funcs, TASK_TYPE.PVP_HERO_SCORE, 0, false, { heroScores }); return resResult(STATUS.SUCCESS, { score, hisScore, heroScores }); } async debugPvpSeasonReset(msg: {}, session: BackendSession) { let { seasonNum, seasonEndTime } = await setPvpSeasonResult({ name: 'exce setPvpSeasonResult debug' }); return resResult(STATUS.SUCCESS, { seasonNum, seasonEndTime }) } async debugPvpWarReset(msg: {}, session: BackendSession) { let systemConfig = await resetPvpWarId(); return resResult(STATUS.SUCCESS, { systemConfig }); } async debugPvpSeasonResetTime(msg: { day: number }, session: BackendSession) { let { day: hour } = msg; let { seasonNum, seasonEndTime } = await pinus.app.rpc.systimer.systimerRemote.resetPvpSeasonTime.toServer('systimer-server-1', hour); return resResult(STATUS.SUCCESS, { seasonNum, seasonEndTime }); } async debugAddChallengeCnt(msg: { challengeCnt: number }, session: BackendSession) { let { challengeCnt } = msg; let roleId = session.get('roleId'); if (challengeCnt > PVP.PVP_CHALLENGE_COUNTS) { challengeCnt = PVP.PVP_CHALLENGE_COUNTS; } let { challengeRefTime } = await PvpDefenseModel.updateInfoAndInclude(roleId, { challengeCnt, challengeRefTime: nowSeconds(), refOppCnt: 0 }); return resResult(STATUS.SUCCESS, { challengeCnt, challengeRefTime }); } async getData(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let { pvpDefense, warId, seasonEndTime } = await findPvpDefAllByRoleId(roleId); let oppPlayers = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); let { isDefaultHero, heroes, score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry, seasonNum } = pvpDefense; if (isFirstEntry) { await PvpDefenseModel.updateInfo(roleId, { isFirstEntry: false }); } let pvpSeasonResult = await PvpSeasonResultModel.getPvpSeasonResult(roleId); let flag = false; if (!!pvpSeasonResult) { var { oldSeasonData, show, heroGoods, rankGoods } = pvpSeasonResult; if (oldSeasonData.seasonEndTime > nowSeconds()) {//结算中锁定玩家信息,结算结束后统一展示修改完成的信息 seasonEndTime = oldSeasonData.seasonEndTime; heroScores = oldSeasonData.heroScores; score = oldSeasonData.score; refOppCnt = oldSeasonData.refOppCnt; challengeCnt = oldSeasonData.challengeCnt; challengeRefTime = oldSeasonData.challengeRefTime; } else if (show) {//是否需要弹出结算奖励界面 await PvpSeasonResultModel.updatePvpSeasonResult(roleId, { show: false }); flag = true; } } let r = new Rank(REDIS_KEY.PVP_RANK, {}); let myRank = await r.getMyRank({ roleId });//去redis中获取排名 let data: any = { warId, seasonNum, seasonEndTime, myRank, oppPlayers, heroes: heroes.map(cur => { let { actorId, dataId, order } = cur; return { actorId, dataId, order } }), score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry, isDefaultHero } if (flag) {//弹出结赛季结算奖励 data.resultRecord = { oldSeasonData, heroGoods, rankGoods } } return resResult(STATUS.SUCCESS, data); } // 刷新对手 async refreshOppPlayer(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let sid = session.get('sid'); let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId); // 刷新次数及消耗 let { refOppCnt, refOppTime, consume } = getRefOppCnt(pvpDefense.refOppCnt, pvpDefense.refOppTime); if (refOppCnt >= gameData.maxPvpRefreshCnt.max) { return resResult(STATUS.PVP_REFRESH_CNT_REACH_MAX); } let costResult = await handleCost(roleId, sid, consume); if (!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); // 刷新对手 let role = pvpDefense.role; let oppPlayers = await refreshEnemies(role, pvpDefense.score, pvpDefense.pLv); pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers, refOppCnt: refOppCnt + 1, refOppTime }); let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); return resResult(STATUS.SUCCESS, { oppPlayers: result, refOppCnt: pvpDefense.refOppCnt }); } // 获取对手阵容具体信息 async getOppPlayer(msg: { roleId: string }, session: BackendSession) { let roleId = session.get('roleId'); let oppoRoleId = msg.roleId; let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId); let { oppPlayers } = pvpDefense; let curOpp = oppPlayers.find(cur => cur.roleId == oppoRoleId); if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND); let { oppRoleId, heroes } = curOpp.oppDef; return resResult(STATUS.SUCCESS, { roleId: oppRoleId, pos: curOpp.pos, heroes }); } // 开战 async pvpStart(msg: { warId: number, heroes: number[], roleId: string }, session: BackendSession) { const { warId, heroes, roleId: oppRoleId } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let warInfo = gameData.war.get(warId); if (!warInfo) { return resResult(STATUS.BATTLE_MISS_INFO); } let { isOK } = await checkBattleHeroesByHid(roleId, heroes); if (!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); const pvpDefense = await PvpDefenseModel.findByRoleId(roleId); if (!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); // 检查挑战次数 let { seasonEndTime } = await SystemConfigModel.findSystemConfig(); let { challengeCnt } = refresh(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime); if (challengeCnt == 0) { return resResult(STATUS.PVP_CHALLENGE_TIMES_NOT_ENOUGH); } let { oppPlayers } = pvpDefense; let curOpp = oppPlayers.find(cur => cur.roleId == oppRoleId); if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND) const battleCode = genCode(8); // 关卡唯一值 await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { roleId, roleName, battleId: warId, status: 0, warName: warInfo.gk_name, warType: warInfo.warType, record: { heroes, pos: curOpp.pos, oppRoleId } } }, true); return resResult(STATUS.SUCCESS, { battleCode }); } // 结算 async pvpEnd(msg: { battleCode: string, isSuccess: boolean, myHeroes: pvpEndParamInter[], oppHeroes: pvpEndParamInter[] }, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); const funcs: number[] = session.get('funcs'); const serverId = session.get('serverId'); const { battleCode, isSuccess, myHeroes, oppHeroes } = msg; const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true); if (!BattleRecord || BattleRecord.status != 0) { return resResult(STATUS.BATTLE_STATUS_WRONG); } let { record: { heroes: dbHeroes, oppRoleId, pos } } = BattleRecord; let flag = 1; // 对比hero信息 for (let { hid } of myHeroes) { if (dbHeroes.indexOf(hid) == -1) flag = 0; } if (!flag) return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR); // 更新军功 let { pvpDefense, warId } = await findPvpDefByRoleId(roleId); if (!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN); let { oppPlayers, winStreakNum, heroScores, score, hisScore } = pvpDefense; let curOpp = oppPlayers.find(cur => cur.roleId == oppRoleId && cur.pos == pos); if (!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND); const role = await RoleModel.findByRoleId(roleId, null, true); if (isSuccess) { winStreakNum++; } else { winStreakNum = 0; } const myRecInfo = await generMyRecInfo(heroScores, winStreakNum, role, isSuccess, pos, myHeroes); let { attackInfo, showHeroScores, addSumScore } = myRecInfo score += addSumScore; let pLv = getLvByScore(heroScores); const defenseInfo = await generPVPOppRecInfo(isSuccess, curOpp, oppHeroes, role.lv); // 战报记录 await PvpRecordModel.createRec({ roleId1: roleId, roleId2: robotIdComBack(oppRoleId), warId: BattleRecord.battleId, attackInfo, defenseInfo, createTime: nowSeconds() }); // 对手记录更新 await PvpHistoryOppModel.setStatus(roleId, oppRoleId, 1); // 刷新对手 let newOppPlayers: Array = await refreshEnemies(role, score, pLv); // 更新battleRecord await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { status: isSuccess ? 1 : 2 } }, true); let { seasonEndTime } = await SystemConfigModel.findSystemConfig(); // 减少挑战次数 let { challengeCnt, challengeRefTime } = comsumeChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, seasonEndTime); if (hisScore < score) { hisScore = score; } pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers: newOppPlayers, heroScores, score, pLv, winStreakNum, challengeCnt, challengeRefTime, hisScore }); let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum); // 加入排行榜 let r = new Rank(REDIS_KEY.PVP_RANK, {}); await r.setRankWithRoleInfo(roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), role); let myRank = await r.getMyRank({ roleId }); await checkTaskInPvpEnd(roleId, sid, funcs, isSuccess, heroScores); await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.PVP, 1) if (isSuccess) { await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.PVP_WIN, 1) await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.PVP_WIN_SERIES, 1) } return resResult(STATUS.SUCCESS, { battleCode, isSuccess, score, pLv, myRank, hisScore, heroScores: showHeroScores, oppPlayers: result, refOppCnt: pvpDefense.refOppCnt, challengeCnt: pvpDefense.challengeCnt, challengeRefTime: pvpDefense.challengeRefTime, winStreakNum: pvpDefense.winStreakNum, warId }); } async saveDefense(msg: { heroes: Array<{ actorId: number, dataId: number, order: number }>, isDefaultHero: boolean }, session: BackendSession) { let { heroes, isDefaultHero } = msg; let roleId = session.get('roleId'); if (heroes.length > LINEUP_NUM || heroes.length <= 0) { return resResult(STATUS.WRONG_PARMS); } heroes = uniq(heroes, function (item) { return item.order; }); let { seasonEndTime } = await SystemConfigModel.findSystemConfig(); let { heroes: defHeros, challengeCnt: lastChallengeCnt, challengeRefTime: lastChallengeRefTime } = await PvpDefenseModel.findByRoleId(roleId); let defCe = 0; let { challengeCnt, challengeRefTime } = refresh(lastChallengeCnt, lastChallengeRefTime, seasonEndTime); if (!!isDefaultHero) { let { topLineup } = await RoleModel.findByRoleId(roleId); let hids = topLineup.filter(cur => { return !heroes.find(ccur => ccur.actorId == cur.hid); }).map(cur => cur.hid); let dataIds = new Array(), orders = new Array(); for (let hero of heroes) { if (hero.actorId) { let isInTop = topLineup.find(cur => cur.hid == hero.actorId); if (!isInTop) { hero.actorId = hids.shift(); } dataIds.push(hero.dataId); orders.push(hero.order); } } for (let hid of hids) { let dataId = 0; for (let i = PVP_HERO_POS.START; i <= PVP_HERO_POS.END; i++) { if (dataIds.includes(i)) continue; dataIds.push(i); dataId = i; break; } let order = 0; for (let i = PVP_HERO_ORDER.START; i <= PVP_HERO_ORDER.END; i++) { if (orders.includes(i)) continue; orders.push(i); order = i; break; } heroes.push({ actorId: hid, dataId, order }) } } for (let dataId = PVP_HERO_POS.START; dataId <= PVP_HERO_POS.END; dataId++) { let index = findIndex(heroes, { dataId }); let defIndex = findIndex(defHeros, { dataId }); if (defIndex == -1) { defIndex = defHeros.length; defHeros.push({ actorId: 0, order: 0, ce: 0, hero: null, dataId }); } if (index == -1) { defHeros[defIndex].actorId = 0; defHeros[defIndex].order = 0; defHeros[defIndex].ce = 0; defHeros[defIndex].hero = null; defHeros[defIndex].dataId = dataId; continue; } if (heroes[index].order < 1 || heroes[index].order > LINEUP_NUM) { return resResult(STATUS.WRONG_PARMS); } let hero = await HeroModel.findByHidAndRole(heroes[index].actorId, roleId); if (!hero) { continue; } defHeros[defIndex].actorId = heroes[index].actorId; defHeros[defIndex].order = heroes[index].order; defHeros[defIndex].ce = hero.ce; defHeros[defIndex].hero = hero._id; defCe += hero.ce; } let { heroes: resHeroes } = await PvpDefenseModel.updateInfo(roleId, { defCe, heroes: defHeros, challengeCnt, challengeRefTime, isDefaultHero }); return resResult(STATUS.SUCCESS, { heroes: resHeroes, challengeCnt, challengeRefTime, isDefaultHero }); } async getRank(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let r = new Rank(REDIS_KEY.PVP_RANK, {}); let { ranks, myRank } = await r.getRankListWithMyRank({ roleId }); if (!myRank) { let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); myRank = await r.generMyRankWithRole(roleId, pvpDefense.score, getSeconds(pvpDefense.refOppTime)); } return resResult(STATUS.SUCCESS, { ranks, myRank }); } async getPlayerDetail(msg: { roleId: string }, session: BackendSession) { let roleId = session.get('roleId'); let { roleId: oppoRoleId } = msg; let isRobot = checkRoleIsRobot(oppoRoleId); let result: PlayerDetail; if (isRobot) { // 如果是机器人,从自己的pvpDefense中寻找 let pvpHistoryOpp = await PvpHistoryOppModel.findByRoleIdAndOppId(roleId, oppoRoleId); if (!pvpHistoryOpp) { return resResult(STATUS.PVP_ROLE_NOT_FOUND); } let heroes = new Array(); for (let hero of pvpHistoryOpp.heroes) { let newHero = new PlayerDetailHero(); newHero.setPvpHeroInfo(hero); heroes.push(newHero); } for (let hero of pvpHistoryOpp.otherHeroes) { let newHero = new PlayerDetailHero(); newHero.setPvpHeroInfo(hero); heroes.push(newHero); } result = new PlayerDetail({ ...pvpHistoryOpp, roleId: pvpHistoryOpp.oppRoleId, heroes, rank: pvpHistoryOpp.rankLv }); } else { // 查询对方pvpDefense let pvpDefense = await PvpDefenseModel.findByRoleId(oppoRoleId); let dbHeroes = await HeroModel.findByRole(oppoRoleId); let role = await RoleModel.findByRoleId(oppoRoleId); let heroes = new Array(); for (let { hid, lv, star, colorStar, quality } of dbHeroes) { let heroScore = pvpDefense.heroScores.find(cur => cur.hid == hid); heroes.push({ actorId: hid, lv, star, colorStar, quality, score: heroScore ? heroScore.score : 0 }); } heroes.sort((a, b) => b.score - a.score); let r = new Rank(REDIS_KEY.PVP_RANK, {}); let rank = await r.getMyRank({ roleId: oppoRoleId });//去redis中获取排名 result = new PlayerDetail({ ...role, ...pvpDefense, heroes, rank }); } return resResult(STATUS.SUCCESS, result); } async receiveBox(msg: { id: number }, session: BackendSession) { let { id } = msg; let roleId = session.get('roleId'); let sid: string = session.get('sid'); let roleName = session.get('roleName'); const funcs: number[] = session.get('funcs'); let { seasonEndTime } = await SystemConfigModel.findSystemConfig(); let { hisScore, receivedBox, challengeCnt: lastChallengeCnt, challengeRefTime: lastChallengeRefTime } = await PvpDefenseModel.findByRoleIdIncludeAll(roleId); let pvpBoxs = getPvpBoxs(); let pvpBox = findWhere(pvpBoxs, { id }); if (hisScore < pvpBox.score) { return resResult(STATUS.PVP_NOT_REACH_BOX_SCORE); } if (receivedBox.indexOf(id) != -1) { return resResult(STATUS.PVP_BOX_IS_GOT); } receivedBox.push(id); let { challengeCnt, challengeRefTime } = refresh(lastChallengeCnt, lastChallengeRefTime, seasonEndTime); await PvpDefenseModel.updateInfo(roleId, { receivedBox, challengeCnt, challengeRefTime }); let result = await addItems(roleId, roleName, sid, pvpBox.reward); // 任务 await checkTask(roleId, sid, funcs, TASK_TYPE.PVP_RECEIVE_BOX, 1, true, {}); return resResult(STATUS.SUCCESS, { goods: result, receivedBox, challengeCnt, challengeRefTime }); } async getRec(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let pvpRecords = await PvpRecordModel.getRecByRoleId(roleId); return resResult(STATUS.SUCCESS, { list: pvpRecords }); } }