import { FIGURE_UNLOCK_CONDITION, ITEM_CHANGE_REASON, REDIS_KEY, STATUS, TASK_TYPE, HERO_SYSTEM_TYPE } from "../../consts"; import { SkinModel } from "../../db/Skin"; import { HeroModel, HeroSkin, HeroType, HeroUpdate } from "../../db/Hero"; import { RoleModel, RoleType, RoleUpdate } from "../../db/Role"; import { SkinUpdate } from "../../db/Skin"; import { Figure, TopHero } from "../../domain/dbGeneral"; import { TaskListReturn } from "../../domain/roleField/task"; import { GuildModel, GuildType } from "../../db/Guild"; import { PvpDefenseModel } from "../../db/PvpDefense"; import { pick } from "underscore"; import { calculatetopLineup } from "../../pubUtils/playerCe"; import { nowSeconds } from "../../pubUtils/timeUtil"; import { saveCeChangeLog } from "../../pubUtils/logUtil"; import { getRandSingleEelm, reduceCe, resResult } from "../../pubUtils/util"; import { AttributeCal } from "../../domain/roleField/attribute"; import { CreateHeroParam, HeroParam, HeroShowParam } from "../../domain/roleField/hero"; import { pinus } from "pinus"; import { Rank } from "../rankService"; import { checkTaskInCreateHero } from "../task/taskService"; import { ItemInter, RewardInter } from "../../pubUtils/interface"; import { transPiece } from "./util"; import { getInitHeroById } from "../roleService"; import { addItems, combineFigureInfo, unlockFigureWithoutSave } from "./rewardService"; export class UpdateHeroes { roleId: string; roleName: string; serverId: number; incHeroNum: number = 0; incRoleCe: number = 0; pushHeroes: {hid: number, incHeroCe: number, ce: number, hero: HeroUpdate}[] = []; roleUpdate: RoleUpdate; role: RoleType; guild: GuildType; constructor(roleId: string, roleName: string, serverId: number) { this.roleId = roleId; this.roleName = roleName; this.serverId = serverId; } public setRole(role: RoleType) { this.role = role; } public async getRole() { if(!this.role) { this.role = await RoleModel.findByRoleId(this.roleId); } return this.role; } public addRoleUpdateParam(param: RoleUpdate) { this.roleUpdate = {...this.roleUpdate, ...param}; } public async updateDbCe(isCreate: boolean, heroInfo: HeroUpdate, originCe = 0) { let role = await this.getRole(); if(isCreate) this.incHeroNum ++; if(heroInfo != originCe) this.incRoleCe += heroInfo.ce - originCe; this.addRoleUpdateParam(await calculatetopLineup(role, heroInfo.hid, heroInfo.ce, heroInfo._id )); this.pushHeroes.push({ hid: heroInfo.hid, incHeroCe: heroInfo.ce - originCe, ce: heroInfo.ce, hero: heroInfo }); } // 更新战力相关的各个表 public async saveCeToDb() { let role = await this.getRole(); // 更新role表 this.role = await RoleModel.updateRoleInfo(this.roleId, { heroNum: this.incHeroNum + role.heroNum, ce: this.incRoleCe + role.ce, heroNumUpdatedAt: nowSeconds(), ...this.roleUpdate }); // 更新guild表 if(role.hasGuild) { this.guild = await GuildModel.updateCe(this.roleId, this.incRoleCe, true); // 公会更新战力 } for(let { hid, incHeroCe } of this.pushHeroes) { await PvpDefenseModel.updateCe(this.roleId, hid, incHeroCe); // 更新pvp防守阵战力 } saveCeChangeLog(this.role, this.incRoleCe, this.role.ce, HERO_SYSTEM_TYPE.INIT, this.pushHeroes.map(cur => cur.hid)); } public async updateRedisRank() { let role = await this.getRole(); let { serverId, roleId, pushHeroes } = this; // 更新军团信息 if(this.guild) { let r = new Rank(REDIS_KEY.GUILD_INFO, { guildCode: this.guild.code }); await r.generParamAndSet(REDIS_KEY.GUILD_INFO, { guildCode: this.guild.code }, { guild: this.guild }); } // 武将数量 if(this.incHeroNum > 0) { let r = new Rank(REDIS_KEY.HERO_NUM_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, role.heroNum, role.heroNumUpdatedAt, role); } // 最强阵容 let r = new Rank(REDIS_KEY.TOP_LINEUP_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, reduceCe(role.topLineupCe), 0, role); // 最强武将 for(let { hid, ce, hero } of pushHeroes) { let r2 = new Rank(REDIS_KEY.TOP_HERO_RANK, { serverId }); await r2.setRankWithHeroInfo(roleId, hid, reduceCe(ce), 0, hero); let r4 = new Rank(REDIS_KEY.HERO_RANK, { serverId, hid }); await r4.setRankWithHeroInfo(roleId, hid, reduceCe(ce), 0, hero); } // 总战力 let r3 = new Rank(REDIS_KEY.SUM_CE_RANK, { serverId }); await r3.setRankWithRoleInfo(roleId, reduceCe(role.ce), 0, role); // 更新最强五人阵容信息 let r5 = new Rank(REDIS_KEY.TOP_LINEUP_INFO, { serverId }); await r5.generParamAndSet(REDIS_KEY.TOP_LINEUP_INFO, { roleId }, { role }); } public async pushMessage(pinus: any, sid: string) { let role = await this.getRole(); let uids = [{ uid: this.roleId, sid }]; pinus.app.get('channelService').pushMessageByUids('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: reduceCe(role.ce) , heros: this.pushHeroes.map(cur => { return {...cur, ce: reduceCe(cur.ce), incHeroCe: reduceCe(cur.incHeroCe) }}), topLineupCe: reduceCe(role.topLineupCe) }), uids); } } export class CreateHeroes extends UpdateHeroes { private resultHeroes: HeroType[] = []; private heroNum = 0; // 推送信息 private figureInfos: { heads: Figure[], frames: Figure[], spines: Figure[] }[] = []; private skinPushMessages: { heros: {skins: HeroSkin[], hid: number}[], skins: {id: number, hid: number, inc: number, reason: number }[]} = { heros: [], skins: [] }; private async getSkinsOfThisHero(hid: number, initSkinInfo: SkinUpdate, isInit: boolean) { let allSkins = isInit? []: await SkinModel.findbyRoleAndHid(this.roleId, hid); let skin = await SkinModel.insertSkins(this.roleId, this.roleName, [initSkinInfo]); let skinInfos = skin.map(cur => ({ id: cur.id, hid, inc: 1, reason: ITEM_CHANGE_REASON.GET_HERO_UNLOCK_SKIN})) this.skinPushMessages.skins.push(...skinInfos); if(skin) allSkins.push(...skin); let skins: HeroSkin[] = []; for(let skin of allSkins) { skins.push(new HeroSkin(skin.id, skin.skinId, skin._id, skin.id == initSkinInfo.id)); } return skins } // game-server里面创建武将 public async createWithHeroInfo(infos: Map) { let role = await this.getRole(); // 数据处理 let conditions = new Array<{ type: number, paramHid?: number, paramFavourLv?: number, paramSkinId?: number }>(); // 解锁头像条件 let initHeroInfos: HeroUpdate[] = []; for (let [ hid, { heroInfo, skinInfo }] of infos) { conditions.push({ type: FIGURE_UNLOCK_CONDITION.GET_HERO, paramHid: heroInfo.hid }); this.updateDbCe(true, heroInfo); // 皮肤使用初始加载进内存的数据 let skins = await this.getSkinsOfThisHero(hid, { ...skinInfo, _id: new SkinModel()._id }, false); let newAttr = new AttributeCal(); newAttr.setLv(heroInfo.lv); newAttr.setByDbData(role.attr, heroInfo.attr); let heroCe = newAttr.calCe(); // 计算最终战力 initHeroInfos.push({ ...heroInfo, skins, _id: new HeroModel()._id, ce: heroCe }); this.heroNum ++; } // 武将使用初始加载数据插入 this.resultHeroes = await HeroModel.insertHeroes(this.roleId, this.roleName, this.serverId, initHeroInfos); let heroSkins = this.resultHeroes.map(cur => { return pick(cur, ['hid', 'skins']) }); this.skinPushMessages.heros.push(...heroSkins); // 头像解锁 let { figureInfo, frames, heads, spines } = unlockFigureWithoutSave(conditions, role); this.figureInfos.push(figureInfo); this.addRoleUpdateParam({ frames, heads, spines }); // 更新战力 await this.saveCeToDb(); } // 创建初始账号时候的初始 public async createWithInitInfo(infos: Map, figureInfo: { heads: Figure[], frames: Figure[], spines: Figure[] }) { this.figureInfos.push(figureInfo); let heroeInfos: HeroUpdate[] = []; for (let [ hid, { heroInfo, skinInfo }] of infos) { this.updateDbCe(true, heroInfo); let model = new SkinModel(); let skins = await this.getSkinsOfThisHero(hid, { ...skinInfo, _id: model._id }, true); heroeInfos.push({ ...heroInfo, skins, _id: new HeroModel()._id}); this.heroNum ++; } this.resultHeroes = await HeroModel.insertHeroes(this.roleId, this.roleName, this.serverId, heroeInfos); } public async pushMessage(sid: string) { let role = await this.getRole(); let uids = [{ uid: this.roleId, sid }]; pinus.app.get('channelService').pushMessageByUids('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: reduceCe(role.ce) , heros: this.pushHeroes.map(cur => { return {...cur, ce: reduceCe(cur.ce), incHeroCe: reduceCe(cur.incHeroCe) }}), topLineupCe: reduceCe(role.topLineupCe) }), uids); let figureInfo = combineFigureInfo(this.figureInfos); if (!!figureInfo && (figureInfo.heads.length > 0 || figureInfo.frames.length > 0 || figureInfo.spines.length > 0)) { pinus.app.get('channelService').pushMessageByUids('onHeadChange', resResult(STATUS.SUCCESS, { ...figureInfo }), uids); } pinus.app.get('channelService').pushMessageByUids('onHeroSkinChange', resResult(STATUS.SUCCESS, this.skinPushMessages), uids); pinus.app.get('channelService').pushMessageByUids('onHeroUpdate', resResult(STATUS.SUCCESS, { heroes: this.getResultHeroes() }), uids); checkTaskInCreateHero(this.serverId, this.roleId, sid, this.heroNum, this.resultHeroes) } public getResultHeroes() { return this.resultHeroes; } public getShowHeroes() { return this.resultHeroes.map(cur => { let hero = new HeroShowParam(cur); return { ...hero, ce: reduceCe(cur.ce)} }); } } /** * 创建多个武将 * @param roleId * @param sid * @param serverId * @param heroInfo */ export async function createHeroes(roleId: string, roleName: string, sid: string, serverId: number, heroInfo: CreateHeroParam[]) { let hids = heroInfo.map(cur => cur.hid); let userHeroesMap = await HeroModel.findMapByHidRange(hids, roleId); let infos: Map = new Map(), pieces: ItemInter[] = []; for (let h of heroInfo) { let heroCount = h.count || 1; if (userHeroesMap.has(h.hid)) { let { pieceId, count } = transPiece(h.hid); pieces.push({ id: pieceId, count: count * heroCount }); } else { let initInfo: { heroInfo: HeroUpdate, skinInfo: SkinUpdate }; if(pinus.app.getServerType() == 'role') { initInfo = getInitHeroById(h.hid); } else { let roleServers = pinus.app.getServersByType('role'); let server = getRandSingleEelm(roleServers); initInfo = await pinus.app.rpc.role.roleRemote.getInitHeroById.toServer(server.id, h.hid); } initInfo.heroInfo = { ...initInfo.heroInfo, ...h }; infos.set(h.hid, initInfo); userHeroesMap.set(h.hid, null); if (heroCount > 1) { let { pieceId, count } = transPiece(h.hid); pieces.push({ id: pieceId, count: count * (heroCount - 1) }); } } } let resultHeroes: HeroType[] = [], resultItems: RewardInter[] = [], heroes: HeroShowParam[] = []; if (infos.size > 0) { let createHero = new CreateHeroes(roleId, roleName, serverId); await createHero.createWithHeroInfo(infos); await createHero.pushMessage(sid); await createHero.updateRedisRank(); heroes = createHero.getShowHeroes(); resultHeroes = createHero.getResultHeroes(); } if (pieces.length > 0) { let goods = await addItems(roleId, roleName, sid, pieces, ITEM_CHANGE_REASON.HERO_TRANSFER_PIECE); resultItems = goods; } return { heroes, resultHeroes, goods: resultItems } } export async function createHero(roleId: string, roleName: string, sid: string, serverId: number, heroInfo: CreateHeroParam) { let result = await createHeroes(roleId, roleName, sid, serverId, [heroInfo]); return result; }