Files
ZYZ/shared/db/Role.ts
2021-02-01 17:34:32 +08:00

463 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { HANG_UP_CONSTS, ROLE_TERAPH, ROLE } from './../consts';
import BaseModel from './BaseModel';
import { CeAttrRole } from './generalField';
import { index, getModelForClass, prop, DocumentType, Ref, mongoose } from '@typegoose/typegoose';
import User from './User';
import { shouldRefresh, reduceCe } from '../pubUtils/util';
import { initRoleAtrr } from '../pubUtils/playerCe';
import Hero,{} from '../db/Hero';
import { nowSeconds } from '../pubUtils/timeUtil';
class TopHero {
@prop({ required: true })
hid: number; // 武将id
@prop({ required: true })
ce: number; // 战力
@prop({ ref: Hero, type: mongoose.Schema.Types.ObjectId })
hero: Ref<Hero>;
}
class DungeonHero {
@prop({ required: true })
battleId: number; // 关卡id
@prop({ required: true, type: Number, default:[] })
heroes: Array<number>; // 武将id
}
class PayRecord {
@prop({ required: true })
id: string; // 购买项 product id
@prop({ required: true })
cnt: number; // 购买次数
}
class WarStar {
@prop({ required: true })
id: number; // 关卡 id
@prop({ required: true })
warType: number; // 关卡类型
@prop({ required: true })
star: number; // 星级
}
class Teraph{
@prop({ required: true, default: 1 })
id: number; // 神像的id
@prop({ required: true, default: 1 })
grade: number; // 等级
@prop({ required: true, default: 0 })
hp: number;
@prop({ required: true, default: 0 })
atk: number;
@prop({ required: true, default: 0 })
def: number;
@prop({ required: true, default: 0 })
mdef: number;
@prop({ required: true, default: 0 })
agi: number;
@prop({ required: true, default: 0 })
luk: number;
}
// 初始化
function getInitialTeraph() {
let teraphs = new Array<Teraph>();
for(let i = ROLE_TERAPH.START; i <= ROLE_TERAPH.END; i++) {
let p = new Teraph();
p.id = i;
p.grade = 1;
p.hp = 0;
p.atk = 0;
p.def = 0;
p.mdef = 0;
p.agi = 0;
p.luk = 0;
teraphs.push(p);
}
return teraphs;
}
/**
* 角色字段接口
*/
@index({ roleId: 1 })
@index({ serverId: 1, roleId: 1})
@index({ towerLv: -1, towerUpTime: 1 })
// @index({ userInfo.uid: 1, serverId: 1 })
export default class Role extends BaseModel {
@prop({ required: true })
userInfo: User;
@prop({ required: true })
seqId: number;
@prop({ required: true })
roleId: string; // 角色 id生成编码
@prop({ required: true })
roleName: string; // 角色名
@prop({ required: true })
serverType: string; // 服务器类型
@prop({ required: true })
serverId: number; // 区服 id
@prop({ required: true, default: false })
blocked: boolean; // 是否屏蔽
@prop({ required: true })
code: string; // 邀请码
@prop({ required: true, default: 19 })
headHid: number; // 头像所用武将 Id默认赵云
@prop({ required: true, default: 19 })
sHid: 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: new CeAttrRole(), _id: false })
globalCeAttr: CeAttrRole; // 总战力
@prop({ required: true, default: 0 })
topFiveCe: number; // 最强5人战力
@prop({ required: true, type: TopHero, default: [], _id: false })
topFive: Array<TopHero>; // 总战力
@prop({ required: true, default: 100 })
tili: number; // 体力值
@prop({ required: true, default: 0 })
vLv: number; // VIP 等级
@prop({ required: true, default: 100 })
gold: number; // 总金币
@prop({ required: true, default: 0 })
paidGold: number; // 支付所得金币
@prop({ required: true, default: 100 })
giftGold: number; // 赠送所得金币
@prop({ required: true, default: 0 })
totalPay: number; // 总支付金额
@prop({ required: true, default: 0 })
totalBuy: number; // 总金币购买
@prop({ required: true, default: 0 })
totalCost: number; // 金币总花费
@prop({ required: true, default: [] })
payRecord: PayRecord[]; // 支付记录
@prop({ required: true, default: 0 })
coin: number; // 总铜钱
@prop({ required: true, default: 0 })
frdCnt: number; // 情谊点
@prop({ required: true, type: WarStar, default: [], _id: false })
warStar: WarStar[]; // 关卡星级
@prop({ required: true, default: 1 })
loginCnt: number; // 登录次数
@prop({ required: true, default: nowSeconds() })
createTime: number; // 创建时间
@prop({ required: true, default: nowSeconds() })
loginTime: number; // 更新 / 登录时间
@prop({ required: true, default: 0 })
quitTime: number; // 更新 / 登录时间
@prop({ required: true, type: Number, default: [], _id: false })
funcs: Array<number>; // 开启了的功能
// 天梯相关
@prop({ required: true, default: 1 })
towerLv: number; // 天梯当前层数
@prop({ required: true, default: new Date() })
towerUpTime: Date; // 天梯爬到这一层的时间
@prop({ required: true, default: HANG_UP_CONSTS.MAX_SPD_UP_CNT})
hangUpSpdUpCnt: number; // 挂机加速次数
@prop({ required: true, default: new Date()})
lastSpdUpTime: Date; // 最后一次挂机加速时间
@prop({ required: true, default: 0})
towerTaskCnt: number; // 刷新派遣任务的次数向上累加每天8个
@prop({ required: false})
towerTaskRefTime: Date; // 刷新派遣任务的时间
@prop({ required: true, default: 0})
towerTaskReCnt: number; // 刷新派遣任务刷新次数
// 奇遇事件相关
@prop({ required: true, default: 0 })
eventStatus: number; // 奇遇开启状态, 0-未开启 1-开启了第一场事件 2-完全开启
// 远征相关
@prop({ required: true, default: 0 })
expeditionPoint: number; // 远征点数
@prop({ required: true, default: 0 })
expeditionResetCnt: number; // 远征重置次数
@prop({ required: true, default: new Date() })
expeditionResetRefTime: Date; // 远征重置次数刷新时间
// 秘境相关
@prop({ required: true, default: 0 })
dungeonCnt: number; // 秘境挑战次数
@prop({ required: true, default: 0 })
dungeonBuyCnt: number; // 秘境购买次数
@prop({ required: true, default: new Date() })
dungeonRefTime: Date; // 秘境刷新时间
@prop({ required: true, type: DungeonHero, default: [], _id: false })
dungeonHeroes: Array<DungeonHero>; // 秘境首通使用的武将
// 全局养成
@prop({ required: true, default: 1 })
title: number; //爵位
//神像
@prop({ required: true, type: Teraph, default: getInitialTeraph(), _id: false })
teraphs:Array<Teraph>;
// 公会
@prop({ required: true, default: false })
hasGuild: boolean; // 是否加入过公会
@prop({ required: true, default: 0 })
quitGuildTime: number; // 上次退出公会的时间
public static async findAllByUid(uid: number, lean = true) {
const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId').lean(lean);
return role;
}
public static async findByUid(uid: number, serverId: number, lean = true) {
const role: RoleType = await RoleModel.findOneAndUpdate({ 'userInfo.uid': uid, serverId }, { loginTime: nowSeconds() }, { new: true }).lean(lean);
return role;
}
/**
* 根据roleId获取一条数据
* @param roleId 玩家id
* @param select 选取字段,来自 selectConst/ROLE
* @param getters 是否使用get方法如ce使用了自动缩小1w倍
*/
public static async findByRoleId(roleId: string, select?: string, getters = false) {
const role: RoleType = await RoleModel.findOne({ roleId }).select(select).lean({getters});
return role;
}
public static async createRole(uid: number, serverId: number, roleInfo: {roleId: string; roleName: string; seqId: number; code: string, lv?:number, exp?: number}, lean = true) {
const user = await User.findUserByUid(uid);
if (!user) return null;
const doc = new RoleModel();
const update = Object.assign(doc.toJSON(), roleInfo, { userInfo: user, serverType: user.serverType, serverId });
initRoleAtrr(update);
const role: RoleType = await RoleModel.findOneAndUpdate({ 'userInfo.uid': uid, serverId }, update, { upsert: true, new: true }).lean(lean);
return role;
}
public static async findRoleByField(field: string, value?: Array<number|string>, lean = true) {
let searchObj = {};
if(field != 'all') {
searchObj[field] = {
$in: value
};
}
//.select('uid tel username')
const user: RoleType[] = await RoleModel.find(searchObj).lean(lean);
return user;
}
public static async setEventStatus(roleId: string, eventStatus: number, lean = true) {
let role: RoleType = await RoleModel.findOneAndUpdate({ roleId }, { eventStatus }, {new: true}).lean(lean);
return role;
}
public static async towerLvUp(roleId: string, lean = true) {
let role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$inc: {towerLv: 1}, towerUpTime: new Date()}, {new: true}).lean(lean);
return role;
}
public static async hangUpSpdUp(roleId: string, cnt: number, curTime: Date, lean = true) {
if (cnt < 0) return null;
const result = await RoleModel.findOne({roleId}).lean(lean);
const lastSpdUpTime = result?.lastSpdUpTime;
let role: RoleType;
if (!lastSpdUpTime || (shouldRefresh(lastSpdUpTime, curTime, HANG_UP_CONSTS.REFRESH_TIME, 1) && cnt <= HANG_UP_CONSTS.MAX_SPD_UP_CNT)) {
role = await RoleModel.findOneAndUpdate({roleId}, {hangUpSpdUpCnt: HANG_UP_CONSTS.MAX_SPD_UP_CNT - cnt, lastSpdUpTime: curTime}, {new: true}).lean(lean);
} else {
role = await RoleModel.findOneAndUpdate({roleId, hangUpSpdUpCnt: {$gte: cnt}}, {$inc: {hangUpSpdUpCnt: -cnt}, lastSpdUpTime: curTime}, {new: true}).lean(lean);
}
return role;
}
public static async increaseExpeditionPoint(roleId: string, point: number, lean = true) {
let role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$inc: { expeditionPoint: point }}, {new: true}).lean(lean);
return role;
}
public static async levelup(roleId: string, lv: number, exp: number, lean = true) {
let role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$set: { exp, lv }}, {new: true}).lean(lean);
return role;
}
public static async deleteAccount(roleId: string) {
let result = await RoleModel.deleteMany({roleId});
return result;
}
public static async addCoin(roleId: string, cnt: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, { $inc: {coin: cnt} }, { "new": true, "upsert": true}).lean(lean);
return result;
}
public static async addGoldFree(roleId: string, cnt: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, { $inc: { gold: cnt, giftGold: cnt } }, { "new": true, "upsert": true}).lean(lean);
return result;
}
public static async costCoin(roleId: string, cnt: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate({roleId, coin: {$gte: cnt}}, { $inc: { coin: -cnt } }, { "new": true}).lean(lean);
return result;
}
public static async costGold(roleId: string, cnt: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate({roleId, gold: {$gte: cnt}}, { $inc: { gold: -cnt, totalCost: cnt } }, { "new": true}).lean(lean);
return result;
}
public static async pushWarStar(roleId: string, battleId: number, warType: number, star: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, { $addToSet: { warStar: {id: battleId, warType, star }} }, { "new": true, "upsert": true}).lean(lean);
return result;
}
public static async updateWarStar(roleId: string, battleId: number, star: number, lean = true) {
let result: RoleType = await RoleModel.findOneAndUpdate(
{roleId, 'warStar.id': battleId},
{ $set: { 'warStar.$.star': star } },
{ "new": true, "upsert": true}
).lean(lean);
return result;
}
// 重置派遣次数
public static async resetTowerCnt(roleId: string, curTime: Date, lean = true) {
const role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {towerTaskCnt: 0, towerTaskRefTime: curTime, towerTaskReCnt: 0}, {new: true}).lean(lean);
return role;
}
// 刷新派遣任务次数增长
public static async increaseTowerCnt(roleId: string, num: number, lean = true) {
const role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$inc: {towerTaskCnt: num}}, {new: true}).lean(lean);
return role;
}
// 派遣任务增加刷新次数
public static async increaseTowerRefCnt(roleId: string, num: number, lean = true) {
const role: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$inc: {towerTaskReCnt: num}}, {new: true}).lean(lean);
return role;
}
// 刷新远征重置次数
public static async increaseExpeditionResetCnt(roleId: string, needRefresh: boolean, curTime: Date, lean = true) {
let role: RoleType;
if (needRefresh) {
role = await RoleModel.findOneAndUpdate({roleId}, {expeditionResetCnt: 1, expeditionResetRefTime: curTime}, {new: true}).lean(lean);
} else {
role = await RoleModel.findOneAndUpdate({roleId}, {$inc: {expeditionResetCnt: 1}}, {new: true}).lean(lean);
}
return role;
}
// 购买次数
public static async buyCnt(roleId: string, needRefresh: boolean, inc: number, curTime: Date, lean = true) {
let role: RoleType;
if (needRefresh) {
role = await RoleModel.findOneAndUpdate({roleId}, {dungeonCnt: 0, dungeonRefTime: curTime, dungeonBuyCnt: inc}, {new: true}).lean(lean);
} else {
role = await RoleModel.findOneAndUpdate({roleId}, {$inc: {dungeonBuyCnt: inc}}, {new: true}).lean(lean);
}
return role;
}
// 增加次数
public static async increaseDungeonCnt(roleId: string, needRefresh: boolean, inc: number, curTime: Date, lean = true) {
let role: RoleType;
if (needRefresh) {
role = await RoleModel.findOneAndUpdate({roleId}, {dungeonCnt: inc, dungeonRefTime: curTime, dungeonBuyCnt: 0}, {new: true}).lean(lean);
} else {
role = await RoleModel.findOneAndUpdate({roleId}, {$inc: {dungeonCnt: inc}}, {new: true}).lean(lean);
}
return role;
}
// 获取排行榜
public static async getRank(type: string, serverId: number, fields: Array<string>, page = 1, limit = 100, lean = true) {
let sortBy = {};
if(type == 'tower') {
sortBy['towerLv'] = -1;
sortBy['towerUpTime'] = 1;
}
const ranks: RoleType[] = await RoleModel.find({serverId}).select(fields.join(' ')).sort(sortBy).limit(limit).skip((page - 1) * limit).lean(lean);
return ranks;
}
// 保存秘境首通队伍
public static async saveDungeonHero(roleId: string, battleId: number, heroes: Array<number>, isSuccess: boolean) {
if(isSuccess) {
let role = await Role.findByRoleId(roleId);
let dungeonHeroes = role && role.dungeonHeroes;
let hasHero = dungeonHeroes&&dungeonHeroes.find(cur => cur.battleId == battleId);
if(!dungeonHeroes || !hasHero) {
role = await RoleModel.findOneAndUpdate({roleId}, {$push:{dungeonHeroes: {battleId, heroes}}})
}
return role;
}
}
// 保存开启功能
public static async pushFuncs(roleId: string, funcs: Array<number>, lean = true) {
const recs: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$push: {funcs: {$each: funcs}}}, {new: true}).lean(lean);
return recs
}
public static async updateRoleInfo(roleId: string, roleUpdate:roleUpdate, lean = true) {
delete roleUpdate._id;
let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$set:roleUpdate}, {new: true}).lean(lean);
return result;
}
// 记录加入公会
public static async joinGuild(roleId: string) {
const result = await RoleModel.findOneAndUpdate({ roleId, hasGuild: false }, { hasGuild: true }, { new: true }).lean();
return result;
}
// 获取未加入公会且登录时间在三天内的人
public static async getInviteList(time: number, serverId: number) {
const result = await RoleModel.find({ quitTime: { $gt: time }, hasGuild: false, serverId })
.select('roleId roleName ce headHid sHid lv title job quitTime')
.sort({quitTime: -1, lv: -1, ce: -1})
.limit(100).lean();
return result;
}
// 获取好友推荐列表
public static async getRecommedList(minLv: number, maxLv: number, time: number) {
const result = await RoleModel.find({ quitTime: { $gt: time }, lv: { $gte: minLv, $lte: maxLv } }, { _id: 0 })
.select(ROLE.SHOW_SIMPLE)
.sort({quitTime: -1, lv: -1, ce: -1})
.limit(100).lean({ getters: true });
return result;
}
// 公会解散
public static async dissmissGuild(members: string[]) {
const result = await RoleModel.updateMany({ roleId: { $in: members } }, { hasGuild: false }).lean();
return result;
}
// 退出公会
public static async quitGuild(roleId: string, now: number) {
const result = await RoleModel.findOneAndUpdate({ roleId, hasGuild: true }, { hasGuild: false, quitGuildTime: now }, { new: true }).lean();
return result;
}
}
export const RoleModel = getModelForClass(Role);
export interface RoleType extends Pick<DocumentType<Role>, keyof Role>{};
type roleUpdate = Partial<RoleType>; // 将所有字段变成可选项