✨ feat(gvg): 征战中原锁定对手
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
import { Application, BackendSession, ChannelService, HandlerService } from "pinus";
|
||||
import { GVG_PERIOD, STATUS } from "../../../consts";
|
||||
import { GVG_ITEM, GVG_PERIOD, ITEM_CHANGE_REASON, STATUS, VESTIGE_OPP_STATUS } from "../../../consts";
|
||||
import { GVGLeagueModel } from "../../../db/GVGLeague";
|
||||
import { GVGUserItemModel } from "../../../db/GVGUserItem";
|
||||
import { GVGVestigeLockModel } from "../../../db/GVGVestigeLock";
|
||||
import { GVGVestigeRankModel } 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 { resResult } from "../../../pubUtils/util";
|
||||
import { checkVestige, getOppPlayerByRanks, refreshVestigeOppRanks } from "../../../services/gvg/gvgFightService";
|
||||
import { checkVestige, checkVestigeOppStatus, checkVestigeRank, generateAttackInfo, generateDefenseInfo, getOppDetailData, getOppPlayerByRanks, getVestigeUsedHeroes, isRobot, refreshVestigeOppRanks } from "../../../services/gvg/gvgFightService";
|
||||
import { addGVGReward, handleGVGCost } from "../../../services/gvg/gvgItemService";
|
||||
import { getGroupIdOfServer, getGVGPeriodData } from "../../../services/gvg/gvgService";
|
||||
import { getAllServerName } from "../../../services/redisService";
|
||||
|
||||
@@ -42,7 +47,7 @@ export class GVGProduceHandler {
|
||||
let dicRankMap = gameData.gvgVestige.get(vestigeId);
|
||||
if(!dicRankMap) return resResult(STATUS.DIC_DATA_NOT_FOUND);
|
||||
|
||||
let myVestigateRank = await GVGVestigeRankModel.findRankByRole(vestigeId, roleId); // 我在这个遗迹的排名
|
||||
let myVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
|
||||
if(!myVestigateRank) {
|
||||
let role = await RoleModel.findByRoleId(roleId, 'roleId');
|
||||
let oppRanks = refreshVestigeOppRanks(-1);
|
||||
@@ -53,6 +58,7 @@ export class GVGProduceHandler {
|
||||
|
||||
let lineupCe = lineup.reduce((pre, cur) => pre + cur.ce, 0);
|
||||
let oppPlayers = await getOppPlayerByRanks(serverId, groupId, vestigeId, oppRanks);
|
||||
let usedHeroes = await getVestigeUsedHeroes(roleId, vestigeId);
|
||||
|
||||
return resResult(STATUS.SUCCESS, {
|
||||
vestigeId,
|
||||
@@ -60,7 +66,8 @@ export class GVGProduceHandler {
|
||||
score,
|
||||
lineup, lineupCe,
|
||||
oppPlayers,
|
||||
refreshCnt
|
||||
refreshCnt,
|
||||
usedHeroes
|
||||
})
|
||||
}
|
||||
|
||||
@@ -75,7 +82,7 @@ export class GVGProduceHandler {
|
||||
const serverId: number = session.get('serverId');
|
||||
|
||||
let { vestigeId, roleId: targetRoleId, rank } = msg;
|
||||
let myVestigateRank = await GVGVestigeRankModel.findRankByRole(vestigeId, roleId); // 我在这个遗迹的排名
|
||||
let myVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); // 我在这个遗迹的排名
|
||||
|
||||
const serverNames = await getAllServerName();
|
||||
|
||||
@@ -90,7 +97,7 @@ export class GVGProduceHandler {
|
||||
let dicWarJson = gameData.warJson.get(dicWar.dispatchJsonId);
|
||||
result.setRobot(dicGVGVestige, dicWarJson, serverNames[serverId]);
|
||||
} else {
|
||||
let hisVestigateRank = await GVGVestigeRankModel.findRankByRole(vestigeId, roleId); // 我在这个遗迹的排名
|
||||
let hisVestigateRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId);
|
||||
if(!hisVestigateRank) 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')
|
||||
@@ -109,8 +116,57 @@ export class GVGProduceHandler {
|
||||
}
|
||||
|
||||
// 选择对手
|
||||
async chooseOpp(msg: { vestigeId: number, rank: number, myRank: number }, session: BackendSession) {
|
||||
async chooseOpp(msg: { vestigeId: number, roleId: string, rank: number, myRank: number }, session: BackendSession) {
|
||||
|
||||
let roleId = session.get('roleId');
|
||||
let roleName = session.get('roleName');
|
||||
let serverId = session.get('serverId');
|
||||
let guildCode = session.get('guildCode');
|
||||
let sid = session.get('sid');
|
||||
let { vestigeId, roleId: targetRoleId, rank, myRank } = msg;
|
||||
|
||||
let { configId, period } = getGVGPeriodData();
|
||||
if(period != GVG_PERIOD.PREPARE) return resResult(STATUS.GVG_NOT_PREPARE_PERIOD);
|
||||
|
||||
let dicRank = gameData.gvgVestige.get(vestigeId)?.get(rank);
|
||||
if(!dicRank) return resResult(STATUS.DIC_DATA_NOT_FOUND);
|
||||
|
||||
let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
|
||||
if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
|
||||
|
||||
// 检查对手排名/自己排名
|
||||
if(!checkVestigeRank(myRank, rank)) return resResult(STATUS.GVG_VESTIGE_RANK_ERR);
|
||||
|
||||
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);
|
||||
|
||||
let status = await checkVestigeOppStatus(configId, groupId, vestigeId, roleId, myRank, targetRoleId, rank); // 锁
|
||||
if(status != VESTIGE_OPP_STATUS.BATTLE) {
|
||||
let oppRanks = refreshVestigeOppRanks(myRank);
|
||||
let oppPlayers = await getOppPlayerByRanks(serverId, groupId, vestigeId, oppRanks);
|
||||
return resResult(STATUS.SUCCESS, { status, oppPlayers });
|
||||
}
|
||||
|
||||
// 扣征战令
|
||||
const costResult = await handleGVGCost(roleId, myLeague.leagueCode, sid, [{ id: GVG_ITEM.FIGHT_COIN, count: 1 }], [], ITEM_CHANGE_REASON.GVG_VESTIGE_START);
|
||||
if(!costResult) {
|
||||
await GVGVestigeLockModel.releaseLock(groupId, vestigeId, rank);
|
||||
return resResult(STATUS.GVG_ITEMS_NOT_ENOUGH);
|
||||
}
|
||||
// 获取征战令对应奖励
|
||||
const leagueGoods = await addGVGReward(roleId, roleName, myLeague.leagueCode, sid, dicRank.battleLeagueReward, dicRank.battleReward, ITEM_CHANGE_REASON.GVG_VESTIGE_START);
|
||||
// 创建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 oppDetail = await getOppDetailData(rec);
|
||||
|
||||
return resResult(STATUS.SUCCESS, {
|
||||
battleCode: rec.battleCode,
|
||||
time: rec.checkTime,
|
||||
...oppDetail
|
||||
});
|
||||
}
|
||||
|
||||
// 出战界面撤退
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
// 征战中原相关
|
||||
|
||||
import { GVG_PERIOD } from "../../consts";
|
||||
import { GVG_PERIOD, STATUS, VESTIGE_OPP_STATUS } from "../../consts";
|
||||
import { ArtifactModel } from "../../db/Artifact";
|
||||
import { GVGVestigeModel } from "../../db/GVGVestige";
|
||||
import { GVGVestigeRankModel } from "../../db/GVGVestigeRank";
|
||||
import { GVGVestigeLockModel } from "../../db/GVGVestigeLock";
|
||||
import { GVGVestigeRankModel, GVGVestigeRankType } from "../../db/GVGVestigeRank";
|
||||
import { GVGVestigeRecType } from "../../db/GVGVestigeRec";
|
||||
import { HeroModel } from "../../db/Hero";
|
||||
import { RoleType } from "../../db/Role";
|
||||
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 { getTimeFun } from "../../pubUtils/timeUtil";
|
||||
import { getRandEelm, getRandValueByMinMax } from "../../pubUtils/util";
|
||||
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";
|
||||
@@ -65,6 +70,7 @@ function randomRank(min: number, max: number, len: number) {
|
||||
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);
|
||||
@@ -86,4 +92,123 @@ export async function getOppPlayerByRanks(serverId: number, groupId: number, ves
|
||||
}
|
||||
|
||||
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 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?.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 null;
|
||||
|
||||
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');
|
||||
|
||||
let info = new OppPlayerInfo();
|
||||
info.initByPlayer(playerVestigeData.rank, role, heroes, lineup, true);
|
||||
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 getOppDetailData(rec: GVGVestigeRecType) {
|
||||
let isRobot = rec.defenseInfo.isRobot;
|
||||
let dicLadderDifficultRatio = gameData.ladderDifficultRatio.get(rec.defenseInfo.oldRank);
|
||||
let result = new OppDetailData();
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export enum GVG_ITEM {
|
||||
CORN = 2, // 粟米
|
||||
RICE = 3, // 水稻
|
||||
PRODUCE_COIN = 10, // 内政令
|
||||
FIGHT_COIN = 11, // 征战令
|
||||
BATTLE_FEAT = 12, // 战功
|
||||
}
|
||||
|
||||
@@ -114,4 +115,19 @@ export enum GVG_REC_ID {
|
||||
VESTIGE_RANK = 5, // 联军每日的征战排名
|
||||
LEAGUE_JOIN_GUILD = 6, // 军团加入联军
|
||||
LEAGUE_QUIT_GUILD = 7, // 军团退出联军
|
||||
}
|
||||
}
|
||||
|
||||
// 遗迹选择对手状态
|
||||
export enum VESTIGE_OPP_STATUS {
|
||||
BATTLE = 1, // 可以挑战
|
||||
OPP_IS_LOCKED = 2, // 对手被挑战
|
||||
OPP_RANK_CHANGE = 3, // 对手排名变化
|
||||
MY_RANK_CHANGE = 4, // 自己排名变化
|
||||
}
|
||||
|
||||
export enum VESTIGE_STATUS {
|
||||
NO = 0, // 无战场
|
||||
CHECK = 1, // 出兵中
|
||||
BATTLE = 2, // 战斗中
|
||||
COMPLETE = 3, // 战斗结束
|
||||
}
|
||||
@@ -1092,6 +1092,7 @@ export enum ITEM_CHANGE_REASON {
|
||||
GVG_RECEIVE_BOX = 167, // 领取宝箱
|
||||
GVG_RECEIVE_LV = 168, // 领取等级奖励
|
||||
GVG_RECEIVE_TASK = 169, // 领取任务奖励
|
||||
GVG_VESTIGE_START = 170, // gvg征战中原挑战
|
||||
}
|
||||
|
||||
export enum TA_EVENT {
|
||||
|
||||
@@ -336,8 +336,11 @@ export const STATUS = {
|
||||
GVG_TASK_HAS_RECEIVED: { code: 21330, simStr: '任务已领取过' },
|
||||
GVG_BATTLE_CITY_FULL: { code: 21331, simStr: '城市已满员' },
|
||||
GVG_BATTLE_TEAM_INVALID: { code: 21332, simStr: '无效的队伍' },
|
||||
GVG_VESTIGE_ERR: { code: 21333, simStr: '今日未开放该遗迹' },
|
||||
GVG_VESTIGE_TARGET_NOT_FOUND: { code: 21334, simStr: '对手未找到' },
|
||||
|
||||
// GVG征战中原
|
||||
GVG_VESTIGE_ERR: { code: 21350, simStr: '今日未开放该遗迹' },
|
||||
GVG_VESTIGE_TARGET_NOT_FOUND: { code: 21351, simStr: '对手未找到' },
|
||||
GVG_VESTIGE_RANK_ERR: { code: 21352, simStr: '该排名玩家不可挑战' },
|
||||
|
||||
// 通用 30000 - 30099
|
||||
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },
|
||||
|
||||
59
shared/db/GVGVestigeLock.ts
Normal file
59
shared/db/GVGVestigeLock.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
// 征战中原对手锁
|
||||
import BaseModel from './BaseModel';
|
||||
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
|
||||
import { getZeroPoint, nowSeconds } from '../pubUtils/timeUtil';
|
||||
import { GVG } from '../pubUtils/dicParam';
|
||||
|
||||
@index({ day: 1, groupId: 1, vestigeId: 1, rank: 1 })
|
||||
export default class GVGVestigeLock extends BaseModel {
|
||||
|
||||
@prop({ required: true })
|
||||
configId: number; // 赛期
|
||||
|
||||
@prop({ required: true })
|
||||
day: number; // 每天5点
|
||||
|
||||
@prop({ required: true })
|
||||
groupId: number; // 战区id
|
||||
|
||||
@prop({ required: true })
|
||||
vestigeId: number; // 遗迹id
|
||||
|
||||
@prop({ required: true })
|
||||
rank: number; // 排名
|
||||
|
||||
@prop({ required: true })
|
||||
unlockTime: number; // 锁定到什么时候
|
||||
|
||||
@prop({ required: true })
|
||||
attackRoleId: string; // 锁定到什么时候
|
||||
|
||||
@prop({ required: true })
|
||||
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();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async releaseLock(groupId: number, vestigeId: number, rank: number) {
|
||||
let day = getZeroPoint();
|
||||
let result: GVGVestigeLockType = await GVGVestigeLockModel.findOneAndUpdate({ day, groupId, vestigeId, rank }, { $set: { unlockTime: 0 } }, { new: true }).lean();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export const GVGVestigeLockModel = getModelForClass(GVGVestigeLock);
|
||||
|
||||
export interface GVGVestigeLockType extends Pick<DocumentType<GVGVestigeLock>, keyof GVGVestigeLock> {
|
||||
id: number;
|
||||
};
|
||||
export type GVGVestigeLockUpdate = Partial<GVGVestigeLockType>; // 将所有字段变成可选项
|
||||
@@ -3,7 +3,7 @@ import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typ
|
||||
import Role, { RoleType } from './Role';
|
||||
import { getZeroPoint } from '../pubUtils/timeUtil';
|
||||
|
||||
class Lineup {
|
||||
export class Lineup {
|
||||
@prop({ required: true })
|
||||
actorId: number; // 武将
|
||||
@prop({ required: true })
|
||||
@@ -60,12 +60,24 @@ export default class GVGVestigeRank extends BaseModel {
|
||||
@prop({ required: true, default: 0 })
|
||||
refreshCnt: number; // 刷新次数
|
||||
|
||||
public static async findRankByRole(vestigeId: number, roleId: string) {
|
||||
public static async findAllByRole(roleId: string) {
|
||||
let today = getZeroPoint();
|
||||
let result: GVGVestigeRankType[] = await GVGVestigeRankModel.find({ day: today, roleId }).lean();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async findByRole(vestigeId: number, roleId: string) {
|
||||
let today = getZeroPoint();
|
||||
let result: GVGVestigeRankType = await GVGVestigeRankModel.findOne({ day: today, vestigeId, roleId }).lean();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async findByRank(vestigeId: number, rank: number) {
|
||||
let today = getZeroPoint();
|
||||
let result: GVGVestigeRankType = await GVGVestigeRankModel.findOne({ day: today, vestigeId, rank }).lean();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async initRank(configId: number, vestigeId: number, groupId: number, role: RoleType, oppRanks: number[]) {
|
||||
let today = getZeroPoint();
|
||||
let doc = new GVGVestigeRankModel();
|
||||
|
||||
76
shared/db/GVGVestigeRec.ts
Normal file
76
shared/db/GVGVestigeRec.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
// 征战中原对手锁
|
||||
import BaseModel from './BaseModel';
|
||||
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
|
||||
import { OppPlayerInfo } from '../domain/gvgField/gvgDb';
|
||||
import { genCode } from '../pubUtils/util';
|
||||
import { VESTIGE_STATUS } from '../consts';
|
||||
|
||||
class LeagueGood {
|
||||
@prop({ required: true })
|
||||
itemType: number;
|
||||
|
||||
@prop({ required: true })
|
||||
id: number;
|
||||
|
||||
@prop({ required: true })
|
||||
count: number
|
||||
}
|
||||
|
||||
@index({ day: 1, groupId: 1, vestigeId: 1, rank: 1 })
|
||||
export default class GVGVestigeRec extends BaseModel {
|
||||
|
||||
@prop({ required: true })
|
||||
battleCode: string; // 唯一code
|
||||
|
||||
@prop({ required: true })
|
||||
attackRoleId: string; // 攻方玩家id
|
||||
|
||||
@prop({ required: true })
|
||||
defenseRoleId: string; // 守方玩家id
|
||||
|
||||
@prop({ required: true })
|
||||
groupId: number; // 战区id
|
||||
|
||||
@prop({ required: true })
|
||||
vestigeId: number; // 遗迹id
|
||||
|
||||
@prop({ required: true })
|
||||
status: number; // 1-出兵中 2-挑战中 3-挑战完毕 4-取消
|
||||
|
||||
@prop({ required: true })
|
||||
checkTime: number; // 开始出兵的时间,13位时间戳
|
||||
|
||||
@prop({ required: true })
|
||||
battleTime: number; // 开始挑战的时间,13位时间
|
||||
|
||||
@prop({ required: true })
|
||||
endTime: number; // 结束时间,13位时间戳
|
||||
|
||||
@prop({ required: true, type: () => OppPlayerInfo, default: {}, _id: false })
|
||||
attackInfo: OppPlayerInfo; // 攻方信息
|
||||
|
||||
@prop({ required: true, type: () => OppPlayerInfo, default: {}, _id: false })
|
||||
defenseInfo: OppPlayerInfo; // 守方信息
|
||||
|
||||
@prop({ required: true, type: () => LeagueGood, default: [], _id: false })
|
||||
leagueGoods: LeagueGood[]; // 奖励
|
||||
|
||||
@prop({ required: true, default: false })
|
||||
hasRpl: boolean; // 是否存在对应录像
|
||||
|
||||
public static async createRec(configId: number, vestigeId: number, groupId: 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 }
|
||||
}, { new: true, upsert: true }).lean();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const GVGVestigeRecModel = getModelForClass(GVGVestigeRec);
|
||||
|
||||
export interface GVGVestigeRecType extends Pick<DocumentType<GVGVestigeRec>, keyof GVGVestigeRec> {
|
||||
id: number;
|
||||
};
|
||||
export type GVGVestigeRecUpdate = Partial<GVGVestigeRecType>; // 将所有字段变成可选项
|
||||
219
shared/domain/gvgField/gvgDb.ts
Normal file
219
shared/domain/gvgField/gvgDb.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
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";
|
||||
|
||||
export class OppPlayerHeroInfo {
|
||||
@prop({ required: true })
|
||||
hid: number; // 武将id
|
||||
@prop({ required: true })
|
||||
skinId: number; // 皮肤id
|
||||
@prop({ required: true })
|
||||
quality: number; // 品质
|
||||
@prop({ required: true })
|
||||
star: number; // 星级
|
||||
@prop({ required: true })
|
||||
colorStar: number; // 彩星
|
||||
@prop({ required: true })
|
||||
lv: number; // 等级
|
||||
@prop({ required: true })
|
||||
dataId: number; // 出兵表上所占位置
|
||||
@prop({ required: true })
|
||||
order: number; // 行动顺序
|
||||
|
||||
setByWarJson(warJson: DicWarJson) {
|
||||
this.hid = warJson.actorId;
|
||||
this.skinId = warJson.actorId;
|
||||
this.lv = warJson.lv;
|
||||
this.dataId = warJson.dataId;
|
||||
this.order = warJson.outIndex;
|
||||
let dicHero = gameData.hero.get(warJson.actorId);
|
||||
|
||||
if(dicHero) {
|
||||
this.quality = dicHero.quality;
|
||||
if(this.quality == 4) {
|
||||
this.star = 6;
|
||||
this.colorStar = warJson.star;
|
||||
} else {
|
||||
this.star = warJson.star;
|
||||
this.colorStar = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setByDefenseHero(hero: HeroType, lineup: Lineup[]) {
|
||||
this.hid = hero.hid;
|
||||
this.skinId = hero.skinId;
|
||||
this.quality = hero.quality;
|
||||
this.star = hero.star;
|
||||
this.colorStar = hero.colorStar;
|
||||
this.lv = hero.lv;
|
||||
let curLineup = lineup.find(cur => cur.actorId == hero.hid);
|
||||
if(curLineup) {
|
||||
this.dataId = curLineup.dataId;
|
||||
this.order = curLineup.order;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ladderMatchRec
|
||||
export class OppPlayerInfo {
|
||||
@prop({ required: true })
|
||||
oldRank: number = 0; // 原排名
|
||||
@prop({ required: true })
|
||||
newRank: number = 0; // 交换后的排名
|
||||
@prop({ required: true })
|
||||
roleId: string = ''; // 角色 id
|
||||
@prop({ required: true })
|
||||
roleName: string = GVG.GVG_ROBOT_NAME; // 角色 名
|
||||
@prop({ required: true, default: 0 })
|
||||
lv: number = 1; // 等级
|
||||
@prop({ required: true, default: EXTERIOR.EXTERIOR_FACE })
|
||||
head: number = EXTERIOR.EXTERIOR_FACE; // 头像
|
||||
@prop({ required: true, default: EXTERIOR.EXTERIOR_FACECASE })
|
||||
frame: number = EXTERIOR.EXTERIOR_FACECASE; // 相框
|
||||
@prop({ required: true, default: EXTERIOR.EXTERIOR_APPEARANCE })
|
||||
spine: number = EXTERIOR.EXTERIOR_APPEARANCE; // 形象
|
||||
@prop({ required: true, default: 0 })
|
||||
title: number = 1; // 爵位
|
||||
@prop({ required: true, default: 0 })
|
||||
ce: number = 0; // 防守战力
|
||||
@prop({ required: true, default: false })
|
||||
isSuccess: boolean = false; // 是否胜利
|
||||
@prop({ required: true, default: [], type: OppPlayerHeroInfo, _id: false })
|
||||
heroes: OppPlayerHeroInfo[] = []; // 武将
|
||||
@prop({ required: true })
|
||||
isRobot: boolean = false; // 原排名
|
||||
|
||||
initByPlayer(rank: number, role: RoleType, heroes: HeroType[], lineup: Lineup[], isSuccess: boolean ) {
|
||||
this.oldRank = rank;
|
||||
this.newRank = rank;
|
||||
this.roleId = role.roleId;
|
||||
this.roleName = role.roleName;
|
||||
this.head = role.head;
|
||||
this.frame = role.frame;
|
||||
this.spine = role.spine;
|
||||
this.title = role.title;
|
||||
this.lv = role.lv;
|
||||
this.isSuccess = isSuccess;
|
||||
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) {
|
||||
this.oldRank = dic.rank;
|
||||
this.newRank = dic.rank;
|
||||
this.roleId = `robot${this.oldRank}`;
|
||||
this.head = dic.head;
|
||||
this.spine = dic.spine;
|
||||
this.ce = dic.ce;
|
||||
this.lv = dic.level;
|
||||
this.isSuccess = isSuccess;
|
||||
this.heroes = heroes;
|
||||
this.isRobot = true;
|
||||
}
|
||||
}
|
||||
|
||||
class HeroArtifact {
|
||||
@prop({ required: true })
|
||||
artifactId: number;
|
||||
|
||||
@prop({ required: true })
|
||||
lv: number;
|
||||
}
|
||||
|
||||
export class OppDetailHeroData {
|
||||
actorId: number = 0; // 武将id
|
||||
skinId: number = 0; // 皮肤id,fashions表的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; // 品质
|
||||
job: number = 0; // 职业
|
||||
skill: string = ''; // 技能
|
||||
seid: string = ''; // 技能
|
||||
spine: string = ''; // 动画
|
||||
talent: Talent[] = [];
|
||||
subHid: number = 0; // 副将
|
||||
artifact: HeroArtifact[] = [];
|
||||
|
||||
constructor(warJson: DicWarJson, defensHero: OppPlayerHeroInfo, hero: HeroType, artifacts: ArtifactModelType[]) {
|
||||
this.dataId = warJson.dataId;
|
||||
this.relation = warJson.relation;
|
||||
this.dirction = warJson.dirction;
|
||||
this.initial_ai = warJson.initial_ai;
|
||||
this.x = warJson.x;
|
||||
this.y = warJson.y;
|
||||
this.var = warJson.var;
|
||||
this.hide = warJson.hide;
|
||||
this.skill = warJson.skill;
|
||||
this.seid = warJson.seid;
|
||||
this.spine = warJson.spine;
|
||||
let dicHero = gameData.hero.get(warJson.actorId);
|
||||
if(dicHero) this.job = dicHero.jobid;
|
||||
|
||||
if(defensHero) {
|
||||
this.outIndex = defensHero.order;
|
||||
if(hero) {
|
||||
this.actorId = hero.hid;
|
||||
this.skinId = hero.skinId;
|
||||
this.actorName = hero.hName;
|
||||
this.lv = hero.lv;
|
||||
this.star = hero.star;
|
||||
this.colorStar = hero.colorStar;
|
||||
let skin = hero.skins.find(cur => cur.enable);
|
||||
if(skin) this.talent = skin.talent;
|
||||
this.job = hero.job;
|
||||
this.subHid = hero.subHid;
|
||||
let artifact = artifacts.find(cur => cur.seqId == hero.artifact);
|
||||
if(artifact) this.artifact.push({ artifactId: artifact.artifactId, lv: artifact.lv });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setAttribute(attribute: string) {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
export class OppDetailData{
|
||||
heroes: OppDetailHeroData[] = [];
|
||||
lineupCe: number = 0;
|
||||
|
||||
|
||||
setByPlayer(dicWarJson: DicWarJson[], defenseHeroes: OppPlayerHeroInfo[], heroes: HeroType[], artifacts: ArtifactModelType[]) {
|
||||
for(let warJson of dicWarJson) {
|
||||
let defenseHero = defenseHeroes.find(cur => cur.dataId == warJson.dataId);
|
||||
let curHero = heroes.find(cur => cur.hid == defenseHero.hid);
|
||||
let hero = new OppDetailHeroData(warJson, defenseHero, curHero, artifacts);
|
||||
this.heroes.push(hero);
|
||||
this.lineupCe += curHero.ce;
|
||||
}
|
||||
}
|
||||
|
||||
setAttribute(hid: number, attribute: string) {
|
||||
let hero = this.heroes.find(cur => cur.actorId == hid);
|
||||
if(hero) hero.setAttribute(attribute);
|
||||
}
|
||||
}
|
||||
@@ -1172,15 +1172,15 @@ function parseGVGVestigeCnt() {
|
||||
}
|
||||
|
||||
export function getGVGVestigeRange(myRank: number) {
|
||||
let latestRank: DicGVGVestigeRange;
|
||||
let lastRank: DicGVGVestigeRange;
|
||||
for(let dic of gameData.gvgVestigeRange) {
|
||||
latestRank = dic;
|
||||
lastRank = dic;
|
||||
let { rankMin, rankMax } = dic;
|
||||
if((rankMin < myRank && (rankMax >= myRank || rankMax == -1))) {
|
||||
return dic;
|
||||
}
|
||||
}
|
||||
return latestRank
|
||||
return lastRank
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
|
||||
@@ -394,5 +394,7 @@ export const GVG = {
|
||||
GVG_FIELD_TYPE_RATIO: '1&5%|2&10%|3&10%', // 全联盟的特殊格子上限百分比(a%的格子为小麦这个)1&a|2&b|3&c
|
||||
GVG_SP_FIELD_RATIO: '10%&30%', // 分配给玩家的时候有多少特殊格子 min&max 填最大最小百分比即可
|
||||
GVG_REFRESH_TIME: 5, // 0
|
||||
GVG_ROBOT_NAME: '遗迹守护者', // 0
|
||||
GVG_ROBOT_NAME: '遗迹守护者', // 0,
|
||||
GVG_VESTIGE_PREPARE_COUNTDOWN: 120, //
|
||||
GVG_VESTIGE_BATTLE_COUNTDOWN: 300, //
|
||||
};
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
"value": 100,
|
||||
"reward": "31002&5000",
|
||||
"leagueReward": "12&100",
|
||||
"ripeTime": 43200
|
||||
"ripeTime": 43200,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
@@ -25,7 +27,9 @@
|
||||
"value": 150,
|
||||
"reward": "31002&5001",
|
||||
"leagueReward": "12&150",
|
||||
"ripeTime": 36000
|
||||
"ripeTime": 36000,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
@@ -39,7 +43,9 @@
|
||||
"value": 200,
|
||||
"reward": "31002&5002",
|
||||
"leagueReward": "12&150",
|
||||
"ripeTime": 43200
|
||||
"ripeTime": 43200,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
@@ -53,7 +59,9 @@
|
||||
"value": 15,
|
||||
"reward": "31002&5003",
|
||||
"leagueReward": "12&200",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
@@ -67,7 +75,9 @@
|
||||
"value": 20,
|
||||
"reward": "31002&5004",
|
||||
"leagueReward": "12&300",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
@@ -81,7 +91,9 @@
|
||||
"value": 30,
|
||||
"reward": "31002&5005",
|
||||
"leagueReward": "12&300",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
@@ -95,7 +107,9 @@
|
||||
"value": 25,
|
||||
"reward": "31002&5006",
|
||||
"leagueReward": "12&200",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
@@ -109,7 +123,9 @@
|
||||
"value": 30,
|
||||
"reward": "31002&5007",
|
||||
"leagueReward": "12&300",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
@@ -123,7 +139,9 @@
|
||||
"value": 40,
|
||||
"reward": "31002&5008",
|
||||
"leagueReward": "12&300",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
@@ -137,7 +155,9 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
@@ -151,7 +171,9 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
@@ -165,7 +187,9 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "62&63",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
@@ -179,7 +203,9 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
@@ -193,7 +219,9 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
@@ -207,6 +235,8 @@
|
||||
"value": 0,
|
||||
"reward": "&",
|
||||
"leagueReward": "&",
|
||||
"ripeTime": 0
|
||||
"ripeTime": 0,
|
||||
"getWays": "&",
|
||||
"info_1": "&"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user