import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, Ref, mongoose } from '@typegoose/typegoose'; import Hero, { } from './Hero'; import Role, { } from './Role'; import { PVP_PLAYER_POS, PVP_HERO_POS } from '../consts'; import PvpHistoryOpp from './PvpHistoryOpp'; import { reduceCe } from '../pubUtils/util'; export class Heroes { @prop({ required: true }) actorId: number; // 武将id @prop({ ref: 'Hero', type: mongoose.Schema.Types.ObjectId }) hero: Ref; @prop({ required: true }) ce: number; // 战斗力 @prop({ required: true }) dataId: number; @prop({ required: true }) order: number; } // 初始化 function getInitialOppPlayers() { let players = new Array(); for(let i = PVP_PLAYER_POS.START; i <= PVP_PLAYER_POS.END; i++) { let p = new OppPlayers(); p.pos = i; players.push(p); } return players; } // 初始化 function getInitialOppHeros() { let heros = new Array(); for(let i = PVP_HERO_POS.START; i <= PVP_HERO_POS.END; i++) { let p = new Heroes(); p.dataId = i; p.order = i; heros.push(p); } return heros; } export class OppPlayers { @prop({ required: true }) roleId: string; @prop({ ref: 'PvpHistoryOpp', type: mongoose.Schema.Types.ObjectId }) oppDef: Ref; @prop({ required: true }) pos: number; @prop({ required: true }) isRobot: boolean; } export class HeroScores { @prop({ required: true }) hid: number; @prop({ required: true }) score: number; } @index({ roleId: 1 }) export default class PvpDefense extends BaseModel { @prop({ required: true }) roleId: string; // 角色 id @prop({ required: true }) roleName: string; // 角色名称 @prop({ ref: 'Role', type: mongoose.Schema.Types.ObjectId }) role: Ref; @prop({ required: true, type: Heroes, default: getInitialOppHeros(), _id: false }) heroes: Array; @prop({ required: true, default: 0 }) score: number; @prop({ required: true, default: 1 }) pLv: number; @prop({ required: true, default: 0 }) hisScore: number; //历史最高积分 @prop({ required: true, default: 0 }) winStreakNum: number; //连胜次数 @prop({ required: true, default: 0, get: (val: number) => reduceCe(val), set: (val: number) => val }) defCe: number; //防守ce @prop({ required: true, type: OppPlayers, default: getInitialOppPlayers(), _id: false }) oppPlayers: Array; @prop({ required: true, type: HeroScores, default: [], _id: false }) heroScores: Array; @prop({ required: true, default: true }) isDefaultHero: boolean; @prop({ required: true, default: 0 }) refOppCnt: number; // 刷新对手总次数,消耗可根据消耗表算出 @prop({ required: true, default: new Date() }) refOppTime: Date; // 刷新对手时间 @prop({ required: true, default: 0 }) challengeCnt: number; // 可挑战次数 @prop({ required: true, default: 0 }) challengeRefTime: number; // 上一次刷新的时间 @prop({ required: true, type: Number, default: [] }) receivedBox: Array; @prop({ required: true, default: 0 }) seasonNum: number; @prop({ required: true, default: true }) isFirstEntry: boolean; public static async findByRoleId(roleId: string, getters = false) { const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId }).lean({ getters}); return result; } public static async findByScale(roleId: string, min: number, max: number) { const result: PvpDefenseType[] = await PvpDefenseModel.find({ roleId: { $ne: roleId }, defCe: { $lte: max, $gte: min } }) .populate('role', 'head frame spine topLineupCe roleId roleName lv globalCeAttr') .populate('heroes.hero') .sort({ updatedAt: -1 }).limit(100).lean({ getters: true, virtuals: true }); return result; } public static async createPvpDefense(params: { roleId: string, roleName: string, role: string, heroes: Array, oppPlayers: Array, defCe: number, seasonNum: number,challengeCnt: number }, lean = true) { const doc = new PvpDefenseModel(); const update = Object.assign(doc.toJSON(), params); const defense: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId: params.roleId }, update, { upsert: true, new: true }).lean(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, defCe: number, lean = true) { const rec: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({ roleId, 'heroes.actorId': hid }, { $inc: { defCe } }).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', 'head frame spine topLineupCe roleId roleName lv globalCeAttr') .populate('heroes.hero') .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine rankLv title lv pLv defCe heroes').lean({ getters: true, virtuals: true }); return result; } public static async findByTeamLv(seasonNum: number, min: number, max: number) { const result: PvpDefenseType[] = await PvpDefenseModel.find({ seasonNum, pLv: { $gte: min, $lte: max } }) .populate('role', 'head frame spine topLineupCe roleId roleName lv globalCeAttr') .populate('heroes.hero') .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine rankLv pLv title lv defCe heroes') .lean({ getters: true, virtuals: true }); return result; } public static async updateInfoAndInclude(roleId: string, update: pvpUpdateInter) { delete update._id; let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true}) .populate('role', 'head frame spine topLineupCe roleId roleName lv') .populate('oppPlayers.oppDef', 'oppRoleId pos roleName head frame spine rankLv pLv title lv defCe heroes').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 = await PvpDefenseModel.find().sort({ score: -1 }).limit(limit).skip((page) * limit).lean(lean); return result; } public static async getRank(seasonNum: number, page = 1, limit = 1000) { let sortBy = { score: -1, updatedAt: 1 }; const ranks: PvpDefenseType[] = await PvpDefenseModel.find({seasonNum}).select('roleId role score updatedAt') .populate('role', 'roleId roleName head frame spine title lv vLv') .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:{heroes: {actorId:hid}}}, {new: true}).lean(); return result; } } export const PvpDefenseModel = getModelForClass(PvpDefense); export interface PvpDefenseType extends Pick, keyof PvpDefense> { }; export type pvpUpdateInter = Partial;