From 1bdace30f9064b4995056ead624a0836c20bb8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=86=E8=8E=B9?= Date: Fri, 25 Mar 2022 14:14:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=AD=A6=E5=B0=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/servers/chat/remote/guildRemote.ts | 1 - .../app/servers/gm/handler/gmRoleHandler.ts | 2 +- .../app/servers/role/handler/heroHandler.ts | 7 +- .../app/servers/role/handler/roleHandler.ts | 18 +- .../app/servers/role/remote/roleRemote.ts | 83 +--- game-server/app/services/pvpService.ts | 1 - .../app/services/role/_calCe.ts | 2 +- game-server/app/services/role/calCe.ts | 465 ++++++++++++++++++ game-server/app/services/role/createHero.ts | 216 ++++---- .../app/services/role/initRoleService.ts | 61 --- .../app/services/role/rewardService.ts | 2 +- game-server/app/services/roleService.ts | 6 +- shared/db/Hero.ts | 24 +- shared/db/RoleCe.ts | 98 ++++ shared/db/Skin.ts | 10 + shared/pubUtils/playerCe.ts | 49 +- shared/pubUtils/util.ts | 59 ++- 17 files changed, 747 insertions(+), 357 deletions(-) rename shared/domain/roleField/calCe.ts => game-server/app/services/role/_calCe.ts (99%) create mode 100644 game-server/app/services/role/calCe.ts delete mode 100644 game-server/app/services/role/initRoleService.ts create mode 100644 shared/db/RoleCe.ts diff --git a/game-server/app/servers/chat/remote/guildRemote.ts b/game-server/app/servers/chat/remote/guildRemote.ts index a5cc1cada..c297ba571 100644 --- a/game-server/app/servers/chat/remote/guildRemote.ts +++ b/game-server/app/servers/chat/remote/guildRemote.ts @@ -92,7 +92,6 @@ export class GuildRemote { */ private pushMessage(guildCode: string, path: string, message: any) { let channel = this.getChannel(guildCode); - console.log('##### channel', guildCode, channel) if (!!channel) { channel.pushMessage(path, resResult(STATUS.SUCCESS, message)); } diff --git a/game-server/app/servers/gm/handler/gmRoleHandler.ts b/game-server/app/servers/gm/handler/gmRoleHandler.ts index f1d783bef..cccf9f17a 100644 --- a/game-server/app/servers/gm/handler/gmRoleHandler.ts +++ b/game-server/app/servers/gm/handler/gmRoleHandler.ts @@ -21,7 +21,7 @@ import { HeroModel } from '../../../db/Hero'; import { calAllHeroCe, calPlayerCeAndSave } from '../../../services/playerCeService'; import { SkinModel } from '../../../db/Skin'; import { PvpDefenseModel } from '../../../db/PvpDefense'; -import { calculatetopLineup } from '../../../pubUtils/playerCe'; +import { calculatetopLineup } from '../../../pubUtils/util'; import { createHeroes } from '../../../services/role/createHero'; let timer: NodeJS.Timer; diff --git a/game-server/app/servers/role/handler/heroHandler.ts b/game-server/app/servers/role/handler/heroHandler.ts index 2b8035e82..01fa865fb 100644 --- a/game-server/app/servers/role/handler/heroHandler.ts +++ b/game-server/app/servers/role/handler/heroHandler.ts @@ -11,14 +11,14 @@ import { gameData, getHeroExpByLv, getHeroStarByQuality, getHeroWakeByQuality, g import { ItemInter, RewardInter } from '../../../pubUtils/interface'; import { getDropItems, FIGURE_UNLOCK_CONDITION } from '../../../consts/constModules/itemConst' import { pushComposeOrangeHero, pushHeroQualityUpMsg, pushHeroStarMax, pushHeroWakeUp } from '../../../services/chatService'; -import { calculatetopLineup } from '../../../pubUtils/playerCe'; +import { calculatetopLineup } from '../../../pubUtils/util'; import { PvpDefenseModel } from '../../../db/PvpDefense'; import { checkTask, checkTaskInHeroQUalityUp, checkTaskInHeroStarUp, checkTaskInHeroTrain, checkTaskInHeroWakeUp } from '../../../services/task/taskService'; import { isNumber, pick } from 'underscore'; import { updateEplaces } from '../../../services/equipService'; import { addConsumeToHero, checkUnlockTalentCondition, initSkinTalent, updateSkinTalent } from '../../../services/roleService'; import { JewelModel, jewelUpdate } from '../../../db/Jewel'; -import { CalHeroCe } from '../../../domain/roleField/calCe'; +import { CalHeroCe } from '../../../services/role/_calCe'; import { HERO, REBORN } from '../../../pubUtils/dicParam'; import { createHero, createHeroes } from '../../../services/role/createHero'; import { CheckMeterial } from '../../../services/role/checkMaterial'; @@ -654,9 +654,8 @@ export class HeroHandler { let newSkins = initSkinTalent(skins); let dicHeroScroll = getScollByStar(dicHero.quality, dicHero.initialStars, dicHero.quality, 0); - let initInfo = HeroModel.getInitInfo({ + let initInfo = HeroModel.getInitInfo(hid, { job: dicJob.jobid, skins: newSkins, skinId, ce, - star: dicHero.initialStars, quality: dicHero.quality, scrollActive: scrollActive, scrollId: scrollActive? dicHeroScroll.id: 0, scrollStar: scrollActive? dicHeroScroll.stars: 0, diff --git a/game-server/app/servers/role/handler/roleHandler.ts b/game-server/app/servers/role/handler/roleHandler.ts index ba0d7e60d..02584462b 100644 --- a/game-server/app/servers/role/handler/roleHandler.ts +++ b/game-server/app/servers/role/handler/roleHandler.ts @@ -25,7 +25,7 @@ import * as dicParam from '../../../pubUtils/dicParam'; import Counter from '../../../db/Counter'; import { UserModel } from '../../../db/User'; import { checkFilterWords, reportTAEvent, treatRoleName } from '../../../services/sdkService'; -import { CreateHeroes } from '../../../services/role/createHero'; +import { createHeroes, CreateHeroes } from '../../../services/role/createHero'; export default function (app: Application) { new HandlerService(app, {}); @@ -50,20 +50,8 @@ export class RoleHandler { let checkName = await RoleModel.checkName(roleName, serverId); if (checkName) return resResult(STATUS.NAME_HAS_USED); - let initInfos: { role: RoleUpdate, initInfos: {heroInfo: HeroUpdate, skinInfo: SkinUpdate}[], figureInfo: { heads: Figure[], frames: Figure[], spines: Figure[] }} - = this.app.get('initRoleInfos'); - role = await RoleModel.updateRoleInfo(roleId, {...initInfos.role, roleName, hasInit: true}); - let createHero = new CreateHeroes(roleId, roleName, serverId); - - let infos = new Map(); - for(let {heroInfo, skinInfo} of initInfos.initInfos) { - infos.set(heroInfo.hid, { heroInfo, skinInfo }); - } - await createHero.createWithInitInfo(infos, initInfos.figureInfo); - await createHero.pushMessage(sid); - await createHero.updateRedisRank(); - let heroes = createHero.getResultHeroes(); - + let { resultHeroes: heroes } = await createHeroes(roleId, roleName, sid, serverId, DEFAULT_HEROES.map(hid => ({hid, count: 1}))); + role = await RoleModel.updateRoleInfo(roleId, { roleName, hasInit: true }); session.set('roleName', roleName); session.push('roleName', () => { }); diff --git a/game-server/app/servers/role/remote/roleRemote.ts b/game-server/app/servers/role/remote/roleRemote.ts index 06a58e6f8..eb705dfe4 100644 --- a/game-server/app/servers/role/remote/roleRemote.ts +++ b/game-server/app/servers/role/remote/roleRemote.ts @@ -5,14 +5,11 @@ import { HeroUpdate } from '../../../db/Hero'; import { RoleUpdate } from '../../../db/Role'; import { SkinUpdate } from '../../../db/Skin'; import { RankFirstModel, RankFirstType } from '../../../db/RankFirst'; -import { DEFAULT_HEROES } from '../../../consts'; import { Figure } from '../../../domain/dbGeneral'; -import { getDefaultRoleInfo } from '../../../services/roleService'; import { PVPConfigModel, PVPConfigType } from '../../../db/SystemConfig'; import { treatRoleName, taflush } from '../../../services/sdkService'; import { getServerMainten, setServerMainten, stopServerMainten } from '../../../services/gmService'; import { errlogger } from '../../../util/logger'; -import { getInitRoleInfo } from '../../../services/role/initRoleService'; export default function (app: Application) { new HandlerService(app, {}); @@ -23,16 +20,12 @@ export class RoleRemote { constructor(private app: Application) { this.app = app; - this.channelService = app.get('channelService'); - this.setInitRole(); + // this.channelService = app.get('channelService'); this.loadRankFirst(); this.initPvpSeasonNum(); } - private channelService: ChannelService; - private initHeroes: Map = new Map(); // hid => hero - private initRole: RoleUpdate = {}; - private initSkins: Map = new Map(); // hid => skin - private figureInfo: {heads: Figure[], frames: Figure[], spines: Figure[]}; + // private channelService: ChannelService; + private rankFirstRewards: Map> = new Map(); private async loadRankFirst() { @@ -68,76 +61,6 @@ export class RoleRemote { } } - public setInitRole() { - try { - let result = getInitRoleInfo(); - let { role, heroes, skins, figureInfo } = result; - for(let hero of heroes) { - this.initHeroes.set(hero.hid, hero); - } - for(let skin of skins) { - this.initSkins.set(skin.hid, skin); - } - this.initRole = role; - this.figureInfo = figureInfo; - const initRoleInfos = getDefaultRoleInfo(this.initHeroes, this.initSkins, this.initRole, this.figureInfo); - this.app.set('initRoleInfos', initRoleInfos); - this.app.set('initHeroes', this.initHeroes); - this.app.set('initSkins', this.initSkins); - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - - public getInitRoleInfos() { - try { - let initRoleInfos = this.app.get('initRoleInfos'); - if (!initRoleInfos) { - initRoleInfos = getDefaultRoleInfo(this.initHeroes, this.initSkins, this.initRole, this.figureInfo); - this.app.set('initRoleInfos', initRoleInfos); - } - return initRoleInfos; - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - - public getInitHeroes() { - try { - let result: HeroUpdate[] = []; - for(let hid of DEFAULT_HEROES) { - result.push(this.initHeroes.get(hid)); - } - return result; - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - - public getInitSkins() { - try { - let result: SkinUpdate[] = []; - for(let hid of DEFAULT_HEROES) { - result.push(this.initSkins.get(hid)); - } - return result; - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - - public getInitHeroById(hid: number) { - try { - return { - heroInfo: this.initHeroes.get(hid), - skinInfo: this.initSkins.get(hid) - } - } catch(e) { - errlogger.error(`remote ${__filename} \n ${e.stack}`); - } - } - - /** * 重载json资源 */ diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index b86abcd26..e94976c74 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -61,7 +61,6 @@ export async function getEnemies(oppPlayers: OppPlayer[], winStreakNum: number) * @param pLv 我的排名 */ export async function refreshEnemies(role: RoleType, seasonNum: number, sumScore: number, score: number, pLv: number) { - console.log('#####',seasonNum, sumScore, score, pLv) let { roleId } = role; let chosenOpps: string[] = []; let pvpHistoryOppParam: PvpOppCreateParam[] = []; diff --git a/shared/domain/roleField/calCe.ts b/game-server/app/services/role/_calCe.ts similarity index 99% rename from shared/domain/roleField/calCe.ts rename to game-server/app/services/role/_calCe.ts index 5257f336d..4c9c69ce1 100644 --- a/shared/domain/roleField/calCe.ts +++ b/game-server/app/services/role/_calCe.ts @@ -5,7 +5,7 @@ import { gameData, getHeroStarByQuality, getHeroWakeByQuality } from "../../pubU import { DicRandomEffectPool } from "../../pubUtils/dictionary/DicRandomEffectPool"; import { DicSe } from "../../pubUtils/dictionary/DicSe"; import { deepCopy } from "../../pubUtils/util"; -import { AttributeCal } from "./attribute"; +import { AttributeCal } from "../../domain/roleField/attribute"; export class CalRoleCe { private roleInfo: RoleUpdate; diff --git a/game-server/app/services/role/calCe.ts b/game-server/app/services/role/calCe.ts new file mode 100644 index 000000000..7dc7aaf2b --- /dev/null +++ b/game-server/app/services/role/calCe.ts @@ -0,0 +1,465 @@ +import { ABI_STAGE, ABI_STAGE_TO_TYPE, ABI_TYPE_MAIN, SEID_TYPE } from "../../consts"; +import { HeroUpdate } from "../../db/Hero"; +import { RoleUpdate, Teraph } from "../../db/Role"; +import { GlobalAttr, HeroAttr, HeroAttrCell, RoleCeType } from "../../db/RoleCe"; +import { AttributeCal } from "../../domain/roleField/attribute"; +import { gameData, getHeroStarByQuality, getHeroWakeByQuality, getTeraph } from "../../pubUtils/data"; +import { DicRandomEffectPool } from "../../pubUtils/dictionary/DicRandomEffectPool"; +import { DicSe } from "../../pubUtils/dictionary/DicSe"; +import { addToMap, deepCopy } from "../../pubUtils/util"; + +class RoleCe { + roleId: string; + globalAttrs: Map = new Map(); // attrId => GlobalCe + heroAttrs: Map = new Map(); // hid+attrId => HeroCe + heroAttrsByHid: Map = new Map(); // hid => [hid+attrId] + heroLv: Map = new Map(); + + setRoleCe(roleCe: RoleCeType) { + this.roleId = roleCe.roleId; + for(let globalAttr of roleCe.globalAttrs) { + let obj = this.getGlobalAttrById(globalAttr.attrId); + obj.setByRoleCe(globalAttr); + } + for(let {hid, lv, attrs} of roleCe.heroAttrs) { + this.heroLv.set(hid, lv); + for(let cell of attrs) { + let obj = this.getHeroAttrByHidAndId(hid, cell.attrId); + obj.setByRoleCe(cell); + } + } + } + + public getGlobalAttrById(attrId: number) { + if(!this.globalAttrs.has(attrId)) { + if(ABI_TYPE_MAIN.indexOf(attrId) != -1) { + let obj = new GlobalMainAttr(attrId); + this.globalAttrs.set(attrId, obj); + } else { + let obj = new GlobalSubAttr(attrId); + this.globalAttrs.set(attrId, obj); + } + } + return this.globalAttrs.get(attrId); + } + + public getHeroAttrByHidAndId(hid: number, attrId: number) { + let key = `${hid}_${attrId}`; + if(!this.heroAttrs.has(key)) { + if(ABI_TYPE_MAIN.indexOf(attrId) != -1) { + let obj = new HeroMainAttr(hid, attrId); + this.heroAttrs.set(key, obj); + } else { + let obj = new HeroSubAttr(hid, attrId); + this.heroAttrs.set(key, obj); + } + + if(!this.heroAttrsByHid.has(hid)) { + this.heroAttrsByHid.set(hid, []); + } + this.heroAttrsByHid.get(hid).push(key); + } + return this.heroAttrs.get(key); + } + + public calHeroCe() { + let ces = new Map(); // hid => [{attrId, val}] + for(let [hid, keys] of this.heroAttrsByHid) { + let lv = this.heroLv.get(hid)||1; + for(let key of keys) { + let { attrId, base, baseUp, starUp, skillRatio, skill, job } = this.heroAttrs.get(key); + let { schoolRatio, title, teraph } = this.getGlobalAttrById(attrId); + let val = ( base + lv * ( baseUp + starUp ) + skill + job) * (1 + skillRatio + schoolRatio ) + teraph + title; + if(!ces.has(hid)) ces.set(hid, []); + ces.get(hid).push({ id: attrId, val }); + } + } + let result = new Map(); + for(let [hid, arr] of ces) { + let obj = new AttributeCal(); + obj.setByWarJson(arr); + result.set(hid, obj.calCe()); + } + return result; + } + + public getRoleCeTable() { + let globalAttrs: GlobalAttr[] = []; + for(let [_, globalAttr] of this.globalAttrs) { + globalAttrs.push(globalAttr.getGlobalAttr()); + } + let heroAttrs: HeroAttr[] = []; + for(let [hid, keys] of this.heroAttrsByHid) { + let lv = this.heroLv.get(hid); + let attrs: HeroAttrCell[] = []; + for(let key of keys) { + let heroAttr = this.heroAttrs.get(key); + attrs.push(heroAttr.getHeroAttrCell()); + } + heroAttrs.push({ + hid, lv, attrs + }); + } + return { + roleId: this.roleId, globalAttrs, heroAttrs + } + } +} + +// 计算函数 +export class CalCe extends RoleCe { + public setInitHero(role: RoleUpdate, heroes: HeroUpdate[]) { + for(let { hid, skinId, lv, quality, star, starStage, colorStar, colorStarStage, job, jobStage, } of heroes) { + this.setHeroBase(hid, skinId); + this.setHeroLv(hid, lv); + this.setHeroStar(hid, job, quality, star, starStage, colorStar, colorStarStage); + this.setSkill(hid, skinId, star, colorStar); + this.setJob(hid, job, jobStage); + } + this.setTitle(role.title); + this.setTeraph(role.teraphs); + } + + // 武将基础&成长 + public setHeroBase(hid: number, skinId: number) { + let dicHero = gameData.hero.get(skinId); + for(let [attrId, value] of dicHero.baseAbilityArr) { + let heroAttr = this.getHeroAttrByHidAndId(hid, attrId); + heroAttr.base = value; + } + for(let [attrId, value] of dicHero.baseAbilityUpArr) { + let heroAttr = this.getHeroAttrByHidAndId(hid, attrId); + heroAttr.baseUp = value; + } + } + + // 武将等级 + public setHeroLv(hid: number, lv: number) { + this.heroLv.set(hid, lv); + } + + // 星级相关 + public setHeroStar(hid: number, job: number, quality: number, star: number, starStage: number, colorStar: number, colorStarStage: number) { + let dicJob = gameData.job.get(job); + let jobClass = dicJob.job_class; + const isWake = colorStar > 0; // 是否觉醒,只要激活了觉醒,彩星就会 > 1 + const dicStar = isWake ? getHeroWakeByQuality(jobClass, quality, colorStar) : getHeroStarByQuality(jobClass, quality, star); // 星级表 + const dicPreStar = isWake? getHeroWakeByQuality(jobClass, quality, colorStar - 1): getHeroStarByQuality(jobClass, quality, star - 1); + let curStage = isWake? colorStarStage: starStage; + + for (let stage = ABI_STAGE.START + 1; stage <= ABI_STAGE.END; stage++) { + let attrId = ABI_STAGE_TO_TYPE.get(stage); + let value = 0; // 星级成长 + if(curStage >= stage) { + value = dicStar?.ceAttr.get(stage)||0; + } else { + value = dicPreStar?.ceAttr.get(stage)||0; + } + let heroAttr = this.getHeroAttrByHidAndId(hid, attrId); + heroAttr.starUp = value; + }; + + } + + // 武将星级解锁被动技能计算 + public setSkill(hid: number, skinId: number, _star: number, _colorStar: number) { + let seidList = new Map(); // type => seid + let dicHero = gameData.hero.get(skinId); + let { starSeidArr, colorStarSeidArr } = gameData.heroSkill.get(dicHero.skill); + for (let { star, value, type } of starSeidArr) { + if (_star >= star) seidList.set(type, value); + } + for (let { star, value, type } of colorStarSeidArr) { + if (_colorStar >= star) seidList.set(type, value); + } + let list: number[] = []; + for(let [_type, value] of seidList) list.push(value); + let { fixUp, ratioUp } = this.addSeidEffect(list); + for(let [attrId, value] of fixUp) { + let heroAttr = this.getHeroAttrByHidAndId(hid, attrId); + heroAttr.skill = value; + } + for(let [attrId, value] of ratioUp) { + let heroAttr = this.getHeroAttrByHidAndId(hid, attrId); + heroAttr.skillRatio = value; + } + } + + // 职业基础 + public setJob(hid: number, job: number, jobStage: number) { + const dicJob = gameData.job.get(job); + for(let i = 1; i <= dicJob.maxStage; i++) { + if(jobStage >= i) { + let { id, attr } = dicJob.ceAttr.get(i); + let heroAttr = this.getHeroAttrByHidAndId(hid, id); + heroAttr.job = attr; + } + } + } + + // 爵位 + public setTitle(title: number) { + let dicTitle = gameData.title.get(title)||{ mainAttrValue: new Map(), assiAttrValue: new Map() }; + for(let [attrId, value] of dicTitle.mainAttrValue) { + let globalAttr = this.getGlobalAttrById(attrId); + globalAttr.title = value; + } + for(let [attrId, value] of dicTitle.assiAttrValue) { + let globalAttr = this.getGlobalAttrById(attrId); + globalAttr.title = value; + } + } + + // 神像相关 + public setTeraph(teraphs: Teraph[]) { + let teraphOfAttrId = new Map(); + for(let teraph of teraphs) { + for(let [attrId, value] of teraph.attr) { // 主属性 + addToMap(teraphOfAttrId, attrId, value); + } + let dicTeraph = getTeraph(teraph.id, teraph.grade); + for(let [attrId, value] of dicTeraph.assiAttrValue) { // 次属性 + addToMap(teraphOfAttrId, attrId, value); + } + } + for(let [attrId, value] of teraphOfAttrId) { + let globalAttr = this.getGlobalAttrById(attrId); + globalAttr.teraph = value; + } + } + + // 添加技能增加的被动属性 + private addSeidEffect(seidList: number[]) { + let fixUp = new Map(), ratioUp = new Map(); + let effectList: DicSe[] = []; // any: dic_zyz_se表内容 + + for (let ii = 0; ii < seidList.length; ii += 2) { + let seid = seidList[ii]; + let rand = seidList[ii + 1] || 0; + let dicSeid: DicSe | DicRandomEffectPool = gameData.se.get(seid); + if (!dicSeid) dicSeid = gameData.randomEffectPool.get(seid); + if (dicSeid && dicSeid.id > 0) { + this.addSeid(effectList, dicSeid.id, rand, dicSeid.gainValueArr) + } + } + + // console.log('effectList', JSON.stringify(effectList)); + for (let { type, gainValueArr: [ability, value] } of effectList) { + if (type == SEID_TYPE.TYPE101) { // 加值 + addToMap(fixUp, ability, value); + } else if (type == SEID_TYPE.TYPE103) { // 主属性加百分比 + if(ABI_TYPE_MAIN.includes(ability)) { + addToMap(ratioUp, ability, value / 1000); + } + } else if (type == SEID_TYPE.TYPE104) { // 次级属性加百分比 + if(!ABI_TYPE_MAIN.includes(ability)) { + addToMap(ratioUp, ability, value * 100); + } + } + + } + return { fixUp, ratioUp }; + } + + // 获取dic_zyz_se内容 + private addSeid(effectList: (DicSe | DicRandomEffectPool)[], seidId: number, rand: number, seidValue: number[] = []) { + let curSeid: DicSe | DicRandomEffectPool = gameData.se.get(seidId); + if (!curSeid) curSeid = gameData.randomEffectPool.get(seidId); + if (!curSeid) { console.log("seidId not found:" + seidId); return; } + if (!seidValue) seidValue = curSeid.gainValueArr; + + if (curSeid.type === SEID_TYPE.TYPE999) { + for (let i = 0; i < seidValue.length; i++) { + this.addSeid(effectList, seidValue[i], rand); + } + return; + } + let seid: DicSe | DicRandomEffectPool = deepCopy(curSeid); + if (curSeid.index > 0) { + seid.gainValueArr[curSeid.index - 1] = rand; + } + effectList.push(seid); + } +} + +abstract class GlobalAllAttr { + attrId: number; + schoolRatio: number = 0; + title: number = 0; + teraph: number = 0; + + constructor(attrId: number) { + this.attrId = attrId; + } + + abstract setByRoleCe(data: GlobalAttr): void; + abstract getValues(): number[]; + + public getGlobalAttr() { + return { + attrId: this.attrId, + values: this.getValues() + } + } +} + +class GlobalMainAttr extends GlobalAllAttr { + + public setByRoleCe(globalAttr: GlobalAttr) { + for(let i = 0; i < globalAttr.values.length; i++) { + let value = globalAttr.values[i]; + if(value != undefined) { + switch(i) { + case GLOBAL_ATTR_INDEX.SCHOOL: + this.schoolRatio = value; break; + case GLOBAL_ATTR_INDEX.TITLE: + this.title = value; break; + case GLOBAL_ATTR_INDEX.TERAPH: + this.teraph = value; break; + } + } + } + } + + public getValues() { + let values: number[] = []; + for(let i = GLOBAL_ATTR_INDEX.START; i < GLOBAL_ATTR_INDEX.END; i++) { + switch(i) { + case GLOBAL_ATTR_INDEX.SCHOOL: + values.push(this.schoolRatio); break; + case GLOBAL_ATTR_INDEX.TITLE: + values.push(this.title); break; + case GLOBAL_ATTR_INDEX.TERAPH: + values.push(this.teraph); break; + } + } + return values; + } +} + +class GlobalSubAttr extends GlobalAllAttr { + + public setByRoleCe(globalAttr: GlobalAttr) { + for(let i = 0; i < globalAttr.values.length; i++) { + let value = globalAttr.values[i]; + if(value != undefined) { + switch(i) { + case GLOBAL_ATTR_INDEX.SCHOOL: + this.schoolRatio = value; break; + case GLOBAL_ATTR_INDEX.TITLE: + this.title = value; break; + case GLOBAL_ATTR_INDEX.TERAPH: + this.teraph = value; break; + } + } + } + } + + public getValues() { + let values: number[] = []; + for(let i = GLOBAL_ATTR_INDEX.START; i < GLOBAL_ATTR_INDEX.END; i++) { + switch(i) { + case GLOBAL_ATTR_INDEX.SCHOOL: + values.push(this.schoolRatio); break; + case GLOBAL_ATTR_INDEX.TITLE: + values.push(this.title); break; + case GLOBAL_ATTR_INDEX.TERAPH: + values.push(this.teraph); break; + } + } + return values; + } +} + +abstract class HeroAllAttr { + hid: number; + attrId: number; + base: number = 0; + lv: number = 0; + baseUp: number = 0; + starUp: number = 0; + skillRatio: number = 0; + skill: number = 0; + job: number = 0; + + constructor(hid: number, attrId: number, ) { + this.hid = hid; + this.attrId = attrId; + + } + + abstract setByRoleCe(data: GlobalAttr): void; + abstract getValues(): number[]; + + public getHeroAttrCell() { + return { + attrId: this.attrId, + values: this.getValues() + } + } +} + +class HeroMainAttr extends HeroAllAttr { + public setByRoleCe(heroAttr: HeroAttrCell) { + for(let i = 0; i < heroAttr.values.length; i++) { + let value = heroAttr.values[i]; + if(value != undefined) { + switch(i) { + case HERO_ATTR_INDEX.BASE: + this.base = value; + } + } + } + } + + public getValues() { + let values: number[] = []; + for(let i = HERO_ATTR_INDEX.START; i < HERO_ATTR_INDEX.END; i++) { + switch(i) { + case HERO_ATTR_INDEX.BASE: + values.push(this.base); break; + } + } + return values; + } +} + +class HeroSubAttr extends HeroAllAttr { + public setByRoleCe(heroAttr: HeroAttrCell) { + for(let i = 0; i < heroAttr.values.length; i++) { + let value = heroAttr.values[i]; + if(value != undefined) { + switch(i) { + case HERO_ATTR_INDEX.BASE: + this.base = value; + } + } + } + } + + public getValues() { + let values: number[] = []; + for(let i = HERO_ATTR_INDEX.START; i < HERO_ATTR_INDEX.END; i++) { + switch(i) { + case HERO_ATTR_INDEX.BASE: + values.push(this.base); break; + } + } + return values; + } +} + +enum GLOBAL_ATTR_INDEX { + START, + SCHOOL = 0, + TITLE = 1, + TERAPH = 2, + END +} + +enum HERO_ATTR_INDEX { + START, + BASE = 0, // 角色基础属性(dic_zyz_hero的hp) + BASE_UP = 1, + END +} \ No newline at end of file diff --git a/game-server/app/services/role/createHero.ts b/game-server/app/services/role/createHero.ts index a3942cec1..4bcf77620 100644 --- a/game-server/app/services/role/createHero.ts +++ b/game-server/app/services/role/createHero.ts @@ -1,4 +1,4 @@ -import { FIGURE_UNLOCK_CONDITION, ITEM_CHANGE_REASON, REDIS_KEY, STATUS, TASK_TYPE, HERO_SYSTEM_TYPE } from "../../consts"; +import { FIGURE_UNLOCK_CONDITION, ITEM_CHANGE_REASON, REDIS_KEY, STATUS, TASK_TYPE, HERO_SYSTEM_TYPE, LINEUP_NUM } from "../../consts"; import { SkinModel } from "../../db/Skin"; import { HeroModel, HeroSkin, HeroType, HeroUpdate } from "../../db/Hero"; import { RoleModel, RoleType, RoleUpdate } from "../../db/Role"; @@ -8,7 +8,7 @@ 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 { calculatetopLineup } from "../../pubUtils/util"; import { nowSeconds } from "../../pubUtils/timeUtil"; import { saveCeChangeLog } from "../../pubUtils/logUtil"; import { getRandSingleEelm, reduceCe, resResult } from "../../pubUtils/util"; @@ -20,18 +20,28 @@ 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"; +import { addItems, combineFigureInfo, unlockFigure, unlockFigureWithoutSave } from "./rewardService"; +import { gameData } from "../../pubUtils/data"; +import { CalCe } from "./calCe"; +import { RoleCeUpdate } from "../../db/RoleCe"; -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; +export class CreateHeroes { + private roleId: string; + private roleName: string; + private serverId: number; + private incHeroNum: number = 0; + private incRoleCe: number = 0; + private role: RoleType; + private guild: GuildType; + + // 推送信息 + private figureConditions: { type: FIGURE_UNLOCK_CONDITION, paramHid: number }[] = []; + private skins: SkinUpdate[] = []; + private heroes: HeroUpdate[] = []; + private roleCe: RoleCeUpdate = {}; + private resultHeroes: HeroType[] = []; + private topLineup: TopHero[] = []; + private topLineupCe: number = 0; constructor(roleId: string, roleName: string, serverId: number) { this.roleId = roleId; @@ -46,43 +56,66 @@ export class UpdateHeroes { public async getRole() { if(!this.role) { this.role = await RoleModel.findByRoleId(this.roleId); + this.topLineup = this.role.topLineup; + this.topLineupCe = this.role.topLineupCe; } return this.role; } - public addRoleUpdateParam(param: RoleUpdate) { - this.roleUpdate = {...this.roleUpdate, ...param}; + public async createHeroes(hids: number[]) { + let { roleId, roleName } = this; + for(let hid of hids) { + let initSkin = SkinModel.getInitInfo(hid); + let initHero = HeroModel.getInitInfo(hid, { roleId, roleName, skins: [new HeroSkin(initSkin)] }); + this.heroes.push(initHero); + this.skins.push(initSkin); + this.figureConditions.push({ type: FIGURE_UNLOCK_CONDITION.GET_HERO, paramHid: hid }); + this.incHeroNum ++; + } + await this.calCe(); // 计算战力 + await this.saveCeToDb(); } - public async updateDbCe(isCreate: boolean, heroInfo: HeroUpdate, originCe = 0) { + private async calCe() { 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 }); + let calCe = new CalCe(); + calCe.setInitHero(role, this.heroes); // 设置武将初始信息 + let ces = calCe.calHeroCe(); // 战力 + for(let hero of this.heroes) { + hero.ce = ces.get(hero.hid)||0; + hero.historyCe = hero.ce; + this.incRoleCe += hero.ce; + } + this.roleCe = calCe.getRoleCeTable(); } // 更新战力相关的各个表 - public async saveCeToDb() { + private async saveCeToDb() { let role = await this.getRole(); + // 更新武将表 + for(let hero of this.heroes) { + let resultHero = await HeroModel.createHero(hero); + this.resultHeroes.push(resultHero); + await calculatetopLineup(role, resultHero.hid, resultHero.ce, resultHero._id); + } + this.heroes = []; // 更新role表 - this.role = await RoleModel.updateRoleInfo(this.roleId, { - heroNum: this.incHeroNum + role.heroNum, ce: this.incRoleCe + role.ce, heroNumUpdatedAt: nowSeconds(), ...this.roleUpdate - }); - + role = await RoleModel.incRoleInfo(this.roleId, { heroNum: this.incHeroNum, ce: this.incRoleCe }, { heroNumUpdatedAt: nowSeconds(), }); + this.setRole(role); + // 更新皮肤表 + await SkinModel.insertSkins(this.roleId, this.roleName, this.skins) // 更新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防守阵战力 + for(let { hid, ce } of this.resultHeroes) { + await PvpDefenseModel.updateCe(this.roleId, hid, ce); // 更新pvp防守阵战力 } - saveCeChangeLog(this.role, this.incRoleCe, this.role.ce, HERO_SYSTEM_TYPE.INIT, this.pushHeroes.map(cur => cur.hid)); + saveCeChangeLog(role, this.incRoleCe, role.ce, HERO_SYSTEM_TYPE.INIT, this.resultHeroes.map(cur => cur.hid)); } public async updateRedisRank() { - let role = await this.getRole(); - let { serverId, roleId, pushHeroes } = this; + let { serverId, roleId, resultHeroes, role } = this; // 更新军团信息 if(this.guild) { let r = new Rank(REDIS_KEY.GUILD_INFO, { guildCode: this.guild.code }); @@ -99,12 +132,12 @@ export class UpdateHeroes { await r.setRankWithRoleInfo(roleId, reduceCe(role.topLineupCe), 0, role); // 最强武将 - for(let { hid, ce, hero } of pushHeroes) { + for(let hero of resultHeroes) { let r2 = new Rank(REDIS_KEY.TOP_HERO_RANK, { serverId }); - await r2.setRankWithHeroInfo(roleId, hid, reduceCe(ce), 0, hero); + await r2.setRankWithHeroInfo(roleId, hero.hid, hero.ce, 0, hero); - let r4 = new Rank(REDIS_KEY.HERO_RANK, { serverId, hid }); - await r4.setRankWithHeroInfo(roleId, hid, reduceCe(ce), 0, hero); + let r4 = new Rank(REDIS_KEY.HERO_RANK, { serverId, hid: hero.hid }); + await r4.setRankWithHeroInfo(roleId, hero.hid, hero.ce, 0, hero); } // 总战力 let r3 = new Rank(REDIS_KEY.SUM_CE_RANK, { serverId }); @@ -115,90 +148,26 @@ export class UpdateHeroes { 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('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: role.ce, heros: this.resultHeroes.map(({ hid, ce }) => ({ hid, ce, incHeroCe: ce})), topLineupCe: role.topLineupCe}), uids); + + pinus.app.get('channelService').pushMessageByUids('onHeroSkinChange', resResult(STATUS.SUCCESS, this.getSkinPushMsg()), uids); pinus.app.get('channelService').pushMessageByUids('onHeroUpdate', resResult(STATUS.SUCCESS, { heroes: this.getResultHeroes() }), uids); - checkTaskInCreateHero(this.serverId, this.roleId, sid, this.heroNum, this.resultHeroes) + checkTaskInCreateHero(this.serverId, this.roleId, sid, this.incHeroNum, this.resultHeroes); + await unlockFigure(sid, this.roleId, this.figureConditions); + } + + private getSkinPushMsg() { + let skinPushMessages: {heros: {skins: HeroSkin[], hid: number}[], skins: {id: number, hid: number, inc: number, reason: number }[]} = { heros: [], skins:[] }; // 皮肤推送信息 + for(let { hid, skins } of this.resultHeroes) { + skinPushMessages.heros.push({ hid, skins }); + } + for(let { id, hid } of this.skins) { + skinPushMessages.skins.push({ id, hid, inc: 1, reason: ITEM_CHANGE_REASON.GET_HERO_UNLOCK_SKIN }) + } + return skinPushMessages; } public getResultHeroes() { @@ -225,25 +194,14 @@ export class CreateHeroes extends UpdateHeroes { let hids = heroInfo.map(cur => cur.hid); let userHeroesMap = await HeroModel.findMapByHidRange(hids, roleId); - let infos: Map = new Map(), pieces: ItemInter[] = []; + let createHids: number[] = [], 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); + createHids.push(h.hid); userHeroesMap.set(h.hid, null); if (heroCount > 1) { let { pieceId, count } = transPiece(h.hid); @@ -253,9 +211,9 @@ export class CreateHeroes extends UpdateHeroes { } let resultHeroes: HeroType[] = [], resultItems: RewardInter[] = [], heroes: HeroShowParam[] = []; - if (infos.size > 0) { + if (createHids.length > 0) { let createHero = new CreateHeroes(roleId, roleName, serverId); - await createHero.createWithHeroInfo(infos); + await createHero.createHeroes(createHids); await createHero.pushMessage(sid); await createHero.updateRedisRank(); heroes = createHero.getShowHeroes(); diff --git a/game-server/app/services/role/initRoleService.ts b/game-server/app/services/role/initRoleService.ts deleted file mode 100644 index dc086cf86..000000000 --- a/game-server/app/services/role/initRoleService.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { DEFAULT_HEROES, DEFAULT_HERO_LV, FIGURE_UNLOCK_CONDITION, HERO_SYSTEM_TYPE, LINEUP_NUM } from "../../consts"; -import { HeroModel, HeroSkin, HeroUpdate } from "../../db/Hero"; -import { RoleModel, RoleUpdate } from "../../db/Role"; -import { SkinModel, SkinUpdate } from "../../db/Skin"; -import { TopHero } from "../../domain/dbGeneral"; -import { CalHeroCe, CalRoleCe } from "../../domain/roleField/calCe"; -import { gameData, getHeroExpByLv } from "../../pubUtils/data"; -import { unlockFigureWithoutSave } from "./rewardService"; - -// 储存在内存中的初始数据 -export function getInitRoleInfo() { - let topLineup: TopHero[] = [], topLineupCe = 0, allCe = 0, - heroes: HeroUpdate[] = [], initHeroes: HeroUpdate[] = [], initSkins: SkinUpdate[] = [], heroNum = 0, - conditions: {type: FIGURE_UNLOCK_CONDITION, paramHid: number }[] = []; - let role = new RoleModel(); - let calRoleCe = new CalRoleCe(role); - let roleAttr = calRoleCe.cal(HERO_SYSTEM_TYPE.INIT); - - for(let { actorId: hid } of gameData.recruit) { - let { quality, initialStars: star, jobid: job, name: hName, initialSkin } = gameData.hero.get(hid); - // 皮肤 - let skin = new SkinModel(); - let dicFashion = gameData.fashion.get(initialSkin); - if(!dicFashion) { - console.log(`not found skin: ${initialSkin} of ${hid}`); - continue; - } - let skinInfo = { ...skin.toJSON(), id: initialSkin, hid, skinName: dicFashion.name, skinId: dicFashion.heroId }; - initSkins.push(skinInfo); - // 武将 - let hero = new HeroModel(); - let heroInfo = {...hero.toJSON(), hid, star, quality, hName, job, skins: [new HeroSkin(initialSkin, skinInfo.skinId, skinInfo._id, true)], skinId: skinInfo.skinId, lv: DEFAULT_HERO_LV, exp: getHeroExpByLv(DEFAULT_HERO_LV - 1) || 0 }; - let calHeroCe = new CalHeroCe(hid, heroInfo); - let heroAttr = calHeroCe.cal(HERO_SYSTEM_TYPE.INIT); - let ce = calHeroCe.getCalculatedCe(roleAttr); - heroes.push({ ...heroInfo, attr: heroAttr, ce, historyCe: ce }); - // 更新role表 - if(DEFAULT_HEROES.includes(hid)) { - // 头像 - conditions.push({ type: FIGURE_UNLOCK_CONDITION.GET_HERO, paramHid: hid }); - allCe += ce; - heroNum++; - initHeroes.push({ ...heroInfo, attr: heroAttr, ce, historyCe: ce }); - } - } - let { figureInfo, heads, frames, spines } = unlockFigureWithoutSave(conditions, role); - // 最强阵容 - initHeroes.sort((a, b) => { return b.ce - a.ce }); - for(let i = 0; i < LINEUP_NUM; i++) { - if(initHeroes[i]) { - let { hid, ce, _id } = initHeroes[i]; - topLineup.push({ hid, ce, hero: _id }); - topLineupCe += ce; - } - } - - let initRole: RoleUpdate = { topLineupCe, topLineup, attr: roleAttr, ce: allCe, heroNum, heroNumUpdatedAt: Date.now(), heads, frames, spines }; - return { - role: initRole, heroes, skins: initSkins, figureInfo - } -} \ No newline at end of file diff --git a/game-server/app/services/role/rewardService.ts b/game-server/app/services/role/rewardService.ts index 4702ce9b2..88baa19ee 100644 --- a/game-server/app/services/role/rewardService.ts +++ b/game-server/app/services/role/rewardService.ts @@ -367,7 +367,7 @@ export async function addSkin(roleId: string, roleName: string, sid: string, ski if (hero) { // 有武将的,将皮肤链接到武将上 let curSkin = hero.skins.find(cur => cur.id == skinId); if (!curSkin) { - hero.skins.push(new HeroSkin(skin.id, skin.skinId, skin._id, enable )); + hero.skins.push(new HeroSkin(skin, enable)); await HeroModel.updateHeroInfo(roleId, hero.hid, hero); } return hero; diff --git a/game-server/app/services/roleService.ts b/game-server/app/services/roleService.ts index ac51365fd..7af0e6390 100644 --- a/game-server/app/services/roleService.ts +++ b/game-server/app/services/roleService.ts @@ -1,14 +1,14 @@ import { ChannelUser } from './../domain/ChannelUser'; import { Channel, pinus } from 'pinus'; import { getRandValueByMinMax, getRandEelm, decodeIdCntArrayStr } from '../pubUtils/util'; -import { DEFAULT_HEROES, ROLE_SELECT, TALENT_RELATION_TYPE, TERAPH_RANDOM } from "../consts"; +import { DEFAULT_HEROES, LINEUP_NUM, ROLE_SELECT, TALENT_RELATION_TYPE, TERAPH_RANDOM } from "../consts"; import { DicTeraph } from '../pubUtils/dictionary/DicTeraph'; import { Teraph, RoleModel, RoleType, RoleUpdate } from '../db/Role'; import { SCHOOL } from '../pubUtils/dicParam'; import { gameData, getHeroInitTalent } from '../pubUtils/data'; import { SchoolModel } from '../db/School'; import { SclResultInter, SclPosInter, RewardInter, ItemInter } from '../pubUtils/interface'; -import { HeroSkin, HeroUpdate, Talent } from '../db/Hero'; +import { HeroModel, HeroSkin, HeroUpdate, Talent } from '../db/Hero'; import { SkinUpdate } from '../db/Skin'; import { Figure } from '../domain/dbGeneral'; import { pick } from 'underscore'; @@ -251,4 +251,4 @@ export function initSkinTalent(skins: HeroSkin[], isAll = false) { } } return newSkins -} \ No newline at end of file +} diff --git a/shared/db/Hero.ts b/shared/db/Hero.ts index e98d12233..a41a73341 100644 --- a/shared/db/Hero.ts +++ b/shared/db/Hero.ts @@ -2,12 +2,12 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, Ref, mongoose, DocumentType } from '@typegoose/typegoose'; // import Equip, { } from './Equip'; import { CounterModel } from './Counter'; -import { COUNTER, HERO_CE_RATIO } from '../consts'; +import { COUNTER, DEFAULT_HERO_LV, HERO_CE_RATIO } from '../consts'; import { reduceCe } from '../pubUtils/util'; -import Skin from './Skin'; +import Skin, { SkinUpdate } from './Skin'; import { SearchHeroParam } from '../domain/backEndField/search'; import { Reward } from '../domain/battleField/pvp'; -import { getHeroInitTalent } from '../pubUtils/data'; +import { gameData, getHeroExpByLv, getHeroInitTalent } from '../pubUtils/data'; type CeAttrUpdate = Partial; export class CeAttrData { @@ -88,12 +88,12 @@ export class HeroSkin { @prop({ required: true }) usedTalentPoint: number; // 已使用的天赋点数 - constructor(id: number, skinId: number, skin: string, enable: boolean) { - this.id = id; - this.skinId = skinId; - this.skin = skin; + constructor(skin: SkinUpdate, enable = true) { + this.id = skin.id; + this.skinId = skin.skinId; + this.skin = skin._id; this.enable = enable; - this.talent = getHeroInitTalent(skinId); + this.talent = getHeroInitTalent(skin.skinId); this.usedTalentPoint = 0; } } @@ -274,16 +274,18 @@ export default class Hero extends BaseModel { return hero; } - public static getInitInfo(heroInfo: HeroUpdate = {}): HeroUpdate { + public static getInitInfo(hid: number, heroInfo: HeroUpdate = {}): HeroUpdate { + let dicHero = gameData.hero.get(hid) + let { quality, initialStars: star, jobid: job, name: hName } = dicHero; const doc = new HeroModel(); - const update = { ...doc.toJSON(), ...heroInfo}; + const update = { ...doc.toJSON(), hid, skinId: hid, hName, star, quality, job, lv: DEFAULT_HERO_LV, exp: getHeroExpByLv(DEFAULT_HERO_LV - 1) || 0, ...heroInfo}; delete update._id; return update } public static async createHero(heroInfo: HeroUpdate, lean = true) { const seqId = await CounterModel.getNewCounter(COUNTER.HID) || -1; - const update = this.getInitInfo({ ...heroInfo, seqId }); + const update = this.getInitInfo(heroInfo.hid, { ...heroInfo, seqId }); const hero: HeroType = await HeroModel.findOneAndUpdate({ roleId: heroInfo.roleId, hid: heroInfo.hid }, update, { upsert: true, new: true }).lean(lean); return hero; } diff --git a/shared/db/RoleCe.ts b/shared/db/RoleCe.ts new file mode 100644 index 000000000..5fd8bb26c --- /dev/null +++ b/shared/db/RoleCe.ts @@ -0,0 +1,98 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +// 全局加成 +export class GlobalAttr { + @prop({ required: true }) + attrId: number; // 属性id + @prop({ required: true }) + values: number[]; // 战力公式中的全局加成的数据,查表后的结果 +} + +// 单武将加成 +export class HeroAttr { + @prop({ required: true }) + hid: number; // 武将id + @prop({ required: true }) + lv: number; + @prop({ required: true, type: () => HeroAttrCell, _id: false }) + attrs: HeroAttrCell[]; +} + +export class HeroAttrCell { + @prop({ required: true }) + attrId: number; // 属性id + @prop({ required: true }) + values: number[]; // 战力公式中的武将加成的数据,查表后的结果 +} + +// 装备加成 +class EquipAttr { + @prop({ required: true }) + hid: number; // 武将id + @prop({ required: true }) + eplaceId: number; // 装备位置 + @prop({ required: true }) + attrId: number; // 属性id + @prop({ required: true }) + values: number[]; // 战力公式中的武将加成的数据,查表后的结果 +} + +// 百家学宫加成 +class SchoolAttr { + @prop({ required: true }) + hid: number; // 武将id + @prop({ required: true }) + attrId: number; // 属性id + @prop({ required: true }) + value: number; // 百家学宫有多个武将,单独拎出来方便计算,计算之后结果存到globaAttrs的global1 +} + +// 名将谱加成 +class ScrollAttr { + @prop({ required: true }) + hid: number; // 武将id + @prop({ required: true }) + attrId: number; // 属性id + @prop({ required: true }) + value: number; // 百家学宫有多个武将,单独拎出来方便计算,计算之后结果存到globaAttrs的global1 +} + +/** + * 属性表 +*/ + +@index({ roleId: 1 }) +@index({ roleId: 1 }) + +export default class RoleCe extends BaseModel { + + @prop({ required: true }) + roleId: string; // 角色 id + + @prop({ required: true, type: GlobalAttr, _id: false }) + globalAttrs: GlobalAttr[] + + @prop({ required: true, type: HeroAttr, _id: false }) + heroAttrs: HeroAttr[] + + @prop({ required: true, type: EquipAttr, _id: false }) + equipAttrs: EquipAttr[] + + @prop({ required: true, type: SchoolAttr, _id: false }) + schoolAttr: SchoolAttr[]; + + @prop({ required: true, type: ScrollAttr, _id: false }) + scrollAttrs: ScrollAttr[]; + + public static async findByRoleId(roleId: string) { + let result: RoleCeType[] = await RoleCeModel.find({ roleId }).lean(); + return result; + } + +} + +export const RoleCeModel = getModelForClass(RoleCe); + +export interface RoleCeType extends Pick, keyof RoleCe> { }; +export type RoleCeUpdate = Partial; \ No newline at end of file diff --git a/shared/db/Skin.ts b/shared/db/Skin.ts index e8bb3c54b..62f2201ad 100644 --- a/shared/db/Skin.ts +++ b/shared/db/Skin.ts @@ -1,5 +1,6 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; +import { gameData } from '../pubUtils/data'; @index({ roleId: 1, id: 1 }) @index({ seqId: 1 }) @modelOptions({ schemaOptions: { id: false } }) @@ -28,6 +29,15 @@ export default class Skin extends BaseModel { return rec; } + public static getInitInfo(hid: number): SkinUpdate { + let dicHero = gameData.hero.get(hid); + let dicFashion = gameData.fashion.get(dicHero.initialSkin) + const doc = new SkinModel(); + const update = { ...doc.toJSON(), id: dicFashion.id, skinId: dicFashion.heroId, skinName: dicFashion.name, hid}; + delete update._id; + return update + } + public static async insertSkins(roleId: string, roleName: string, skinInfos: SkinUpdate[]) { let insertInfos: SkinUpdate[] = []; for(let skinInfo of skinInfos) { diff --git a/shared/pubUtils/playerCe.ts b/shared/pubUtils/playerCe.ts index f67f9e374..53732b10a 100644 --- a/shared/pubUtils/playerCe.ts +++ b/shared/pubUtils/playerCe.ts @@ -4,7 +4,7 @@ import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, LINEUP_NUM, TALENT_RELATION_TYPE } from '../consts'; -import { cal, deepCopy, getAllAttrStage, reduceCe } from './util'; +import { cal, calculatetopLineup, deepCopy, getAllAttrStage, reduceCe } from './util'; import { HeroModel, HeroType, HeroUpdate, CeAttrData, EPlace, Stone, Talent } from '../db/Hero'; import { RoleModel, RoleType, RoleUpdate, CeAttrDataRole } from '../db/Role'; import { AttributeCal } from '../domain/roleField/attribute'; @@ -209,53 +209,6 @@ export async function calPlayerCe(hero: HeroType, update: HeroUpdate, type: numb return heroAttrs; } -/** - * 计算最强阵容战力 - * @param role - * @param hid - * @param ce - * @param heroId - */ -export async function calculatetopLineup(role: RoleType, hid?: number, ce?: number, heroId?: string) { - let topLineup = role?.topLineup || new Array(); - if(!hid) { // 直接重新排 - let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); - topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); - } else { - topLineup.sort((a, b) => { return b.ce - a.ce }); // 0-6,最大-最小 - let index = topLineup.findIndex(cur => cur.hid == hid); - if(index != -1 && !heroId) { - let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); - topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); - } else { - if (index == -1) { // 不在最强列表 - if (topLineup.length < LINEUP_NUM) { // 不满6人 - topLineup.push({ hid, ce, hero: heroId }); - } else if (topLineup.length == LINEUP_NUM) { - if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 - topLineup.pop(); - topLineup.push({ hid, ce, hero: heroId }); - } - } else { - topLineup.splice(LINEUP_NUM, topLineup.length - LINEUP_NUM); - } - } else { // 原来就是最强6人 - if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 - let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); - topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); - } else { - topLineup[index].ce = ce; - } - } - } - } - - let topLineupCe = topLineup.reduce((pre, cur) => { - return pre + cur.ce - }, 0); - - return { topLineup, topLineupCe }; -} /** * 添加皮肤全局加成 diff --git a/shared/pubUtils/util.ts b/shared/pubUtils/util.ts index c221dd410..ee094136f 100644 --- a/shared/pubUtils/util.ts +++ b/shared/pubUtils/util.ts @@ -6,13 +6,14 @@ import { isNumber } from 'underscore'; const csprng = require('csprng'); import fs = require('fs'); import path = require('path'); -import { HERO_CE_RATIO, ABI_STAGE, GACHA_TO_FLOOR, REFRESH_TIME, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, WAR_TYPE } from '../consts'; +import { HERO_CE_RATIO, ABI_STAGE, GACHA_TO_FLOOR, REFRESH_TIME, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, WAR_TYPE, LINEUP_NUM } from '../consts'; import { findIndex } from 'underscore'; import { getTimeFunM } from './timeUtil'; import { Floor } from '../domain/activityField/gachaField'; import { WhiteListModel } from '../db/RegionWhiteList'; import { RewardInter } from './interface'; +import { RoleType } from '../db/Role'; const randomName = require("chinese-random-name"); const moment = require('moment'); const crypto = require('crypto'); @@ -788,3 +789,59 @@ export function stringToRewardInter(rewardStr: string): Array { } return result } + +export function addToMap(map: Map, id: T, value: number) { + if(!map.has(id)) { + map.set(id, value); + } else { + map.set(id, map.get(id) + value); + } +} + +/** + * 计算最强阵容战力 + * @param role + * @param hid + * @param ce + * @param heroId + */ + export async function calculatetopLineup(role: RoleType, hid?: number, ce?: number, heroId?: string) { + let topLineup = role?.topLineup || new Array(); + if(!hid) { // 直接重新排 + let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); + topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); + } else { + topLineup.sort((a, b) => { return b.ce - a.ce }); // 0-6,最大-最小 + let index = topLineup.findIndex(cur => cur.hid == hid); + if(index != -1 && !heroId) { + let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); + topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); + } else { + if (index == -1) { // 不在最强列表 + if (topLineup.length < LINEUP_NUM) { // 不满6人 + topLineup.push({ hid, ce, hero: heroId }); + } else if (topLineup.length == LINEUP_NUM) { + if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 + topLineup.pop(); + topLineup.push({ hid, ce, hero: heroId }); + } + } else { + topLineup.splice(LINEUP_NUM, topLineup.length - LINEUP_NUM); + } + } else { // 原来就是最强6人 + if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 + let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); + topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); + } else { + topLineup[index].ce = ce; + } + } + } + } + + let topLineupCe = topLineup.reduce((pre, cur) => { + return pre + cur.ce + }, 0); + + return { topLineup, topLineupCe }; +}