名将擂台:获取对手详细信息,结算

This commit is contained in:
luying
2022-07-15 21:13:37 +08:00
parent f56dbc29de
commit df8032cb06
9 changed files with 292 additions and 39 deletions

View File

@@ -165,8 +165,6 @@ export enum LADDER_STATUS {
COMPLETE = 3, // 战斗结束
}
export const LADDER_CHECK_STOP_TIME = 2 * 60;
export const LADDER_BATTLE_STOP_TIME = 5 * 60;
export const LADDER_SERVER_GAP_TIME = 5; // 服务器比客户端晚5秒
export enum LADDER_OPP_STATUS {

View File

@@ -382,6 +382,7 @@ export const KEY_TO_COMPOSE_FIELD = new Map([
[REDIS_KEY.PVP_RANK, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.GUILD_FUND, COMPOSE_FIELD_TYPE.GUILD],
[REDIS_KEY.SUM_CE_SNAPSHOT, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.LADDER, COMPOSE_FIELD_TYPE.ROLE],
]);

View File

@@ -263,6 +263,10 @@ export const STATUS = {
LADDER_BUY_MAX: { code: 21201, simStr: '名将擂台购买次数达到上限' },
LADDER_RANK_ERROR: { code: 21202, simStr: '该排名玩家不可挑战' },
LADDER_REFRESH_CNT_MAX: { code: 21203, simStr: '刷新次数达到上限' },
LADDER_REC_NOT_FOUND: { code: 21204, simStr: '未找到该条记录' },
LADDER_REC_STATUS_IS_COMPLETE: { code: 21205, simStr: '该战斗已结束' },
LADDER_CHALLENGE_CNT_MAX: { code: 21206, simStr: '挑战次数已达上限' },
LADDER_REC_STATUS_ERR: { code: 21207, simStr: '战斗状态错误' },
// 通用 30000 - 30099
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },

View File

@@ -1,6 +1,6 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import { LadderDefense, LadderOppPlayerInDB } from '../domain/battleField/ladder';
import { LadderDefense, LadderOppPlayerInDB, LadderOppPlayerInfo } from '../domain/battleField/ladder';
import Role from './Role';
@index({ roleId: 1 })
@@ -14,6 +14,8 @@ export default class LadderMatch extends BaseModel {
@prop({ required: true, default: 0 })
rank: number; // 排名
@prop({ required: true, default: 0 })
oldRank: number; // 交换前排名
@prop({ required: true, default: 0 })
historyRank: number; // 历史最高排名
@prop({ required: true, default: 0 })
@@ -66,10 +68,17 @@ export default class LadderMatch extends BaseModel {
return defense;
}
public static async updateByRoleIdAndInclude(roleId: string, params: LadderUpdateInter) {
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: params}, { new: true })
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
.populate('defense.hero', 'hid skinId quality star colorStar lv')
.lean();
return defense;
}
public static async findAll(serverId: number) {
let result: LadderMatchType[] = [], latestTime = new Date();
while(latestTime) {
let ladderMatch = await LadderMatchModel.find({ serverId, rank: { $gt: 0 }, createdAt: { $lt: latestTime } })
let ladderMatch = await LadderMatchModel.find({ serverId, rank: { $gt: 0, $lte: 3000 }, createdAt: { $lt: latestTime } })
.sort({ createdAt: -1 })
.populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt')
.limit(1000);
@@ -83,6 +92,27 @@ export default class LadderMatch extends BaseModel {
const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId, rank, locked: 0 }, { $set: { locked: 1 }}, { new: true }).lean();
return defense;
}
public static async changeRank(isSuccess: boolean, attackInfo: LadderOppPlayerInfo, defenseInfo: LadderOppPlayerInfo) {
// TODO transaction
let atkLadderMatch: LadderMatchType, defLadderMatch: LadderMatchType, isChange = false;
if(defenseInfo.isRobot) {
atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
if(isSuccess && atkLadderMatch && atkLadderMatch.rank > defenseInfo.oldRank) {
atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defenseInfo.oldRank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
isChange = true;
}
} else {
atkLadderMatch = await LadderMatchModel.findOne({ roleId: attackInfo.roleId }).lean();
defLadderMatch = await LadderMatchModel.findOne({ roleId: defenseInfo.roleId }).lean();
if(isSuccess && atkLadderMatch && defLadderMatch && atkLadderMatch.rank > defLadderMatch.rank) {
atkLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: attackInfo.roleId }, { $set: { rank: defLadderMatch.rank, oldRank: atkLadderMatch.rank } }, { new: true }).lean();
defLadderMatch = await LadderMatchModel.findOneAndUpdate({ roleId: defenseInfo.roleId }, { $set: { rank: atkLadderMatch.rank, oldRank: defLadderMatch.rank } }, { new: true }).lean();
isChange = true;
}
}
return { isChange, atkLadderMatch, defLadderMatch }
}
}
export const LadderMatchModel = getModelForClass(LadderMatch);

View File

@@ -5,7 +5,7 @@ import { Defense, Attack, LineupCe, OppPlayer, HeroScore, } from '../domain/batt
import { CounterModel } from './Counter';
import { COUNTER, LADDER_STATUS } from '../consts';
import { EXTERIOR, PVP } from '../pubUtils/dicParam';
import { LadderDefense, LadderOppPlayerInfo } from '../domain/battleField/ladder';
import { LadderDefense, LadderOppPlayerInfo, LadderOppPlayerHeroInfo } from '../domain/battleField/ladder';
import { genCode } from '../pubUtils/util';
import { nowSeconds } from '../pubUtils/timeUtil';
@@ -56,12 +56,41 @@ export default class LadderMatchRec extends BaseModel {
}
public static async timeout(battleCode: string) {
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.COMPLETE, timeout: true } }).lean();
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.COMPLETE, timeout: true } }, { new: true }).lean();
return result;
}
public static async giveup(battleCode: string) {
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.NO } }).lean();
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: { status: LADDER_STATUS.NO } }, { new: true }).lean();
return result;
}
public static async findByBattleCode(battleCode: string, select: string = '') {
const result: LadderMatchRecType = await LadderMatchRecModel.findOne({ battleCode }).select(select).lean();
return result;
}
public static async startBattle(battleCode: string, attackHeroes: LadderOppPlayerHeroInfo[]) {
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, {
$set: { status: LADDER_STATUS.BATTLE, battleTime: nowSeconds(), 'attackInfo.heroes': attackHeroes }
}, { new: true }).lean();
return result;
}
public static async battleEnd(battleCode: string, isSuccess: boolean, atkNewRank?: number, defNewRank?: number) {
let update: LadderMatchRecUpdate = { status: LADDER_STATUS.COMPLETE, endTime: nowSeconds() };
if(isSuccess) {
update['attackInfo.isSuccess'] = true;
update['defenseInfo.isSuccess'] = false;
}
if(atkNewRank != undefined && defNewRank != undefined) {
update['attackInfo.rank'] = atkNewRank;
update['attackInfo.oldRank'] = defNewRank;
update['defenseInfo.rank'] = defNewRank;
update['defenseInfo.oldRank'] = atkNewRank;
}
const result: LadderMatchRecType = await LadderMatchRecModel.findOneAndUpdate({ battleCode }, { $set: update }, { new: true }).lean();
return result;
}
}
@@ -69,4 +98,4 @@ export default class LadderMatchRec extends BaseModel {
export const LadderMatchRecModel = getModelForClass(LadderMatchRec);
export interface LadderMatchRecType extends Pick<DocumentType<LadderMatchRec>, keyof LadderMatchRec> { };
export type pvpUpdateInter = Partial<LadderMatchRecType>;
export type LadderMatchRecUpdate = Partial<LadderMatchRecType>;

View File

@@ -1,5 +1,5 @@
import { mongoose, prop, Ref } from "@typegoose/typegoose";
import { LADDER_BATTLE_STOP_TIME, LADDER_CHECK_STOP_TIME, LADDER_STATUS } from "../../consts";
import { LADDER_STATUS } from "../../consts";
import Hero, { HeroType } from '../../db/Hero';
import { LadderMatchType } from "../../db/LadderMatch";
import { LadderMatchRecType } from "../../db/LadderMatchRec";
@@ -137,6 +137,7 @@ export class LadderOppPlayerInfo {
this.lv = role.lv;
this.isSuccess = isSuccess;
this.heroes = heroes;
this.isRobot = false;
}
initByRobot(dicLadderDifficultRatio: DicLadderDifficultRatio, heroes: LadderOppPlayerHeroInfo[], isSuccess: boolean) {
@@ -149,7 +150,9 @@ export class LadderOppPlayerInfo {
this.lv = dicLadderDifficultRatio.level;
this.isSuccess = isSuccess;
this.heroes = heroes;
this.isRobot = true;
}
}
// defense字段 接口返回
@@ -245,9 +248,9 @@ export class LadderDataReturn {
if(ladderRec) {
this.status = ladderRec.status;
if(this.status == LADDER_STATUS.BATTLE) {
this.time = ladderRec.battleTime + LADDER_BATTLE_STOP_TIME;
this.time = ladderRec.battleTime + LADDER.LADDER_BATTLE_COUNTDOWN;
} else if (this.status == LADDER_STATUS.CHECK) {
this.time = ladderRec.checkTime + LADDER_CHECK_STOP_TIME;
this.time = ladderRec.checkTime + LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN;
}
}
}
@@ -307,4 +310,105 @@ export class LadderOppLineupReturn {
this.heroes.push(hero);
}
}
}
// getOppData接口的返回
export class LadderOppDetailHeroReturn {
actorId: number = 0; // 武将id
skinId: number = 0; // 皮肤idfashions表的heroId
actorName: string = ''; // 武将名
dataId: number = 0; // 出兵表唯一id
relation: number = 0; // 地方还是我方
dirction: number = 0; // 方向
outIndex: number = 0; // 玩家设置的出场顺序即order字段
x: number = 0; // 战场x坐标
y: number = 0; // 战场y坐标
var: number = 0; // 变量
lv: number = 0; // 等级
hide: number = 0; // 是否隐藏
initial_ai: number = 0; // ai类型
attribute: string = ''; // 武将属性,格式 id&val|id&val|...这里的次级属性都是没有除1000的值
star: number = 0; // 星级
colorStar: number = 0; // 彩星
quality: number = 0; // 品质
skill: string = ''; // 技能
seid: string = ''; // 技能
spine: string = ''; // 动画
constructor(warJson: DicWarJson, defensHero: LadderDefenseHero) {
this.dataId = warJson.actorId;
this.relation = warJson.relation;
this.dirction = warJson.dirction;
this.x = warJson.x;
this.y = warJson.y;
this.var = warJson.var;
this.hide = warJson.hide;
if(defensHero) {
this.outIndex = defensHero.order;
this.initial_ai = defensHero.ai;
let hero = <HeroType>defensHero.hero;
if(hero) {
this.actorId = hero.hid;
this.skinId = hero.skinId;
this.actorName = hero.hName;
this.lv = hero.lv;
}
}
}
setAttribute(attribute: string) {
this.attribute = attribute;
}
}
// getOppData接口的返回
export class LadderOppDetailReturn {
battleCode: string = '';
roleId: string = '';
status: LADDER_STATUS = LADDER_STATUS.NO;
time: number = 0;
isRobot: boolean = false;
title: number = 1;
warId: number = 0;
heroes: LadderOppDetailHeroReturn[] = [];
constructor(ladderRec: LadderMatchRecType) {
this.battleCode = ladderRec.battleCode;
this.roleId = ladderRec.roleId2;
this.status = ladderRec.status;
if(this.status == LADDER_STATUS.BATTLE) {
this.time = ladderRec.battleTime + LADDER.LADDER_BATTLE_COUNTDOWN;
} else if (this.status == LADDER_STATUS.CHECK) {
this.time = ladderRec.checkTime + LADDER.LADDER_BATTLE_PREPARE_COUNTDOWN;
}
}
setByPlayer(ladderMatch: LadderMatchType, warJsons: DicWarJson[]) {
this.isRobot = false;
let role = <RoleType>ladderMatch.role;
this.title = role.title;
if(ladderMatch.defense) {
this.warId = ladderMatch.defense.warId;
let heroes = ladderMatch.defense.heroes||[];
for(let hero of heroes) {
let warJson = warJsons.find(cur => cur.dataId == hero.dataId);
if(warJson) {
let obj = new LadderOppDetailHeroReturn(warJson, hero);
this.heroes.push(obj);
}
}
}
}
setByRobot(dicLadderDifficultRatio: DicLadderDifficultRatio) {
this.isRobot = true;
this.roleId = `robot${dicLadderDifficultRatio.rank}`;
this.warId = dicLadderDifficultRatio.gkId;
}
setAttribute(hid: number, attribute: string) {
let hero = this.heroes.find(cur => cur.actorId == hid);
if(hero) hero.setAttribute(attribute);
}
}