200 lines
9.9 KiB
TypeScript
200 lines
9.9 KiB
TypeScript
import BaseModel from './BaseModel';
|
||
import { index, getModelForClass, prop, DocumentType, Ref, mongoose } from '@typegoose/typegoose';
|
||
import Role, { } from './Role';
|
||
import { Defense, Attack, LineupCe, OppPlayer, HeroScore, } from '../domain/battleField/pvp';
|
||
import { PVP } from '../pubUtils/dicParam';
|
||
|
||
@index({ roleId: 1 })
|
||
@index({ serverId: 1, score: 1 })
|
||
@index({ serverId: 1, seasonNum: 1 })
|
||
export default class PvpDefense extends BaseModel {
|
||
@prop({ required: true })
|
||
serverId: number; // 区 id
|
||
@prop({ required: true })
|
||
roleId: string; // 角色 id
|
||
@prop({ required: true })
|
||
roleName: string; // 角色名称
|
||
@prop({ ref: 'Role', type: mongoose.Schema.Types.ObjectId })
|
||
role: Ref<Role>;
|
||
@prop({ required: true, default: null, _id: false })
|
||
hasDefense: boolean;
|
||
@prop({ required: true, default: null, _id: false })
|
||
defense: Defense;
|
||
@prop({ required: true, default: null, _id: false })
|
||
attack: Attack;
|
||
@prop({ required: true, type: () => LineupCe, default: [], _id: false })
|
||
lineupCe: LineupCe[];
|
||
@prop({ required: true, type: () => OppPlayer, default: [], _id: false })
|
||
oppPlayers: OppPlayer[];
|
||
@prop({ required: true, type: () => OppPlayer, default: [], _id: false })
|
||
oppBeforePlayers: OppPlayer[];
|
||
@prop({ required: true, type: () => HeroScore, default: [], _id: false })
|
||
heroScores: HeroScore[];
|
||
|
||
@prop({ required: true, default: 0 })
|
||
score: number;
|
||
@prop({ required: true, default: 0 })
|
||
hisScore: number; //历史最高积分
|
||
@prop({ required: true, default: 0 })
|
||
winStreakNum: number; //连胜次数
|
||
@prop({ required: true, default: 0 })
|
||
hisWinStreakNum: number; //历史最高连胜次数
|
||
|
||
@prop({ required: true, default: () => { return new Date() } })
|
||
refDaily: Date; // 每日刷新,控制refOppCnt和setAttackCnt
|
||
@prop({ required: true, default: 0 })
|
||
refOppCnt: number; // 刷新对手总次数,消耗可根据消耗表算出
|
||
@prop({ required: true, default: 0 })
|
||
setAttackCnt: number; // 设置挑战阵容次数
|
||
@prop({ required: true, default: 0 })
|
||
buyAttackCnt: number; // 购买挑战阵容次数
|
||
|
||
@prop({ required: true, default: 0 })
|
||
challengeCnt: number; // 可挑战次数,每2小时回复一次
|
||
@prop({ required: true, default: 0 })
|
||
challengeRefTime: number; // 上一次刷新的时间
|
||
|
||
@prop({ required: true, type: Number, default: [] })
|
||
receivedBox: Array<number>;
|
||
@prop({ required: true, default: 0 })
|
||
seasonNum: number;
|
||
@prop({ required: true, default: 0 })
|
||
seasonWinNum: number; // 本赛季胜利次数
|
||
@prop({ required: true, default: 1 })
|
||
rankSeasonNum: number;
|
||
|
||
@prop({ required: true, default: 0 })
|
||
defenseScoreCnt: number;
|
||
@prop({ required: true })
|
||
refDefenseScore: Date;
|
||
|
||
@prop({required: true, default : 0})
|
||
buyChallengeCnt:number; // 每日已购买次数
|
||
@prop({ required: true, default: 0 })
|
||
buyChallengeTime: number; // 上一次购买时间
|
||
|
||
public static async findByRoleId(roleId: string, getters = false) {
|
||
const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId }).lean({ getters});
|
||
return result;
|
||
}
|
||
|
||
public static async createPvpDefense(seasonNum: number, params: pvpUpdateInter) {
|
||
const doc = new PvpDefenseModel();
|
||
|
||
const update = Object.assign(doc.toJSON(), params, { rankSeasonNum: seasonNum, challengeCnt: PVP.PVP_CHALLENGE_COUNTS });
|
||
const defense: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId: params.roleId }, update, { upsert: true, new: true })
|
||
.populate('role')
|
||
.lean();
|
||
return defense;
|
||
|
||
}
|
||
|
||
public static async addHeroToDefense(roleId: string, heroInfo: any, defCe: number, lean = true) {
|
||
const defense: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId: roleId }, {
|
||
$inc: { defCe },
|
||
$push: { heroes: heroInfo }
|
||
}, { upsert: true, new: true }).lean(lean);
|
||
return defense;
|
||
|
||
}
|
||
|
||
public static async removeHeroFromDefense(roleId: string, hid: number, defCe: number, lean = true) {
|
||
const defense: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId: roleId }, {
|
||
$inc: { defCe: -1 * defCe },
|
||
$pull: { heroes: { actorId: hid } }
|
||
}, { upsert: true, new: true }).lean(lean);
|
||
return defense;
|
||
|
||
}
|
||
|
||
public static async updateCe(roleId: string, hid: number, ce: number, lean = true) {
|
||
const rec: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId, 'lineupCe.hid': hid }, { $set: { 'lineupCe.$.ce': ce } }).lean(lean);
|
||
return rec
|
||
}
|
||
|
||
public static async deleteAccount(roleId: string) {
|
||
let result = await PvpDefenseModel.deleteMany({ roleId });
|
||
return result;
|
||
}
|
||
|
||
public static async findByRoleIdIncludeAll(roleId: string) {
|
||
const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId })
|
||
.populate('role', 'serverId head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title')
|
||
.populate('heroes.hero')
|
||
.populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv title lv pLv defCe heroes warId buff combo')
|
||
.populate('oppBeforePlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv title lv pLv defCe heroes warId buff combo').lean({ getters: true, virtuals: true });
|
||
return result;
|
||
}
|
||
|
||
public static async findByTeamLv(serverIds: number[], seasonNum: number, min: number, max: number) {
|
||
const result: PvpDefenseType[] = await PvpDefenseModel.find({ serverId: {$in: serverIds}, seasonNum, hasDefense: true, 'defense.pLv': { $gte: min, $lte: max } })
|
||
.populate('role', '_id serverId head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title')
|
||
.populate('heroes.hero')
|
||
.populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff')
|
||
.lean({ getters: true, virtuals: true });
|
||
return result;
|
||
}
|
||
|
||
public static async findNeighborByScore(seasonNum: number, score: number) {
|
||
const beforeData: PvpDefenseType[] = await PvpDefenseModel.find({
|
||
seasonNum, hasDefense: true, score: { $lt: score }
|
||
}).sort({ score: -1 }).limit(10)
|
||
.populate('role', '_id serverId head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title')
|
||
.populate('heroes.hero')
|
||
.populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff')
|
||
.lean({ getters: true, virtuals: true });
|
||
const afterData: PvpDefenseType[] = await PvpDefenseModel.find({
|
||
seasonNum, hasDefense: true, score: { $gt: score }
|
||
}).sort({ score: 1 }).limit(10)
|
||
.populate('role', '_id serverId head frame spine heads frames spines topLineupCe roleId roleName lv globalCeAttr title')
|
||
.populate('heroes.hero')
|
||
.populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff')
|
||
.lean({ getters: true, virtuals: true });
|
||
|
||
return [...beforeData, ...afterData];
|
||
}
|
||
|
||
public static async updateInfoAndInclude(roleId: string, update: pvpUpdateInter) {
|
||
delete update._id;
|
||
let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true})
|
||
.populate('role', 'serverId head frame spine heads frames spines topLineupCe roleId roleName lv title')
|
||
.populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine heads frames spines rankLv pLv title lv defCe heroes warId buff').lean({ getters: true, virtuals: true });
|
||
return result;
|
||
}
|
||
public static async updateInfo(roleId: string, update: pvpUpdateInter, lean = true) {
|
||
let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true}).lean(lean);
|
||
return result;
|
||
}
|
||
|
||
public static async getPvpDef(limit: number, page: number, lean = true) {
|
||
let result: Array<PvpDefenseType> = await PvpDefenseModel.find().sort({ score: -1 }).limit(limit).skip((page) * limit).lean(lean);
|
||
return result;
|
||
}
|
||
|
||
public static async getRank(serverIds: number[], seasonNum: number, page = 1, limit = 1000) {
|
||
let sortBy = { score: -1, updatedAt: 1 };
|
||
const ranks: PvpDefenseType[] = await PvpDefenseModel.find({ serverId: {$in: serverIds}, rankSeasonNum: seasonNum, score: { $gt: 0 }}).select('serverId roleId role score updatedAt')
|
||
.populate('role', 'serverId roleId roleName head frame spine heads frames spines title lv vLv updatedAt')
|
||
.sort(sortBy).limit(limit).skip((page - 1) * limit).lean({ getters: true, virtuals: true });
|
||
return ranks;
|
||
}
|
||
|
||
public static async deleteHero(roleId: string, hid: number) {
|
||
let result:PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$pull:{lineupCe: {hid}, heroScores: {hid}}, $set: {defense: null, attack: null}}, {new: true}).lean();
|
||
return result;
|
||
}
|
||
|
||
public static async resetDefense() {
|
||
await PvpDefenseModel.updateMany({}, { $set: { hasDefense: false, defense: null } });
|
||
}
|
||
|
||
public static async removeBySub(roleId: string, subHid: number) {
|
||
await PvpDefenseModel.updateMany({ roleId, hasDefense: true }, { $pull: { 'defense.heroes': { actorId: subHid } } });
|
||
await PvpDefenseModel.updateMany({ roleId, 'attack.heroes': { $exists: true } }, { $pull: { 'attack.heroes': { actorId: subHid } } });
|
||
}
|
||
}
|
||
|
||
export const PvpDefenseModel = getModelForClass(PvpDefense);
|
||
|
||
export interface PvpDefenseType extends Pick<DocumentType<PvpDefense>, keyof PvpDefense> { };
|
||
export type pvpUpdateInter = Partial<PvpDefenseType>; |