import { PvpDefenseModel, PvpDefenseType, pvpUpdateInter } from '../db/PvpDefense'; import { Defense, Attack, LineupCe, OppPlayer, HeroScore, HeroReward, OppPlayerReturn, AttackHero, DefenseHero } from '../domain/battleField/pvp'; import { RoleType } from '../db/Role'; import { REDIS_KEY, TASK_TYPE, MAIL_TYPE, TA_EVENT, ITID, getHeadItid, getFrameItid, getSpineItid, PVP_SEASON_STATUS } from '../consts'; import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent"; import { getRandSingleIndex, genCode, shouldRefresh, getChineseName, makeRobotId, robotIdComBack, getRandSingleEelm } from '../pubUtils/util'; import { pvpEndParamInter, RewardInter } from '../pubUtils/interface'; import { gameData, getPLvByScore, getPvpHeroRewardsByScore, getPvpRankRewardsByRank, getPvpDifficultByScore, getPlvAndScore, getPvpBoxsBySeasonNum, getPvpRankMaxRewardsBySeasonNum, randomGoodsByItid } from "../pubUtils/data"; import { EXTERIOR, PVP } from '../pubUtils/dicParam'; import { PVPConfigModel } from '../db/PvpConfig' import { nowSeconds, getTimeFun } from '../pubUtils/timeUtil'; import { HeroesRecord, PvpRecordPlayerInfo } from '../db/PvpRecord'; import { HeroModel, HeroType } from '../db/Hero'; import { AttributeCal } from '../domain/roleField/attribute'; import { PvpEnemies, PvpHeroInfo, PvpOtherHeroes } from '../domain/dbGeneral'; import { pinus } from 'pinus'; import { PvpHistoryOppModel, PvpHistoryOppType, PvpOppCreateParam } from '../db/PvpHistoryOpp'; import { Rank } from './rankService'; import { DicRankRewads } from '../pubUtils/dictionary/DicPvpRankReward'; import { PvpSeasonResultModel, PvpSeasonResultType } from '../db/PvpSeasonResult'; import { checkTask } from './task/taskService'; import { sendMailByContent } from './mailService'; import { RoleRankInfo } from '../domain/rank'; import { reportTAEvent } from './sdkService'; import { getVipPvpChallengeMaxCnt } from './activity/monthlyTicketService'; import { getHeroesAttributes } from './playerCeService'; import { setPvpSettleSeasonNumToRemote } from './timeTaskService'; import { ArtifactModel } from '../db/Artifact'; import { getPVPGroupIdOfServer, getPvpServersByGroupId } from './serverService'; import { findKeys } from './redisService'; /** * 返回对手三人信息 * * @param oppPlayers pvpDefense表中的oppPlayers字段,需要populate过的 * @param pLv 玩家本人的队伍等级 */ export async function getEnemies(oppPlayers: OppPlayer[], winStreakNum: number) { let result = new Array(); for (let oppPlayer of oppPlayers) { let dicOpponent = dicPvpOpponent.get(oppPlayer.pos); let oppDef = oppPlayer.oppDef; // select 'oppRoleId pos roleName head frame spine rankLv pLv defCe' if (oppDef) delete oppDef.heroes; result.push({ ...oppDef, roleId: oppDef.oppRoleId, defCe: oppDef.defCe, addScore: dicOpponent.score, rankLv: oppDef.rankLv, plusScore: getPlusScore(winStreakNum) }); } return result } /** * @description 刷新对手三个人 * @param role 数据库里我的role * @param score 我的军功 * @param pLv 我的排名 */ export async function refreshEnemies(role: RoleType, seasonNum: number, sumScore: number, score: number, pLv: number) { let { roleId, serverId } = role; let groupId = await getPVPGroupIdOfServer(serverId); let chosenOpps: string[] = []; let pvpHistoryOppParam: PvpOppCreateParam[] = []; let opp = dicPvpOpponent.values() for (let dicOpp of opp) { let pvpHistoryOpp: PvpOppCreateParam; // 是否筛选成功 if (sumScore >= PVP.PVP_MATCH_ROBOT) { pvpHistoryOpp = await matchPlayer(groupId, seasonNum, chosenOpps, roleId, pLv, dicOpp); // 按照等级匹配对手 if (!pvpHistoryOpp) pvpHistoryOpp = await matchPlayerByRank(groupId, seasonNum, chosenOpps, roleId, dicOpp.id); // 当前后分数段没有时,返回前一名的玩家 if (!pvpHistoryOpp) pvpHistoryOpp = await matchRobot(chosenOpps, role, score, dicOpp); } else { pvpHistoryOpp = await matchRobot(chosenOpps, role, score, dicOpp); } if (!pvpHistoryOpp) continue; pvpHistoryOppParam.push(pvpHistoryOpp); } let oppPlayers: OppPlayer[] = []; pvpHistoryOppParam.sort((a, b) => { if(a.pLv != b.pLv) return b.pLv - a.pLv; return b.defCe - a.defCe; }); for(let i = 0; i < pvpHistoryOppParam.length; i++) { let param = pvpHistoryOppParam[i]; param.pos = i + 1; let pvpHistoryOpp = await PvpHistoryOppModel.createPvpOpp(param); oppPlayers.push({ roleId: pvpHistoryOpp.oppRoleId, oppDef: pvpHistoryOpp._id, isRobot: pvpHistoryOpp.isRobot, pos: pvpHistoryOpp.pos, }); } return oppPlayers; } export async function matchPlayerByRank(groupId: number, seasonNum: number, chosenOpps: string[], roleId: string, pos: number) { // console.log('matchPlayerByRank', JSON.stringify(oppPlayers)) let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum, groupId }); let ridRanks = new Array(); // 已经被使用了的排名 for (let curRoleId of chosenOpps) { let rankLv = await r.getMyRank({ roleId: robotIdComBack(curRoleId) }); ridRanks.push(rankLv); } let myRank = await r.getMyRank({ roleId }); ridRanks.push(myRank); let oppRoleId = ''; let oppRank = 0; if (myRank == 0) { return null } else if (myRank == 1) { // 第一名 if (pos == 1) { oppRank = 2; while (ridRanks.includes(oppRank)) { oppRank--; } } else if (pos == 2) { oppRank = 3; while (ridRanks.includes(oppRank)) { oppRank--; } } else { oppRank = 4; while (ridRanks.includes(oppRank)) { oppRank++; } } } else if (myRank == 2) { // 第二名 if (pos == 1) { oppRank = 1; while (ridRanks.includes(oppRank)) { oppRank--; } } else if (pos == 2) { oppRank = 3; while (ridRanks.includes(oppRank)) { oppRank++; } } else { oppRank = 4; while (ridRanks.includes(oppRank)) { oppRank++; } } } else { if (pos == 1 || pos == 2) { // 刷新我前一名 oppRank = myRank - 1; while (ridRanks.includes(oppRank)) { oppRank--; } } else { // 刷新我后一名 oppRank = myRank + 1; while (ridRanks.includes(oppRank)) { oppRank++; } } } if(oppRank <= 0) return null; let result = await r.getUserByRank(oppRank); if (result.length <= 0) return null; oppRoleId = result[0]; let pvpdefense = await PvpDefenseModel.findByRoleIdIncludeAll(oppRoleId); if (!pvpdefense || pvpdefense.seasonNum != seasonNum || !pvpdefense.hasDefense) return null; let pvpHistoryOpp = await generPlayerOppHis(pvpdefense, roleId, pos, groupId); if (!pvpHistoryOpp) return null; chosenOpps.push(pvpHistoryOpp.oppRoleId); return pvpHistoryOpp; } async function matchPlayer(groupId: number, seasonNum: number, chosenOpps: string[], roleId: string, pLv: number, dicOpp: DicPvpOpponent) { // console.log('matchPlayer', JSON.stringify(oppPlayers)) let serverIds = await getPvpServersByGroupId(groupId); let { id: pos, minLv, maxLv } = dicOpp let range = await PvpDefenseModel.findByTeamLv(serverIds, seasonNum, pLv + minLv, pLv + maxLv); range = range.filter(cur => { return chosenOpps.indexOf(makeRobotId(cur.roleId)) == -1; }); if (range.length <= 0) return null; let index = getRandSingleIndex(range.length); let result = range[index]; // 本次匹配结果 pvpdefense if (!result) return null; if (result.roleId == roleId) { range.splice(index, 1); if (range.length <= 0) return null; index = getRandSingleIndex(range.length); result = range[index]; } let pvpHistoryOpp = await generPlayerOppHis(result, roleId, pos, groupId); if (!pvpHistoryOpp) return null; chosenOpps.push(pvpHistoryOpp.oppRoleId); return pvpHistoryOpp; } /** * @description 对手是玩家时,生成并返回pvpHistoryOpp * @param result 随机出的对手pvpDefense * @param roleId 自己的玩家id * @param pos 刷新这个对手的位置 */ async function generPlayerOppHis(pvpdefense: PvpDefenseType, roleId: string, pos: number, groupId: number) { let { heroScores, defense } = pvpdefense; if(!defense) return false; let { warId, heroes: defenseHeroes } = defense; let role = pvpdefense.role; let seasonNum: number = pinus.app.get('pvpSeasonNum'); let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum, groupId }); let rankLv = await r.getMyRank({ roleId: role.roleId }); let dbHeroes = await HeroModel.findByRole(role.roleId, [{ field: 'ce', sortBy: -1 }]); let heroes = new Array(); let otherHeroes = new Array(); // 阵容外的所有武将信息 let defCe = 0; let attrByHid = await getHeroesAttributes(role.roleId); for (let dbHero of dbHeroes) { let artifact = dbHero.artifact? await ArtifactModel.findbySeqId(role.roleId, dbHero.artifact): null; let h = defenseHeroes.find(cur => cur.actorId == dbHero.hid); // 阵容里是否有这个武将 let hs = heroScores.find(cur => cur.hid == dbHero.hid); // 这个武将是否有这个得分 if (!!h) { let dicWar = gameData.war.get(warId); let mapWarJson = gameData.warJson.get(dicWar.dispatchJsonId); let warJson = mapWarJson.find(cur => cur.dataId == h.dataId); if (warJson && warJson.relation == 2) { let heroInfo = new PvpHeroInfo(); heroInfo.setHeroInfo(dbHero, artifact); // heroInfo.setOutIndex(h.order); let attr = attrByHid.get(h.actorId); if(!attr) continue; let attribute = attr.getAttributesToString(); let ce = attr.calCe(); heroInfo.setAttribute(attribute); let enemy = new PvpEnemies(warJson, heroInfo, hs ? hs.score : 0, ce); enemy.setOutIndex(h.order); heroes.push(enemy); defCe += ce; } } else { let heroInfo = new PvpOtherHeroes(hs ? hs.score : 0); heroInfo.setHeroInfo(dbHero, artifact); otherHeroes.push(heroInfo); } } heroes.sort((a, b) => b.score - a.score); otherHeroes.sort((a, b) => b.score - a.score); return { isRobot: false, ...defense, defCe, ...role, pos, rankLv, heroes, otherHeroes, roleId, oppRoleId: makeRobotId(pvpdefense.roleId) }; } async function matchRobot(chosenOpps: string[], role: RoleType, score: number, dicOpp: DicPvpOpponent) { // console.log('matchRobot', JSON.stringify(oppPlayers)) let { lv: myLv, roleId } = role; let { id: pos, minLv, maxLv, ratio } = dicOpp; let pvpConfig = await PVPConfigModel.findCurPVPConfig(); let range = pvpConfig?.warIds||[]; let warId = getRandSingleEelm(range); if (!warId) return null; let result = gameData.war.get(warId); if (!result) return null; let robotWarjson = gameData.warJson.get(result.dispatchJsonId); if (!robotWarjson) return null let heroes: PvpEnemies[] = []; let defCe = 0; for (let h of robotWarjson) { if (h.relation == 1) continue; let actorId = h.randomEnemy.length > 0? getRandSingleEelm(h.randomEnemy): 0; let dicHero = gameData.hero.get(actorId); if (!dicHero) continue; let heroInfo = new PvpHeroInfo(); let robotInfo = getRobotAttribute(actorId, ratio, score); if(!robotInfo) continue; let { attribute, ce, lv } = robotInfo; heroInfo.setRobotInfo(dicHero, lv); defCe += ce; heroInfo.setAttribute(attribute); let enemy = new PvpEnemies(h, heroInfo, 0, ce); enemy.setOutIndex(h.outIndex); heroes.push(enemy); } let oppRoleId = generateRobotRoleId(); chosenOpps.push(oppRoleId); let roleName = getChineseName(); let pLv = getPLvByScore(score); let hisPLv = Math.floor(pLv + (minLv + maxLv) / 2); if (hisPLv < 1) hisPLv = 1 return { isRobot: true, roleId, oppRoleId, roleName, pos, defCe, pLv: hisPLv, lv: myLv, heroes, rankLv: 0, warId: result.war_id, buff: getRandSingleEelm(result.mapseid)||0, head: randomHead(), frame: randomFrame(), spine: randomSpine() }; } function randomHead() { return randomGoodsByItid(getHeadItid())||EXTERIOR.EXTERIOR_FACE; } function randomFrame() { return randomGoodsByItid(getFrameItid())||EXTERIOR.EXTERIOR_FACECASE; } function randomSpine() { return randomGoodsByItid(getSpineItid())||EXTERIOR.EXTERIOR_APPEARANCE; } // 生成机器人roleId function generateRobotRoleId() { return `${genCode(10)}_r`; } // 根据连胜次数,获得加成的积分 export function getPlusScore(win: number) { let result = win - 1; if (result < 0) result = 0; if (result > PVP.PVP_WINREWARD_UPLIMIT) result = PVP.PVP_WINREWARD_UPLIMIT; return result; } export function getLvByScore(heroScores: HeroScore[]) { heroScores.sort((a, b) => b.score - a.score); let score = 0; for (let i = 0; i < 5; i++) { if (!heroScores[i]) break; score += heroScores[i].score; } return getPLvByScore(score); } export async function refChallengeCnt(challengeCnt: number, challengeRefTime: number, seasonEndTime: number, roleId: string, vipStartTime?: number) { let hasChanged = false; let initCount = await getVipPvpChallengeMaxCnt(roleId, vipStartTime) if (challengeCnt >= initCount) { return { hasChanged, challengeCnt, challengeRefTime: nowSeconds() }; } let period = PVP.PVP_CHALLENGE_NORMALTIMES * 60; if (getTimeFun(seasonEndTime).checkDay()) { period = PVP.PVP_CHALLENGE_FINALTIMES * 60; } let time = nowSeconds(); let num = Math.floor((time - challengeRefTime) / period); if (num > 0) { challengeCnt += num; challengeRefTime = challengeRefTime + period * num; hasChanged = true; } if(challengeCnt > initCount) challengeCnt = initCount; return { hasChanged, challengeCnt, challengeRefTime }; } export async function comsumeChallengeCnt(challengeCnt: number, challengeRefTime: number, seasonEndTime: number, roleId: string) { let initCount = await getVipPvpChallengeMaxCnt(roleId) challengeCnt--; if (challengeCnt >= initCount) { return { challengeCnt, challengeRefTime }; } if (challengeCnt == initCount - 1) { challengeRefTime = nowSeconds(); return { challengeCnt, challengeRefTime }; } return refChallengeCnt(challengeCnt, challengeRefTime, seasonEndTime, roleId); } export async function sendLastSeasonRewardIfNotSent(pvpDefense: PvpDefenseType) { let seasonSettleNum: number = pinus.app.get('pvpSettleSeasonNum'); console.log('##### sendLastSeasonRewardIfNotSent seasonSettleNum', pvpDefense.roleId, pvpDefense.rankSeasonNum, seasonSettleNum) if(seasonSettleNum && pvpDefense.rankSeasonNum < seasonSettleNum) { let oldPvpCongig = await PVPConfigModel.findPVPConfig(seasonSettleNum); let result = await sendPVPRewardToUser(pvpDefense, seasonSettleNum, oldPvpCongig.seasonEndTime); pvpDefense = result.pvpDefense; } return pvpDefense; } // async function checkHasSettled(seasonSettleNum: number, roleId: string) { // let hasData = await PvpSeasonResultModel.checkResultBySeasonNum(roleId, seasonSettleNum); // return hasData; // } // 获取刷新对手次数及消耗 export function refreshRefOppCnt(pvpDefense: PvpDefenseType) { let { refOppCnt = 0, setAttackCnt = 0, buyAttackCnt = 0, refDaily } = pvpDefense; let curTime = new Date(); let shouldRefOpp = shouldRefresh(refDaily, curTime); if (shouldRefOpp) { refOppCnt = 0; setAttackCnt = 0; buyAttackCnt =0; refDaily = curTime; } return { shouldRefOpp, refOppCnt, refDaily, setAttackCnt, buyAttackCnt, consume: gameData.pvpRefreshConsume.get(refOppCnt + 1) } } /** * 根据比例计算机器人属性 * @param attribute 出兵表中的属性字段 * @param ce 我的战力 * @param enemyCe 出兵表对手战力 * @param ratio 系数 */ export function getRobotAttribute(hid: number, posRatio: number, score: number) { let difficultRatio = getPvpDifficultByScore(score); if(!difficultRatio) return null let dicHero = gameData.hero.get(hid); let newAttribute = new AttributeCal(); newAttribute.setLv(difficultRatio.enemyLv); newAttribute.setByMap(hid, dicHero.baseAbilityArr, difficultRatio.value / 10000 * posRatio); let subAttr = gameData.towerPvpSubAttr.get(difficultRatio.secondAttrLevel); if(subAttr) newAttribute.setByWarJson(hid, subAttr.secondAtr); let attrArr = newAttribute.getAttributesToString(); let newCe = newAttribute.calCe(); return { attribute: attrArr, ce: newCe, lv: difficultRatio.enemyLv }; } // 获取我方战报记录 export async function generMyRecInfo(pvpDefense: PvpDefenseType, role: RoleType, isSuccess: boolean, pos: number, myHeroes: pvpEndParamInter[]) { let { attack, defense, heroScores, winStreakNum, hisWinStreakNum = 0, score, hisScore, seasonWinNum = 0 } = pvpDefense; let { roleId } = role; if (isSuccess) { winStreakNum ++; seasonWinNum ++; } else { winStreakNum = 0; } if(winStreakNum > hisWinStreakNum) { hisWinStreakNum = winStreakNum; } const dicOpp = gameData.pvpOpponent.get(pos); const plusScore = getPlusScore(winStreakNum); let myHeroRecords: HeroesRecord[] = []; // 存入rec里面的数据 let showHeroScores = new Array<{ hid: number, addScore: number, plusScore: number, score: number }>(); let addSumScore = 0; for (let { actorId: hid } of attack.heroes) { if(hid == 0) continue; let params = myHeroes.find(cur => cur.hid == hid); let curHeroScore = heroScores.find(cur => cur.hid == hid); if (isSuccess) { if (!curHeroScore) { curHeroScore = { hid, score: dicOpp.score + plusScore }; heroScores.push(curHeroScore); } else { curHeroScore.score += dicOpp.score + plusScore; } addSumScore += dicOpp.score + plusScore; showHeroScores.push({ hid, addScore: dicOpp.score, plusScore, score: curHeroScore.score }); } else { showHeroScores.push({ hid, addScore: 0, plusScore: 0, score: curHeroScore ? curHeroScore.score : 0 }); } const myHero = await HeroModel.findByHidAndRole(hid, roleId, 'quality star colorStar lv skinId'); let record = new HeroesRecord(); record.setByHero(myHero, params); myHeroRecords.push(record); } let attackInfo = new PvpRecordPlayerInfo(); attackInfo.setByRole(role, myHeroRecords, isSuccess, isSuccess ? addSumScore : 0, attack.pLv); let newAttack = calLineupScore(attack, heroScores); let newDefense = calLineupScore(defense, heroScores); let updateParam = { winStreakNum, hisWinStreakNum, attack: newAttack, defense: newDefense, heroScores, score: score + addSumScore, hisScore: hisScore > score + addSumScore? hisScore: score + addSumScore, seasonWinNum } return { attackInfo, showHeroScores, updateParam } } export function calLineupScore(lineup: Attack|Defense, heroScores: HeroScore[]) { if(!lineup) return lineup; let scores: number[] = []; for(let { actorId } of lineup.heroes) { let hs = heroScores.find(cur => cur.hid == actorId); if(hs) { scores.push(hs.score); } } let { pLv, score } = getPlvAndScore(scores); return {...lineup, score, pLv} } // 获取对手战报记录 export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayer, oppHeroes: pvpEndParamInter[], serverId: number) { let oppHeroRecords = new Array(); let oppRole = curOpp.oppDef; if (!oppRole) { console.error('opp role not found') } for (let params of oppHeroes) { let historyHero = oppRole.heroes.find(cur => cur.actorId == params.hid); if (historyHero) { let hs = new HeroesRecord(); hs.setByPvpHeroInfo(historyHero, params); oppHeroRecords.push(hs); } } let addSumScore = 0; if(!curOpp.isRobot && !isSuccess) { let pvpDefense = await PvpDefenseModel.findByRoleId(robotIdComBack(curOpp.roleId)); if(pvpDefense && pvpDefense.defense) { let { attack, defense, heroScores, score, defenseScoreCnt, refDefenseScore } = pvpDefense; if(shouldRefresh(refDefenseScore, new Date())) { defenseScoreCnt = 0; refDefenseScore = new Date(); } if(defenseScoreCnt < PVP.PVP_DEFENSE_SUCCESS_REWARD_MAX_CNT) { for(let { actorId } of defense.heroes) { let hs = heroScores.find(cur => cur.hid == actorId); const dicOpp = gameData.pvpOpponent.get(curOpp.pos); let addScore = PVP.PVP_DEFENSE_SUCCESS_REWARD - dicOpp.score; if(hs) { hs.score += addScore; } else { heroScores.push({ hid: actorId, score: addScore }) } addSumScore += addScore; } let newAttack = calLineupScore(attack, heroScores); let newDefense = calLineupScore(defense, heroScores); await PvpDefenseModel.updateInfo(pvpDefense.roleId, { attack: newAttack, defense: newDefense, heroScores, score: score + addSumScore, defenseScoreCnt: defenseScoreCnt + 1, refDefenseScore }); } else { await PvpDefenseModel.updateInfo(pvpDefense.roleId, { defenseScoreCnt: defenseScoreCnt + 1, refDefenseScore }); } } } let defenseInfo = new PvpRecordPlayerInfo(); defenseInfo.setByHistoryOpp(oppRole, oppHeroRecords, !isSuccess, isSuccess ? 0 : addSumScore, serverId) return defenseInfo } /** * pvp定时任务赛季结算 * @param obj */ export async function pvpSeasonEnd(seasonNum: number) { let pvpConfig = await PVPConfigModel.findPVPConfig(seasonNum); if(pvpConfig.hasSettleReward) return; console.log('exce pvpSeasonEnd ' + pvpConfig.seasonNum); let resultMaxRank = getPvpRankMaxRewardsBySeasonNum(pvpConfig.seasonNum);//根据排行榜的奖励表,获得最大排名挡位的最小值,其余不在结算中结算的玩家按照最大排名挡位在登录或进入pvp时结算 if(!resultMaxRank) return; let pvpKeys = await findKeys(`${REDIS_KEY.PVP_RANK}:${pvpConfig.seasonNum}:`); for(let key of pvpKeys) { let [,, groupId] = key.split(':'); let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: pvpConfig.seasonNum, groupId: parseInt(groupId) }, false, resultMaxRank.min - 1); let allRank = (await r.getRankByRange()); console.log('******** allRank', 0, resultMaxRank.min - 2, allRank) for(let { rank, roleId } of allRank) { console.log('******** pvpSeasonEnd: ', rank, roleId); let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); let { pvpSeasonResult } = await sendPVPRewardToUser(pvpDefense, pvpConfig.seasonNum, pvpConfig.seasonEndTime); reportTAEvent(roleId, TA_EVENT.PVP_SEASON_END, { top_rank: rank, hero_score: pvpSeasonResult.heroScores }) } } await PvpDefenseModel.resetDefense(); let settledPvpConfig = await PVPConfigModel.setReward(pvpConfig.seasonNum); await setPvpSettleSeasonNumToRemote(settledPvpConfig); } /** * pvp定时任务结算获得添加邮件信息 * @param pvpDefense * @param seasonNum * @param oldSeasonEndTime */ export async function sendPVPRewardToUser(pvpDefense: PvpDefenseType, seasonNum: number, seasonEndTime: number) { //检查并返回排名结算以及武将功勋结算 let pvpSeasonResult = await savePvpSeasonResult(pvpDefense, seasonNum, seasonEndTime); let { rankGoods, heroGoods, rankLv, seasonWinNum, receivedBox } = pvpSeasonResult; //下发邮件 if (rankGoods.length > 0) //排名奖励 await sendMailByContent(MAIL_TYPE.PVP_RANK_REWARD, pvpDefense.roleId, { params: [JSON.stringify(seasonNum), (rankLv > 1000 ? '999+' : JSON.stringify(rankLv))], goods: rankGoods }); if (heroGoods.length > 0) //武将功勋奖励 await sendMailByContent(MAIL_TYPE.PVP_RESULT, pvpDefense.roleId, { params: [JSON.stringify(seasonNum)], goods: heroGoods }); if(receivedBox.length > 0) await sendUnreceivedPvpBox(pvpDefense.roleId, seasonNum, seasonWinNum, receivedBox); return { pvpSeasonResult, pvpDefense: await resetPvpScores(pvpDefense, pvpSeasonResult) } } async function sendUnreceivedPvpBox(roleId: string, seasonNum: number, seasonWinNum: number, receivedBox: number[]) { let rewards: RewardInter[] = []; let pvpBoxes = getPvpBoxsBySeasonNum(seasonNum); for(let { index, winTimes, reward } of pvpBoxes) { if(seasonWinNum >= winTimes && receivedBox.indexOf(index) == -1) { rewards.push(...reward); } } if(rewards.length > 0) { await sendMailByContent(MAIL_TYPE.PVP_BOX, roleId, { goods: rewards }); } } async function resetPvpScores(pvpDefense: PvpDefenseType, pvpSeasonResult: PvpSeasonResultType) { let { roleId, attack } = pvpDefense; let { newHeroScores, newScore, seasonNum } = pvpSeasonResult; let initCount = await getVipPvpChallengeMaxCnt(roleId) let newAttack = calLineupScore(attack, newHeroScores); pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { heroScores: newHeroScores, score: newScore, attack: newAttack, defense: null, hasDefense: false, rankSeasonNum: seasonNum + 1, challengeCnt: initCount, challengeRefTime: 0, winStreakNum: 0, seasonWinNum: 0, receivedBox: [] }); return pvpDefense; } /** * 检查并返回排名结算以及武将功勋结算 * @param pvpDefense * @param seasonNum * @param oldSeasonEndTime * @param rankLv */ export async function savePvpSeasonResult(pvpDefense: PvpDefenseType, seasonNum: number, seasonEndTime: number, rankLv?: number) { let groupId = await getPVPGroupIdOfServer(pvpDefense.serverId); if (!rankLv) { let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum, groupId }); rankLv = await r.getMyRank({ roleId: pvpDefense.roleId });// 获得排行榜排名 } let pvpRankReward: DicRankRewads = getPvpRankRewardsByRank(seasonNum, rankLv); let rankGoods: RewardInter[] = []; if (pvpRankReward) { rankGoods = pvpRankReward.reward;//排名奖励 } let heroGoods: HeroReward[] = []; let newHeroScores: HeroScore[] = [], newScore = 0; for (let heroScore of pvpDefense.heroScores) { let pvpHeroReward = getPvpHeroRewardsByScore(heroScore.score); //获得武将功勋奖励 if (pvpHeroReward) { newHeroScores.push({...heroScore, score: pvpHeroReward.heroscore }); for(let { id, count } of pvpHeroReward.reward) { heroGoods.push({ hid: heroScore.hid, id, count }); } newScore += pvpHeroReward.heroscore; } else { newHeroScores.push(heroScore); newScore += heroScore.score; } } //pvp锁定的信息存入赛季结算表中 let {receivedBox, score, seasonWinNum, heroScores } = pvpDefense; let pvpSeasonResult = await PvpSeasonResultModel.updatePvpSeasonResult(pvpDefense.roleId, seasonNum, { receivedBox, score, seasonWinNum, heroScores, rankLv, heroGoods, rankGoods, show: true, newScore, newHeroScores, seasonEndTime });//结算修改玩家pvp信息 if(newScore > 0) { let r = new Rank(REDIS_KEY.PVP_RANK, { seasonNum: seasonNum + 1, groupId }); await r.setRankWithRoleInfo(pvpDefense.roleId, newScore, Date.now()); } // 更新任务 await checkTask(pvpDefense.serverId, pvpDefense.roleId, null, TASK_TYPE.PVP_HERO_SCORE, { heroScores: pvpDefense.heroScores }); await checkTask(pvpDefense.serverId, pvpDefense.roleId, null, TASK_TYPE.PVP_RANK, { pvpRank: rankLv }); return pvpSeasonResult; } export async function generPvpLineupCe(roleId: string, lineupCe: LineupCe[], attackHero: AttackHero[], defenseHero: DefenseHero[], dbHeroes: HeroType[]) { let newHids: number[] = []; // 本次新增武将 let newLineupCe: { hid: number, ce: number }[] = []; // 新生成的lineupCe字段 for(let { actorId } of [...attackHero, ...defenseHero]) { let n = newLineupCe.find(cur => cur.hid == actorId); if(!n) { let lineup = lineupCe.find(cur => cur.hid == actorId); if(lineup) { newLineupCe.push(lineup); } else { let dbHero = dbHeroes.find(cur => cur.hid == actorId); if(dbHero) { newLineupCe.push({ hid: actorId, ce: dbHero.ce }); } else { newHids.push(actorId); } } } } let heroes = await HeroModel.findByHidRange(newHids, roleId, 'hid ce', true); for(let { hid, ce } of heroes) { newLineupCe.push({ hid, ce }); } return newLineupCe; } export function getPvpSeasonStatus() { let { seasonEndTime, seasonStartTime, seasonRewardTime } = getPvpTime(); let now = nowSeconds(); if(now >= seasonStartTime && now < seasonEndTime) { return PVP_SEASON_STATUS.START; } else if (now >= seasonEndTime && now < seasonRewardTime) { return PVP_SEASON_STATUS.SUMMIT; } else { return PVP_SEASON_STATUS.WAITING; } } interface PvpTime { seasonNum: number, seasonEndTime: number, seasonStartTime: number, seasonRewardTime: number } export function getPvpTime(): PvpTime { return { seasonNum: pinus.app.get('pvpSeasonNum'), seasonEndTime: pinus.app.get('pvpSeasonEndTime'), seasonStartTime: pinus.app.get('pvpSeasonStartTime'), seasonRewardTime: pinus.app.get('pvpSeasonRewardTime') } } export async function getPvpTimeFromRemote(): Promise { let serverType = pinus.app.getServerType(); if(serverType == 'battle') { return getPvpTime(); } else { let battleServers = pinus.app.getServersByType('battle'); let server = getRandSingleEelm(battleServers); return await pinus.app.rpc.battle.battleRemote.getPvpTime.toServer(server.id); } } export function checkPvpSeasonIsStart() { let status = getPvpSeasonStatus(); return status == PVP_SEASON_STATUS.START; } export function checkPvpSeasonIsSummit() { let status = getPvpSeasonStatus(); return status == PVP_SEASON_STATUS.SUMMIT; } export function checkPvpSeasonIsWaiting() { let status = getPvpSeasonStatus(); return status == PVP_SEASON_STATUS.WAITING; }