273 lines
9.7 KiB
TypeScript
273 lines
9.7 KiB
TypeScript
import BaseModel from './BaseModel';
|
|
import { CeAttr } from '../domain/roleField/attribute';
|
|
import { index, getModelForClass, prop, Ref, mongoose, DocumentType } from '@typegoose/typegoose';
|
|
import Equip, { } from './Equip';
|
|
import { CounterModel } from './Counter';
|
|
import { COUNTER, EQUIP_TYPE } from '../consts';
|
|
import { reduceCe } from '../pubUtils/util';
|
|
|
|
|
|
/**
|
|
* 英雄表
|
|
*/
|
|
|
|
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<Equip>;
|
|
@prop({ required: true })
|
|
lv: number;
|
|
@prop({ required: true })
|
|
refineLv: number;
|
|
}
|
|
|
|
// 初始化
|
|
function getInitialEplace() {
|
|
let ePlace = new Array<EPlace>();
|
|
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, set: (val: number) => val, get: (val: number) => reduceCe(val) })
|
|
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 }[] = [], select?: string, getters = false) {
|
|
let sortParam = {};
|
|
for(let {field, sortBy} of sort) {
|
|
sortParam[field] = sortBy;
|
|
}
|
|
const heros: HeroType[] = await HeroModel.find({ roleId }).sort(sortParam).select(select).lean({ getters });
|
|
return heros;
|
|
}
|
|
|
|
public static async findBySeqIdRange(seqIds: Array<number>, roleId: string, lean = true) {
|
|
const hero: HeroType[] = await HeroModel.find({ seqId: {$in: seqIds}, roleId }).lean(lean);
|
|
return hero;
|
|
}
|
|
|
|
public static async findByHidRange(hids: Array<number>, 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, getters = false) {
|
|
const hero: HeroType = await HeroModel.findOne({ hid, roleId }).select(select).lean({ getters });
|
|
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<DocumentType<Hero>, keyof Hero>{};
|