feat(gvg): 开始挑战和结束挑战

This commit is contained in:
luying
2023-02-01 21:26:24 +08:00
parent b727249106
commit ddce23d7fd
12 changed files with 34095 additions and 179 deletions

View File

@@ -1,18 +1,23 @@
import { Application, BackendSession, ChannelService, HandlerService } from "pinus";
import { GVG_ITEM, GVG_PERIOD, ITEM_CHANGE_REASON, STATUS, VESTIGE_OPP_STATUS } from "../../../consts";
import { GVG_ACTIVE_TYPE, GVG_ITEM, GVG_PERIOD, ITEM_CHANGE_REASON, STATUS, VESTIGE_OPP_STATUS, VESTIGE_STATUS } from "../../../consts";
import { BattleRecordModel } from "../../../db/BattleRecord";
import { GVGLeagueModel } from "../../../db/GVGLeague";
import { GVGUserItemModel } from "../../../db/GVGUserItem";
import { GVGVestigeLockModel } from "../../../db/GVGVestigeLock";
import { GVGVestigeRankModel } from "../../../db/GVGVestigeRank";
import { GVGVestigeRankModel, GVGVestigeRankType } from "../../../db/GVGVestigeRank";
import { GVGVestigeRecModel } from "../../../db/GVGVestigeRec";
import { HeroModel } from "../../../db/Hero";
import { RoleModel } from "../../../db/Role";
import { GVGVestigeOppLineup } from "../../../domain/gvgField/returnData";
import { gameData } from "../../../pubUtils/data";
import { GVG } from "../../../pubUtils/dicParam";
import { resResult } from "../../../pubUtils/util";
import { checkVestige, checkVestigeOppStatus, checkVestigeRank, generateAttackInfo, generateDefenseInfo, getOppDetailData, getOppPlayerByRanks, getVestigeUsedHeroes, isRobot, refreshVestigeOppRanks } from "../../../services/gvg/gvgFightService";
import { isHeroHidden } from "../../../services/dataService";
import { calBreakGoods, checkHeroIsUsedInOtherVestige, checkVestige, checkVestigeOppStatus, checkVestigeRank, generateAttackHeroInfo, generateAttackInfo, generateDefenseInfo, getOppDetailData, getOppPlayerByRanks, getVestigeRecStatus, getVestigeUsedHeroes, isRobot, refreshVestigeOppRanks, updateMyVestigeRank } from "../../../services/gvg/gvgFightService";
import { addGVGReward, handleGVGCost } from "../../../services/gvg/gvgItemService";
import { addGVGActive } from "../../../services/gvg/gvgPrepareService";
import { getGroupIdOfServer, getGVGPeriodData } from "../../../services/gvg/gvgService";
import { checkBattleHeroesByHid } from "../../../services/normalBattleService";
import { getAllServerName } from "../../../services/redisService";
export default function (app: Application) {
@@ -26,11 +31,6 @@ export class GVGProduceHandler {
this.channelService = app.get('channelService');
}
// 领取排行榜获得的每日奖励
async receiveBox(msg: { vestigeId: number }, session: BackendSession) {
}
// 遗迹页面
async getVestige(msg: { vestigeId: number }, session: BackendSession) {
const roleId = session.get('roleId');
@@ -40,20 +40,20 @@ export class GVGProduceHandler {
let { configId, period } = getGVGPeriodData();
if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);
let groupId = await getGroupIdOfServer(serverId);
if(!await checkVestige(groupId, vestigeId)) {
if(!await checkVestige(serverId, vestigeId)) {
return resResult(STATUS.GVG_VESTIGE_ERR);
}
let groupId = await getGroupIdOfServer(serverId);
let dicRankMap = gameData.gvgVestige.get(vestigeId);
if(!dicRankMap) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let myVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
if(!myVestigateRank) {
let myVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
if(!myVestigeRank) {
let role = await RoleModel.findByRoleId(roleId, 'roleId');
let oppRanks = refreshVestigeOppRanks(-1);
myVestigateRank = await GVGVestigeRankModel.initRank(configId, vestigeId, groupId, role, oppRanks );
myVestigeRank = await GVGVestigeRankModel.initRank(configId, vestigeId, groupId, role, oppRanks );
}
let { rank, lineup, oppRanks, refreshCnt } = myVestigateRank;
let { rank, lineup, oppRanks, refreshCnt } = myVestigeRank;
let score = dicRankMap?.get(rank)||0;
let lineupCe = lineup.reduce((pre, cur) => pre + cur.ce, 0);
@@ -82,13 +82,13 @@ export class GVGProduceHandler {
const serverId: number = session.get('serverId');
let { vestigeId, roleId: targetRoleId, rank } = msg;
let myVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
let myVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
const serverNames = await getAllServerName();
let isRobot = targetRoleId.startsWith('robot');
let result = new GVGVestigeOppLineup(vestigeId);
result.setMyRank(myVestigateRank?.rank||0);
result.setMyRank(myVestigeRank?.rank||0);
let dicGVGVestige = gameData.gvgVestige.get(vestigeId)?.get(rank);
if(!dicGVGVestige) return resResult(STATUS.DIC_DATA_NOT_FOUND);
@@ -97,13 +97,13 @@ export class GVGProduceHandler {
let dicWarJson = gameData.warJson.get(dicWar.dispatchJsonId);
result.setRobot(dicGVGVestige, dicWarJson, serverNames[serverId]);
} else {
let hisVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId);
if(!hisVestigateRank) return resResult(STATUS.GVG_VESTIGE_TARGET_NOT_FOUND);
let hisVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId);
if(!hisVestigeRank) return resResult(STATUS.GVG_VESTIGE_TARGET_NOT_FOUND);
let role = await RoleModel.findByRoleId(hisVestigateRank.roleId, 'roleId roleName serverId guildName title lv heads head spines spine frames frame')
if(!hisVestigateRank) return resResult(STATUS.GVG_VESTIGE_TARGET_NOT_FOUND);
let role = await RoleModel.findByRoleId(hisVestigeRank.roleId, 'roleId roleName serverId guildName title lv heads head spines spine frames frame')
if(!hisVestigeRank) return resResult(STATUS.GVG_VESTIGE_TARGET_NOT_FOUND);
let hids = hisVestigateRank.lineup?.map(cur => cur.actorId)||[];
let hids = hisVestigeRank.lineup?.map(cur => cur.actorId)||[];
let heroes = await HeroModel.findByHidRange(hids, roleId, 'hid skinId quality star colorStar lv');
result.setPlayer(dicGVGVestige, role, heroes, serverNames);
}
@@ -139,7 +139,7 @@ export class GVGProduceHandler {
const hasItem = await GVGUserItemModel.checkItemCnt(configId, myLeague.leagueCode, roleId, GVG_ITEM.FIGHT_COIN, 1);
if(!hasItem) return resResult(STATUS.GVG_ITEMS_NOT_ENOUGH);
let groupId = await getGroupIdOfServer(serverId);
const groupId = await getGroupIdOfServer(serverId);
let status = await checkVestigeOppStatus(configId, groupId, vestigeId, roleId, myRank, targetRoleId, rank); // 锁
if(status != VESTIGE_OPP_STATUS.BATTLE) {
@@ -156,37 +156,143 @@ export class GVGProduceHandler {
}
// 获取征战令对应奖励
const leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, dicRank.battleLeagueReward, dicRank.battleReward, ITEM_CHANGE_REASON.GVG_VESTIGE_START);
// 消耗征战令的获得活跃
let active = await addGVGActive(myLeague.leagueCode, roleId, GVG_ACTIVE_TYPE.COST_FIGHT_COIN);
// 创建rec
const attackInfo = await generateAttackInfo(roleId, myRank);
const defenseInfo = await generateDefenseInfo(targetRoleId, vestigeId, rank);
const rec = await GVGVestigeRecModel.createRec(configId, vestigeId, groupId, attackInfo, defenseInfo, leagueGoods);
const rec = await GVGVestigeRecModel.createRec(configId, vestigeId, groupId, dicRank.warId, attackInfo, defenseInfo, leagueGoods);
const oppDetail = await getOppDetailData(rec);
return resResult(STATUS.SUCCESS, {
battleCode: rec.battleCode,
time: rec.checkTime,
time: Math.floor(rec.checkTime/100) + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN,
active,
...oppDetail
});
}
// 出战界面撤退
async giveupCheck(msg: { battleCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let { battleCode } = msg;
// 更新ladderMatchRec
let rec = await GVGVestigeRecModel.giveup(roleId, battleCode);
if(rec && rec.defenseInfo) {
await GVGVestigeLockModel.releaseLock(rec.groupId, rec.vestigeId, rec.defenseInfo.oldRank);
}
return resResult(STATUS.SUCCESS, {
status: 0, time: 0,
leagueGoods: rec.leagueGoods
});
}
// 获取对手具体战场数据
async getOppData(msg: { battleCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let { battleCode } = msg;
let rec = await GVGVestigeRecModel.findByBattleCode(battleCode);
if(!rec || rec.attackRoleId != roleId) return resResult(STATUS.LADDER_REC_NOT_FOUND);
let status = getVestigeRecStatus(rec);
if(status == VESTIGE_STATUS.COMPLETE || status == VESTIGE_STATUS.NO) return resResult(STATUS.LADDER_REC_STATUS_IS_COMPLETE);
let result = await getOppDetailData(rec);
return resResult(STATUS.SUCCESS, result);
}
// 布完阵开始挑战
async checkBattle(msg: { battleCode: string, heroes: [{ actorId: number, dataId: number, order: number }] }, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const serverId = session.get('serverId');
const { battleCode, heroes } = msg;
let rec = await GVGVestigeRecModel.findByBattleCode(battleCode);
if(!rec || rec.attackRoleId != roleId) return resResult(STATUS.GVG_VESTIGE_REC_NOT_FOUND);
if(getVestigeRecStatus(rec) != VESTIGE_STATUS.CHECK) return resResult(STATUS.GVG_VESTIGE_CHECK_BATTLE_STATUS_ERR);
const { vestigeId, defenseInfo: { oldRank: rank }, warId } = rec;
for(let { actorId } of heroes) {
if(isHeroHidden(actorId)) return resResult(STATUS.HERO_IS_HIDDEN);
}
let { isOK, heroes: dbHeroes } = await checkBattleHeroesByHid(roleId, heroes.map(cur => cur.actorId));
if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND);
// 检查武将是否在其他遗迹中使用了
if(await checkHeroIsUsedInOtherVestige(roleId, vestigeId, heroes)) return resResult(STATUS.GVG_VESTIGE_HERO_USED);
// 更新锁
const groupId = await getGroupIdOfServer(serverId);
let lock = await GVGVestigeLockModel.checkBattleLock(groupId, vestigeId, rank, roleId);
if(!lock) return resResult(STATUS.GVG_VESTIGE_CHECK_BATTLE_STATUS_ERR);
// 向vestigerec保存阵容
const attackHeroes = await generateAttackHeroInfo(heroes, dbHeroes);
rec = await GVGVestigeRecModel.startBattle(battleCode, attackHeroes);
// 更新battleRecord
let warInfo = gameData.war.get(warId);
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: { roleId, roleName, battleId: warId, status: 0, warName: warInfo?.gk_name, warType: warInfo?.warType, }
});
return resResult(STATUS.SUCCESS, {
time: Math.floor(rec.battleTime/1000) + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN,
battleCode: rec.battleCode
});
}
// 挑战结算
async battleEnd(msg: { battleCode: string, isSuccess: boolean }, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const serverId = session.get('serverId');
const sid = session.get('sid');
const guildCode = session.get('guildCode');
const { battleCode, isSuccess } = msg;
let rec = await GVGVestigeRecModel.findByBattleCode(battleCode);
if(!rec || rec.attackRoleId != roleId) return resResult(STATUS.GVG_VESTIGE_REC_NOT_FOUND);
if(getVestigeRecStatus(rec) != VESTIGE_STATUS.BATTLE) return resResult(STATUS.GVG_VESTIGE_BATTLE_END_STATUS_ERR);
let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
let historyData = await GVGVestigeRankModel.findByRole(rec.vestigeId, roleId);
let historyRank = historyData?.rank||0;
// 交换排名
let { isChange, atkData, defData, endTime } = await GVGVestigeRankModel.changeRank(isSuccess, rec.attackInfo, rec.defenseInfo);
atkData = await updateMyVestigeRank(isChange, atkData, historyRank, rec);
// 更新vestigeRec
rec = await GVGVestigeRecModel.battleEnd(battleCode, isSuccess, endTime, atkData?.rank, defData?.rank);
// 更新锁
await GVGVestigeLockModel.releaseLock(rec.groupId, rec.vestigeId, rec.defenseInfo.oldRank);
// 更新battleRecord
await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { status: isSuccess? 1: 2 } });
// 突破排名奖励
let { rewards, leagueRewards } = calBreakGoods(rec.vestigeId, historyRank, atkData.rank);
let breakGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, leagueRewards, rewards, ITEM_CHANGE_REASON.GVG_VESTIGE_END);
// TODO 更新redis排行榜
return resResult(STATUS.SUCCESS, {
vestigeId: rec.vestigeId,
battleCode: rec.battleCode,
leagueGoods: rec.leagueGoods,
rank: atkData.rank,
score: gameData.gvgVestige.get(rec.vestigeId)?.get(atkData.rank)?.score,
historyRank: atkData.historyRank,
status: getVestigeRecStatus(rec),
time: endTime,
oppPlayers: await getOppPlayerByRanks(serverId, rec.groupId, rec.vestigeId, atkData.oppRanks),
breakGoods,
lineup: atkData.lineup,
lineupCe: atkData.lineup.reduce((pre, cur) => pre + cur.ce, 0),
});
}
// 征战中原简单小排行榜
@@ -203,4 +309,9 @@ export class GVGProduceHandler {
async getPlayerRank(msg: { vestigeId: number }, session: BackendSession) {
}
// 领取排行榜获得的每日奖励
async receiveBox(msg: { vestigeId: number }, session: BackendSession) {
}
}

View File

@@ -1,21 +1,22 @@
// 征战中原相关
import { GVG_PERIOD, STATUS, VESTIGE_OPP_STATUS } from "../../consts";
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 } from "../../db/GVGVestigeRank";
import { GVGVestigeRankModel, GVGVestigeRankType, GVGVestigeRankUpdate } from "../../db/GVGVestigeRank";
import { GVGVestigeRecType } from "../../db/GVGVestigeRec";
import { HeroModel } from "../../db/Hero";
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 { calLineupScore } from "../pvpService";
import { getAllServerName } from "../redisService";
import { getGroupIdOfServer, getGVGServerType } from "./gvgService";
@@ -34,20 +35,19 @@ export function getFightTimeByPeriod(period: GVG_PERIOD) {
export async function getVestiges(serverId: number) {
let groupId = await getGroupIdOfServer(serverId);
let serverType = await getGVGServerType(serverId);
let vestige = await GVGVestigeModel.getVestigate(groupId);
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.initTodayVestigate(groupId, serverType, randResult);
vestige = await GVGVestigeModel.initTodayVestige(groupId, serverType, randResult);
}
return vestige.vestiges||[];
}
export async function checkVestige(groupId: number, vestigeId: number) {
let todayVestige = await GVGVestigeModel.getVestigate(groupId);
if(!todayVestige) return false;
return !!todayVestige.vestiges.find(cur => cur.vestigeId == vestigeId);
export async function checkVestige(serverId: number, vestigeId: number) {
let vestiges = await getVestiges(serverId);
return !!vestiges.find(cur => cur.vestigeId == vestigeId);
}
// 根据自己排名随机出对手排名
@@ -105,6 +105,15 @@ export async function getVestigeUsedHeroes(roleId: string, curVestigeId: number)
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);
@@ -135,6 +144,11 @@ export function isRobot(roleId: string) {
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)) {
@@ -175,10 +189,11 @@ export async function generateDefenseInfo(roleId: string, vestigeId: number, ran
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');
let heroes = await HeroModel.findByHidRange(hids, playerVestigeData.roleId, 'hid skinId lv star colorStar quality ce');
let info = new OppPlayerInfo();
info.initByPlayer(playerVestigeData.rank, role, heroes, lineup, true);
info.initByPlayer(playerVestigeData.rank, role, true);
info.setPlayerHeroes(heroes, lineup);
return info;
}
}
@@ -186,10 +201,16 @@ export async function generateDefenseInfo(roleId: string, vestigeId: number, ran
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);
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.heroes;
}
export async function getOppDetailData(rec: GVGVestigeRecType) {
let isRobot = rec.defenseInfo.isRobot;
let dicLadderDifficultRatio = gameData.ladderDifficultRatio.get(rec.defenseInfo.oldRank);
@@ -212,3 +233,52 @@ export async function getOppDetailData(rec: GVGVestigeRecType) {
return result;
}
// 根据记录里的时间判断当前状态
export function getVestigeRecStatus(rec: GVGVestigeRecType) {
let { checkTime = 0, battleTime = 0, endTime = 0, cancel } = rec;
if(cancel) return VESTIGE_STATUS.COMPLETE;
if(endTime > 0 && endTime <= Date.now()) return VESTIGE_STATUS.COMPLETE;
if(battleTime > 0 && battleTime <= Date.now() && battleTime + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 > Date.now()) return VESTIGE_STATUS.BATTLE;
if(checkTime > 0 && checkTime <= Date.now() && checkTime + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000 > Date.now()) return VESTIGE_STATUS.CHECK;
return VESTIGE_STATUS.NO;
}
// 将开始战斗时候的阵容存到防守阵容
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;
needUpdate = true;
}
if(atkData && atkData.rank > historyRank) { // 更新历史最高排名
update.historyRank = atkData.rank;
needUpdate = true;
}
if(atkData) { // 排名变化时刷新对手
let oppRanks = refreshVestigeOppRanks(atkData.rank);
update.oppRanks = oppRanks;
}
}
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;
rewards.push(...dicRank.onceReward);
leagueRewards.push(...dicRank.onceLeagueReward);
}
return { rewards, leagueRewards }
}

View File

@@ -1093,6 +1093,7 @@ export enum ITEM_CHANGE_REASON {
GVG_RECEIVE_LV = 168, // 领取等级奖励
GVG_RECEIVE_TASK = 169, // 领取任务奖励
GVG_VESTIGE_START = 170, // gvg征战中原挑战
GVG_VESTIGE_END = 171, // gvg征战中原挑战
}
export enum TA_EVENT {

View File

@@ -341,6 +341,11 @@ export const STATUS = {
GVG_VESTIGE_ERR: { code: 21350, simStr: '今日未开放该遗迹' },
GVG_VESTIGE_TARGET_NOT_FOUND: { code: 21351, simStr: '对手未找到' },
GVG_VESTIGE_RANK_ERR: { code: 21352, simStr: '该排名玩家不可挑战' },
GVG_VESTIGE_REC_NOT_FOUND: { code: 21353, simStr: '未找到该条记录' },
GVG_VESTIGE_CHECK_BATTLE_STATUS_ERR: { code: 21363, simStr: '备战时间超时' },
GVG_VESTIGE_HERO_USED: { code: 21364, simStr: '该武将在其他遗迹已使用' },
GVG_VESTIGE_BATTLE_END_STATUS_ERR: { code: 21365, simStr: '挑战时间超时' },
GVG_VESTIGE_RANK_NOT_INIT: { code: 21366, simStr: '玩家数据未初始' },
// 通用 30000 - 30099
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },

View File

@@ -25,13 +25,13 @@ export default class GVGVestige extends BaseModel {
@prop({ required: true })
day: number; // 每天5点
public static async getVestigate(groupId: number) {
public static async getVestige(groupId: number) {
let day = getZeroPoint();
let result: GVGVestigeType = await GVGVestigeModel.findOne({ groupId, day }).lean();
return result;
}
public static async initTodayVestigate(groupId: number, type: number, vestiges: Vestige[]) {
public static async initTodayVestige(groupId: number, type: number, vestiges: Vestige[]) {
let day = getZeroPoint();
let result: GVGVestigeType = await GVGVestigeModel.findOneAndUpdate({ groupId, day }, { $setOnInsert: { type, vestiges } }, { new: true, upsert: true }).lean();
return result;

View File

@@ -23,24 +23,28 @@ export default class GVGVestigeLock extends BaseModel {
rank: number; // 排名
@prop({ required: true })
unlockTime: number; // 锁定到什么时候
unlockTime: number; // 锁定到什么时候,13位时间戳
@prop({ required: true })
attackRoleId: string; // 锁定到什么时候
attackRoleId: string; // 挑战玩家
@prop({ required: true })
defenseRoleId: string; // 锁定到什么时候
defenseRoleId: string; // 防守玩家
public static async chooseOppLock(groupId: number, vestigeId: number, rank: number, configId: number, attackRoleId: string, defenseRoleId: string ) {
return await this.lock(groupId, vestigeId, rank, configId, attackRoleId, defenseRoleId, nowSeconds() + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN);
}
private static async lock(groupId: number, vestigeId: number, rank: number, configId: number, attackRoleId: string, defenseRoleId: string, unlockTime: number) {
let day = getZeroPoint();
await GVGVestigeLockModel.findOneAndUpdate({ day, groupId, vestigeId, rank }, { $setOnInsert: { configId, unlockTime: 0 } }, { upsert: true });
let result: GVGVestigeLockType = await GVGVestigeLockModel.findOneAndUpdate({
day, groupId, vestigeId, rank, unlockTime: { $lt: nowSeconds() }
}, { $set: { unlockTime, attackRoleId, defenseRoleId } }, { new: true }).lean();
day, groupId, vestigeId, rank, unlockTime: { $lt: Date.now() }
}, { $set: { unlockTime: Date.now() + GVG.GVG_VESTIGE_PREPARE_COUNTDOWN * 1000, attackRoleId, defenseRoleId } }, { new: true }).lean();
return result;
}
public static async checkBattleLock(groupId: number, vestigeId: number, rank: number, attackRoleId: string) {
let day = getZeroPoint();
let result: GVGVestigeLockType = await GVGVestigeLockModel.findOneAndUpdate({
day, groupId, vestigeId, rank, attackRoleId, unlockTime: { $gt: Date.now() }
}, { $set: { unlockTime: Date.now() + GVG.GVG_VESTIGE_BATTLE_COUNTDOWN * 1000 } }, { new: true }).lean();
return result;
}

View File

@@ -45,16 +45,13 @@ export default class GVGVestigeRank extends BaseModel {
@prop({ required: true, default: 0 })
historyRank: number; // 历史最高排名
@prop({ required: true, default: 0 })
locked: number; // 是否被挑战
@prop({ required: true, default: false })
hasAdjustLineup: boolean; // 是否调整过阵容
hasDefense: boolean; // 是否调整过阵容,首次挑战自动保存阵容
@prop({ required: true, type: Lineup, default: [] })
@prop({ required: true, type: Lineup, default: [], _id: false })
lineup: Lineup[]; // 阵容
@prop({ required: true, type: Number, default: [] })
@prop({ required: true, type: Number, default: [], _id: false })
oppRanks: number[]; // 对手的排名
@prop({ required: true, default: 0 })
@@ -86,6 +83,12 @@ export default class GVGVestigeRank extends BaseModel {
return result;
}
public static async updateByRoleId(vestigeId: number, roleId: string, update: GVGVestigeRankUpdate) {
let today = getZeroPoint();
let result: GVGVestigeRankType = await GVGVestigeRankModel.findOneAndUpdate({ day: today, vestigeId, roleId }, { $set: update }, { new: true, upsert: true }).lean();
return result;
}
public static async findByRanks(groupId: number, vestigeId: number, ranks: number[]) {
let today = getZeroPoint();
let result: GVGVestigeRankType[] = await GVGVestigeRankModel.find({ day: today, vestigeId, groupId, rank: { $in: ranks } })
@@ -96,13 +99,45 @@ export default class GVGVestigeRank extends BaseModel {
public static async updateCe(roleId: string, hid: number, ce: number) {
let today = getZeroPoint();
await GVGVestigeRankModel.updateMany({ day: today, roleId, 'lineup.hid': hid }, { $set: { 'lineupCe.$.ce': ce } });
await GVGVestigeRankModel.updateMany({ day: today, hasDefense: true, roleId, 'lineup.hid': hid }, { $set: { 'lineupCe.$.ce': ce } });
}
public static async changeRank(isSuccess: boolean, attackInfo: { roleId: string }, defenseInfo: { isRobot: boolean, roleId: string, oldRank: number }): Promise<{ isChange: boolean, atkData?: GVGVestigeRankType, defData?: GVGVestigeRankType, endTime: number }> {
const session = await mongoose.connection.startSession();
session.startTransaction()
try {
let newAtkData: GVGVestigeRankType, newDefData: GVGVestigeRankType, isChange = false, endTime = Date.now();
if(defenseInfo.isRobot) {
let atkData = await GVGVestigeRankModel.findOne({ roleId: attackInfo.roleId }).lean();
if(isSuccess && atkData && (atkData.rank == 0 || atkData.rank > defenseInfo.oldRank)) {
newAtkData = await GVGVestigeRankModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defenseInfo.oldRank, oldRank: atkData.rank } }, { new: true, session }).lean();
isChange = true;
endTime = Date.now();
} else {
newAtkData = atkData;
}
} else {
let atkData = await GVGVestigeRankModel.findOne({ roleId: attackInfo.roleId }).lean();
let defData = await GVGVestigeRankModel.findOne({ roleId: defenseInfo.roleId }).lean();
if(isSuccess && atkData && defData && (atkData.rank == 0 || atkData.rank > defData.rank)) {
newAtkData = await GVGVestigeRankModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defData.rank, oldRank: atkData.rank } }, { new: true, session }).lean();
newDefData = await GVGVestigeRankModel.findOneAndUpdate({ roleId: defenseInfo.roleId }, { $set: { rank: atkData.rank, oldRank: defData.rank } }, { new: true, session }).lean();
isChange = true;
endTime = Date.now();
} else {
newAtkData = atkData;
newDefData = defData;
}
}
await session.commitTransaction()
return { isChange, atkData: newAtkData, defData: newDefData, endTime }
} finally {
session.endSession()
}
}
}
export const GVGVestigeRankModel = getModelForClass(GVGVestigeRank);
export interface GVGVestigeRankType extends Pick<DocumentType<GVGVestigeRank>, keyof GVGVestigeRank> {
id: number;
};
export interface GVGVestigeRankType extends Pick<DocumentType<GVGVestigeRank>, keyof GVGVestigeRank> {};
export type GVGVestigeRankUpdate = Partial<GVGVestigeRankType>; // 将所有字段变成可选项

View File

@@ -1,9 +1,8 @@
// 征战中原对手锁
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { OppPlayerInfo } from '../domain/gvgField/gvgDb';
import { OppPlayerInfo, OppPlayerHeroInfo } from '../domain/gvgField/gvgDb';
import { genCode } from '../pubUtils/util';
import { VESTIGE_STATUS } from '../consts';
class LeagueGood {
@prop({ required: true })
@@ -16,12 +15,16 @@ class LeagueGood {
count: number
}
@index({ battleCode: 1 })
@index({ day: 1, groupId: 1, vestigeId: 1, rank: 1 })
export default class GVGVestigeRec extends BaseModel {
@prop({ required: true })
battleCode: string; // 唯一code
@prop({ required: true })
warId: number; // 关卡id
@prop({ required: true })
attackRoleId: string; // 攻方玩家id
@@ -35,7 +38,7 @@ export default class GVGVestigeRec extends BaseModel {
vestigeId: number; // 遗迹id
@prop({ required: true })
status: number; // 1-出兵中 2-挑战中 3-挑战完毕 4-取消
cancel: boolean; // 是否取消
@prop({ required: true })
checkTime: number; // 开始出兵的时间13位时间戳
@@ -58,19 +61,50 @@ export default class GVGVestigeRec extends BaseModel {
@prop({ required: true, default: false })
hasRpl: boolean; // 是否存在对应录像
public static async createRec(configId: number, vestigeId: number, groupId: number, attackInfo: OppPlayerInfo, defenseInfo: OppPlayerInfo, leagueGoods: LeagueGood[]) {
public static async createRec(configId: number, vestigeId: number, groupId: number, warId: number, attackInfo: OppPlayerInfo, defenseInfo: OppPlayerInfo, leagueGoods: LeagueGood[]) {
const battleCode = genCode(10);
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOneAndUpdate({ battleCode }, {
$set: { configId, vestigeId, groupId, attackRoleId: attackInfo.roleId, defenseRoleId: defenseInfo.roleId, status: VESTIGE_STATUS.CHECK, checkTime: Date.now(), attackInfo, defenseInfo, leagueGoods }
$set: { configId, vestigeId, groupId, attackRoleId: attackInfo.roleId, defenseRoleId: defenseInfo.roleId, warId, checkTime: Date.now(), attackInfo, defenseInfo, leagueGoods }
}, { new: true, upsert: true }).lean();
return result;
}
public static async findByBattleCode(battleCode: string, select = '') {
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOne({ battleCode }).select(select).lean();
return result;
}
public static async startBattle(battleCode: string, attackHeroes: OppPlayerHeroInfo[]) {
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOneAndUpdate({ battleCode }, {
$set: { battleTime: Date.now(), 'attackInfo.heroes': attackHeroes }
}, { new: true }).lean();
return result;
}
public static async battleEnd(battleCode: string, isSuccess: boolean, endTime: number, atkNewRank?: number, defNewRank?: number) {
let update: GVGVestigeRecUpdate = { endTime };
if(isSuccess) {
update['attackInfo.isSuccess'] = true;
update['defenseInfo.isSuccess'] = false;
}
if(atkNewRank != undefined && defNewRank != undefined) {
update['attackInfo.newRank'] = atkNewRank;
update['attackInfo.oldRank'] = defNewRank;
update['defenseInfo.newRank'] = defNewRank;
update['defenseInfo.oldRank'] = atkNewRank;
}
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOneAndUpdate({ battleCode }, { $set: update }, { new: true }).lean();
return result;
}
public static async giveup(roleId: string, battleCode: string) {
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOneAndUpdate({ attackRoleId: roleId, battleCode }, { $set: { cancel: true }}, { new: true }).lean();
return result;
}
}
export const GVGVestigeRecModel = getModelForClass(GVGVestigeRec);
export interface GVGVestigeRecType extends Pick<DocumentType<GVGVestigeRec>, keyof GVGVestigeRec> {
id: number;
};
export interface GVGVestigeRecType extends Pick<DocumentType<GVGVestigeRec>, keyof GVGVestigeRec> {};
export type GVGVestigeRecUpdate = Partial<GVGVestigeRecType>; // 将所有字段变成可选项

View File

@@ -1,30 +1,31 @@
import { prop } from "@typegoose/typegoose";
import { ArtifactModelType } from "../../db/Artifact";
import { Lineup } from "../../db/GVGVestigeRank";
import { HeroType, Talent } from "../../db/Hero";
import { RoleType } from "../../db/Role";
import { gameData } from "../../pubUtils/data";
import { EXTERIOR, GVG } from "../../pubUtils/dicParam";
import { DicGVGVestige } from "../../pubUtils/dictionary/DicGVGVestige";
import { dicWarJson, DicWarJson } from "../../pubUtils/dictionary/DicWarJson";
import { DicWarJson } from "../../pubUtils/dictionary/DicWarJson";
export class OppPlayerHeroInfo {
@prop({ required: true })
hid: number; // 武将id
hid: number; // 武将id
@prop({ required: true })
skinId: number; // 皮肤id
skinId: number; // 皮肤id
@prop({ required: true })
quality: number; // 品质
quality: number; // 品质
@prop({ required: true })
star: number; // 星级
star: number; // 星级
@prop({ required: true })
colorStar: number; // 彩星
@prop({ required: true })
lv: number; // 等级
lv: number; // 等级
@prop({ required: true })
dataId: number; // 出兵表上所占位置
dataId: number; // 出兵表上所占位置
@prop({ required: true })
order: number; // 行动顺序
order: number; // 行动顺序
@prop({ required: true })
ce: number; // 战力
setByWarJson(warJson: DicWarJson) {
this.hid = warJson.actorId;
@@ -46,13 +47,14 @@ export class OppPlayerHeroInfo {
}
}
setByDefenseHero(hero: HeroType, lineup: Lineup[]) {
setByDefenseHero(hero: HeroType, lineup: {actorId: number, dataId: number, order: number}[]) {
this.hid = hero.hid;
this.skinId = hero.skinId;
this.quality = hero.quality;
this.star = hero.star;
this.colorStar = hero.colorStar;
this.lv = hero.lv;
this.ce = hero.ce;
let curLineup = lineup.find(cur => cur.actorId == hero.hid);
if(curLineup) {
this.dataId = curLineup.dataId;
@@ -90,7 +92,7 @@ export class OppPlayerInfo {
@prop({ required: true })
isRobot: boolean = false; // 原排名
initByPlayer(rank: number, role: RoleType, heroes: HeroType[], lineup: Lineup[], isSuccess: boolean ) {
initByPlayer(rank: number, role: RoleType, isSuccess: boolean ) {
this.oldRank = rank;
this.newRank = rank;
this.roleId = role.roleId;
@@ -101,13 +103,16 @@ export class OppPlayerInfo {
this.title = role.title;
this.lv = role.lv;
this.isSuccess = isSuccess;
this.isRobot = false;
}
setPlayerHeroes(heroes: HeroType[], lineup: {actorId: number, dataId: number, order: number}[]) {
for(let hero of heroes) {
let obj = new OppPlayerHeroInfo();
obj.setByDefenseHero(hero, lineup);
this.ce += hero.ce;
this.heroes.push(obj);
}
this.isRobot = false;
}
initByRobot(dic: DicGVGVestige, heroes: OppPlayerHeroInfo[], isSuccess: boolean) {

View File

@@ -1,7 +1,7 @@
[
{
"id": 1,
"cityType": 1,
"cityType": 3,
"foodAdd": 10,
"mineralAdd": 10,
"woodAdd": 10
@@ -15,7 +15,7 @@
},
{
"id": 3,
"cityType": 3,
"cityType": 1,
"foodAdd": 50,
"mineralAdd": 50,
"woodAdd": 50

File diff suppressed because it is too large Load Diff

View File

@@ -20,104 +20,5 @@
"additionValue": "6&1000",
"content": "策士",
"position": "&"
},
{
"id": 3,
"vestigeId": 3,
"name": "燕都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "5&1000",
"content": "游侠",
"position": "&"
},
{
"id": 4,
"vestigeId": 4,
"name": "韩都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "4&1000",
"content": "弓兵",
"position": "&"
},
{
"id": 5,
"vestigeId": 5,
"name": "赵都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "3&1000",
"content": "骑兵",
"position": "&"
},
{
"id": 6,
"vestigeId": 6,
"name": "魏都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "1&1000",
"content": "步兵",
"position": "&"
},
{
"id": 7,
"vestigeId": 7,
"name": "山巅帝陵",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "1&1000",
"content": "魏国",
"position": "&"
},
{
"id": 8,
"vestigeId": 8,
"name": "崖底河泽",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "2&1000",
"content": "吴国",
"position": "&"
},
{
"id": 9,
"vestigeId": 9,
"name": "深山迷林",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "3&1000",
"content": "蜀国",
"position": "&"
},
{
"id": 10,
"vestigeId": 10,
"name": "桃源古村",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "4&1000",
"content": "群雄",
"position": "&"
},
{
"id": 11,
"vestigeId": 11,
"name": "鹿鸣幽谷",
"mapType": "1&2",
"imageName": "&",
"additionType": 3,
"additionValue": "2&1000",
"content": "女性",
"position": "&"
}
]