import BaseModel from './BaseModel'; import { CeAttr } from './generalField'; import { index, getModelForClass, prop, Ref, mongoose, DocumentType } from '@typegoose/typegoose'; import Equip, { } from './Equip'; import { CounterModel } from './Counter'; import { COUNTER, EQUIP_TYPE } from '../consts'; /** * 英雄表 */ class Connect { @prop({ required: true }) shipId: number; @prop({ required: true }) level: number; } class Skin { @prop({ required: true }) id: number; @prop({ required: true }) enable: boolean; } export class EPlace { @prop({ required: true }) id: number; @prop({ ref: Equip, type: mongoose.Schema.Types.ObjectId }) equip: Ref; @prop({ required: true }) lv: number; @prop({ required: true }) refineLv: number; } // 初始化 function getInitialEplace() { let ePlace = new Array(); for(let i = EQUIP_TYPE.START; i <= EQUIP_TYPE.END; i++) { let p = new EPlace(); p.id = i; p.equip = null; p.lv = 0; p.refineLv = 0; ePlace.push(p); } return ePlace; } interface heroUpdate { exp?: number; lv?: number; ce?: number; star?: number; starStage?: number; colorStar?: number; colorStarStage?: number; quality?: number; job?:number; jobStage?:number; favour?:number; favourLv?:number; skins?: Skin[]; connections?: Connect[]; ePlace?:EPlace[]; _id?:number; scrollActive?: boolean; scrollId?: number; scrollStar?: number; scrollColorStar?: number; scrollQuality?: number; historyCe?: number; } @index({ roleId: 1, hid: 1 }) @index({ roleId: 1, seqId: 1 }) export default class Hero extends BaseModel { @prop({ required: true }) roleId: string; // 角色 id @prop({ required: true }) roleName: string; // 角色名称 @prop({ required: true }) serverId: number; // 区服 id @prop({ required: true }) hid: number; // 武将 id @prop({ required: true }) hName: string; // 武将名 @prop({ required: true }) seqId: number; // 武将表自增 id @prop({ required: true, default: 0 }) exp: number; // 经验值 @prop({ required: true, default: 1 }) lv: number; // 武将等级 @prop({ required: true, default: 0 }) ce: number; // 武将战力 @prop({ required: true, default: 0 }) historyCe: number; // 武将历史最高战力 @prop({required: true, default: new CeAttr(), _id: false }) ceAttr: CeAttr; // 影响战力的属性 @prop({ required: true, default: 1 }) star: number; // 星级 @prop({ required: true, default: 0 }) starStage: number; // 星级六维阶段 @prop({ required: true, default: 0 }) colorStar: number; // 觉醒, 彩星 @prop({ required: true, default: 0 }) colorStarStage: number; // 觉醒六维阶段 @prop({ required: true, default: 0 }) quality: number; // 品质 @prop({ required: true, default: false }) scrollActive: boolean; // 是否在名将谱中激活 @prop({ required: true, default: 0 }) scrollId: number; // 名将谱id @prop({ required: true, default: 0 }) scrollStar: number; // 名将谱中保存的星级 @prop({ required: true, default: 0 }) scrollColorStar: number; // 名将谱中保存的觉醒等级 @prop({ required: true, default: 0 }) scrollQuality: number; // 名将谱中保存的品质 @prop({ required: true, default: 0 }) job: number; // 职业 @prop({ required: true, default: 0 }) jobStage: number; // 职阶 @prop({ required: true, default: 0 }) favour: number; // 好感度 @prop({ required: true, default: 1 }) favourLv: number; // 好感等级 @prop({ required: true, type:Connect, default: [], _id: false }) connections: Connect[]; // 羁绊 @prop({ required: true, type: Skin, default: [], _id: false }) skins: Skin[]; // 皮肤 @prop({ required: true, type: EPlace, default: getInitialEplace(), _id: false }) ePlace: EPlace[]; // 武将装备引用数组 public static async findByRole(roleId: string, sort: { field: string, sortBy: number }[] = []) { let sortParam = {}; for(let {field, sortBy} of sort) { sortParam[field] = sortBy; } const heros: HeroType[] = await HeroModel.find({ roleId }).sort(sortParam).lean(); return heros; } public static async findBySeqIdRange(seqIds: Array, roleId: string, lean = true) { const hero: HeroType[] = await HeroModel.find({ seqId: {$in: seqIds}, roleId }).lean(lean); return hero; } public static async findByHidRange(hids: Array, roleId: string, lean = true) { const hero: HeroType[] = await HeroModel.find({ hid: {$in: hids}, roleId }).lean(lean); return hero; } public static async findBySeqIdAndRole(seqId: number, roleId: string, lean = true) { const hero: HeroType = await HeroModel.findOne({ seqId, roleId }).lean(lean); return hero; } public static async findByHidAndRole(hid: number, roleId: string, select?: string, lean = true) { const hero: HeroType = await HeroModel.findOne({ hid, roleId }).select(select).lean(lean); return hero; } public static async findByHidAndRoleWithEquip(hid: number, roleId: string, lean = true) { const hero: HeroType = await HeroModel.findOne({ hid, roleId }).populate('ePlace.equip').lean(lean); return hero; } public static async addEquip(roleId: string, hid: number, ePlaceId: number, equipId: string, lean = true) { const hero: HeroType = await HeroModel.findOneAndUpdate( { roleId, hid, 'ePlace.id': ePlaceId }, {$set: {'ePlace.$.equip': equipId, 'ePlace.$.hid':hid, 'ePlace.$.ePlaceId':ePlaceId}}, {new: true}).populate('ePlace.equip').lean(lean); if (hero) { await Equip.putOn(hero.hid, equipId); } return hero; } public static async createHero(heroInfo: {roleId: string, serverId: number, roleName: string, hid: number, hName: string, star: number, quality: number, job: number, lv?: number, exp?: number, skins:Skin[]}, lean = true) { const doc = new HeroModel(); const seqId = await CounterModel.getNewCounter(COUNTER.HID)||-1; const update = Object.assign(doc.toJSON(), heroInfo, {seqId}); delete update._id; const hero: HeroType = await HeroModel.findOneAndUpdate({roleId: heroInfo.roleId, hid: heroInfo.hid}, update, {upsert: true, new: true}).lean(lean); return hero; } public static async sumTopHeroCe(roleId: string, num: number) { let ce: Array<{historyCe: number}> = await HeroModel.aggregate([ { $match : { roleId } }, { $sort: {historyCe: -1} }, { $limit: num }, { $group: { _id: null, historyCe: { $sum: '$historyCe' } } } ]); return ce.length > 0?ce[0].historyCe:0; } public static async sumHeroCe(roleId: string) { let ce: Array<{ce: number}> = await HeroModel.aggregate([ { $match : { roleId } }, { $group: { _id: null, ce: { $sum: '$ce' } } } ]); return ce.length > 0?ce[0].ce:0; } public static async getTopHero(roleId: string, num: number, lean = true) { const heroes: HeroType[] = await HeroModel.find({roleId}).limit(num).sort({ce: -1}).lean(lean); return heroes; } public static async updateCe(roleId: string, hid: number, ce: number, oldCe: number, historyCe: number, lean = true) { let distance = ce - oldCe; let historyDistance = ce > historyCe ?ce - historyCe: 0; let result: HeroType = await HeroModel.findOneAndUpdate({roleId, hid}, {$inc:{ce: distance, historyCe: historyDistance}}).lean(lean); return result; } public static async deleteAccount(roleId: string) { let result = await HeroModel.deleteMany({roleId}); return result; } public static async deleteHero(roleId: string, hid: number) { let result = await HeroModel.deleteMany({roleId, hid}); return result; } public static async updateHeroInfo(roleId: string, hid:number, heroUpdate:heroUpdate, select?: string, lean = true) { delete heroUpdate._id; let result: HeroType = await HeroModel.findOneAndUpdate({roleId, hid}, {$set:heroUpdate}, {new: true}).select(select).lean(lean); return result; } public static async unloadHeroAndEquip(roleId: string, hid: number, id: number, lean = true) { const hero: HeroType = await HeroModel.findOneAndUpdate( { roleId, hid, 'ePlace.id': id }, {$set: {'ePlace.$.equip': null}}, {new: true}).lean(lean); return hero; } public static async findByField(field: string, value?: number|string, lean = true) { let searchObj = {}; if(field != 'all') { if(field == 'roleName') { searchObj['roleName'] = { $regex: new RegExp(value.toString(), 'i') } } else { searchObj[field] = value; } } //.select('uid tel username') const user: HeroType[] = await HeroModel.find(searchObj).lean(lean); return user; } } export const HeroModel = getModelForClass(Hero); export interface HeroType extends Pick, keyof Hero>{};