Files
ZYZ/game-server/app/services/gvg/gvgFightService.ts
T

303 lines
14 KiB
TypeScript

// 征战中原相关
import { GVG_PERIOD, STATUS, VESTIGE_OPP_STATUS, VESTIGE_STATUS } from "../../consts";
import { ArtifactModel } from "../../db/Artifact";
import { GVGVestigeModel } from "../../db/GVGVestige";
import { GVGVestigeLockModel } from "../../db/GVGVestigeLock";
import { GVGVestigeRankModel, GVGVestigeRankType, GVGVestigeRankUpdate } from "../../db/GVGVestigeRank";
import { GVGVestigeRecType } from "../../db/GVGVestigeRec";
import { HeroModel, HeroType } from "../../db/Hero";
import { RoleModel, RoleType } from "../../db/Role";
import { OppDetailData, OppDetailHeroData, OppPlayerHeroInfo, OppPlayerInfo } from "../../domain/gvgField/gvgDb";
import { GVGVestigeOppPlayer } from "../../domain/gvgField/returnData";
import { gameData, getGVGVestigeRange } from "../../pubUtils/data";
import { GVG } from "../../pubUtils/dicParam";
import { RewardInter } from "../../pubUtils/interface";
import { getTimeFun } from "../../pubUtils/timeUtil";
import { getRandEelm, getRandValueByMinMax, resResult } from "../../pubUtils/util";
import { getNumberArr, uniqueArr } from "../ladderService";
import { getHeroesAttributes } from "../playerCeService";
import { getAllServerName } from "../redisService";
import { combineItems } from "../role/util";
import { getGroupIdOfServer, getGVGServerType } from "./gvgService";
// 备战期的遗迹和激战期的开始结束战斗时间
export function getFightTimeByPeriod(period: GVG_PERIOD) {
let dicPeriod = gameData.gvgPeriod.get(period);
if(!dicPeriod) return { startFightTime: 0, endFightTime: 0 };
return {
startFightTime: <number>getTimeFun().getTimeWithHour(dicPeriod.startHour, dicPeriod.startMinute, dicPeriod.startSecond),
endFightTime: <number>getTimeFun().getTimeWithHour(dicPeriod.endHour, dicPeriod.endMinute, dicPeriod.endSecond),
}
}
// 征战中原每天随机的遗迹点
export async function getVestiges(serverId: number) {
let groupId = await getGroupIdOfServer(serverId);
let serverType = await getGVGServerType(serverId);
let vestige = await GVGVestigeModel.getVestige(groupId);
if(!vestige) {
let dicGVGVestige = gameData.gvgVestigeByServerType.get(serverType)||[];
let cnt = gameData.gvgVestigeCntByServerType.get(serverType)||0;
let randResult = getRandEelm(dicGVGVestige, cnt);
vestige = await GVGVestigeModel.initTodayVestige(groupId, serverType, randResult);
}
return vestige.vestiges||[];
}
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 + 1, 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, groupId: number, vestigeId: number, ranks: number[]) {
let serverNames = await getAllServerName();
let opps = await GVGVestigeRankModel.findByRanks(groupId, vestigeId, ranks);
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 = <RoleType>opp.role;
let lineupce = opp.lineup.reduce((pre, cur) => pre + cur.ce, 0);
obj.setByRole(role, serverNames, lineupce, dicCurRank?.score||0);
} 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;
result.push(...lineup.map(cur => cur.actorId));
}
return result;
}
// 是否在其他遗迹中使用过这个武将
export async function checkHeroIsUsedInOtherVestige(roleId: string, curVestigeId: number, heroes: { actorId: number }[]) {
let usedHeroes = await getVestigeUsedHeroes(roleId, curVestigeId);
for(let { actorId } of heroes) {
if(usedHeroes.indexOf(actorId) != -1) 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, groupId: number, vestigeId: number, roleId: string, myRank: number, targetRoleId: string, rank: number) {
let myData = await GVGVestigeRankModel.findByRole(vestigeId, roleId);
if(!myData) {
let role = await RoleModel.findByRoleId(roleId, 'roleId');
let oppRanks = refreshVestigeOppRanks(-1);
myData = await GVGVestigeRankModel.initRank(configId, vestigeId, groupId, role, oppRanks );
}
if(myData?.rank != myRank) return VESTIGE_OPP_STATUS.MY_RANK_CHANGE;
if(isRobot(targetRoleId)) {
let targetData = await GVGVestigeRankModel.findByRank(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(groupId, 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 info = new OppPlayerInfo();
info.initByPlayer(playerVestigeData.rank, role, true);
info.setPlayerHeroes(heroes, lineup);
return info;
}
}
export async function generateAttackInfo(roleId: string, 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, false);
return info;
}
export async function generateAttackHeroInfo(lineup: { actorId: number, dataId: number, order: number }[], dbHeroes: HeroType[]) {
let info = new OppPlayerInfo();
info.setPlayerHeroes(dbHeroes, lineup);
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 = defenseInfo.map(cur => cur.hid);
const heroes = await HeroModel.findByHidRange(hids, rec.defenseRoleId, 'hid lv quality star colorStar');
const artifactSeids = heroes.map(hero => hero.artifact);
const artifacts = await ArtifactModel.findbySeqIds(rec.defenseRoleId, artifactSeids);
result.setByPlayer(dicWarJson, defenseInfo, heroes, artifacts);
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: endTime };
if(endTime > 0 && endTime <= Date.now()) return { status: VESTIGE_STATUS.COMPLETE, time: endTime };
if(battleTime > 0 && battleTime <= Date.now() && battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 > Date.now()) return { status: VESTIGE_STATUS.BATTLE, time: battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 };
if(checkTime > 0 && checkTime <= Date.now() && checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000 > Date.now()) return { status: VESTIGE_STATUS.CHECK, time: checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000 };
// 超时的
if(battleTime > 0 && endTime == 0 && battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 <= Date.now()) return { status: VESTIGE_STATUS.COMPLETE, time: battleTime + 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: checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN };
return { status: VESTIGE_STATUS.NO, time: 0 };
}
// 将开始战斗时候的阵容存到防守阵容
export async function updateMyVestigeRank(isChange: boolean, atkData: 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 }));
update.lineup = lineup;
update.hasDefense = true;
needUpdate = true;
}
if(atkData && 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);
}
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;
for(let { id, count } of dicRank.onceReward) {
let obj = rewards.find(obj => obj.id == id);
if(!obj) {
rewards.push({ id, count });
} else {
obj.count += count;
}
}
for(let { id, count } of dicRank.onceLeagueReward) {
let obj = leagueRewards.find(obj => obj.id == id);
if(!obj) {
leagueRewards.push({ id, count });
} else {
obj.count += count;
}
}
}
return { rewards, leagueRewards }
}