Files
ZYZ/game-server/app/services/gvg/gvgFightService.ts
2023-09-01 11:01:35 +08:00

548 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 征战中原相关
import moment = require("moment");
import { GVG_PERIOD, GVG_RETURN_ITEM_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, MAIL_TYPE, PUSH_ROUTE, REDIS_KEY, VESTIGE_OPP_STATUS, VESTIGE_STATUS } from "../../consts";
import { ArtifactModel } from "../../db/Artifact";
import { GVGConfigModel } from "../../db/GVGConfig";
import { GVGLeagueModel, GVGLeagueType } from "../../db/GVGLeague";
import { GVGUserDataModel } from "../../db/GVGUserData";
import { GVGVestigeModel } from "../../db/GVGVestige";
import { GVGVestigeLeagueRankModel, GVGVestigeLeagueRankType } from "../../db/GVGVestigeLeagueRank";
import { GVGVestigeLockModel } from "../../db/GVGVestigeLock";
import { GVGVestigeRankModel, GVGVestigeRankType, GVGVestigeRankUpdate } from "../../db/GVGVestigeRank";
import { GVGVestigeRecModel, GVGVestigeRecType, GVGVestigeRecUpdate } from "../../db/GVGVestigeRec";
import { GVGVestigeSumRankModel, GVGVestigeSumRankType } from "../../db/GVGVestigeSumRank";
import { HeroModel, HeroType } from "../../db/Hero";
import { RoleModel } from "../../db/Role";
import { OppDetailData, OppPlayerHeroInfo, OppPlayerInfo } from "../../domain/gvgField/gvgDb";
import { GVGVestigeOppPlayer } from "../../domain/gvgField/returnData";
import { KeyNameParam, LeagueRankInfo, myIdInter, RoleRankInfo } from "../../domain/rank";
import { gameData, getGVGVestigeLeagueRank, getGVGVestigePlayerRank, getGVGVestigeRange } from "../../pubUtils/data";
import { GVG } from "../../pubUtils/dicParam";
import { RewardInter } from "../../pubUtils/interface";
import { getTimeFun, nowSeconds } from "../../pubUtils/timeUtil";
import { getRandEelm } from "../../pubUtils/util";
import { getNumberArr, uniqueArr } from "../ladderService";
import { sendMailByContent } from "../mailService";
import { getHeroesAttributes } from "../playerCeService";
import { sendMessageToUserWithSuc } from "../pushService";
import { Rank } from "../rankService";
import { findKeys, getAllServerName, redisClient } from "../redisService";
import { isDevelopEnv } from "../utilService";
import { addGVGReward, combinePushItem } from "./gvgItemService";
import { calFighterContribute } from "./gvgPrepareService";
import { addVestigeLeagueRankRec, addVestigeRankMessage } from "./gvgRecService";
import { getGroupKey, getGVGServerType, getPeriodByTime } from "./gvgService";
import { Combo } from "../../domain/battleField/pvp";
import { getRemoteRplPrefix } from "../../pubUtils/battleUtils";
import { pinus } from "pinus";
import { pushIconShow } from "../connectorService";
let gvgFightTime = undefined;
// !!注意,这个函数会改动内存,线上不应该使用
export function setPeriodTime(startFightTime: number, endFightTime: number) {
gvgFightTime = { startFightTime, endFightTime }
}
export function resetPeriodTime() {
gvgFightTime = undefined;
}
// 备战期的遗迹和激战期的开始结束战斗时间
export function getFightTimeByPeriod(period: GVG_PERIOD, time?: number) {
let dicPeriod = gameData.gvgPeriod.get(period);
if(!dicPeriod) return { startFightTime: 0, endFightTime: 0 };
if(isDevelopEnv() && gvgFightTime) {
return gvgFightTime;
}
return {
startFightTime: <number>getTimeFun(time).getTimeWithHour(dicPeriod.startHour, dicPeriod.startMinute, dicPeriod.startSecond),
endFightTime: <number>getTimeFun(time).getTimeWithHour(dicPeriod.endHour, dicPeriod.endMinute, dicPeriod.endSecond),
}
}
export function checkFightTime() {
let { startFightTime, endFightTime } = getFightTimeByPeriod(GVG_PERIOD.PREPARE);
let now = nowSeconds();
return startFightTime <= now && endFightTime >= now;
}
// 征战中原每天随机的遗迹点
export async function getVestiges(serverId: number) {
let groupKey = await getGroupKey(serverId);
let serverType = await getGVGServerType(serverId);
let vestige = await GVGVestigeModel.getVestige(groupKey);
if(!vestige) {
let dicGVGVestige = gameData.gvgVestigeByServerType.get(serverType)||[];
let cnt = gameData.gvgVestigeCntByServerType.get(serverType)||0;
let randResult = getRandEelm(dicGVGVestige, cnt);
vestige = await GVGVestigeModel.initTodayVestige(groupKey, randResult);
}
return vestige.vestiges||[];
}
export async function getMyVestiges(serverId: number, roleId: string) {
let vestiges = await getVestiges(serverId);
let myRanks = await GVGVestigeRankModel.findAllByRole(roleId);
let result: { vestigeId: number, position: string, myRank: number }[] = [];
for(let vestige of vestiges) {
let myRank = myRanks.find(cur => cur.vestigeId == vestige.vestigeId);
result.push({ ...vestige, myRank: myRank?.rank||0 });
}
return result;
}
export async function checkVestige(serverId: number, vestigeId: number) {
let vestiges = await getVestiges(serverId);
return !!vestiges.find(cur => cur.vestigeId == vestigeId);
}
// 根据自己排名随机出对手排名
export function refreshVestigeOppRanks(rank: number) {
let dicRange = getGVGVestigeRange(rank);
if(!dicRange) return [];
let { rangeBeforeFrom, rangeBeforeTo, rangeBeforeNum, rangeAfterFrom, rangeAfterTo, rangeAfterNum } = dicRange;
let beforeRanks = randomRank(rangeBeforeFrom == -1? rank: rangeBeforeFrom, rangeBeforeTo == -1? rank: rangeBeforeTo, rangeBeforeNum);
let afterRanks = randomRank(rangeAfterFrom == -1? rank: rangeAfterFrom, rangeAfterTo == -1? rank: rangeAfterTo, rangeAfterNum);
let topRanks = getNumberArr(dicRange.topChallengeFrom, dicRange.topChallengeTo);
let ranks = [...topRanks, ...beforeRanks, ...afterRanks];
return uniqueArr(ranks.sort((a, b) => a - b));
}
function randomRank(min: number, max: number, len: number) {
if(min == max || len == 0) return [];
let arr = getNumberArr(min + 1, max);
return getRandEelm(arr, len);
}
// 根据ranks获取oppPlayer显示数据
export async function getOppPlayerByRanks(serverId: number, groupKey: string, vestigeId: number, ranks: number[]) {
let serverNames = await getAllServerName();
let opps = await GVGVestigeRankModel.findByRanks(groupKey, vestigeId, ranks);
let roleIds = opps.map(cur => cur.roleId);
let roles = await RoleModel.findByRoleIds(roleIds, 'roleId roleName head frame spine heads frames spines title lv guildName serverId updatedAt')
let dicRankMap = gameData.gvgVestige.get(vestigeId);
if(!dicRankMap) return [];
let result: GVGVestigeOppPlayer[] = [];
for(let rank of ranks) {
let obj = new GVGVestigeOppPlayer(rank);
let opp = opps.find(cur => cur.rank == rank);
let dicCurRank = dicRankMap.get(rank);
if(opp) {
let role = roles.find(cur => cur.roleId == opp.roleId);
if(!role) continue;
let lineupce = opp.lineup.reduce((pre, cur) => pre + cur.ce, 0);
const { leagueCode, name } = opp;
obj.setByRole(role, serverNames, lineupce, dicCurRank?.score||0, leagueCode, name);
} else {
obj.setByDic(dicCurRank, serverNames[serverId]);
}
result.push(obj);
}
return result;
}
// 获取其他遗迹里使用过的武将
export async function getVestigeUsedHeroes(roleId: string, curVestigeId: number) {
let myDatas = await GVGVestigeRankModel.findAllByRole(roleId);
let result: number[] = [];
for(let { vestigeId, lineup = [] } of myDatas) {
if(vestigeId == curVestigeId) continue;
for(let { actorId, subHid } of lineup) {
result.push(actorId);
if(subHid) result.push(subHid);
}
}
return result;
}
// 是否在其他遗迹中使用过这个武将
export async function checkHeroIsUsedInOtherVestige(roleId: string, curVestigeId: number, heroes: { actorId: number, subHid: number }[]) {
let usedHeroes = await getVestigeUsedHeroes(roleId, curVestigeId);
for(let { actorId, subHid } of heroes) {
if(usedHeroes.indexOf(actorId) != -1) return true;
// 查副将
if(subHid) {
if(usedHeroes.indexOf(subHid) != -1) return true;
let hasSubHero = heroes.find(hero => hero.actorId == subHid);
if(hasSubHero) return true;
}
}
return false;
}
// 检查我的排名是否可以挑战对方的排名
export function checkVestigeRank(myRank: number, targetRank: number) {
let dicRange = getGVGVestigeRange(myRank);
if(!dicRange) return false;
if(myRank == targetRank || targetRank == 0) return false;
// 是否可以挑战最前的几个排名
if(dicRange.topChallengeFrom <= targetRank && dicRange.topChallengeTo >= targetRank) return true;
if(dicRange.rangeBeforeTo == -1) {
if(dicRange.rangeBeforeFrom < targetRank && myRank > targetRank) return true;
} else {
if(dicRange.rangeBeforeFrom < targetRank && dicRange.rangeBeforeTo >= targetRank) return true;
}
if(dicRange.rangeAfterTo == -1) {
if(dicRange.rangeAfterFrom < targetRank && myRank > targetRank) return true;
} else {
if(dicRange.rangeAfterFrom < targetRank && dicRange.rangeAfterTo >= targetRank) return true;
}
return false;
}
export function isRobot(roleId: string) {
if(!roleId) roleId = '';
return roleId.startsWith('robot');
}
export async function checkVestigeOppStatus(configId: number, groupKey: string, vestigeId: number, roleId: string, myRank: number, targetRoleId: string, rank: number) {
let myData = await getMyVestigeRank(configId, groupKey, vestigeId, roleId);
if(!myData || myData.rank != myRank) return VESTIGE_OPP_STATUS.MY_RANK_CHANGE;
if(isRobot(targetRoleId)) {
let targetData = await GVGVestigeRankModel.findByRank(configId, groupKey, vestigeId, rank);
if(targetData) return VESTIGE_OPP_STATUS.OPP_RANK_CHANGE;
} else {
let targetData = await GVGVestigeRankModel.findByRole(vestigeId, targetRoleId);
if(targetData?.rank != rank) return VESTIGE_OPP_STATUS.OPP_RANK_CHANGE;
}
let lockResult = await GVGVestigeLockModel.chooseOppLock(groupKey, vestigeId, rank, configId, roleId, targetRoleId);
if(!lockResult) return VESTIGE_OPP_STATUS.OPP_IS_LOCKED;
return VESTIGE_OPP_STATUS.BATTLE;
}
// 生成防守数据
export async function generateDefenseInfo(roleId: string, vestigeId: number, rank: number) {
if(isRobot(roleId)) {
let dicRank = gameData.gvgVestige.get(vestigeId)?.get(rank); // 调用之前已经验证过了
let dicWar = gameData.war.get(dicRank?.warId);
let dicWarJson = gameData.warJson.get(dicWar?.dispatchJsonId);
if(!dicWarJson) return new OppPlayerInfo();
let heroes: OppPlayerHeroInfo[] = [];
for(let json of dicWarJson) {
if(json.relation == 2) {
let hero = new OppPlayerHeroInfo();
hero.setByWarJson(json);
heroes.push(hero);
}
}
let info = new OppPlayerInfo();
info.initByRobot(dicRank, heroes, true);
return info;
} else {
let playerVestigeData = await GVGVestigeRankModel.findByRole(vestigeId, roleId);
if(!playerVestigeData) return null;
let lineup = playerVestigeData.lineup||[];
let hids = lineup.map(cur => cur.actorId);
let role = await RoleModel.findByRoleId(playerVestigeData.roleId, 'roleId roleName heads head frames frame spines spine title lv');
let heroes = await HeroModel.findByHidRange(hids, playerVestigeData.roleId, 'hid skinId lv star colorStar quality ce');
let league = await GVGLeagueModel.findByCode(playerVestigeData.leagueCode);
let info = new OppPlayerInfo();
info.initByPlayer(playerVestigeData.rank, role, league, true);
info.setPlayerHeroes(heroes, lineup, playerVestigeData.combo||[]);
return info;
}
}
export async function generateAttackInfo(roleId: string, league: GVGLeagueType, rank: number) {
let role = await RoleModel.findByRoleId(roleId, 'roleId roleName heads head frames frame spines spine title lv');
let info = new OppPlayerInfo();
info.initByPlayer(rank, role, league, false);
return info;
}
export async function generateAttackHeroInfo(lineup: { actorId: number, dataId: number, order: number, subHid: number }[], dbHeroes: HeroType[], combo: Combo[]) {
let info = new OppPlayerInfo();
info.setPlayerHeroes(dbHeroes, lineup, combo);
return info;
}
export async function getOppDetailData(rec: GVGVestigeRecType) {
let isRobot = rec.defenseInfo.isRobot;
let dicLadderDifficultRatio = gameData.ladderDifficultRatio.get(rec.defenseInfo.oldRank);
let result = new OppDetailData(rec, getVestigeRecStatus(rec));
if(!isRobot) {
const dicWar = gameData.war.get(dicLadderDifficultRatio.gkId);
const dicWarJson = gameData.warJson.get(dicWar.dispatchJsonId);
const defenseInfo = rec.defenseInfo.heroes||[];
const hids: number[] = [];
for(let { hid, subHid } of defenseInfo) {
hids.push(hid);
if(subHid) hids.push(subHid);
}
const heroes = await HeroModel.findByHidRange(hids, rec.defenseRoleId, 'hid lv quality star colorStar skins ce skinId');
const artifactSeids = heroes.map(hero => hero.artifact);
const artifacts = await ArtifactModel.findbySeqIds(rec.defenseRoleId, artifactSeids);
result.setByPlayer(dicWarJson, defenseInfo, heroes, artifacts, rec.defenseInfo.combo);
let attrByHid = await getHeroesAttributes(rec.defenseRoleId);
for(let [hid, attribute] of attrByHid) {
result.setAttribute(hid, attribute.getAttributesToString());
}
}
return result;
}
// 根据记录里的时间判断当前状态
export function getVestigeRecStatus(rec: GVGVestigeRecType) {
let { checkTime = 0, battleTime = 0, endTime = 0, cancel } = rec;
if(cancel) return { status: VESTIGE_STATUS.COMPLETE, time: Math.floor(endTime/1000) };
if(endTime > 0 && endTime <= Date.now()) return { status: VESTIGE_STATUS.COMPLETE, time: Math.floor(endTime/1000) };
if(battleTime > 0 && battleTime <= Date.now() && battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 > Date.now()) return { status: VESTIGE_STATUS.BATTLE, time: Math.floor(battleTime/1000) + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN };
if(checkTime > 0 && checkTime <= Date.now() && checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000 > Date.now()) return { status: VESTIGE_STATUS.CHECK, time: Math.floor(checkTime/1000) + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN };
// 超时的
if(battleTime > 0 && endTime == 0 && battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 <= Date.now()) return { status: VESTIGE_STATUS.COMPLETE, time: Math.floor(battleTime/1000) + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN };
if(checkTime > 0 && battleTime == 0 && checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000 <= Date.now()) return { status: VESTIGE_STATUS.COMPLETE, time: Math.floor(checkTime/1000) + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN };
return { status: VESTIGE_STATUS.NO, time: 0 };
}
// 将开始战斗时候的阵容存到防守阵容
export async function updateMyVestigeRank(isChange: boolean, atkData: GVGVestigeRankType, defData: GVGVestigeRankType, historyRank: number, rec: GVGVestigeRecType) {
let update: GVGVestigeRankUpdate = {}, needUpdate = false;
if(isChange) {
if(atkData && !atkData.hasDefense) { // 只有第一次挑战且自己没有主动保存过阵容的时候才会这么保存
let heroes = rec.attackInfo.heroes||[];
let lineup = heroes.map(hero => ({ actorId: hero.hid, dataId: hero.dataId, order: hero.order, ce: hero.ce, subHid: hero.subHid }));
update.lineup = lineup;
update.hasDefense = true;
needUpdate = true;
}
if(atkData && (historyRank == 0 || atkData.rank < historyRank)) { // 更新历史最高排名
update.historyRank = atkData.rank;
needUpdate = true;
}
if(atkData) { // 排名变化时刷新对手
let oppRanks = refreshVestigeOppRanks(atkData.rank);
update.oppRanks = oppRanks;
needUpdate = true;
}
}
if(needUpdate) {
atkData = await GVGVestigeRankModel.updateByRoleId(atkData.vestigeId, atkData.roleId, update);
}
if(isChange && defData) {
let oppRanks = refreshVestigeOppRanks(defData.rank);
defData = await GVGVestigeRankModel.updateByRoleId(defData.vestigeId, defData.roleId, { oppRanks });
}
return atkData
}
export function calBreakGoods(vestige: number, historyRank: number, rank: number) {
let dicRankMap = gameData.gvgVestige.get(vestige);
if(!dicRankMap) return { rewards: [], leagueRewards: [] };
let rewards: RewardInter[] = [], leagueRewards: RewardInter[] = [];
for(let i = historyRank + 1; i <= rank; i++) {
let dicRank = dicRankMap.get(i);
if(!dicRank) continue;
combinePushItem(rewards, dicRank.onceReward);
combinePushItem(leagueRewards, dicRank.onceLeagueReward);
}
return { rewards, leagueRewards }
}
// 玩家当天的驻扎记录,没有的话就创建一个
export async function getMyVestigeRank(configId: number, groupKey: string, vestigeId: number, roleId: string, myLeague?: GVGLeagueType) {
let myVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
if(!myVestigeRank) {
let role = await RoleModel.findByRoleId(roleId, 'roleId guildCode');
let oppRanks = refreshVestigeOppRanks(-1);
if(!myLeague) {
myLeague = await GVGLeagueModel.findLeagueByGuild(role.guildCode);
if(!myLeague) return null
}
const { leagueCode, name } = myLeague;
myVestigeRank = await GVGVestigeRankModel.initRank(configId, vestigeId, groupKey, role, leagueCode, name, oppRanks );
}
return myVestigeRank;
}
// 保存排行榜
export async function saveScoreToRank(rec: GVGVestigeRecType) {
await savePlayerRank(rec.configId, rec.groupKey, rec.vestigeId, rec.attackInfo);
await savePlayerRank(rec.configId, rec.groupKey, rec.vestigeId, rec.defenseInfo);
}
export function getDayKeyInfo() {
return moment().format('YYMMDD');
}
export async function savePlayerRank(configId: number, groupKey: string, vestigeId: number, playerInfo: Partial<OppPlayerInfo>) {
if(playerInfo.isRobot) return
let dicRankMap = gameData.gvgVestige.get(vestigeId);
let newRank = dicRankMap?.get(playerInfo.newRank)?.score||0;
let oldRank = dicRankMap?.get(playerInfo.oldRank)?.score||0;
let nextWeek = <number>getTimeFun().getAfterDayWithHour(7);
let myScore = await GVGVestigeSumRankModel.incScore(playerInfo.roleId, playerInfo.leagueCode, configId, groupKey, newRank - oldRank);
let r1 = new Rank(REDIS_KEY.GVG_VESTIGE_MEMBER_ALL, { groupKey, day: getDayKeyInfo() });
await r1.setExpire(nextWeek);
await r1.setRankWithRoleInfo(playerInfo.roleId, myScore.score, myScore.updatedAt.getTime());
let leagueScore = await GVGVestigeLeagueRankModel.incScore(configId, playerInfo.leagueCode, groupKey, newRank - oldRank);
let r2 = new Rank(REDIS_KEY.GVG_VESTIGE_LEAGUE, { groupKey, day: getDayKeyInfo() });
await r2.setExpire(nextWeek);
await r2.setRankWithLeagueInfo(playerInfo.leagueCode, leagueScore.score, leagueScore.updatedAt.getTime());
}
export async function getVestigeRank(redisKey: REDIS_KEY, isSimple: boolean, keyParam: KeyNameParam, myId: myIdInter, serverNames?: any) {
let r = new Rank(redisKey, keyParam);
r.setGenerFieldsFun((obj => {
if(redisKey == REDIS_KEY.GVG_VESTIGE_MEMBER_ALL && obj instanceof RoleRankInfo) {
if(isSimple) {
return { rank: obj.rank, name: obj.roleName, serverName: serverNames[obj.serverId], score: obj.num }
} else {
return { ...obj, serverName: serverNames[obj.serverId], score: obj.num }
}
}
if(redisKey == REDIS_KEY.GVG_VESTIGE_LEAGUE && obj instanceof LeagueRankInfo) {
if(isSimple) {
return { rank: obj.rank, name: obj.name, score: obj.num }
} else {
return { ...obj, score: obj.num, leader: {...obj.leader, serverName: serverNames[obj.leader.serverId]}};
}
}
return obj
}));
let { ranks, myRank } = await r.getRankListWithMyRank(myId);
if (!myRank) {
if(redisKey == REDIS_KEY.GVG_VESTIGE_MEMBER_ALL) {
myRank = await r.generMyRankWithRole(myId.roleId, 0, 0);
} else if (redisKey == REDIS_KEY.GVG_VESTIGE_LEAGUE) {
myRank = await r.generMyRankWithLeague(myId.leagueCode, 0, 0);
}
}
return { ranks, myRank }
}
// systimer 服 每天晚上22点
export async function saveVestigeRankSchedule() {
let config = await GVGConfigModel.findConfig();
let period = getPeriodByTime(config.teamTime, config.prepareTime, config.battleTime, config.scheduleTime);
if(period != GVG_PERIOD.PREPARE) return;
let day = getDayKeyInfo();
let keys = await findKeys(`${REDIS_KEY.GVG_VESTIGE_LEAGUE}:${day}:`);
for(let key of keys) {
let [,, groupKey] = key.split(':');
let r = new Rank(REDIS_KEY.GVG_VESTIGE_LEAGUE, { groupKey, day});
let ranks = await r.getRankByRangeRaw();
await GVGVestigeLeagueRankModel.saveRank(groupKey, ranks);
await addVestigeLeagueRankRec(config.configId, groupKey, ranks);
await addVestigeRankMessage(ranks);
}
let memberKeys = await findKeys(`${REDIS_KEY.GVG_VESTIGE_MEMBER_ALL}:${day}:`);
for(let key of memberKeys) {
let [,, groupKey] = key.split(':');
let r = new Rank(REDIS_KEY.GVG_VESTIGE_MEMBER_ALL, { groupKey, day});
let ranks = await r.getRankByRangeRaw();
await GVGVestigeSumRankModel.saveRank(groupKey, ranks);
}
let playerSumRanks = await GVGVestigeSumRankModel.findAllScores();
let userDatas = await GVGUserDataModel.addVestigeScores(config.configId, playerSumRanks);
for(let userData of userDatas) {
await sendMessageToUserWithSuc(userData.roleId, PUSH_ROUTE.GVG_CONTRIBUTE_UPDATE, { leagueCode: userData.leagueCode, job: LEAGUE_JOB.FIGHTER, sumContribute: calFighterContribute(userData.contribute) });
}
}
// systimer 服每周六5点
export async function gvgBattlePeriodSchedule() {
const config = await GVGConfigModel.findConfig();
await sendUngotVestigeReward(config.configId);
}
export async function sendUngotVestigeReward(configId: number) {
const playerDatas = await GVGVestigeSumRankModel.getAllCanReceiveRanks(configId);
const leagueCodes: string[] = [];
const dataByLeague = new Map<string, Map<string, { playerRanks: {_id: string, rank: number }[], leagueRanks: { _id: string, rank: number }[] }>>(); // leagueCode => playerdata
const receiveLeagueParam: { _id: string, roleIds: string[] }[] = [], receivePlayerParam: string[] = [];
for(let player of playerDatas) {
if(leagueCodes.indexOf(player.leagueCode) == -1) {
leagueCodes.push(player.leagueCode);
}
if(!dataByLeague.has(player.leagueCode)) dataByLeague.set(player.leagueCode, new Map());
if(!dataByLeague.get(player.leagueCode).has(player.roleId)) dataByLeague.get(player.leagueCode).set(player.roleId, { playerRanks: [], leagueRanks: [] });
dataByLeague.get(player.leagueCode).get(player.roleId).playerRanks.push({ _id: player._id, rank: player.rank });
receivePlayerParam.push(player._id);
}
const leagueDatas = await GVGVestigeLeagueRankModel.getAllCanReceiveRanks(configId, leagueCodes);
for(let leagueData of leagueDatas) {
let players = dataByLeague.get(leagueData.leagueCode);
if(!players) continue;
for(let [roleId, data] of players) {
if(leagueData.receiveMembers.indexOf(roleId) == -1) {
data.leagueRanks.push({ _id: leagueData._id, rank: leagueData.rank });
let index = receiveLeagueParam.findIndex(cur => cur._id == leagueData._id);
if(index == -1) {
receiveLeagueParam.push({ _id: leagueData._id, roleIds: [ roleId ] });
} else {
receiveLeagueParam[index].roleIds.push(roleId);
}
}
}
}
for(let [ leagueCode, players ] of dataByLeague) {
for(let [ roleId, { playerRanks, leagueRanks }] of players) {
let { leagueReward, rewards } = calVestigeLeagueBoxRewards(leagueRanks, playerRanks);
if(leagueReward.length > 0) await addGVGReward(roleId, '', leagueCode, null, leagueReward, [], ITEM_CHANGE_REASON.GVG_VESTIGE_RECEIVE_RANK);
if(rewards.length > 0) await sendMailByContent(MAIL_TYPE.VESTIGE_REWARD, roleId, { params: [`${configId}`], goods: rewards });
}
}
await GVGVestigeSumRankModel.receiveRanks(receivePlayerParam);
await GVGVestigeLeagueRankModel.receiveManyRanks(receiveLeagueParam);
}
export function calVestigeLeagueBoxRewards(canReceiveRanks: { rank: number }[], canReceivePlayerRanks: { rank: number }[]) {
let rewards: RewardInter[] = [], leagueReward: RewardInter[] = [];
for(let { rank } of canReceiveRanks) {
let dicRank = getGVGVestigeLeagueRank(rank);
if(!dicRank) { console.error('dic_zyz_GVGVestigeLeagueRank error'); continue; }
// console.log('###### league', rank, dicRank)
combinePushItem(rewards, dicRank.rankReward);
combinePushItem(leagueReward, dicRank.rankLeagueReward);
}
for(let { rank } of canReceivePlayerRanks) {
let dicRank = getGVGVestigePlayerRank(rank);
if(!dicRank) { console.error('dic_zyz_GVGVestigPlayerRank error'); continue; }
// console.log('###### player', rank, dicRank)
combinePushItem(rewards, dicRank.rankPlayerReward);
combinePushItem(leagueReward, dicRank.rankPlayerLeagueReward);
}
let boxPreview: { id: number, count: number, itemType: number }[] = [];
for(let { id, count } of rewards) boxPreview.push({ id, count, itemType: GVG_RETURN_ITEM_TYPE.NORMAL_ITEM });
for(let { id, count } of leagueReward) boxPreview.push({ id, count, itemType: GVG_RETURN_ITEM_TYPE.GVG_ITEM });
return {
leagueReward, rewards, boxPreview, canReceiveBox: canReceiveRanks.length > 0 || canReceivePlayerRanks.length > 0
}
}
export async function pushGvgFightIconShow(roleId: string, battleCode: string) {
const rec = await GVGVestigeRecModel.findByBattleCode(battleCode);
let result: (GVGVestigeRecUpdate & { rplFileUrl: string })[] = [];
const { attackRoleId, hasRpl, remoteUrl } = rec;
const rplFileUrl = battleCode && hasRpl ? remoteUrl : '';
const obj = getVestigeRecStatus(rec);
if (obj.status == VESTIGE_STATUS.COMPLETE) result.push({ ...rec, endTime: obj.time, rplFileUrl });
let gvgFightRecs = { list: result, rplPrefixUrl: getRemoteRplPrefix(pinus.app.get('env')) };
await pushIconShow(roleId, false, gvgFightRecs)
}