diff --git a/game-server/app.ts b/game-server/app.ts index 0c18d760b..05da25337 100644 --- a/game-server/app.ts +++ b/game-server/app.ts @@ -62,7 +62,7 @@ app.configure(function() { } }); - const redisClient = connectRedis(app.get('database').redis); + const redisClient = connectRedis(app.get('database').redis, app.get('database').redispw); app.set('redis', redisClient); redLockService.initRedlock(redisClient); redlockCacheService.init(); @@ -78,7 +78,7 @@ app.configure(function() { }); // app configuration -app.configure('production|development|alpha|dev', 'connector', function () { +app.configure('production|development|alpha|dev|isbn', 'connector', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, @@ -103,7 +103,7 @@ app.configure('production|development|alpha|dev', 'connector', function () { }); }); -app.configure('production|development|alpha|dev', 'gate', function () { +app.configure('production|development|alpha|dev|isbn', 'gate', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, @@ -111,7 +111,7 @@ app.configure('production|development|alpha|dev', 'gate', function () { }); }); -app.configure('production|development|alpha|dev', 'gm', function () { +app.configure('production|development|alpha|dev|isbn', 'gm', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, @@ -120,7 +120,7 @@ app.configure('production|development|alpha|dev', 'gm', function () { init();//将gm后台数据加载到gate服 }); -app.configure('production|development|alpha|dev', 'systimer', function () { +app.configure('production|development|alpha|dev|isbn', 'systimer', function () { app.set('connectorConfig', { connector: pinus.connectors.hybridconnector, @@ -154,7 +154,7 @@ export function globalErrorHandler(err: Error, msg: any, resp: any, } // app configure -app.configure('production|development|alpha|dev', function () { +app.configure('production|development|alpha|dev|isbn', function () { app.set(RESERVED.ERROR_HANDLER, errorHandler); app.set(RESERVED.GLOBAL_ERROR_HANDLER, globalErrorHandler); app.globalAfter((err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, cb: HandlerCallback) => { diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index 059348952..3fbf69333 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -55,7 +55,7 @@ export class EntryHandler { await self.app.rpc.connector.connectorRemote.remoteLogin.toServer(connect.sid, role.roleId); } let serverName = this.app.getServerId(); - await roleLogin(role.roleId, user.userCode, serverName); // 保存在线用户 + await roleLogin(role.roleId, user.userCode, serverName, user.pkgName); // 保存在线用户 await session.abind(role.roleId); session.set('uid', role.roleId); session.set('roleId', role.roleId); diff --git a/game-server/app/servers/role/handler/equipHandler.ts b/game-server/app/servers/role/handler/equipHandler.ts index 10e6e688d..819818a74 100644 --- a/game-server/app/servers/role/handler/equipHandler.ts +++ b/game-server/app/servers/role/handler/equipHandler.ts @@ -138,7 +138,7 @@ export class EquipHandler { hero.ePlace = ePlace; - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.EQUIP_BASE); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP_BASE, sid, roleId, hero, { ePlace }); const curHero = { hid, ePlace: strengthenArr @@ -197,7 +197,7 @@ export class EquipHandler { hero.ePlace = ePlace; - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.EQUIP_BASE); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP_BASE, sid, roleId, hero, { ePlace }); const curHero = { hid, ePlace: strengthenArr @@ -261,7 +261,7 @@ export class EquipHandler { let result = await handleCost(roleId, sid, cost); if (!result) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.EQUIP_BASE); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP_BASE, sid, roleId, hero, { ePlace }); const curHero = { hid, @@ -381,7 +381,7 @@ export class EquipHandler { // 更新战力 const hero = await HeroModel.findByHidAndRoleWithEquip(hid, roleId); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.RESTRENGTHEN, [ePlaceId, ...removeSeidList]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.RESTRENGTHEN, sid, roleId, hero, {}, [ePlaceId, ...removeSeidList]); return resResult(STATUS.SUCCESS,{curEquip}); @@ -448,7 +448,7 @@ export class EquipHandler { } else if (type == 2) { if (!equip.hid) return resResult(STATUS.EQUIP_NOT_EQUIPED); - let curEquip = await takeOffEquipAndCalPlayerCe(roleId, sid, equip.seqId, hero, id) + let curEquip = await takeOffEquipAndCalPlayerCe(roleId, sid, hero, equip, id) curEquips.push(curEquip); } return resResult(STATUS.SUCCESS, { curEquips: curEquips }); @@ -513,7 +513,7 @@ export class EquipHandler { await addItems(roleId, roleName, sid, goods); if (!!equip.hid) { let hero = await HeroModel.findByHidAndRole(equip.hid, roleId); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.JEWEL_ON, [jewel, oldJewel]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.JEWEL_ON, sid, roleId, hero, {}, [jewel, oldJewel]); } return resResult(STATUS.SUCCESS, { curEquip: { seqId: eid, holes: equip.holes } }); } @@ -560,7 +560,7 @@ export class EquipHandler { await addItems(roleId, roleName, sid, goods); if (!!equip.hid) { let hero = await HeroModel.findByHidAndRole(equip.hid, roleId); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.JEWEL_OFF, [jewel]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.JEWEL_OFF, sid, roleId, hero, {}, [jewel]); } return resResult(STATUS.SUCCESS, { curEquip: { seqId: eid, holes: equip.holes } }); } @@ -651,7 +651,7 @@ export class EquipHandler { await EquipModel.updateEquipInfo(eid, { holes: equip.holes }); if (!!equip.hid) { let hero = await HeroModel.findByHidAndRole(equip.hid, roleId); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.JEWEL_ON, [jewel, oldJewel]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.JEWEL_ON, sid, roleId, hero, {}, [jewel, oldJewel]); } return resResult(STATUS.SUCCESS, { curEquip: { seqId: eid, holes: equip.holes } }); } else { diff --git a/game-server/app/servers/role/handler/friendHandler.ts b/game-server/app/servers/role/handler/friendHandler.ts index 2a9af4043..b7fa27c91 100644 --- a/game-server/app/servers/role/handler/friendHandler.ts +++ b/game-server/app/servers/role/handler/friendHandler.ts @@ -681,12 +681,12 @@ export class FriendHandler { if(heroList.length <= 0) return resResult(STATUS.HERO_NOT_FIND); let list = new Array(); - for(let {roleId, roleName, hid, hName, ce, lv, star, colorStar, quality, job, skins, ceAttr} of heroList) { + for(let {roleId, roleName, hid, hName, ce, lv, star, colorStar, quality, job, skins, attr: heroAttrs} of heroList) { let curSkin = skins.find(cur => cur.enable); let equips = await EquipModel.findListByHidAndRole(hisRoleId, hid, EQUIP_SELECT.HERO_DETAIL); - let attributes = getPlayerMainAttribute(ceAttr, role.globalCeAttr); + let attributes = getPlayerMainAttribute(heroAttrs, role.attr); list.push({ roleId, roleName, hid, hName, ce, lv, star, colorStar, quality, job, diff --git a/game-server/app/servers/role/handler/heroHandler.ts b/game-server/app/servers/role/handler/heroHandler.ts index 05d9b4456..7a99d24af 100644 --- a/game-server/app/servers/role/handler/heroHandler.ts +++ b/game-server/app/servers/role/handler/heroHandler.ts @@ -1,9 +1,9 @@ import {Application, BackendSession, ChannelService} from 'pinus'; import { handleCost, addItems } from '../../../services/rewardService'; -import { calPlayerCeAndSave } from '../../../services/playerCeService'; -import { resResult, returnHeroCeRatio } from '../../../pubUtils/util'; +import { calPlayerCeAndSave, calAllHeroCe } from '../../../services/playerCeService'; +import { resResult, returnHeroCeRatio, deepCopy } from '../../../pubUtils/util'; import { STATUS } from '../../../consts/statusCode'; -import {HeroModel} from '../../../db/Hero'; +import { HeroModel, Connect } from '../../../db/Hero'; import {CURRENCY_BY_TYPE, CURRENCY_TYPE, CONSUME_TYPE, HERO_GROW_MAX, HERO_SYSTEM_TYPE, ITID, ABI_STAGE, HERO_CE_RATIO} from '../../../consts'; import { RoleModel } from '../../../db/Role'; import { ItemModel } from '../../../db/Item'; @@ -12,6 +12,8 @@ import { RewardInter } from '../../../pubUtils/interface'; import { getDropItems } from '../../../consts/constModules/itemConst' import { getRoleOnlineInfo, getAllOnlineRoles } from '../../../services/redisService'; import { pushHeroQualityUpMsg } from '../../../services/chatService'; +import { CeAttrDataRole, CeAttrData } from '../../../domain/roleField/attribute'; + export default function(app: Application) { return new HeroHandler(app); } @@ -81,8 +83,9 @@ export class HeroHandler { let curHero = await HeroModel.createHero({ roleId, serverId, roleName, hid, hName, star, quality, job, skins:[{id: initialSkin, enable: true}] }); - await calPlayerCeAndSave(sid, roleId, [curHero], HERO_SYSTEM_TYPE.INIT); - return resResult(STATUS.SUCCESS, {curHero: returnHeroCeRatio(curHero)}); + let hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.INIT, sid, roleId, curHero, {}); + await calAllHeroCe(HERO_SYSTEM_TYPE.ADD_SKIN, sid, roleId, {}, [initialSkin]) + return resResult(STATUS.SUCCESS, {curHero: returnHeroCeRatio(hero)}); } // 武将升级 @@ -138,12 +141,14 @@ export class HeroHandler { let costResult = await handleCost(roleId, sid, material); if(!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); - hero.lv = playerLv > newLv?newLv: playerLv; - hero.exp = newExp; + let update = { + lv: playerLv > newLv?newLv: playerLv, + exp: newExp + } - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.LVUP, [hid]); + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.LVUP, sid, roleId, hero, update); const curHero = { - hid, lv : heros[0].lv, exp : heros[0].exp + hid, lv : hero.lv, exp : hero.exp } return resResult(STATUS.SUCCESS, { curHero }); @@ -178,16 +183,20 @@ export class HeroHandler { if(!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); let isUpStar = oldStarStage + 1 == ABI_STAGE.END; - hero.star = isUpStar? oldStar + 1: oldStar; - hero.starStage = isUpStar? ABI_STAGE.START: oldStarStage + 1; - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.STAR, [hid, isUpStar?1:0]); + let update = { + star: isUpStar? oldStar + 1: oldStar, + starStage: isUpStar? ABI_STAGE.START: oldStarStage + 1 + } + + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.STAR, sid, roleId, hero, update); + if(isUpStar) await calAllHeroCe(HERO_SYSTEM_TYPE.STAR, sid, roleId, {}, [hid, isUpStar?1:0]); // 升星可能影响到百家学院全局加成 const curHero = { hid, - star : heros[0].star, - starStage : heros[0].starStage, - colorStar: heros[0].colorStar, - colorStarStage: heros[0].colorStarStage + star : hero.star, + starStage : hero.starStage, + colorStar: hero.colorStar, + colorStarStage: hero.colorStarStage } return resResult(STATUS.SUCCESS, {isUpStar, curHero}); } @@ -226,11 +235,14 @@ export class HeroHandler { let costResult = await handleCost(roleId, sid, [{id: pieceId, count: fragmentNum}]); if(!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); - hero.quality ++; - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.QUALITY, [hid]); + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.QUALITY, sid, roleId, hero, { + quality: hero.quality + 1 + }); + await calAllHeroCe(HERO_SYSTEM_TYPE.QUALITY, sid, roleId, {}, [hid, 0]); // 升品可能影响到百家学院全局加成 + const curHero = { hid, - quality : heros[0].quality + quality : hero.quality } pushHeroQualityUpMsg(roleId, roleName, serverId, hero); return resResult(STATUS.SUCCESS, {curHero}); @@ -273,16 +285,21 @@ export class HeroHandler { let isWakeUp = oldColorStar == 0; let isUpStar = isWakeUp || oldColorStarStage + 1 == ABI_STAGE.END; - hero.colorStar = isUpStar? oldColorStar + 1: oldColorStar; - hero.colorStarStage = isUpStar? ABI_STAGE.START: oldColorStarStage + 1; - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.COLORSTAR, [hid, isUpStar?1:0, isWakeUp?1:0]); + let update = { + colorStar: isUpStar? oldColorStar + 1: oldColorStar, + colorStarStage: isUpStar? ABI_STAGE.START: oldColorStarStage + 1 + } + + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.COLORSTAR, sid, roleId, hero, update); + if(isUpStar) await calAllHeroCe(HERO_SYSTEM_TYPE.COLORSTAR, sid, roleId, {}, [hid, isUpStar?1:0]); // 升星可能影响到百家学院全局加成 + const curHero = { hid, - star : heros[0].star, - starStage : heros[0].starStage, - colorStar: heros[0].colorStar, - colorStarStage: heros[0].colorStarStage + star : hero.star, + starStage : hero.starStage, + colorStar: hero.colorStar, + colorStarStage: hero.colorStarStage } return resResult(STATUS.SUCCESS, {isUpStar, curHero}); } @@ -293,26 +310,30 @@ export class HeroHandler { let sid: string = session.get('sid'); let { hid } = msg; let hero = await HeroModel.findByHidAndRole(hid, roleId); - if (!hero) - return resResult(STATUS.HERO_NOT_FIND); - let heroJob = gameData.job.get(hero.job); - if (hero.jobStage >= 6) + if (!hero) return resResult(STATUS.HERO_NOT_FIND); + + let dicJob = gameData.job.get(hero.job); + if(!dicJob) return resResult(STATUS.DIC_DATA_NOT_FOUND); + + if (hero.jobStage >= ABI_STAGE.END) return resResult(STATUS.HERO_JOB_STAGE_REACH_MAX_STAGE); - if (hero.job >= getMaxGradeByjobClass(heroJob.job_class)) + if (hero.job >= getMaxGradeByjobClass(dicJob.job_class)) return resResult(STATUS.HERO_JOB_REACH_MAX_STAGE); let consume = new Array(); - if(heroJob.trainingConsume[hero.jobStage]) { - consume.push(heroJob.trainingConsume[hero.jobStage]); + if(dicJob.trainingConsume[hero.jobStage]) { + consume.push(dicJob.trainingConsume[hero.jobStage]); } let result = await handleCost(roleId, sid, consume); if(!result) { return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); } - hero.jobStage = hero.jobStage +1; + //重算战力并下发 - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.TRAIN); - return resResult(STATUS.SUCCESS, { curHero: {hid : heros[0].hid, job : heros[0].job, jobStage: heros[0].jobStage}}); + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.TRAIN, sid, roleId, hero, { + jobStage: hero.jobStage + 1 + }); + return resResult(STATUS.SUCCESS, { curHero: {hid : hero.hid, job : hero.job, jobStage: hero.jobStage}}); } //进阶 @@ -334,27 +355,30 @@ export class HeroHandler { return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); } let nextHeroJob = getJobByGradeAndClass(heroJob.job_class, heroJob.grade + 1); - hero.job = nextHeroJob.jobid; - hero.jobStage = 0; + //重算战力并下发 - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.STAGEUP, [curJob]); - return resResult(STATUS.SUCCESS, { curHero: {hid : heros[0].hid, job : heros[0].job, jobStage : heros[0].jobStage}}); + let update = { + job: nextHeroJob.jobid, + jobStage: 0 + } + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.STAGEUP, sid, roleId, hero, update); + return resResult(STATUS.SUCCESS, { curHero: {hid : hero.hid, job : hero.job, jobStage : hero.jobStage}}); } //激活羁绊 - async heroConectionActivate(msg: {shipId: number}, session: BackendSession) { + async heroConectionActivate(msg: { shipId: number }, session: BackendSession) { let roleId: string = session.get('roleId'); let sid: string = session.get('sid'); let { shipId } = msg; let shipHidAndLevel = gameData.friendShipHidAandIds.get(shipId); - if (!shipHidAndLevel) - return resResult(STATUS.HERO_CONECTION_IS_NOT_EXIT); + if (!shipHidAndLevel) return resResult(STATUS.HERO_CONECTION_IS_NOT_EXIT); let hero = await HeroModel.findByHidAndRole(shipHidAndLevel.actorId, roleId); - if (!hero) - return resResult(STATUS.HERO_NOT_FIND); + if (!hero) return resResult(STATUS.HERO_NOT_FIND); + + let heroConnections: Connect[] = deepCopy(hero.connections); let flag = true; let level = 1; - for (let conection of hero.connections) { + for (let conection of heroConnections) { if (conection.shipId == shipId ) { if (conection.level >= shipHidAndLevel.level) { return resResult(STATUS.HERO_CONECTION_IS_MAX_LEVEL); @@ -366,7 +390,7 @@ export class HeroHandler { } } if (!!flag) { - hero.connections.push({shipId, level}); + heroConnections.push({shipId, level}); } let friendShip = getFriendShipById(shipId, level); if (hero.star < friendShip.level) @@ -386,8 +410,8 @@ export class HeroHandler { return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); } //重算战力并下发 - let heros = await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.CONNECT, [shipId, level]); - return resResult(STATUS.SUCCESS, { curHero: {hid : heros[0].hid, connections : heros[0].connections}}); + hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.CONNECT, sid, roleId, hero, { connections: heroConnections }, [shipId]); + return resResult(STATUS.SUCCESS, { curHero: {hid : hero.hid, connections : hero.connections}}); } //赠送(包括一键赠送) @@ -445,8 +469,6 @@ export class HeroHandler { } let newLv = getFavourLvByExp(newExp); - hero.favour = newExp; - hero.favourLv = newLv; let result = await handleCost(roleId, sid, material); if(!result) { @@ -454,11 +476,13 @@ export class HeroHandler { } //重算战力并下发 if (oldLv != hero.favourLv) { - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.FAVOUR, [oldLv]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.FAVOUR, sid, roleId, hero, { + favour: newExp, favourLv: newLv + }, [oldLv]); } else { await HeroModel.updateHeroInfo(roleId, hero.hid, hero); } - return resResult(STATUS.SUCCESS, { curHero: {hid : hero.hid, favour : hero.favour, favourLv : hero.favourLv}}); + return resResult(STATUS.SUCCESS, { curHero: { hid: hero.hid, favour: hero.favour, favourLv: hero.favourLv } }); } //穿带时装 @@ -467,14 +491,15 @@ export class HeroHandler { let sid: string = session.get('sid'); let { id } = msg; let skinInfo = gameData.fashion.get(id); - if (!skinInfo) - return resResult(STATUS.HERO_SKIN_NOT_FIND); + if (!skinInfo) return resResult(STATUS.HERO_SKIN_NOT_FIND); let hero = await HeroModel.findByHidAndRole(skinInfo.actorId, roleId); - if (!hero) - return resResult(STATUS.HERO_NOT_FIND); + if (!hero) return resResult(STATUS.HERO_NOT_FIND); + + let heroSkins = deepCopy(hero.skins); + let result = false; let lastSkinId: number; - for (let skin of hero.skins) { + for (let skin of heroSkins) { if (skin.id == id) { if (!!skin.enable) { return resResult(STATUS.HERO_SKIN_IS_EQUIPED); @@ -491,7 +516,7 @@ export class HeroHandler { if (!result) { return resResult(STATUS.HERO_SKIN_NOT_FIND); } - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.SKIN, [id, lastSkinId]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.SKIN, sid, roleId, hero, { skins: heroSkins }, [id, lastSkinId]); return resResult(STATUS.SUCCESS, {curHero: {hid : hero.hid, skins : hero.skins} }); } } diff --git a/game-server/app/servers/role/handler/roleHandler.ts b/game-server/app/servers/role/handler/roleHandler.ts index 49b19d45b..53842ec8a 100644 --- a/game-server/app/servers/role/handler/roleHandler.ts +++ b/game-server/app/servers/role/handler/roleHandler.ts @@ -1,12 +1,12 @@ import { STATUS } from '../../../consts/statusCode'; import { RoleModel } from './../../../db/Role'; import { HeroModel } from '../../../db/Hero'; -import { resResult, decodeIdCntArrayStr, parseGoodStr, reduceCe } from '../../../pubUtils/util'; -import {Application, BackendSession} from 'pinus'; +import { resResult, decodeIdCntArrayStr, parseGoodStr } from '../../../pubUtils/util'; +import {Application, BackendSession, pinus} from 'pinus'; import { handleCost } from '../../../services/rewardService'; import { getTitle, getTeraph, gameData, getScollByStar, getFriendLvByExp } from '../../../pubUtils/data'; import { SCHOOL, SCROLL } from '../../../pubUtils/dicParam'; -import { getTeraphAttr, getAtrrNameById } from '../../../consts/constModules/abilityConst' +import { getAtrrNameById } from '../../../consts/constModules/abilityConst' import { findIndex } from 'underscore'; import { SclResultInter, SclPosInter } from '../../../pubUtils/interface'; import { SchoolModel } from '../../../db/School'; @@ -79,11 +79,12 @@ export class RoleHandler { //爵位 async roleTitleLevelUp(msg: {}, session: BackendSession){ let roleId = session.get('roleId'); - let role = await RoleModel.findByRoleId(roleId); - let oldCe = role.ce; let sid: string = session.get('sid'); - let title = ++role.title; - let titleInfo = getTitle(role.title); + + let role = await RoleModel.findByRoleId(roleId); + + let { title } = role; + let titleInfo = getTitle(title + 1); if (!titleInfo) return resResult(STATUS.DIC_DATA_NOT_FOUND) if (titleInfo.lvLimited > role.lv) @@ -92,44 +93,47 @@ export class RoleHandler { let result = await handleCost(roleId, sid, consumes); if (!result) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); - await RoleModel.updateRoleInfo(roleId, { title }); - let {ce} = await calAllHeroCe( sid, roleId, HERO_SYSTEM_TYPE.TITLE, [title]); - return resResult(STATUS.SUCCESS, { roleId, title }); + + let update = { title: title + 1 } + role = await calAllHeroCe(HERO_SYSTEM_TYPE.TITLE, sid, roleId, update); + return resResult(STATUS.SUCCESS, { roleId, title: role.title }); } //神像强化 async roleTeraphStrengthen(msg: {id: number, count: number}, session: BackendSession){ let {id, count} = msg; let roleId = session.get('roleId'); - let role = await RoleModel.findByRoleId(roleId); let sid: string = session.get('sid'); - let index = findIndex(role.teraphs, {id}); + + let role = await RoleModel.findByRoleId(roleId); + let teraphs = role.teraphs; + let index = findIndex(teraphs, {id}); if (index < 0) return resResult(STATUS.WRONG_PARMS); - let teraph = role.teraphs[index]; - let teraphInfo = getTeraph(id, teraph.grade); - if (!teraphInfo) - return resResult(STATUS.DIC_DATA_NOT_FOUND) - let attrs = []; - for (let attrName in getTeraphAttr()) { - let attrNameMax = attrName+'Max'; - if (teraph[attrName] < teraphInfo[attrNameMax]) { - attrs.push(attrName); + let teraph = teraphs[index]; + let dicTeraph = getTeraph(id, teraph.grade); + if (!dicTeraph) + return resResult(STATUS.DIC_DATA_NOT_FOUND); + + let attrs = new Array(); // 可以强化的属性 + dicTeraph.mainAttrMax.forEach(( max, id) => { + let attrName = getAtrrNameById(id); + if (teraph[attrName] < max) { + attrs.push(id); } - } + }); + if (!attrs.length) return resResult(STATUS.ROLE_TERAPH_NOT_STRENGTHEN); - // 随机神像中的一条属性并检查道具是否足够 - let {attr, consumes} = checkTeraphMaterialEnough(count, attrs, teraphInfo, teraph); - for (let key in attr) { - teraph[key] += attr[key]; - role.globalCeAttr[key].fixUp += attr[key]; - } + + // 随机神像中的一条属性并检查道具是否足够,以及更新teraph + let { consumes} = checkTeraphMaterialEnough(count, attrs, dicTeraph, teraph); + let result = await handleCost(roleId, sid, consumes); if (!result) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); - await RoleModel.updateRoleInfo(roleId, { teraphs: role.teraphs, globalCeAttr: role.globalCeAttr}); - await calAllHeroCe( sid, roleId); + + role = await calAllHeroCe(HERO_SYSTEM_TYPE.TERAPH, sid, roleId, { teraphs }, [id]); return resResult(STATUS.SUCCESS, { roleId, teraphs: role.teraphs }); } @@ -137,34 +141,37 @@ export class RoleHandler { async roleTeraphQualityUp(msg: {id: number}, session: BackendSession){ let {id} = msg; let roleId = session.get('roleId'); - let role = await RoleModel.findByRoleId(roleId); let sid: string = session.get('sid'); - let index = findIndex(role.teraphs, {id}); + + let role = await RoleModel.findByRoleId(roleId); + let teraphs = role.teraphs; + let index = findIndex(teraphs, {id}); if (index < 0) return resResult(STATUS.WRONG_PARMS); - let teraph = role.teraphs[index]; + let teraph = teraphs[index]; let teraphInfo = getTeraph(id, teraph.grade); if (!teraphInfo) return resResult(STATUS.DIC_DATA_NOT_FOUND) - for (let attrName in getTeraphAttr()) { - if (teraph[attrName] != teraphInfo[attrName +'Max']) + + for(let [attrId, val] of teraph.attr) { + if (val < teraphInfo.mainAttrMax.get(attrId)) return resResult(STATUS.ROLE_TERAPH_NOT_QUILITY); - teraph[attrName] = 0; + + teraph.attr.set(attrId, 0); } - teraph.grade++; + teraph.grade ++; + + let nextTeraphInfo = getTeraph(id, teraph.grade) if (!nextTeraphInfo) - return resResult(STATUS.DIC_DATA_NOT_FOUND) + return resResult(STATUS.DIC_DATA_NOT_FOUND); + let consumes = teraphInfo.upGradeMaterial; let result = await handleCost(roleId, sid, consumes); if (!result) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH); - for (let {id, number} of nextTeraphInfo.assiAttrValue) { - let attrName = getAtrrNameById(id); - role.globalCeAttr[attrName].ratioUp += number; - } - await RoleModel.updateRoleInfo(roleId, { teraphs: role.teraphs, globalCeAttr: role.globalCeAttr}); - await calAllHeroCe(sid, roleId); + + role = await calAllHeroCe(HERO_SYSTEM_TYPE.TERAPH_UP, sid, roleId, { teraphs }, [id]); return resResult(STATUS.SUCCESS, { roleId, teraphs: role.teraphs }); } @@ -246,7 +253,7 @@ export class RoleHandler { } await SchoolModel.updateBySclAndPos(roleId, schoolId, positionId, { hid, isOpen }) - await calPlayerCeAndSave(sid, roleId, [], HERO_SYSTEM_TYPE.SCHOOL, [schoolId, hid, preHid]); + await calAllHeroCe(HERO_SYSTEM_TYPE.SCHOOL, sid, roleId, {}, [schoolId, hid, preHid]); return resResult(STATUS.SUCCESS, { schoolId, positionId, hid, preHid, isOpen @@ -294,7 +301,7 @@ export class RoleHandler { let { hid } = msg; - let curHero = await HeroModel.findByHidAndRole(hid, roleId, 'star colorStar quality scrollId scrollActive scrollStar scrollColorStar scrollQuality favour favourLv'); + let curHero = await HeroModel.findByHidAndRole(hid, roleId, 'hid star colorStar quality scrollId scrollActive scrollStar scrollColorStar scrollQuality favour favourLv connections attr ce'); if (!curHero) return resResult(STATUS.HERO_NOT_FIND); let dicHero = gameData.hero.get(hid); @@ -334,12 +341,67 @@ export class RoleHandler { let dicHeroScroll = getScollByStar(dicHero.quality, update.scrollStar, update.scrollQuality, update.scrollColorStar); update.scrollId = dicHeroScroll?dicHeroScroll.id: 0; - curHero = await HeroModel.updateHeroInfo(roleId, hid, update, 'hid scrollActive scrollId scrollStar scrollColorStar scrollQuality favour favourLv'); - await calPlayerCeAndSave(sid, roleId, [], HERO_SYSTEM_TYPE.SCROLL, [hid, favourLv]); + let hero = await calPlayerCeAndSave(HERO_SYSTEM_TYPE.SCROLL, sid, roleId, curHero, update); // 更新单个武将战力 + calAllHeroCe(HERO_SYSTEM_TYPE.SCROLL, sid, roleId, {}, [hid]); // 全局增加战力 return resResult(STATUS.SUCCESS, { - curHero + curHero: { + hid: hero.hid, + scrollActive: hero.scrollActive, + scrollId: hero.scrollId, + scrollStar: hero.scrollStar, + scrollColorStar: hero.scrollColorStar, + scrollQuality: hero.scrollQuality, + favour: hero.favour, + favourLv: hero.favourLv, + } }); } + + async debugPlayerTime(msg: { type: number }, session: BackendSession) { + let { type } = msg; + let roleId = session.get('roleId'); + let sid = session.get('sid'); + + if(type == 1) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest: true, + guestTime: 60 * 60, // 游客已体验时间 + hasAuthenticated: false, // 是否进行过实名认证 + isAdult: false, // 是否已成年 + todayPlayTime: 60 * 60, // 今天已游戏时长 + type: 1 + } ), [{uid: roleId, sid: sid}]); + } else if (type == 2) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest: false, + guestTime: 0, // 游客已体验时间 + hasAuthenticated: true, // 是否进行过实名认证 + isAdult: false, // 是否已成年 + todayPlayTime: 60 * 60, // 今天已游戏时长 + type: 2 + } ), [{uid: roleId, sid: sid}]); + } else if (type == 3) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest: false, + guestTime: 0, // 游客已体验时间 + hasAuthenticated: true, // 是否进行过实名认证 + isAdult: false, // 是否已成年 + todayPlayTime: 3 * 60 * 60, // 今天已游戏时长 + type: 3 + } ), [{uid: roleId, sid: sid}]); + } else if (type == 4) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest: false, + guestTime: 0, // 游客已体验时间 + hasAuthenticated: true, // 是否进行过实名认证 + isAdult: false, // 是否已成年 + todayPlayTime: 1.5 * 60 * 60, // 今天已游戏时长 + type: 4 + } ), [{uid: roleId, sid: sid}]); + } + + return resResult(STATUS.SUCCESS); + } } diff --git a/game-server/app/services/battleService.ts b/game-server/app/services/battleService.ts index f19acf10a..acff4446b 100644 --- a/game-server/app/services/battleService.ts +++ b/game-server/app/services/battleService.ts @@ -1,6 +1,6 @@ import { HeroModel } from './../db/Hero'; import { HangUpRecordModel } from './../db/HangUpRecord'; -import { ChannelService, pinus } from 'pinus'; +import { pinus } from 'pinus'; import { HANG_UP_CONSTS, TOWER_TASK_CONST, REDIS_KEY } from './../consts'; import { BattleRecordModel } from './../db/BattleRecord'; import { TowerRecordModel } from './../db/TowerRecord'; diff --git a/game-server/app/services/equipService.ts b/game-server/app/services/equipService.ts index 94abbff46..8e4b1495c 100644 --- a/game-server/app/services/equipService.ts +++ b/game-server/app/services/equipService.ts @@ -1,4 +1,4 @@ -import { mergeSameGoods } from '../pubUtils/util'; +import { mergeSameGoods, deepCopy } from '../pubUtils/util'; import { EquipModel } from "../db/Equip"; import { HeroModel, EPlace, HeroType } from "../db/Hero"; import { getHeroJob, getGoodById, gameData, getJewelById, getHeroEquipByClassId } from "../pubUtils/data"; @@ -77,7 +77,7 @@ export async function changeEquip(roleId: string, sid: string, equip: EquipType, return res; } } else if (!!hero) {//从穿戴装备的武将上卸下装备 - await takeOffEquipAndCalPlayerCe(roleId, sid, seqId, hero, id);//卸下装备并重算战力 + await takeOffEquipAndCalPlayerCe(roleId, sid, hero, equip, id);//卸下装备并重算战力 } } /** @@ -88,15 +88,12 @@ export async function changeEquip(roleId: string, sid: string, equip: EquipType, * @param hero * @param id */ -export async function takeOffEquipAndCalPlayerCe(roleId: string, sid: string, seqId: number, hero:HeroType, id: number ) { - let index = findIndex(hero.ePlace, { id }); - if (index < 0) - return; - await EquipModel.updateEquipInfo(seqId, { hid: 0 }); - hero.ePlace[index].equip = null; +export async function takeOffEquipAndCalPlayerCe(roleId: string, sid: string, hero:HeroType, equip: EquipType, id: number ) { let args = calEquipSeids(hero); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.EQUIP, args); - return { seqId, hid: 0}; + hero = await HeroModel.removeEquip(roleId, hero.hid, id, equip._id); + + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args); + return { seqId: equip.seqId, hid: 0}; } /** * 穿戴装备并重算战力 @@ -106,9 +103,10 @@ export async function takeOffEquipAndCalPlayerCe(roleId: string, sid: string, se * @param equip */ export async function dressEquip(roleId: string, sid: string, hero:HeroType, equip: EquipType) { - hero = await HeroModel.addEquip(roleId, hero.hid, equip.ePlaceId, equip._id); let args = calEquipSeids(hero); - await calPlayerCeAndSave(sid, roleId, [hero], HERO_SYSTEM_TYPE.EQUIP, args); + + hero = await HeroModel.addEquip(roleId, hero.hid, equip.ePlaceId, equip._id); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args); return { seqId: equip.seqId, hid: hero.hid }; } /** diff --git a/game-server/app/services/expeditionService.ts b/game-server/app/services/expeditionService.ts index d956367a5..37d3db932 100644 --- a/game-server/app/services/expeditionService.ts +++ b/game-server/app/services/expeditionService.ts @@ -3,9 +3,9 @@ import { ExpeditionPointModel } from '../db/ExpeditionPoint'; import Role, { RoleModel, RoleType } from '../db/Role'; import { PvpDefenseModel } from '../db/PvpDefense'; -import { getWarJsons, getGamedata, getExpeditionById } from '../pubUtils/gamedata'; -import { decodeStr, resResult, shouldRefresh } from '../pubUtils/util'; -import { EXPEDITION_CONST, HERO_CE_RATIO, getAttrCeRatio } from '../consts'; +import { getWarJsons, getGamedata } from '../pubUtils/gamedata'; +import { decodeStr, shouldRefresh } from '../pubUtils/util'; +import { EXPEDITION_CONST, HERO_CE_RATIO } from '../consts'; import { getAtrrNameById} from '../consts'; import { ExpeditionWarRecordModel } from '../db/ExpeditionWarRecord'; import { HeroType } from '../db/Hero'; @@ -75,7 +75,7 @@ export async function matchPlayers(roleId: string, scale: number, range: number, let result = resultRange[index]; let {roleId, heroes, defCe } = result; let role = result.role; - let { globalCeAttr } = role; + let { attr: roleAttrs } = role; enemyObj.enemyFrom = 1; enemyObj.enemyId = roleId; @@ -87,9 +87,9 @@ export async function matchPlayers(roleId: string, scale: number, range: number, let hero = heroes[heroIndex]; if(hero) { let h = hero.hero; - let { star, lv, ceAttr } = h; + let { star, lv, attr: heroAttrs } = h; let dicHero = gameData.hero.get(hero.actorId); - let newAttribute = getPlayerAttribute(ceAttr, globalCeAttr); + let newAttribute = getPlayerAttribute(heroAttrs, roleAttrs); let heroInfo = { actorId: hero.actorId, actorName: dicHero.name, @@ -127,10 +127,7 @@ export async function matchRobots(scale: number, myCe: number, robotCe: number, const { attribute } = json; let newAttribute = getRobotAttribute(attribute, myCe, robotCe, scale); - let ce = 0; - for(let attrName in newAttribute) { - ce += newAttribute[attrName] * getAttrCeRatio(attrName)||0; - } + let ce = newAttribute.calCelAndReduce(); enemyObj.enemies.push({...json, attribute: newAttribute, lv}); allCe += ce; } @@ -156,21 +153,6 @@ export async function getCEScaleAndRange(roleId: string, curDicExpedition: any) return {scale, range, lv: role.lv} } -// 远征表属性解码 -export function decodeWarJsonAttribute(attribute: string) { - let arr = decodeStr('attribute', attribute); - // 初始化 - let obj = {hp: 0, atk: 0, matk: 0, def: 0, mdef: 0, speed: 0, agi: 0, luk: 0, hit: 0, cri: 0, flee: 0, antCri: 0, damageIncrease: 0, damageDecrease: 0, defIngnore: 0, bloodSuck: 0} - - for(let {id, value} of arr) { - let field = getAtrrNameById(id); - if(field) { - obj[field] = value; - } - } - return obj -} - // 远征累计点数获取 export async function getPointRewardStatus(roleId: string, role?: Role) { if(!role) { diff --git a/game-server/app/services/playerCeService.ts b/game-server/app/services/playerCeService.ts index df4047c8f..0f7acd6d1 100644 --- a/game-server/app/services/playerCeService.ts +++ b/game-server/app/services/playerCeService.ts @@ -7,22 +7,26 @@ import { STATUS } from '../consts/statusCode'; import { resResult, reduceCe } from '../pubUtils/util'; import { calPlayerCeAndSave as pubCalPlayerCeAndSave, reCalAllHeroCe } from '../pubUtils/playerCe'; -import { HeroType } from '../db/Hero'; +import Hero, { HeroType, HeroUpdate } from '../db/Hero'; import { defaultHeroes } from './pvpService'; +import { RoleUpdate } from '../db/Role'; //修改并下发战力 -export async function calPlayerCeAndSave(sid: string, roleId: string, heros: Array, type?: number, args?: Array) { - let {role, pushHeros, topLineupCe} = await pubCalPlayerCeAndSave(roleId, heros, type, args); +export async function calPlayerCeAndSave(type: number, sid: string, roleId: string, originHero: HeroType, update: HeroUpdate, args?: Array) { + let {role, pushHeros, topLineupCe, hero} = await pubCalPlayerCeAndSave(type, roleId, originHero, update, args); + console.log(JSON.stringify(pushHeros)) //下发战力 let uids = [{ uid: roleId, sid }]; pinus.app.get('channelService').pushMessageByUids('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: reduceCe(role.ce) , heros: pushHeros, topLineupCe: reduceCe(topLineupCe) }), uids); defaultHeroes(role); - return heros; + return hero; } -export async function calAllHeroCe(sid: string, roleId: string, type?:number, args?:Array) { - let {ce, pushHeros, topLineupCe }= await reCalAllHeroCe(roleId, type, args); - let uids = [{ uid: roleId, sid }]; - pinus.app.get('channelService').pushMessageByUids('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: reduceCe(ce), heros: pushHeros, topLineupCe: reduceCe(topLineupCe) }), uids); - return {ce: reduceCe(ce)}; +export async function calAllHeroCe(type:number, sid: string, roleId: string, update: RoleUpdate, args?:Array) { + let {role, ce, pushHeros, topLineupCe } = await reCalAllHeroCe(type, roleId, update, args); + if(pushHeros.length > 0) { + let uids = [{ uid: roleId, sid }]; + pinus.app.get('channelService').pushMessageByUids('onPlayerCeUpdate', resResult(STATUS.SUCCESS, { ce: reduceCe(ce), heros: pushHeros, topLineupCe: reduceCe(topLineupCe) }), uids); + } + return role; } \ No newline at end of file diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index 36787b48f..ea8e7ddc4 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -5,7 +5,7 @@ import { PVP_HERO_POS, ROBOT_NAME, REDIS_KEY, PVP_CONST, HERO_CE_RATIO } from '. import { setPvpDefResult } from '../services/timeTaskService'; import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent"; import { getRandomIndexByLen, genCode, getRandomByLen, shouldRefresh, reduceCe, getChineseName } from '../pubUtils/util'; -import { oppPlayersInter, pvpEndParamInter, Attributes } from '../pubUtils/interface'; +import { oppPlayersInter, pvpEndParamInter } from '../pubUtils/interface'; import { RankParam } from '../domain/rank'; import { gameData, getPLvByScore } from "../pubUtils/data"; import { PVP } from '../pubUtils/dicParam'; @@ -14,7 +14,7 @@ import { setRank, getMyRank, getFieldByRank } from './redisService'; import { nowSeconds, checkTodayTime } from '../pubUtils/timeUtil'; import { HeroesRecord } from '../db/PvpRecord'; import { HeroModel, HeroType } from '../db/Hero'; -import { CeAttrNumber, CeAttr, CeAttrRole, MainAttrNumber } from '../domain/roleField/attribute'; +import { MainAttrNumber, Attribute, CeAttrData, CeAttrDataRole } from '../domain/roleField/attribute'; import { PvpEnemies, PvpHeroInfo, PvpOtherHeroes } from '../domain/dbGeneral'; import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; import { findWhere, findIndex } from 'underscore'; @@ -213,7 +213,7 @@ async function generPlayerOppHis(pvpdefense: PvpDefenseType, mapWarJson: DicWarJ let heroInfo = new PvpHeroInfo(); heroInfo.setHeroInfo(dbHero); heroInfo.setOutIndex(h.order); - let attribute = getPlayerAttribute(dbHero.ceAttr, role.globalCeAttr); + let attribute = getPlayerAttribute(dbHero.attr, role.attr); heroInfo.setAttribute(attribute); let enemy = new PvpEnemies(warJson, heroInfo, hs?hs.score: 0); heroes.push(enemy); @@ -491,16 +491,13 @@ export async function findPvpDefAllByRoleId(roleId: string) { * @param enemyCe 出兵表对手战力 * @param ratio 系数 */ -export function getRobotAttribute(attribute: Attributes, ce: number, enemyCe: number, ratio: number) { +export function getRobotAttribute(attribute: {id: number, val: number}[], ce: number, enemyCe: number, ratio: number) { - let newAttribute = new CeAttrNumber(); - for(let attrName in newAttribute) { - newAttribute[attrName] = Math.floor(attribute[attrName] * ce / enemyCe * ratio); - } - newAttribute['speed'] = 0; - newAttribute['ap'] = 0; + let newAttribute = new Attribute(); + newAttribute.setByWarJson(attribute, ce / enemyCe * ratio); + let attrJson = newAttribute.getReduceAttributes(); - return newAttribute; + return attrJson; } /** @@ -508,18 +505,12 @@ export function getRobotAttribute(attribute: Attributes, ce: number, enemyCe: nu * @param ceAttr hero表的ceAttr * @param globalCeAttr role表中的globalCeAttr */ -export function getPlayerAttribute(ceAttr: CeAttr, globalCeAttr: CeAttrRole) { - let newAttribute = new CeAttrNumber(); - for(let attrName in newAttribute) { - let { base, ratioUp, fixUp, equipUp } = ceAttr[attrName]; - let { ratioUp: ratioUp2, fixUp: fixUp2 } = globalCeAttr[attrName]; - let result = base * ( HERO_CE_RATIO + ratioUp + ratioUp2) + (fixUp + fixUp2 + equipUp) * HERO_CE_RATIO; - newAttribute[attrName] += reduceCe(result); - } - newAttribute['speed'] = 0; - newAttribute['ap'] = 0; +export function getPlayerAttribute(heroAttrs: CeAttrData[] = [], roleAttrs: CeAttrDataRole[] = []) { + let newAttribute = new Attribute(); + newAttribute.setByDbData(roleAttrs, heroAttrs); + let attrJson = newAttribute.getReduceAttributes(); - return newAttribute; + return attrJson; } /** @@ -527,8 +518,8 @@ export function getPlayerAttribute(ceAttr: CeAttr, globalCeAttr: CeAttrRole) { * @param ceAttr * @param globalCeAttr */ -export function getPlayerMainAttribute(ceAttr: CeAttr, globalCeAttr: CeAttrRole) { - let attribute = getPlayerAttribute(ceAttr, globalCeAttr); +export function getPlayerMainAttribute(heroAttrs: CeAttrData[], roleAttrs: CeAttrDataRole[]) { + let attribute = getPlayerAttribute(heroAttrs, roleAttrs); let mainAttributes = new MainAttrNumber(attribute); return mainAttributes; diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index e856fe0ff..0073ef6e7 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -10,6 +10,7 @@ import { SystemConfigModel } from '../db/SystemConfig'; import { GuildRankParam, GuildLeader, RankParam } from '../domain/rank'; import { GuildModel } from '../db/Guild'; import { comBtlRanges } from '../pubUtils/gamedata'; +import { stringify } from 'querystring'; /** * 在服务重新启动时,将信息存入redis */ @@ -366,8 +367,8 @@ export async function clearChannelServers() { * @param userCode user表唯一字符串标识 * @param sid connector服的那个sid */ -export async function roleLogin(roleId: string, userCode: string, sid: string) { - let param = { userCode, sid }; +export async function roleLogin(roleId: string, userCode: string, sid: string, pkgName: string) { + let param = { userCode, sid, pkgName }; return await redisClient().hsetAsync(REDIS_KEY.ONLINE_USERS, roleId, JSON.stringify(param)); } @@ -400,7 +401,8 @@ export async function getRoleOnlineInfo(roleId: string) { return { isOnline: true, userCode: result.userCode, - sid: result.sid + sid: result.sid, + pkgName: result.pkgName } } catch(e) { return { isOnline: false } @@ -414,8 +416,20 @@ export async function getRoleOnlineInfo(roleId: string) { * 获得所有在线的玩家 */ export async function getAllOnlineRoles() { + const client: Redis.RedisClient = pinus.app.get('redis'); let allRoles = await redisClient().hgetallAsync(REDIS_KEY.ONLINE_USERS); - return allRoles; + let result = new Array<{roleId: string, userCode: string, sid: string, pkgName: string}>(); + for(let roleId in allRoles) { + try{ + let param = JSON.parse(allRoles[roleId]); + if(param) { + result.push({ roleId, userCode: param.userCode, sid: param.sid, pkgName: param.pkgName }); + } + } catch(e) { + continue; + } + } + return result; } export async function resetPvpRanks() { diff --git a/game-server/app/services/redlockCacheService.ts b/game-server/app/services/redlockCacheService.ts index d1cfb177a..51c85bd67 100644 --- a/game-server/app/services/redlockCacheService.ts +++ b/game-server/app/services/redlockCacheService.ts @@ -9,7 +9,7 @@ interface UserCache { var userCacheMap = new Map(); export function init() { - scheduleJob("0/5 * * * * *", clearDirtyData, {name:'clearDirtyData'});//每个5秒钟,释放redis锁 + scheduleJob('clearDirtyData', "0/5 * * * * *", clearDirtyData);//每个5秒钟,释放redis锁 } /** * 释放锁 diff --git a/game-server/app/services/rewardService.ts b/game-server/app/services/rewardService.ts index 078c687af..375309d60 100644 --- a/game-server/app/services/rewardService.ts +++ b/game-server/app/services/rewardService.ts @@ -156,7 +156,7 @@ export async function addItems(roleId: string, roleName: string, sid: string, go } } if (!!skinInfos.length) { - calAllHeroCe(sid, roleId, HERO_SYSTEM_TYPE.ADD_SKIN, addSkinIds) + calAllHeroCe(HERO_SYSTEM_TYPE.ADD_SKIN, sid, roleId, {}, addSkinIds); pinus.app.get('channelService').pushMessageByUids('onHeroSkinChange', resResult(STATUS.SUCCESS, {skinInfos}), uids); } return showItems; diff --git a/game-server/app/services/roleService.ts b/game-server/app/services/roleService.ts index 8be3c531c..b8f2c0f64 100644 --- a/game-server/app/services/roleService.ts +++ b/game-server/app/services/roleService.ts @@ -3,44 +3,47 @@ import { Channel } from 'pinus'; import { getRandNum, getRandomArr } from '../pubUtils/util'; import { TERAPH_RANDOM } from "../consts/consts"; import { indexOf } from 'underscore'; +import { DicTeraph } from '../pubUtils/dictionary/DicTeraph'; +import { Teraph } from '../db/Role'; const TERAPH_STRENGTHEN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; /** * 计算强化次数和消耗 * @param count 强化次数 - * @param attrNames 可以强化的属性名字 + * @param attrs 可以强化的属性名字 * @param teraphInfo 字典表对应的神像信息 - * @param teraph + * @param teraph 数据库内单个神像信息 */ -export function checkTeraphMaterialEnough(count: number, attrNames:Array, teraphInfo: any, teraph: any) { - let res = {}; +export function checkTeraphMaterialEnough(count: number, attrs:number[], teraphInfo: DicTeraph, teraph: Teraph) { let consumes = []; let times = 0; if (count < 10) { for (let i = 0; i < count; i++) { - if (!attrNames.length) { + if (!attrs.length) { break; } - let num = getRandNum(TERAPH_RANDOM.MIN, TERAPH_RANDOM.MAX); - let arr = getRandomArr(attrNames, num) + let num = getRandNum(TERAPH_RANDOM.MIN, TERAPH_RANDOM.MAX); // 强化时随机增加 2-4 属性 + let arr: number[] = getRandomArr(attrs, num); // 随机出的属性id let critical = getRandNum(0, 100);//属性暴击率 - let criEffect = 1; + let criEffect = 1; // 暴击效果 if (critical <= teraphInfo.criRate) criEffect = teraphInfo.criEffect; - for (let attrName of arr) { - let attrNameMax = attrName+'Max'; - res[attrName] = teraphInfo[attrName] * criEffect; - if (teraph[attrName] + res[attrName] > teraphInfo[attrNameMax]) { - res[attrName] = teraphInfo[attrNameMax] - teraph[attrName]; - let attrIndex = indexOf(attrNames, attrName); - attrNames.splice(attrIndex, 1); + for (let attrId of arr) { + let val = teraph.attr.get(attrId); // 已有的强化值 + val += teraphInfo.mainAttrUp.get(attrId) * criEffect; + let max = teraphInfo.mainAttrMax.get(attrId); + if(val > max) { + val = max; + let attrIndex = attrs.indexOf(attrId); + attrs.splice(attrIndex, 1); } + teraph.attr.set(attrId, val); } times++; } } else if (count == 10){ let criticalArrTimes = getRandomArr(TERAPH_STRENGTHEN, 2);//10次中随机2次发生暴击 for (let item of TERAPH_STRENGTHEN) { - if (!attrNames.length) { + if (!attrs.length) { break; } let criEffect = 1; @@ -49,24 +52,27 @@ export function checkTeraphMaterialEnough(count: number, attrNames:Array, t criEffect = teraphInfo.criEffect;//本次是暴击 item 在 criticalArrTimes 中 } let num = getRandNum(TERAPH_RANDOM.MIN, TERAPH_RANDOM.MAX); - let arr = getRandomArr(attrNames, num); - for (let attrName of arr) { - res[attrName] = (res[attrName]||0) + teraphInfo[attrName] * criEffect; - let attrNameMax = attrName+'Max'; - if (teraph[attrName] + res[attrName] > teraphInfo[attrNameMax]) { - res[attrName] = teraphInfo[attrNameMax] - teraph[attrName]; - let attrIndex = indexOf(attrNames, attrName); - attrNames.splice(attrIndex, 1); + let arr: number[] = getRandomArr(attrs, num); + for (let attrId of arr) { + let val = teraph.attr.get(attrId); // 已有的强化值 + val += teraphInfo.mainAttrUp.get(attrId) * criEffect; + let max = teraphInfo.mainAttrMax.get(attrId); + + if(val > max) { + val = max; + let attrIndex = attrs.indexOf(attrId); + attrs.splice(attrIndex, 1); } + teraph.attr.set(attrId, val); } times++; } } //计算消耗 for (let {id, count} of teraphInfo.upMaterial) { - consumes.push({ id, count: count*times}); + consumes.push({ id, count: count * times}); } - return {attr: res, consumes}; + return { consumes}; } /** * diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index 23cfb5262..43534fcd6 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -3,12 +3,12 @@ import { scheduleJob, Job } from 'node-schedule'; import { SystemConfigModel } from '../db/SystemConfig'; import PvpDefenseType,{ PvpDefenseModel } from '../db/PvpDefense'; import { PVP } from '../pubUtils/dicParam'; -import { nowSeconds, getTodayZeroPoint } from '../pubUtils/timeUtil'; +import { nowSeconds, getTodayZeroPoint, getAge } from '../pubUtils/timeUtil'; import { getPvpGkWarIds, getPvpRankRewards, getPvpHeroRewards, getResultMaxRank } from '../pubUtils/data'; -import { deepCopy, getRandomArr, resResult } from '../pubUtils/util'; +import { deepCopy, getRandomArr, resResult, shouldRefresh } from '../pubUtils/util'; import { getLvByScore } from './pvpService'; -import { getMyRank, setRank, resetPvpRanks } from './redisService'; -import { MAIL_TYPE, REDIS_KEY } from '../consts'; +import { getMyRank, setRank, resetPvpRanks, getAllOnlineRoles } from './redisService'; +import { MAIL_TYPE, REDIS_KEY, ADULT_AGE, GUEST_MAX_TIME, ADDICTION_PREVENTION_CODE } from '../consts'; import { RankParam } from '../domain/rank'; import { RoleModel } from '../db/Role'; import { MailModel, MailType } from '../db/Mail'; @@ -18,6 +18,8 @@ import { PvpSeasonResultModel } from '../db/PvpSeasonResult'; import { settleGuildWeekly } from './guildService'; import { STATUS } from '../consts/statusCode'; import { getMailContent, sendMail } from './mailService'; +import { reportOnline } from '../pubUtils/httpUtil'; +import User, { UserModel } from '../db/User'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; const SETTLE_DIFF = 29 * 60; @@ -34,7 +36,7 @@ export async function init() { let seasonEndTime = 0; let systemConfig = await SystemConfigModel.findSystemConfig();//系统全局参数表 if (!systemConfig) { - console.log('create season seasonNum = '+ systemConfig.seasonNum); + console.log('create season seasonNum = '+ systemConfig?.seasonNum); let warIds = getPvpGkWarIds(); let warId = warIds[0]; seasonEndTime = PVP.PVP_SEASON_DAYS * PER_DAY + getTodayZeroPoint(); @@ -50,21 +52,27 @@ export async function init() { } } let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' });//设置实际赛季结算时间 + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule);//设置实际赛季结算时间 - seasonEndTimeJobId = scheduleJob(seasonEndTime* PER_SECOND, resetPvpRanks, { name: 'resetRank' });//由于24之后,才展示结算之后的信息,为保排行榜信息一致性,设置实际重置排行榜的时间为12点 + seasonEndTimeJobId = scheduleJob('resetRank', seasonEndTime * PER_SECOND, resetPvpRanks);//由于24之后,才展示结算之后的信息,为保排行榜信息一致性,设置实际重置排行榜的时间为12点 warJobId = scheduleJob("0 0 0 * * 1", resetPvpWarId);//每周1零点重置地图 await resetPvpRanks();//服务器重启,重置排行榜的信息 // 周功勋结算任务 - guildWeeklyJobId = scheduleJob('0 0 0 * * 1', settleGuildWeekly, { name: 'settleGuildWeekly' }); + guildWeeklyJobId = scheduleJob('settleGuildWeekly', '0 0 0 * * 1', settleGuildWeekly); + scheduleJob('reportOnline', '0 0/5 * * * *', reportOnlineSchedule) } + +function setPvpSeasonSchdule() { + setPvpSeasonResult(); +} + /** * pvp定时任务赛季结算 * @param obj */ -export async function setPvpSeasonResult(obj:{ name:string, notSetNext?: boolean, notPush?: boolean }) { +export async function setPvpSeasonResult(obj?:{ name:string, notSetNext?: boolean, notPush?: boolean }) { console.log('exce setPvpSeasonResult'+ obj?.name); let { seasonNum, seasonEndTime, oldSeasonEndTime } = await setNextPvpTime(obj?.notSetNext);//设置下个结算任务 let resultMaxRank = getResultMaxRank();//根据排行榜的奖励表,获得最大排名挡位的最小值,其余不在结算中结算的玩家按照最大排名挡位在登录或进入pvp时结算 @@ -214,8 +222,8 @@ async function setNextPvpTime(notSetNext: boolean) { seasonEndTime = (PVP.PVP_SEASON_DAYS + 1) * PER_DAY + getTodayZeroPoint(); await SystemConfigModel.updateSeason(seasonEndTime, oldSeasonEndTime); let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' }); - seasonEndTimeJobId = scheduleJob(seasonEndTime* PER_SECOND, resetPvpRanks, { name: 'resetRank' }); + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule); + seasonEndTimeJobId = scheduleJob('resetRank', seasonEndTime* PER_SECOND, resetPvpRanks); return { seasonEndTime, seasonNum: seasonNum + 1, oldSeasonEndTime }; } @@ -254,6 +262,51 @@ export async function resetPvpSeasonTime(hour: number) { } let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; console.log('settleTime = ' + settleTime) - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' }); + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule); return { seasonEndTime, seasonNum }; +} + + +export async function reportOnlineSchedule() { + let allRoles = await getAllOnlineRoles(); + console.log('reportOnlineSchedule all roles count: ', allRoles.length) + for(let { roleId, userCode, sid, pkgName } of allRoles) { + let result = await reportOnline(userCode, pkgName); // 连接sdk + if(!result || result.code == -1) continue; + + let user = await UserModel.findUserByUserCode(userCode); + if(!user) continue; + let { reportTime = new Date(), lastLoginTime = new Date(), guestTime, isGuest, hasAuthenticated, birthday } = user; + + let age = getAge(birthday); + let isAdult = age >= ADULT_AGE; + + if(result.code != ADDICTION_PREVENTION_CODE.SUCCESS) { // 未成年人防沉迷 + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest, + guestTime, // 游客已体验时间 + hasAuthenticated, // 是否进行过实名认证 + isAdult, // 是否已成年 + todayPlayTime: result.total, // 今天已游戏时长 + type: result.code + } ), [{uid: roleId, sid: sid}]); + } else { + let lastTime = lastLoginTime > reportTime? lastLoginTime.getTime(): reportTime.getTime(); + let guestTimeInc = Math.floor((Date.now() - lastTime)/1000); + user = await UserModel.updatePlayTime(userCode, guestTimeInc, result.total); // 记录时间 + + guestTime = user.guestTime; + if (isGuest && guestTime > GUEST_MAX_TIME) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest, + guestTime, // 游客已体验时间 + hasAuthenticated, // 是否进行过实名认证 + isAdult, // 是否已成年 + todayPlayTime: result.total, // 今天已游戏时长 + type: ADDICTION_PREVENTION_CODE.GUEST, + } ), [{uid: roleId, sid: sid}]); + } + } + + } } \ No newline at end of file diff --git a/game-server/config.js b/game-server/config.js index 9245f0435..94c26d348 100644 --- a/game-server/config.js +++ b/game-server/config.js @@ -7,7 +7,7 @@ function main (){ let env = args[0]; if(args[0] == 'stable') { env = 'production'; - } + } let configObject = { env: env diff --git a/game-server/config/database.ts b/game-server/config/database.ts index 1406d714e..8318bb78c 100644 --- a/game-server/config/database.ts +++ b/game-server/config/database.ts @@ -1,19 +1,28 @@ module.exports = { 'development': { 'mongo': 'mongodb://127.0.0.1/zyz', - 'redis': '127.0.0.1' + 'redis': '127.0.0.1', + 'redispw': 'zyz_2020' }, 'production': { 'mongo': 'mongodb://dbop:zyzdbopbantu@dds-8vbdb47c6fb58a541.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vbdb47c6fb58a542.mongodb.zhangbei.rds.aliyuncs.com:3717/zyz?replicaSet=mgset-500808098', - 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com' + 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com', + 'redispw': 'zyz_2020' }, 'alpha': { 'mongo': 'mongodb://dbop:zyzdbopbantu@dds-8vbdb47c6fb58a541.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vbdb47c6fb58a542.mongodb.zhangbei.rds.aliyuncs.com:3717/zyz?replicaSet=mgset-500808098', - 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com' + 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com', + 'redispw': 'zyz_2020' }, 'dev': { 'mongo': 'mongodb://dbop:zyzdbopbantu@dds-8vbdb47c6fb58a541.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vbdb47c6fb58a542.mongodb.zhangbei.rds.aliyuncs.com:3717/zyz?replicaSet=mgset-500808098', - 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com' + 'redis': 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com', + 'redispw': 'zyz_2020' + }, + 'isbn': { + 'mongo': 'mongodb://root:Bantus123@dds-8vb74337eab84d641.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vb74337eab84d642.mongodb.zhangbei.rds.aliyuncs.com:3717/admin?replicaSet=mgset-504694158', + 'redis': 'r-8vbekkbb3z8ru2ckuj.redis.zhangbei.rds.aliyuncs.com', + 'redispw': 'zyz_isbn_2021' } }; \ No newline at end of file diff --git a/game-server/config/isbn/log4js.pro.ts b/game-server/config/isbn/log4js.pro.ts new file mode 100644 index 000000000..6f40a7e00 --- /dev/null +++ b/game-server/config/isbn/log4js.pro.ts @@ -0,0 +1,170 @@ +module.exports = { + 'appenders': { + 'console': { + 'type': 'console' + }, + 'logger': { + 'type': 'file', + 'filename': '${opts:base}/logs/logger.log', + 'pattern': 'connector', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'log': { + 'type': 'file', + 'filename': '${opts:base}/logs/log.log', + 'pattern': 'connector', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'con-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/con-log-${opts:serverId}.log', + 'pattern': 'connector', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'forward-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/forward-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-debug': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-debug-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'crash-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/crash.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'admin-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-default.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'error': { + 'type': 'file', + 'filename': '${opts:base}/logs/error.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-admin': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-rpc': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-rpc-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + } + }, + + 'categories': { + 'default': { + 'appenders': ['console'], + 'level': 'debug' + }, + 'pinus': { + 'appenders': ['console', 'pinus'], + 'level': 'debug' + }, + 'con-log': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'rpc-log': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'forward-log': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'rpc-debug': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'crash-log': { + 'appenders': ['console', 'crash-log'], + 'level': 'debug' + }, + 'admin-log': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'pinus-admin': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'pinus-rpc': { + 'appenders': ['console', 'log'], + 'level': 'debug' + }, + 'logger': { + 'appenders': ['console', 'logger'], + 'level': 'error' + } + }, + + 'prefix': '${opts:serverId} ', + 'replaceConsole': true, + 'lineDebug': false, + 'errorStack': true +}; diff --git a/game-server/config/isbn/log4js.ts b/game-server/config/isbn/log4js.ts new file mode 100644 index 000000000..88878c40d --- /dev/null +++ b/game-server/config/isbn/log4js.ts @@ -0,0 +1,134 @@ +module.exports = { + 'appenders': { + 'console': { + 'type': 'console' + }, + 'con-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/con-log-${opts:serverId}.log', + 'pattern': 'connector', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'forward-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/forward-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-debug': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-debug-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'crash-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/crash.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'admin-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-admin': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-rpc': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-rpc-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + } + }, + + 'categories': { + 'default': { + 'appenders': ['console', 'pinus'], + 'level': 'debug' + }, + 'con-log': { + 'appenders': ['con-log'], + 'level': 'debug' + }, + 'rpc-log': { + 'appenders': ['rpc-log'], + 'level': 'debug' + }, + 'forward-log': { + 'appenders': ['forward-log'], + 'level': 'debug' + }, + 'rpc-debug': { + 'appenders': ['rpc-debug'], + 'level': 'debug' + }, + 'crash-log': { + 'appenders': ['crash-log'], + 'level': 'debug' + }, + 'admin-log': { + 'appenders': ['admin-log'], + 'level': 'debug' + }, + 'pinus-admin': { + 'appenders': ['pinus-admin'], + 'level': 'debug' + }, + 'pinus-rpc': { + 'appenders': ['pinus-rpc'], + 'level': 'debug' + }, + + }, + + 'prefix': '${opts:serverId} ', + 'replaceConsole': true, + 'lineDebug': false, + 'errorStack': true +}; diff --git a/game-server/config/master.ts b/game-server/config/master.ts index 969a78ee8..e716b4e8d 100644 --- a/game-server/config/master.ts +++ b/game-server/config/master.ts @@ -18,5 +18,10 @@ module.exports = { 'id': 'master-server-1', 'host': '127.0.0.1', 'port': 3005 + }, + 'isbn': { + 'id': 'master-server-1', + 'host': '127.0.0.1', + 'port': 3005 } }; \ No newline at end of file diff --git a/game-server/config/redis.ts b/game-server/config/redis.ts index 8fa9fb20f..586a82176 100644 --- a/game-server/config/redis.ts +++ b/game-server/config/redis.ts @@ -63,11 +63,11 @@ declare module 'redis' { } } -export function connectRedis(redisArr: string) { +export function connectRedis(redisArr: string, redisPw: string) { // 创建 redis 连接 const oldRedisClient = Redis.createClient(6379, redisArr, {detect_buffers: true}); - oldRedisClient.auth('zyz_2020', (err, reply) => { + oldRedisClient.auth(redisPw, (err, reply) => { if (err) { console.log('redis err', err); } else { diff --git a/game-server/config/serverProtos.ts b/game-server/config/serverProtos.ts index f8c5370f7..0f272ccb1 100644 --- a/game-server/config/serverProtos.ts +++ b/game-server/config/serverProtos.ts @@ -21,8 +21,9 @@ module.exports = { "message Hero": { 'required uInt32 hid': 1, 'required uInt32 ce': 2, + 'required sInt32 incHeroCe': 3, }, - 'required uInt32 ce': 1, + 'required sInt32 ce': 1, 'repeated Hero heros': 2, 'required uInt32 topLineupCe': 3 }, diff --git a/game-server/config/servers.ts b/game-server/config/servers.ts index 7f270589e..2578c730b 100644 --- a/game-server/config/servers.ts +++ b/game-server/config/servers.ts @@ -145,5 +145,37 @@ module.exports = { 'systimer': [ {'id': 'systimer-server-1', 'host': '127.0.0.1', 'port': 6056, "args": " --inspect=9233"} ] + }, + 'isbn': { + 'connector': [ + {'id': 'connector-server-1', 'port': 4050, 'clientHost': 'zyz_isbn.trgame.cn', 'host': '127.0.0.1', 'clientPort': 3050, 'frontend': true}, + {'id': 'connector-server-2', 'port': 4051, 'clientHost': 'zyz_isbn.trgame.cn', 'host': '127.0.0.1', 'clientPort': 3051, 'frontend': true}, + {'id': 'connector-server-3', 'port': 4052, 'clientHost': 'zyz_isbn.trgame.cn', 'host': '127.0.0.1', 'clientPort': 3052, 'frontend': true} + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '127.0.0.1', 'port': 6050}, + ], + 'role': [ + {'id': 'role-server-1', 'host': '127.0.0.1', 'port': 6053} + ], + 'battle': [ + {'id': 'battle-server-1', 'host': '127.0.0.1', 'port': 6054} + ], + 'gate': [ + {'id': 'gate-server-1', 'host': '127.0.0.1', 'clientHost': 'zyz_isbn.trgame.cn', 'clientPort': 3014, 'frontend': true}, + { + 'id': 'gate-server-2', + 'host': '127.0.0.1', + 'clientHost': 'zyz_isbn.trgame.cn', + 'clientPort': 3015, + 'frontend': true + } + ], + 'gm': [ + {'id': 'gm-server-1', 'host': '127.0.0.1', 'port': 6055} + ], + 'systimer': [ + {'id': 'systimer-server-1', 'host': '127.0.0.1', 'port': 6056} + ] } }; diff --git a/game-server/config/servers_multi_ser.ts b/game-server/config/servers_multi_ser.ts index c4efa7bd2..a1da4a2e1 100644 --- a/game-server/config/servers_multi_ser.ts +++ b/game-server/config/servers_multi_ser.ts @@ -41,5 +41,20 @@ module.exports = { 'gate': [ {'id': 'gate-server-1', 'host': '127.0.0.1', 'clientPort': 3014, 'frontend': true} ] + }, + 'isbn': { + 'connector': [ + {'id': 'connector-server-1', 'host': '127.0.0.1', 'port': 4050, 'clientPort': 3050, 'frontend': true}, + {'id': 'connector-server-2', 'host': '127.0.0.1', 'port': 4051, 'clientPort': 3051, 'frontend': true}, + {'id': 'connector-server-3', 'host': '127.0.0.1', 'port': 4052, 'clientPort': 3052, 'frontend': true} + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '127.0.0.1', 'port': 6050}, + {'id': 'chat-server-2', 'host': '127.0.0.1', 'port': 6051}, + {'id': 'chat-server-3', 'host': '39.100.68.60', 'port': 6052} + ], + 'gate': [ + {'id': 'gate-server-1', 'host': '127.0.0.1', 'clientPort': 3014, 'frontend': true} + ] } }; diff --git a/game-server/package-lock.json b/game-server/package-lock.json index 565fe14f6..98fd8071d 100644 --- a/game-server/package-lock.json +++ b/game-server/package-lock.json @@ -67,6 +67,11 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, "@types/chai": { "version": "4.2.14", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz", @@ -121,6 +126,15 @@ "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-8.10.54.tgz?cache=0&sync_timestamp=1595281257528&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-8.10.54.tgz", "integrity": "sha1-HIjrJTrBIQ8aWHaVP7cPfMSShAI=" }, + "@types/node-schedule": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-1.3.1.tgz", + "integrity": "sha512-xAY/ZATrThUkMElSDfOk+5uXprCrV6c6GQ5gTw3U04qPS6NofE1dhOUW+yrOF2UyrUiAax/Zc4WtagrbPAN3Tw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/redis": { "version": "2.8.25", "resolved": "https://registry.npm.taobao.org/@types/redis/download/@types/redis-2.8.25.tgz", @@ -129,6 +143,26 @@ "@types/node": "*" } }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/request-promise": { + "version": "4.1.47", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.47.tgz", + "integrity": "sha512-eRSZhAS8SMsrWOM8vbhxFGVZhTbWSJvaRKyufJTdIf4gscUouQvOBlfotPSPHbMR3S7kfkyKbhb1SWPmQdy3KQ==", + "requires": { + "@types/bluebird": "*", + "@types/request": "*" + } + }, "@types/socket.io": { "version": "2.1.10", "resolved": "https://registry.npm.taobao.org/@types/socket.io/download/@types/socket.io-2.1.10.tgz", @@ -138,6 +172,11 @@ "@types/node": "*" } }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, "@types/underscore": { "version": "1.10.24", "resolved": "https://registry.npm.taobao.org/@types/underscore/download/@types/underscore-1.10.24.tgz", @@ -256,6 +295,11 @@ "resolved": "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz", "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz", @@ -520,6 +564,14 @@ "resolved": "https://registry.npm.taobao.org/colors/download/colors-1.0.3.tgz", "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "3.0.2", "resolved": "https://registry.npm.taobao.org/commander/download/commander-3.0.2.tgz?cache=0&sync_timestamp=1595168120323&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-3.0.2.tgz", @@ -639,6 +691,11 @@ "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -817,6 +874,16 @@ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npm.taobao.org/fs-extra/download/fs-extra-8.1.0.tgz", @@ -2177,6 +2244,16 @@ "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, "random-to": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/random-to/-/random-to-0.0.2.tgz", @@ -2285,6 +2362,25 @@ "resolved": "https://registry.npm.taobao.org/regexp-clone/download/regexp-clone-1.0.0.tgz", "integrity": "sha1-Ii25Z2IydwViYLmSYmNUoEzpv2M=" }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", @@ -2532,6 +2628,11 @@ "resolved": "https://registry.npm.taobao.org/stack-trace/download/stack-trace-0.0.10.tgz?cache=0&sync_timestamp=1575992264808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstack-trace%2Fdownload%2Fstack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "stream-pkg": { "version": "0.0.5", "resolved": "https://registry.npm.taobao.org/stream-pkg/download/stream-pkg-0.0.5.tgz", @@ -2676,6 +2777,15 @@ "is-number": "^7.0.0" } }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, "ts-node": { "version": "8.10.2", "resolved": "https://registry.npm.taobao.org/ts-node/download/ts-node-8.10.2.tgz?cache=0&sync_timestamp=1590685779800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fts-node%2Fdownload%2Fts-node-8.10.2.tgz", diff --git a/game-server/package.json b/game-server/package.json index 855d10c35..9fa5f1eb3 100644 --- a/game-server/package.json +++ b/game-server/package.json @@ -24,6 +24,7 @@ "@types/mongoose": "^5.7.36", "@types/node": "8.10.54", "@types/redis": "^2.8.25", + "@types/request-promise": "^4.1.47", "@types/underscore": "^1.10.24", "bcrypt": "^5.0.0", "bluebird": "^3.5.1", @@ -46,10 +47,13 @@ "redis": "^3.0.2", "redlock": "^4.2.0", "reflect-metadata": "^0.1.10", + "request": "^2.88.2", + "request-promise": "^4.2.6", "source-map-support": "^0.5.0", "ts-node": "^8.2.0" }, "devDependencies": { + "@types/node-schedule": "^1.3.1", "tslint": "^5.9.1", "typescript": "^3.9.7" } diff --git a/gm-server/app/service/Utils.ts b/gm-server/app/service/Utils.ts index 4ea97eff2..ede7cfa21 100644 --- a/gm-server/app/service/Utils.ts +++ b/gm-server/app/service/Utils.ts @@ -2,8 +2,6 @@ import { Service } from 'egg'; import { addSkins, addBags, addEquips } from '@pubUtils/itemUtils'; import * as pubUtils from '@pubUtils/util'; import * as pubGamedata from '@pubUtils/gamedata' -import { HeroType } from '@db/Hero'; -import { calPlayerCeAndSave } from '@pubUtils/playerCe'; import { BagInter, EquipInter } from '@pubUtils/interface'; const csprng = require('csprng'); @@ -47,10 +45,6 @@ export default class Utils extends Service { return pubUtils.resResult(status, data, customMsg); } - public calPlayerCeAndSave(roleId: string, heros: HeroType[], type: number, args: number[]) { - return calPlayerCeAndSave(roleId, heros, type, args) - } - public addSkins(roleId: string, id: number) { return addSkins(roleId, id); } diff --git a/gm-server/app/service/users.ts b/gm-server/app/service/users.ts index 111fc2ead..0ad6ba1f9 100644 --- a/gm-server/app/service/users.ts +++ b/gm-server/app/service/users.ts @@ -26,7 +26,7 @@ import { ItemModel } from '@db/Item'; import { gameData, getHeroExpByLv } from '@pubUtils/data'; import { calPlayerCeAndSave, calculatetopLineup, calEquipSeids } from '@pubUtils/playerCe'; import { SchoolModel } from '@db/School'; -import { CeAttrNumber } from '@domain/roleField/attribute'; +import { Attribute } from '@domain/roleField/attribute'; import { smsModel } from '@db/Sms'; import { isString } from 'underscore'; import { FriendShipModel } from '@db/FriendShip'; @@ -267,7 +267,7 @@ export default class GMUsers extends Service { try { for(let heroInfo of heroInfos) { let hero = await HeroModel.createHero(heroInfo); - await calPlayerCeAndSave(heroInfo.roleId, [hero], HERO_SYSTEM_TYPE.INIT); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.INIT, heroInfo.roleId, hero, {}); } return ctx.service.utils.resResult(STATUS.SUCCESS, { uids }); } catch(e) { @@ -436,22 +436,19 @@ export default class GMUsers extends Service { if(!hero || !role) { return ctx.service.utils.resResult(STATUS.GM_HERO_NOT_FOUND); } - let { lv, ce, ceAttr } = hero; - let { globalCeAttr } = role; + let { lv, ce, attr: heroAttrs } = hero; + let { attr: roleAttrs } = role; let dicHero = ctx.service.utils.getHeroById(hid); - let attribute = new CeAttrNumber(); - for(let attrName in attribute) { - let { base, ratioUp, fixUp, equipUp } = ceAttr[attrName]; - let { ratioUp: ratioUp2, fixUp: fixUp2 } = globalCeAttr[attrName]; - attribute[attrName] += base * ( 1 + ratioUp + ratioUp2) + fixUp + fixUp2 + equipUp; - } + let attribute = new Attribute(); + attribute.setByDbData(roleAttrs, heroAttrs); + let heroInfo = { actorId: dicHero.heroId, actorName: dicHero.name, - attribute: {...attribute, speed: 0, ap: 0}, lv, + attribute, lv, ce }; @@ -540,9 +537,9 @@ export default class GMUsers extends Service { let hero = await HeroModel.findByHidAndRole(equip.hid, roleId); let index = hero.ePlace.findIndex(cur => cur.id == equip.ePlaceId); if (index < 0) continue; - hero.ePlace[index].equip = null; let args = calEquipSeids(hero); - await calPlayerCeAndSave(roleId, [hero], HERO_SYSTEM_TYPE.EQUIP, args); + hero.ePlace[index].equip = null; + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, roleId, hero, {}, args); } seqIds.push(seqId); } @@ -617,8 +614,7 @@ export default class GMUsers extends Service { let hero = await HeroModel.findByHidAndRole(hid, roleId); console.log(hid, roleId, !!hero); if(!hero) continue; - hero.lv = hlv; - await calPlayerCeAndSave(roleId, [hero], HERO_SYSTEM_TYPE.LVUP, [hid]); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.LVUP, roleId, hero, {lv: hlv}); } return ctx.service.utils.resResult(STATUS.SUCCESS); diff --git a/gm-server/config/config.isbn.ts b/gm-server/config/config.isbn.ts new file mode 100644 index 000000000..054c18e80 --- /dev/null +++ b/gm-server/config/config.isbn.ts @@ -0,0 +1,55 @@ +import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; + +export default (appInfo: EggAppInfo) => { + const config = {} as PowerPartial; + + // override config from framework / plugin + // use for cookie sign key, should change to your own and keep security + config.keys = appInfo.name + '_1600244957952_7142'; + + // add your egg config in here + config.middleware = []; + + config.cluster = { + listen: { + port: 7500 + } + }; + // add your special config in here + const bizConfig = { + sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`, + }; + + config.mongoose = { + url: 'mongodb://root:Bantus123@dds-8vb74337eab84d641.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vb74337eab84d642.mongodb.zhangbei.rds.aliyuncs.com:3717/admin?replicaSet=mgset-504694158', // 内网 + options: { useNewUrlParser: true, useUnifiedTopology: true }, + }; + + config.security = { + csrf: { + enable: false, + ignoreJSON: true + }, + domainWhiteList: ['http://localhost:9000'] + }; + + // 配置上传 + config.multipart = { + fileSize: '50mb', + mode: 'stream', + fileExtensions: ['.zip', '.tar.gz'], // 扩展几种上传的文件格式 + }; + + config.alinode = { + appid: '86043', + secret: '54ef0364995b0c4f2ab42150e29ad30df8327a3a', + error_log: [ '/root/logs/zyz/zyz-web.log', '/root/logs/zyz/common-error.log', '/root/logs/zyz/egg-agent.log' ], + packages: [ '/root/zyz/web-server/package.json' ], + }; + + // the return config will combines to EggAppConfig + return { + ...config, + ...bizConfig, + }; +}; diff --git a/package-lock.json b/package-lock.json index 2742dfad2..d3db0bb13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,11 @@ } } }, + "@types/bluebird": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.33.tgz", + "integrity": "sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==" + }, "@types/bson": { "version": "4.0.2", "resolved": "https://registry.npm.taobao.org/@types/bson/download/@types/bson-4.0.2.tgz", @@ -31,6 +36,11 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, "@types/mongodb": { "version": "3.5.27", "resolved": "https://registry.npm.taobao.org/@types/mongodb/download/@types/mongodb-3.5.27.tgz?cache=0&sync_timestamp=1599138259359&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fmongodb%2Fdownload%2F%40types%2Fmongodb-3.5.27.tgz", @@ -54,6 +64,31 @@ "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.10.0.tgz?cache=0&sync_timestamp=1599757029267&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.10.0.tgz", "integrity": "sha1-FYFd/4LI3DCCf2sShvhlkClFCVo=" }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/request-promise": { + "version": "4.1.47", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.47.tgz", + "integrity": "sha512-eRSZhAS8SMsrWOM8vbhxFGVZhTbWSJvaRKyufJTdIf4gscUouQvOBlfotPSPHbMR3S7kfkyKbhb1SWPmQdy3KQ==", + "requires": { + "@types/bluebird": "*", + "@types/request": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -87,6 +122,11 @@ "es-abstract": "^1.17.0-next.1" } }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -157,6 +197,14 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -200,6 +248,11 @@ "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -248,6 +301,16 @@ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fs-minipass": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", @@ -417,6 +480,19 @@ "integrity": "sha1-2HUWVdItOEaCdByXLyw9bfo+ZrU=", "optional": true }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -714,6 +790,16 @@ "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, "random-to": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/random-to/-/random-to-0.0.2.tgz", @@ -761,6 +847,25 @@ "resolved": "https://registry.npm.taobao.org/regexp-clone/download/regexp-clone-1.0.0.tgz", "integrity": "sha1-Ii25Z2IydwViYLmSYmNUoEzpv2M=" }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, "require_optional": { "version": "1.0.1", "resolved": "https://registry.npm.taobao.org/require_optional/download/require_optional-1.0.1.tgz", @@ -841,6 +946,11 @@ "memory-pager": "^1.0.2" } }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -911,6 +1021,15 @@ "yallist": "^3.0.3" } }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, "tslib": { "version": "2.0.1", "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.1.tgz?cache=0&sync_timestamp=1596751904317&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-2.0.1.tgz", diff --git a/package.json b/package.json index 834becb6b..0a612e4cb 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "dependencies": { "@typegoose/typegoose": "^7.3.5", "@types/mongoose": "^5.7.36", + "@types/request-promise": "^4.1.47", "bcrypt": "^5.0.0", "chinese-random-name": "^1.0.0", "lodash": "^4.17.20", @@ -14,6 +15,7 @@ "mongoose-lean-getters": "^0.1.2", "mongoose-lean-virtuals": "^0.7.6", "mongoose-transactions": "^1.1.4", + "request-promise": "^4.2.6", "underscore": "^1.12.0" }, "devDependencies": {}, diff --git a/pushdocker.sh b/pushdocker.sh index f7bd19539..70a3d5463 100755 --- a/pushdocker.sh +++ b/pushdocker.sh @@ -13,6 +13,8 @@ elif [ ${1} == 'alpha' ] ; then destUrl="root@zyzalpha:/root/zyz/" elif [ ${1} == 'dev' ] ; then destUrl="root@zyzdev:/root/zyz/" +elif [ ${1} == 'isbn' ] ; then +destUrl="root@zyzisbn:/root/zyz/" else echo "需要一个参数指明服务器" exit 1; diff --git a/shared/consts/constModules/abilityConst.ts b/shared/consts/constModules/abilityConst.ts index 63f1785b5..7776c409e 100644 --- a/shared/consts/constModules/abilityConst.ts +++ b/shared/consts/constModules/abilityConst.ts @@ -4,9 +4,6 @@ * 属性 id */ - -import { JOB_TYPE } from ".."; - export enum ABI_TYPE{ /**生命 */ ABI_HP = 1, @@ -41,12 +38,33 @@ export enum ABI_TYPE{ ABI_DEF_IGNORE = 15, /**吸血等级 */ ABI_BLOOD_SUCK = 16, - /**怒气 */ + /**怒气恢复效果 */ ABI_AP = 17, + /**暴击伤害 */ + ABI_DAMAGE_CRI = 18, ABI_MAX, } +// 主属性 +export const ABI_TYPE_MAIN = [ + ABI_TYPE.ABI_HP, + ABI_TYPE.ABI_ATK, + ABI_TYPE.ABI_DEF, + ABI_TYPE.ABI_MDEF +]; + +// 次级属性 +export const ABI_TYPE_SUB = [ + ABI_TYPE.ABI_HIT, + ABI_TYPE.ABI_CRI, + ABI_TYPE.ABI_FLEE, + ABI_TYPE.ABI_ANT_CRI, + ABI_TYPE.ABI_DAMAGE_INCREASE, + ABI_TYPE.ABI_DAMAGE_DECREASE, + ABI_TYPE.ABI_DEF_IGNORE, + ABI_TYPE.ABI_DAMAGE_CRI +]; export enum SEID_TYPE { /**属性固定值加成(数值) */ @@ -63,39 +81,10 @@ export enum ABI_STAGE { ATK = 2, DEF = 3, MDEF = 4, - AGI = 5, - LUK = 6, - END = 6 + END = 4 } export const ATTR = {} -//武将训练等级 -export const HEROTARIN = { - 1: "hp", - 2: "atk", - 3: "def", - 4: "mdef", - 5: "agi", - 6: "luk" -}; -//战力系数 -export const CE_RATIO = { - "hp" : 1, - "atk" : 2, - "matk": 2, - "def": 2, - "mdef": 2, - "agi": 2, - "luk": 0, - "hit": 0, - "cri": 0, - "flee": 0, - "antCri": 0, - "damageIncrease": 0, - "damageDecrease": 0, - "defIngnore": 0, - "bloodSuck": 0, -}; export const HERO_ATTR = { 1: "hp", // 生命 @@ -114,44 +103,30 @@ export const HERO_ATTR = { 14: "damageDecrease", // 伤害减免等级 15: "defIngnore", // 忽视防御等级 16: "bloodSuck", // 吸血等级 - 17: "ap" // 怒气 + 17: "damageCri", // 暴击伤害 + 18: "ap" // 暴击伤害 }; -export const JEWEL_ATTR = { - 1: "hp", - 2: "atk", - 3: "def", - 4: "mdef", - 5: "agi", - 6: "luk" -} -const BASE_ATTR = { - 'hp' : 1 , - 'atk' : 2, - 'def' : 3, - 'mdef' : 4 -} -export const ABI_TYPE_TO_STAGE = new Map number)>([ +export const ABI_TYPE_TO_STAGE = new Map([ [ABI_STAGE.HP, ABI_TYPE.ABI_HP], - [ABI_STAGE.ATK, (jobType:number) => { return jobType == JOB_TYPE.PHYSIC?ABI_TYPE.ABI_ATK: ABI_TYPE.ABI_MATK}], + [ABI_STAGE.ATK, ABI_TYPE.ABI_ATK], [ABI_STAGE.DEF, ABI_TYPE.ABI_DEF], - [ABI_STAGE.MDEF, ABI_TYPE.ABI_MDEF], - [ABI_STAGE.AGI, ABI_TYPE.ABI_AGI], - [ABI_STAGE.LUK, ABI_TYPE.ABI_LUK] + [ABI_STAGE.MDEF, ABI_TYPE.ABI_MDEF] ]); export function getAtrrNameById(attrId: number):string { return HERO_ATTR[attrId]; }; -export function getAttrCeRatio(attr: string):number { - return CE_RATIO[attr]; -}; - -export function getAttrNameByJobStage(jobStage: number) { - return HEROTARIN[jobStage]; -}; - -export function getTeraphAttr() { - return BASE_ATTR; -}; +export enum CE_CONST { + FLEE_VALUE = 0.3, // 格挡价值 + PUT_HIT = 50000, // 投放总命中 + HIT_RATE_BASE = 0.75, // 命中率基础 + HIT_RATE_MAX = 1, // 命中率上限 + HIT_RATE_MIN = 0, // 命中率下限 + PUT_ANT_CRI = 50000, // 投放总抗暴 + CRI_RATE_BASE = 0.05, // 暴击率基础 + CRI_RATE_MAX = 0.75, // 暴击率上限 + CRI_RATE_MIN = 0.05, // 暴击率下限 + CRI_VALUE_BASE = 1.5, // 暴击价值基础 +} \ No newline at end of file diff --git a/shared/consts/constModules/calcuConst.ts b/shared/consts/constModules/calcuConst.ts index e239a140a..f0c819380 100644 --- a/shared/consts/constModules/calcuConst.ts +++ b/shared/consts/constModules/calcuConst.ts @@ -14,7 +14,3 @@ export const GOLD_COST_RATIO = { "DAILY_REF_NUM": { "A": 50, "B": 0 }, // 每日购买次数花费 "DUNGRON_BUY_NUM": { "A": 0, "B": 50 } // 秘境购买次数花费 } - -export const EXPRESSION = { - "CE": "1*hp+2*atk+2*matk+2*def+2*mdef+2*agi+2*luk+0*hit+0*cri+0*flee+0*antCri+0*damageIncrease+0*damageDecrease+0*defIngnore+0*bloodSuck" -} diff --git a/shared/consts/constModules/heroConst.ts b/shared/consts/constModules/heroConst.ts index 35518b705..efb947bab 100644 --- a/shared/consts/constModules/heroConst.ts +++ b/shared/consts/constModules/heroConst.ts @@ -18,7 +18,9 @@ export const HERO_SYSTEM_TYPE = { ADD_SKIN: 15, SCHOOL: 16, SCROLL: 17, - TITLE:18, + TITLE: 18, + TERAPH: 19, + TERAPH_UP: 20 }; // 武将上限 @@ -36,4 +38,6 @@ export const JOB_TYPE = { } // 武将战力放大系数 -export const HERO_CE_RATIO = 100; \ No newline at end of file +export const HERO_CE_RATIO = 100; +// 次级属性放大系数 +export const HERO_SUB_ATTR_RATIO = 1000; \ No newline at end of file diff --git a/shared/consts/constModules/httpConst.ts b/shared/consts/constModules/httpConst.ts new file mode 100644 index 000000000..6fac35c26 --- /dev/null +++ b/shared/consts/constModules/httpConst.ts @@ -0,0 +1,6 @@ +export enum BANTU_VID_ADDR { + HOST = 'https://sdks.trgame.cn', + IDCARD = '/vid/idcard', // 实名认证 + REPORT_ONLINE = '/addiction_prevention/report_online' +} +export const BANTU_VID_APP_KEY = '05c1c495369769e3c5d98426e9c8c2c0'; diff --git a/shared/consts/constModules/selectConst.ts b/shared/consts/constModules/selectConst.ts index fb9097071..1b854ddfd 100644 --- a/shared/consts/constModules/selectConst.ts +++ b/shared/consts/constModules/selectConst.ts @@ -7,7 +7,7 @@ export enum ROLE_SELECT { // 显示申请需要的信息 SHOW_FRIEND_APPLY_LIST = 'roleId roleName ce headHid sHid lv title job quitTime vLv guildName friendCnt recFrdApplyCnt serverId userInfo.serverType', HANDLE_APPLY = 'roleId friendCnt lv', - ATTR = 'globalCeAttr', + ATTR = 'attr', GET_LV = 'lv', GET_ROLE_ID = 'roleId', GET_MY_SERVER = 'lv serverId userInfo.serverType', @@ -15,8 +15,8 @@ export enum ROLE_SELECT { }; export enum HERO_SELECT { - ENTRY = '-ceAttr', - HERO_DETAIL = 'roleId roleName hid hName ce lv star colorStar quality job skins ceAttr' + ENTRY = '-attr', + HERO_DETAIL = 'roleId roleName hid hName ce lv star colorStar quality job skins attr' } export enum EQUIP_SELECT { diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index b4efd7966..0080d3b1e 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -7,6 +7,10 @@ export const ENCRYPT_KEY = 'fiqaxijabbantusmprc234fj'; export const AUTH_SMS_CNT_PER_DAY = 8; +export const ADULT_AGE = 18; +export const GUEST_MAX_TIME = 60 * 60 * 100; // 游客体验时间 +export const GUEST_DAY = 15; // 同一设备15天内不得重复体验游客模式 + export const COUNTER = { UID: { name: 'uid', def: 1 }, GMUID: { name: 'gmuid', def: 1 }, @@ -392,4 +396,17 @@ export enum BLOCK_OPEATE { REMOVE_BLACK = 2, REMOVE_AND_APPLY = 3, REMOVE_FRIEND = 4 +} + +export enum TIME_FORMAT { + TYPE_SLASH = 1 +} + +export enum ADDICTION_PREVENTION_CODE { + FAIL = -1, + SUCCESS = 1, // 接口的返回 + GUEST = 1, // 返回给客户端时,游客时间超时 + CURFEW = 2, // 每日22时至次日8时,未成年禁止游戏 + HOLIDAY = 3, // 法定节假日每日累计不得超过3小时 + WORKDAY = 4, // 非法定节假日每日累计不得超过1.5小时 } \ No newline at end of file diff --git a/shared/consts/index.ts b/shared/consts/index.ts index b707247af..8ab622c87 100644 --- a/shared/consts/index.ts +++ b/shared/consts/index.ts @@ -7,5 +7,6 @@ export * from './constModules/sysConst'; export * from './constModules/guildConst'; export * from './constModules/selectConst'; export * from './constModules/chatConst'; +export * from './constModules/httpConst'; export * from './statusCode'; export * from './dataName'; \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 10ce968e3..3f96e0f46 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -17,6 +17,12 @@ export const STATUS = { DUP_LOGIN: { code: 10006, simStr: '重复登录' }, NEW_SERVER_ERR: { code: 10007, simStr: '添加新服务器失败' }, SERVER_EXISTS: { code: 10008, simStr: '服务器已存在' }, + PASSWORD_ERR: { code: 10009, simStr: '密码错误' }, + PASSWORD_ILLEGEL: { code: 10010, simStr: '请输入密码' }, + TEL_HAS_USED: { code: 10011, simStr: '该手机号已被使用' }, + ACCOUNT_NOT_GUEST: { code: 10012, simStr: '该账号已绑定过' }, + AUTHEN_FAIL: { code: 10013, simStr: '实名失败' }, + TEL_LEN_ERR: { code: 10014, simStr: '手机长度错误' }, // 战斗相关状态 20000 - 29999 // 战斗通用 20000 - 20099 BATTLE_MISS_INFO: { code: 20001, simStr: '缺少关卡信息' }, diff --git a/shared/db/Equip.ts b/shared/db/Equip.ts index 9d16b7f53..59671d852 100644 --- a/shared/db/Equip.ts +++ b/shared/db/Equip.ts @@ -94,7 +94,7 @@ export default class Equip extends BaseModel { return equip; } - public static async putOn(hid: number, equipId: string, lean = true) { + public static async putOnOrOff(equipId: string, hid: number, lean = true) { const equip: EquipType = await EquipModel.findOneAndUpdate({ _id: equipId }, { hid }, { new: true }).lean(lean); return equip; } diff --git a/shared/db/Game.ts b/shared/db/Game.ts index f17a0d795..fbfa66d00 100644 --- a/shared/db/Game.ts +++ b/shared/db/Game.ts @@ -2,27 +2,58 @@ import { APP_ID } from './../consts'; import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; -class ServerInfo { +export class ServerInfo { @prop({ required: true }) - id: number; + id: number; // 小区id @prop({ required: true }) - name: string; + name: string; // 小区区名 @prop({ required: true }) - host: string; + groupId: number; // 大区id + + @prop({ required: true }) + groupName: string; // 大区区名 + + @prop({ required: true }) + host: string; // pinus连接地址 @prop({ required: false }) - port: number; + port: number; // pinus端口 @prop({ required: true }) - status: number; + serverStatus: number; // 服务器状态 + + public get status() { + let now = new Date(); + if( now > this.openTime) { + return this.serverStatus; + } else { + return 3; // 未开服 + } + } + + @prop({ required: true }) + openTime: Date; @prop({ required: true }) createTime: Date; @prop({ required: true }) serverType: string; + + constructor(id: number, name: string, groupId: number, groupName: string, host: string, port: number, serverStatus: number, serverType: string, openTime?: Date) { + this.id = id; + this.name = name; + this.groupId = groupId; + this.groupName = groupName; + this.host = host; + this.port = port; + this.serverStatus = serverStatus; + this.serverType = serverType; + this.openTime = openTime||new Date(); + this.createTime = new Date(); + } } /** @@ -65,26 +96,23 @@ export default class Game extends BaseModel { } } - public static async getServerListByType(serverType: string) { - let game: GameType = await GameModel.findOne().lean(); + public static async getServerList() { + let game: GameType = await GameModel.findOne().lean({ getter: true, virtuals: true }); if (!game) { - const serverInfo: ServerInfo = { id: 1, name: '常山少年', host: 'pinus_test.trgame.cn', port: 3014, status: 1, createTime: new Date(), serverType: 'official' }; + const serverInfo = new ServerInfo(1, '常山少年', 1, '逍遥津', 'pinus_test.trgame.cn', 3014, 1, 'official'); const iconUrl = `https://download.tgamebox.cn/avatar/${APP_ID}/1.png`; game = await GameModel.findOneAndUpdate( {}, { id: 1, name: '赵云传', nameEn: 'zyz', des: '牛逼的战棋', iconUrl, version: '0.0.1', versionCode: 1, $push: { serverList: serverInfo } }, { upsert: true, new: true }, - ).lean(); + ).lean({ getter: true, virtuals: true }); } - console.log(serverType, game); let serverList: Array = game ? game.serverList : []; - serverList = serverList.filter(item => { return item.serverType === serverType; }); - console.log(serverType, serverList); return serverList; } public static async newServer(serverId: number, serverType: string, name: string, host: string, port: number, status: number, lean = true) { - let serverInfo: ServerInfo = {id: serverId, name, host, port, status, createTime: new Date(), serverType}; + let serverInfo = new ServerInfo(serverId, name, 1, '逍遥津', host, port, status, serverType); let game: GameType = await GameModel.findOneAndUpdate({}, {$push: {serverList: serverInfo}}, {new: true}).lean(lean); return game; } diff --git a/shared/db/GroupMail.ts b/shared/db/GroupMail.ts index aad57e52f..32e411afe 100644 --- a/shared/db/GroupMail.ts +++ b/shared/db/GroupMail.ts @@ -1,9 +1,9 @@ import BaseModel from './BaseModel'; -import { index, getModelForClass, mongoose, prop, DocumentType } from '@typegoose/typegoose'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { nowSeconds } from '../pubUtils/timeUtil'; import { MAIL_STATUS, MAIL_TYPE } from '../consts/constModules/mailConst'; import { findWhere } from 'underscore'; -const { ObjectId } = mongoose.Types; + class RewardInter { @prop({ required: true }) id: number; diff --git a/shared/db/Hero.ts b/shared/db/Hero.ts index 3c0d78279..50f11e841 100644 --- a/shared/db/Hero.ts +++ b/shared/db/Hero.ts @@ -1,17 +1,32 @@ 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 CeAttrData { + @prop({ required: true }) + id: number = 0; + @prop({ required: true }) + base: number = 0; + @prop({ required: true }) + ratioUp: number = 0; + @prop({ required: true }) + fixUp: number = 0; + @prop({ required: true }) + equipUp: number = 0; + + constructor(id: number) { + this.id = id; + } +} /** * 英雄表 */ -class Connect { +export class Connect { @prop({ required: true }) shipId: number; @prop({ required: true }) @@ -51,31 +66,6 @@ function getInitialEplace() { 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 { @@ -102,8 +92,8 @@ export default class Hero extends BaseModel { ce: number; // 武将战力 @prop({ required: true, default: 0 }) historyCe: number; // 武将历史最高战力 - @prop({required: true, default: new CeAttr(), _id: false }) - ceAttr: CeAttr; // 影响战力的属性 + @prop({required: true, type: CeAttrData, default: [], _id: false }) + attr: CeAttrData[]; // 影响战力的属性 @prop({ required: true, default: 1 }) star: number; // 星级 @@ -181,10 +171,21 @@ export default class Hero extends BaseModel { 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}}, + {$set: { 'ePlace.$.equip': equipId }}, {new: true}).populate('ePlace.equip').lean(lean); if (hero) { - await Equip.putOn(hero.hid, equipId); + await Equip.putOnOrOff( equipId, hero.hid ); + } + return hero; + } + + public static async removeEquip(roleId: string, hid: number, ePlaceId: number, equipId: string, lean = true) { + const hero: HeroType = await HeroModel.findOneAndUpdate( + { roleId, hid, 'ePlace.id': ePlaceId }, + {$set: {'ePlace.$.equip': null}}, + {new: true}).populate('ePlace.equip').lean(lean); + if (hero) { + await Equip.putOnOrOff( equipId, 0 ); } return hero; } @@ -238,7 +239,7 @@ export default class Hero extends BaseModel { return result; } - public static async updateHeroInfo(roleId: string, hid:number, heroUpdate:heroUpdate, select?: string, lean = true) { + 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; @@ -270,3 +271,4 @@ export default class Hero extends BaseModel { export const HeroModel = getModelForClass(Hero); export interface HeroType extends Pick, keyof Hero>{}; +export type HeroUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/db/Mail.ts b/shared/db/Mail.ts index ac1ad8879..4191936af 100644 --- a/shared/db/Mail.ts +++ b/shared/db/Mail.ts @@ -1,8 +1,8 @@ import BaseModel from './BaseModel'; -import { index, getModelForClass, prop, DocumentType, mongoose } from '@typegoose/typegoose'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { nowSeconds } from '../pubUtils/timeUtil'; import { MAIL_STATUS, MAIL_TYPE } from '../consts/constModules/mailConst'; -const { ObjectId } = mongoose.Types; + class RewardInter { @prop({ required: true }) id: number; diff --git a/shared/db/Notice.ts b/shared/db/Notice.ts new file mode 100644 index 000000000..e76c150d7 --- /dev/null +++ b/shared/db/Notice.ts @@ -0,0 +1,63 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; +import { formatTime } from '../pubUtils/timeUtil'; +import { TIME_FORMAT } from '../consts' + +/** + * 游戏字段接口 +*/ +@index({ id: 1 }) +@modelOptions({schemaOptions: {id: false}}) +export default class Notice extends BaseModel { + + @prop({ required: true }) + id: number; // 公告id + @prop({ required: true }) + title: string; // 公告标题 + @prop({ required: true }) + tag: number; // 公告显示标签,在系统参数表中配了 + @prop({ required: true }) + type: number; // 类型 1-公告 2-活动 + @prop({ required: true }) + content: number; // 公告内容 + + @prop({ required: true }) + timeStr: string; // 时间显示 + @prop({ required: true }) + startTime: Date; // 活动开始时间 + @prop({ required: true }) + endTime: Date; // 活动结束时间 + public get time() { + let startTime = formatTime(this.startTime, TIME_FORMAT.TYPE_SLASH); + let endTime = formatTime(this.endTime, TIME_FORMAT.TYPE_SLASH); + + return this.timeStr.replace(/%startTime/g, startTime).replace(/%endTime/g, endTime); + } + + @prop({ required: true, select: false }) + sort: number; + + @prop({ required: true, select: false }) + showStartTime: Date; + @prop({ required: true, select: false }) + showEndTime: Date; + @prop({ required: true, select: false }) + serverType: string; // 服务器类型 + @prop({ required: true, select: false }) + isEnable: boolean; + + + public static async getAllNotice(serverType: string) { + let curTime = new Date(); + let notices: NoticeType[] = await NoticeModel.find({ showStartTime: { $lte: curTime }, showEndTime: { $gte: curTime }, isEnable: true, serverType }) + .sort({ sort: -1, createTime: -1 }) + .lean({ virtuals: true }); + return notices; + } +} + +export const NoticeModel = getModelForClass(Notice); + +export interface NoticeType extends Pick, keyof Notice>{ + id: number; +}; diff --git a/shared/db/Role.ts b/shared/db/Role.ts index 388eec6e5..4a94eeb23 100644 --- a/shared/db/Role.ts +++ b/shared/db/Role.ts @@ -1,6 +1,5 @@ -import { HANG_UP_CONSTS, ROLE_TERAPH, ROLE_SELECT } from './../consts'; +import { HANG_UP_CONSTS, ROLE_TERAPH, ROLE_SELECT, ABI_TYPE } from './../consts'; import BaseModel from './BaseModel'; -import { CeAttrRole } from '../domain/roleField/attribute'; import { index, getModelForClass, prop, DocumentType, Ref, mongoose } from '@typegoose/typegoose'; import User from './User'; import { shouldRefresh, reduceCe } from '../pubUtils/util'; @@ -8,6 +7,20 @@ import { initRoleAtrr } from '../pubUtils/playerCe'; import Hero,{} from '../db/Hero'; import { nowSeconds } from '../pubUtils/timeUtil'; +// role表属性格式 +export class CeAttrDataRole { + @prop({ required: true }) + id: number = 0; + @prop({ required: true }) + ratioUp: number = 0; + @prop({ required: true }) + fixUp: number = 0; + + constructor(id: number) { + this.id = id; + } +} + class TopHero { @prop({ required: true }) hid: number; // 武将id @@ -41,37 +54,47 @@ export class WarStar { star: number; // 星级 } -class Teraph{ +export class Teraph{ @prop({ required: true, default: 1 }) id: number; // 神像的id @prop({ required: true, default: 1 }) - grade: number; // 等级 + grade: number = 1; // 等级 @prop({ required: true, default: 0 }) - hp: number; + hp: number = 0; @prop({ required: true, default: 0 }) - atk: number; + atk: number = 0; @prop({ required: true, default: 0 }) - def: number; + def: number = 0; @prop({ required: true, default: 0 }) - mdef: number; - @prop({ required: true, default: 0 }) - agi: number; - @prop({ required: true, default: 0 }) - luk: number; + mdef: number = 0; + + constructor(id: number) { + this.id = id; + } + + public get attr() { + let map = new Map(); + map.set(ABI_TYPE.ABI_HP, this.hp); + map.set(ABI_TYPE.ABI_ATK, this.atk); + map.set(ABI_TYPE.ABI_DEF, this.def); + map.set(ABI_TYPE.ABI_MDEF, this.mdef); + return map + } + + public set attr(value: Map) { + value.forEach((val, id) => { + if(id == ABI_TYPE.ABI_HP) this.hp = val; + if(id == ABI_TYPE.ABI_ATK) this.atk = val; + if(id == ABI_TYPE.ABI_DEF) this.def = val; + if(id == ABI_TYPE.ABI_MDEF) this.mdef = val; + }); + } } // 初始化 function getInitialTeraph() { let teraphs = new Array(); 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; + let p = new Teraph(i); teraphs.push(p); } return teraphs; @@ -114,8 +137,8 @@ export default class Role extends BaseModel { 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, type: CeAttrDataRole, default: [], _id: false }) + attr: CeAttrDataRole[]; // 总战力 @prop({ required: true, default: 0, set: (val: number) => val, get: (val: number) => reduceCe(val) }) topLineupCe: number; // 最强x人战力 @prop({ required: true, type: TopHero, default: [], _id: false }) @@ -227,7 +250,7 @@ export default class Role extends BaseModel { @prop({ required: true, default: 0 }) updatedMailAt: number; public static async findAllByUid(uid: number, lean = true) { - const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId').lean(lean); + const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId headHid sHid lv updatedAt').lean(lean); return role; } @@ -242,8 +265,8 @@ export default class Role extends BaseModel { * @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}); + public static async findByRoleId(roleId: string, select?: string, getters = false, virtuals = true) { + const role: RoleType = await RoleModel.findOne({ roleId }).select(select).lean({getters, virtuals}); return role; } @@ -252,9 +275,8 @@ export default class Role extends BaseModel { 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); - + initRoleAtrr(role); return role; } @@ -427,7 +449,7 @@ export default class Role extends BaseModel { return recs } - public static async updateRoleInfo(roleId: string, roleUpdate:roleUpdate, lean = true) { + 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; @@ -519,4 +541,4 @@ export default class Role extends BaseModel { export const RoleModel = getModelForClass(Role); export interface RoleType extends Pick, keyof Role>{}; -type roleUpdate = Partial; // 将所有字段变成可选项 +export type RoleUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/db/User.ts b/shared/db/User.ts index aa8a17c5f..d80fe654b 100644 --- a/shared/db/User.ts +++ b/shared/db/User.ts @@ -3,6 +3,8 @@ import { CounterModel } from './Counter'; import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { genCode } from '../pubUtils/util'; +const bcrypt = require('bcrypt'); +const SALT_WORK_FACTOR = 5 /** * 用户字段接口 @@ -24,16 +26,42 @@ export default class User extends BaseModel { token: string; @prop({ required: true }) - tel: string; + tel: string; // 账号 @prop({ required: true, default: '' }) telHash: string; + @prop({ required: true }) + password: string; + + @prop({ required: true }) + salt: string; + @prop({ required: true, default: '' }) channelId: string; + // 游客相关 + @prop({ required: false, default: false }) + isGuest: boolean; // 是否是游客 @prop({ required: false }) - guestId: string; + guestId: string; // 游客id + @prop({ required: false, default: 0 }) + guestTime: number; // 游客体验时间 + + // 防沉迷相关 + @prop({ required: false, default: false }) + hasAuthenticated: boolean; // 是否是已认证 + @prop({ required: false }) + birthday: string; // 生日年月 + @prop({ required: false }) + pi: string; // 已通过实名认证用户唯一标识 + @prop({ required: false, default: 0 }) + todayPlayTime: number; // 今日游戏时间 + @prop({ required: false }) + reportTime: Date; // 汇报时间 + + @prop({ required: false, default: false }) + hasSetPw: boolean; // 是否设置过密码 // 最后登录 IP @prop({ required: false }) @@ -52,6 +80,9 @@ export default class User extends BaseModel { unionId: string; // 用户标识 }]; + @prop({ required: true, type: String, default: [], _id: false }) + device: string[]; + @prop({ required: true, default: 'com.bantu.zyz' }) pkgName: string; @@ -67,23 +98,77 @@ export default class User extends BaseModel { @prop({ required: true, default: 0 }) auth: number; - public static async updateToken(tel: string, token: string, platform: string, pkgName: string, serverType: string, lean = true) { - let user: UserType = await UserModel.findOne({ tel }).lean(); + public static async createUser(isGuest: boolean, tel: string, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, guestTime?: number) { const curTime: Date = new Date(); + + const uid = await CounterModel.getNewCounter(COUNTER.UID); + const userCode = genCode(8); + const doc = new UserModel(); let update = {}; - if (!user) { - const uid = await CounterModel.getNewCounter(COUNTER.UID); - const userCode = genCode(8); - const doc = new UserModel(); - update = Object.assign(update, { platform, pkgName, serverType, createTime: curTime, uid, userCode, username: `用户${uid}` }, doc.toJSON()); - } - update = Object.assign(update, { token, lastLoginTime: curTime }); - user = await UserModel.findOneAndUpdate({ tel }, update, { upsert: true, new: true }).lean(lean); + update = Object.assign(update, doc.toJSON(), { platform, pkgName, serverType, createTime: curTime, uid, userCode, username: `用户${uid}`, isGuest, token, lastLoginTime: curTime, guestTime }); + if(isGuest) update["guestId"] = tel; + delete update["device"]; + + const user: UserType = await UserModel.findOneAndUpdate({ tel }, { $set: update, $addToSet: {device: deviceId}}, { upsert: true, new: true }).lean(); return user; } + public static async getLastDeviceGuest(deviceId: string) { + const user: UserType = await UserModel.findOne({ device: { $elemMatch: { $eq: deviceId } }, isGuest: true }).sort({createTime: -1}).lean(); + return user; + } + + public static async updateToken(tel: string, token: string, deviceId: string, lean = true) { + const curTime: Date = new Date(); + + let user = await UserModel.findOneAndUpdate({ tel }, { $set: { token, lastLoginTime: curTime }, $addToSet: {device: deviceId}}, { new: true }).lean(lean); + return user; + } + + public static async createOrUpdate(isGuest: boolean, tel: string, token: string, platform: string, pkgName: string, serverType: string, deviceId: string) { + let user: UserType = await UserModel.findOne({ tel }).lean(); + if (!user) { + user = await UserModel.createUser(isGuest, tel, token, platform, pkgName, serverType, deviceId); + } else { + user = await UserModel.updateToken(tel, token, deviceId); + } + return user; + } + + private static async encryptPass(password: string, salt?: string) { + if (!salt) { + salt = await bcrypt.genSalt(SALT_WORK_FACTOR); + } + let npassword = await bcrypt.hash(password, salt); + return { npassword, salt }; + } + + public static async setPass(uid: number, password: string, lean = true) { + let r = await this.encryptPass(password); + const user: UserType = await UserModel.findOneAndUpdate({ uid }, { $set: { password: r.npassword, salt: r.salt, hasSetPw: true }}, {new: true}).lean(lean); + return user; + } + + public static async bindTel(uid: number, tel: string, lean = true) { + const user: UserType = await UserModel.findOneAndUpdate({ uid, isGuest: true }, { $set: { tel, isGuest: false }}, {new: true}).lean(lean); + return user; + } + + public static async checkPass(tel: string, password: string, token: string, deviceId: string, lean = true) { + const user: UserType = await UserModel.findOne({ tel }).select('salt').lean(); + if (user) { + const curTime: Date = new Date(); + let { salt } = user; + let { npassword } = await this.encryptPass(password, salt); + const checkUser: UserType = await UserModel.findOneAndUpdate({ tel, password: npassword }, { $set: { token, lastLoginTime: curTime }, $addToSet: {device: deviceId}}, { new: true }).lean(lean); + return checkUser; + } else { + return null + } + } + public static async findUserByToken(token: string, lean = true) { - const user: UserType = await UserModel.findOne({ token }).select('uid token serverType auth userCode').lean(lean); + const user: UserType = await UserModel.findOne({ token }).select('uid token serverType auth tel userCode pkgName').lean(lean); return user; } @@ -93,7 +178,7 @@ export default class User extends BaseModel { } public static async findUserByTel(tel: string, lean = true) { - const user: UserType = await UserModel.findOne({ tel }).select('uid tel').lean(lean); + const user: UserType = await UserModel.findOne({ tel }).select('uid tel hasSetPw').lean(lean); return user; } @@ -102,8 +187,18 @@ export default class User extends BaseModel { return user; } + public static async findUserByUserCode(userCode: string, lean = true) { + const user: UserType = await UserModel.findOne({ userCode }).lean(lean); + return user; + } + public static async addAuth(uid: number, auth: number, lean = true) { - const user: UserType = await UserModel.findOneAndUpdate({ uid }, { auth }).select('uid tel').lean(lean); + const user: UserType = await UserModel.findOneAndUpdate({ uid }, { auth }, {new: true}).select('uid tel').lean(lean); + return user; + } + + public static async authentication(uid: number, birthday: string, pi: string, lean = true) { + const user: UserType = await UserModel.findOneAndUpdate({ uid }, { hasAuthenticated: true, birthday, pi }, {new: true}).lean(lean); return user; } @@ -117,8 +212,15 @@ export default class User extends BaseModel { const user: UserType[] = await UserModel.find(searchObj).select('uid tel username serverType auth').lean(lean); return user; } + + + public static async updatePlayTime(userCode: string, guestTimeInc: number, todayPlayTime: number, lean = true) { + const user: UserType = await UserModel.findOneAndUpdate({ userCode }, { $inc: { guestTime: guestTimeInc }, $set: { todayPlayTime, reportTime: new Date() }}, { new: true }).lean(lean); + return user; + } } + export const UserModel = getModelForClass(User); export interface UserType extends Pick, keyof User>{}; diff --git a/shared/domain/dbGeneral.ts b/shared/domain/dbGeneral.ts index 58583484a..c621ea44d 100644 --- a/shared/domain/dbGeneral.ts +++ b/shared/domain/dbGeneral.ts @@ -1,7 +1,7 @@ import { prop } from '@typegoose/typegoose'; import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; import { HeroType } from '../db/Hero'; -import { CeAttrNumber } from './roleField/attribute'; +import { Attribute } from './roleField/attribute'; // 从玩家数据中覆盖warjson的部分字段 export class PvpHeroInfo { @@ -27,7 +27,7 @@ export class PvpHeroInfo { quality?: number = 0; // 品质 @prop({ required: true, _id: false }) - attribute?: CeAttrNumber; // 属性 + attribute?: Attribute; // 属性 setHeroInfo(hero: HeroType) { this.actorId = hero.hid; @@ -46,7 +46,7 @@ export class PvpHeroInfo { this.quality = quality; } - setAttribute(attribute: CeAttrNumber) { + setAttribute(attribute: Attribute) { this.attribute = attribute; } diff --git a/shared/domain/gameField/serverlist.ts b/shared/domain/gameField/serverlist.ts new file mode 100644 index 000000000..230d39f57 --- /dev/null +++ b/shared/domain/gameField/serverlist.ts @@ -0,0 +1,69 @@ +import { ServerInfo } from '../../db/Game'; +import { RoleType } from '../../db/Role'; +import { getSeconds } from '../../pubUtils/timeUtil'; + +export class ServerParam { + id: number; // 区号 + serverStr: string; // 显示的区号 S1 + name: string; // 区名 + host: string; // pinus地址 + port: number; // pinus端口 + status: number; // 状态 + openTime: number; // 开服时间 + serverType: string; // 分区类型 官服 测试服 开发服 + + constructor(server: ServerInfo) { + this.id = server.id; + this.serverStr = `S${this.id}`; + this.name = server.name; + this.host = server.host; + this.port = server.port; + this.status = server.status; + this.openTime = getSeconds(server.openTime); + this.serverType = server.serverType; + } +} + +export class GroupParam { + groupId: number; // 大区号 + groupName: string; // 大区名 + groupStr: string; // 大区内小区编号 S1-S10 + servers: ServerParam[]; // 区 + + constructor(server: ServerInfo) { + this.groupId = server.groupId; + this.groupName = server.groupName; + this.groupStr = `S${server.id}-S${server.id + 9}`; + this.servers = new Array(); + } + + public pushServer(server: ServerInfo) { + let srv = new ServerParam(server); + this.servers.push(srv); + } +} + +export class ServerParamWithRole extends ServerParam { + groupId: number; // 大区号 + groupName: string; // 大区名 + + roleId: string; // 玩家账号 + roleName: string; // 玩家名 + headHid: number; // 头像 + sHid: number; // 形象 + lv: number; // 等级 + updatedAt: Date; + + constructor(role: RoleType, server: ServerInfo) { + super(server); + this.groupId = server.groupId; + this.groupName = server.groupName; + + this.roleId = role.roleId; + this.roleName = role.roleName; + this.headHid = role.headHid; + this.sHid = role.sHid; + this.lv = role.lv; + this.updatedAt = role.updatedAt; + } +} \ No newline at end of file diff --git a/shared/domain/roleField/attribute.ts b/shared/domain/roleField/attribute.ts index f290fc096..7cbcd2e9d 100644 --- a/shared/domain/roleField/attribute.ts +++ b/shared/domain/roleField/attribute.ts @@ -1,7 +1,11 @@ import { prop } from '@typegoose/typegoose'; +import { HERO_CE_RATIO, getAtrrNameById, CE_CONST, HERO_SUB_ATTR_RATIO } from '../../consts'; +import { reduceCe } from '../../pubUtils/util'; // hero表内属性基础格式 export class CeAttrData { + @prop({ required: true }) + id: number = 0; @prop({ required: true }) base: number = 0; @prop({ required: true }) @@ -10,134 +14,175 @@ export class CeAttrData { fixUp: number = 0; @prop({ required: true }) equipUp: number = 0; -} -// hero表全属性 -export class CeAttr { - @prop({ required: false, _id: false }) - hp?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - atk?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - matk?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - def?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - mdef?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - agi?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - luk?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - hit?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - cri?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - flee?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - antCri?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - damageIncrease?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - damageDecrease?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - defIngnore?: CeAttrData = new CeAttrData(); - @prop({ required: false, _id: false }) - bloodSuck?: CeAttrData = new CeAttrData(); + constructor(id: number) { + this.id = id; + } } // role表属性格式 export class CeAttrDataRole { + @prop({ required: true }) + id: number = 0; @prop({ required: true }) ratioUp: number = 0; @prop({ required: true }) fixUp: number = 0; -} - -// role表全属性 -export class CeAttrRole { - @prop({ required: false, _id: false }) - hp?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - atk?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - matk?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - def?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - mdef?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - agi?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - luk?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - hit?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - cri?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - flee?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - antCri?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - damageIncrease?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - damageDecrease?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - defIngnore?: CeAttrDataRole = new CeAttrDataRole(); - @prop({ required: false, _id: false }) - bloodSuck?: CeAttrDataRole = new CeAttrDataRole(); -} - -// 所有属性使用数字格式 -export class CeAttrNumber { - @prop({ required: false }) - hp?: number = 0; - @prop({ required: false }) - atk?: number = 0; - @prop({ required: false }) - matk?: number = 0; - @prop({ required: false }) - def?: number = 0; - @prop({ required: false }) - mdef?: number = 0; - @prop({ required: false }) - agi?: number = 0; - @prop({ required: false }) - luk?: number = 0; - @prop({ required: false }) - hit?: number = 0; - @prop({ required: false }) - cri?: number = 0; - @prop({ required: false }) - flee?: number = 0; - @prop({ required: false }) - antCri?: number = 0; - @prop({ required: false }) - damageIncrease?: number = 0; - @prop({ required: false }) - damageDecrease?: number = 0; - @prop({ required: false }) - defIngnore?: number = 0; - @prop({ required: false }) - bloodSuck?: number = 0; + + constructor(id: number) { + this.id = id; + } } // 主属性 export class MainAttrNumber { hp: number = 0; atk: number = 0; - matk: number = 0; def: number = 0; mdef: number = 0; - agi: number = 0; - luk: number = 0; - constructor(attr: CeAttrNumber) { + constructor(attr: Attribute) { if(attr.hp) this.hp = attr.hp; if(attr.atk) this.atk = attr.atk; if(attr.def) this.def = attr.def; if(attr.mdef) this.mdef = attr.mdef; - if(attr.agi) this.agi = attr.agi; - if(attr.luk) this.luk = attr.luk; + } +} + +export class Attribute { + @prop({ required: false }) + hp: number = 0; + @prop({ required: false }) + atk: number = 0; + @prop({ required: false }) + def: number = 0; + @prop({ required: false }) + mdef: number = 0; + @prop({ required: false }) + speed: number = 0; + @prop({ required: false }) + hit: number = 0; + @prop({ required: false }) + cri: number = 0; + @prop({ required: false }) + flee: number = 0; + @prop({ required: false }) + antCri: number = 0; + @prop({ required: false }) + damageIncrease: number = 0; + @prop({ required: false }) + damageDecrease: number = 0; + @prop({ required: false }) + defIngnore: number = 0; + @prop({ required: false }) + bloodSuck: number = 0; + @prop({ required: false }) + ap: number = 0; + @prop({ required: false }) + damageCri: number = 0; + + setByDbData(roleAttrs: CeAttrDataRole[], heroAttrs: CeAttrData[]) { + for(let { id, fixUp: roleFix, ratioUp: roleRatio } of roleAttrs) { + let attrName = getAtrrNameById(id); + let heroAttr = heroAttrs.find(heroAttr => heroAttr.id == id); + if(heroAttr) { + let { fixUp: heroFix, base: heroBase, ratioUp: heroRatio, equipUp: heroEquip } = heroAttr; + let value = this.calAttrValue(roleFix, roleRatio, heroBase, heroFix, heroRatio, heroEquip); + if(attrName in this) this[attrName] = value; + } else { + let value = this.calAttrValue(roleFix, roleRatio, 0, 0, 0, 0); + if(attrName in this) this[attrName] = value; + } + } + + for(let { id, base: heroBase, fixUp: heroFix, ratioUp: heroRatio, equipUp: heroEquip } of heroAttrs) { + let attrName = getAtrrNameById(id); + let roleAttr = roleAttrs.find(roleAttr => roleAttr.id == id); + if(!roleAttr) { + let value = this.calAttrValue(0, 0, heroBase, heroFix, heroRatio, heroEquip); + if(attrName in this) this[attrName] = value; + } + } + } + + setByWarJson( attributes: {id: number, val: number}[], ratio: number = 1) { + for(let {id, val} of attributes) { + let attrName = getAtrrNameById(id); + if(attrName in this) this[attrName] = Math.floor(val * ratio * HERO_CE_RATIO * HERO_CE_RATIO); + } + } + + private calAttrValue(roleFix: number = 0, roleRatio: number = 0, heroBase: number = 0, heroFix: number = 0, heroRatio: number = 0, heroEquip: number = 0) { + return (heroFix + heroEquip + roleFix) * HERO_CE_RATIO + heroBase * ( HERO_CE_RATIO + heroRatio + roleRatio ); + } + + private getRealSubAttr() { + return { + hit: this.hit / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + cri: this.cri / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + flee: this.flee / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + antCri: this.antCri / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + damageIncrease: this.damageIncrease / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + damageDecrease: this.damageDecrease / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + defIngnore: this.defIngnore / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO, + damageCri: this.damageCri / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO + } + } + + private getRealMainAttr() { + return { + hp: this.hp / HERO_CE_RATIO / HERO_CE_RATIO, + atk: this.atk / HERO_CE_RATIO / HERO_CE_RATIO, + def: this.def / HERO_CE_RATIO / HERO_CE_RATIO, + mdef: this.mdef / HERO_CE_RATIO / HERO_CE_RATIO + } + } + + public getReduceAttributes() { + let newAttr = new Attribute(); + newAttr.hp = reduceCe(this.hp); + newAttr.atk = reduceCe(this.atk); + newAttr.def = reduceCe(this.def); + newAttr.mdef = reduceCe(this.mdef); + newAttr.speed = reduceCe(this.speed); + newAttr.hit = reduceCe(this.hit); + newAttr.cri = reduceCe(this.cri); + newAttr.flee = reduceCe(this.flee); + newAttr.antCri = reduceCe(this.antCri); + newAttr.damageIncrease = reduceCe(this.damageIncrease); + newAttr.damageDecrease = reduceCe(this.damageDecrease); + newAttr.defIngnore = reduceCe(this.defIngnore); + newAttr.bloodSuck = reduceCe(this.bloodSuck); + newAttr.ap = reduceCe(this.ap); + newAttr.damageCri = reduceCe(this.damageCri); + return newAttr; + } + + // 战力计算 + public calCe() { + let { hp, atk, def, mdef } = this.getRealMainAttr(); + let { cri, flee, damageIncrease, damageDecrease, damageCri } = this.getRealSubAttr(); + let putHit = CE_CONST.PUT_HIT / HERO_SUB_ATTR_RATIO; + let putAntCri = CE_CONST.PUT_ANT_CRI / HERO_SUB_ATTR_RATIO; + + let hitRate = CE_CONST.HIT_RATE_BASE + putHit/2 - flee; // 命中率 + if(hitRate > CE_CONST.HIT_RATE_MAX) hitRate = CE_CONST.HIT_RATE_MAX; + if(hitRate < CE_CONST.HIT_RATE_MIN) hitRate = CE_CONST.HIT_RATE_MIN; + let fleeRate = 1 - hitRate; // 格挡率 + + let criRate = CE_CONST.CRI_RATE_BASE + cri - putAntCri/2; + if(criRate > CE_CONST.CRI_RATE_MAX) criRate = CE_CONST.CRI_RATE_MAX; + if(criRate < CE_CONST.CRI_RATE_MIN) criRate = CE_CONST.CRI_RATE_MIN; + + let criValue = CE_CONST.CRI_VALUE_BASE + damageCri; + + let validHp = hp + (def + mdef) * 0.5 / ((1 - fleeRate * CE_CONST.FLEE_VALUE) * (1 - damageDecrease)); // 有效生命 + let validAtk = atk * hitRate * ( 1 + criRate * criValue) * ( 1 + damageIncrease); // 有效输出 + let ce = Math.floor(validHp * validAtk * HERO_CE_RATIO * HERO_CE_RATIO); + return ce > 0? ce: 1; + } + + public calCelAndReduce() { + return Math.floor(this.calCe() / HERO_CE_RATIO / HERO_CE_RATIO); } } \ No newline at end of file diff --git a/shared/pubUtils/data.ts b/shared/pubUtils/data.ts index d73617059..9be842513 100644 --- a/shared/pubUtils/data.ts +++ b/shared/pubUtils/data.ts @@ -35,7 +35,6 @@ import { dicTeraph } from './dictionary/DicTeraph'; import { dicSchool } from './dictionary/DicSchool'; import { dicSchoolRate } from './dictionary/DicSchoolRate'; import { dicHeroScroll, preHeroScroll } from './dictionary/DicHeroScroll'; -import { ABI_TYPE_TO_STAGE } from "../consts"; import { dicPvpOpponent } from './dictionary/DicPvpOpponent'; import { dicPvpTeamLevel } from './dictionary/DicPvpTeamLevel'; import { dicPvpRefreshConsume, maxPvpRefreshCnt } from './dictionary/DicPvpRefreshConsume'; @@ -58,6 +57,7 @@ import { dicArmyBossRank } from '../pubUtils/dictionary/DicArmyBossRank'; import { dicArmyDonate } from '../pubUtils/dictionary/DicArmyDonateBoxReward'; import { dicRoleFriend } from "./dictionary/DicRoleFriend"; import { dicRoleFriendLv } from "./dictionary/DicRoleFriendLv"; +import { Attribute } from "../domain/roleField/attribute"; export const gameData = { blurprtCompose: dicBlueprtCompose, @@ -213,7 +213,11 @@ export function getBossHpByWarId(warId: number) { warInfo.forEach(hero => { let { attribute, dataId, relation, actorId } = hero; if (relation === 2) { - const hp = attribute.hp||0; + let newAttr = new Attribute(); + newAttr.setByWarJson(attribute, 1); + let attrJson = newAttr.getReduceAttributes(); + + const hp = attrJson.hp||0; if (hp > 0) { bossHpArr.push({dataId, hp, actorId}); bossHpSum += hp; @@ -300,17 +304,6 @@ export function getScollByStar(quality: number, star: number, curQuality: number return heroScroll; } -// 根据存在升星表等的stage字段的id对应17维id -export function getFieldByStage(stage: number, jobid: number) { - let targetAttrId = ABI_TYPE_TO_STAGE.get(stage); - if(typeof targetAttrId === 'number') { - return targetAttrId - } else { - const dicJob = gameData.job.get(jobid); - return targetAttrId(dicJob.type); - } -} - export function getSuit(id: number) { const suitInfo = gameData.suit.get(id); return suitInfo; @@ -420,7 +413,7 @@ export function getArmyWishPoolBaseByLv(lv: number) { export function getFriendLvByExp(exp: number) { let resultLv = 1; - for(let [lv, {sum}] of gameData.roleFriendLv) { + for(let [lv, {sum}] of gameData.roleFriendLv.entries()) { resultLv = lv; if(exp < sum) break; } diff --git a/shared/pubUtils/dictionary/DicGoods.ts b/shared/pubUtils/dictionary/DicGoods.ts index 06c13debd..f3bf45fd7 100644 --- a/shared/pubUtils/dictionary/DicGoods.ts +++ b/shared/pubUtils/dictionary/DicGoods.ts @@ -152,12 +152,10 @@ function parseAbility(json) { let map = new Map(); map.set(ABI_TYPE.ABI_HP, json.hp||0); map.set(ABI_TYPE.ABI_ATK, json.atk||0); - map.set(ABI_TYPE.ABI_MATK, json.matk||0); map.set(ABI_TYPE.ABI_DEF, json.def||0); map.set(ABI_TYPE.ABI_MDEF, json.mdef||0); - map.set(ABI_TYPE.ABI_AGI, json.agi||0); - map.set(ABI_TYPE.ABI_LUK, json.luk||0); - map.set(ABI_TYPE.ABI_SPEED, json.speed||0); + map.set(ABI_TYPE.ABI_DAMAGE_INCREASE, json.damageIncrease||0); + map.set(ABI_TYPE.ABI_DAMAGE_DECREASE, json.damageDecrease||0); return map } @@ -165,12 +163,10 @@ function parseAbilityUp(json) { let map = new Map(); map.set(ABI_TYPE.ABI_HP, json.hp_up||0); map.set(ABI_TYPE.ABI_ATK, json.atk_up||0); - map.set(ABI_TYPE.ABI_MATK, json.matk_up||0); map.set(ABI_TYPE.ABI_DEF, json.def_up||0); map.set(ABI_TYPE.ABI_MDEF, json.mdef_up||0); - map.set(ABI_TYPE.ABI_AGI, json.agi_up||0); - map.set(ABI_TYPE.ABI_LUK, json.luk_up||0); - map.set(ABI_TYPE.ABI_SPEED, json.speed_up||0); + map.set(ABI_TYPE.ABI_DAMAGE_INCREASE, json.damageIncrease_up||0); + map.set(ABI_TYPE.ABI_DAMAGE_DECREASE, json.damageDecrease_up||0); return map } diff --git a/shared/pubUtils/dictionary/DicHero.ts b/shared/pubUtils/dictionary/DicHero.ts index 8c448e04b..100703aea 100644 --- a/shared/pubUtils/dictionary/DicHero.ts +++ b/shared/pubUtils/dictionary/DicHero.ts @@ -46,12 +46,8 @@ function parseBaseAbilityArr(json) { let map = new Map(); map.set(ABI_TYPE.ABI_HP, json.hp||0); map.set(ABI_TYPE.ABI_ATK, json.atk||0); - map.set(ABI_TYPE.ABI_MATK, json.matk||0); map.set(ABI_TYPE.ABI_DEF, json.def||0); map.set(ABI_TYPE.ABI_MDEF, json.mdef||0); - map.set(ABI_TYPE.ABI_AGI, json.agi||0); - map.set(ABI_TYPE.ABI_LUK, json.luk||0); - map.set(ABI_TYPE.ABI_SPEED, json.speed||0); return map } @@ -59,11 +55,7 @@ function parseBaseAbilityUpArr(json) { let map = new Map(); map.set(ABI_TYPE.ABI_HP, json.hp_up||0); map.set(ABI_TYPE.ABI_ATK, json.atk_up||0); - map.set(ABI_TYPE.ABI_MATK, json.matk_up||0); map.set(ABI_TYPE.ABI_DEF, json.def_up||0); map.set(ABI_TYPE.ABI_MDEF, json.mdef_up||0); - map.set(ABI_TYPE.ABI_AGI, json.agi_up||0); - map.set(ABI_TYPE.ABI_LUK, json.luk_up||0); - map.set(ABI_TYPE.ABI_SPEED, json.speed_up||0); return map } \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicHeroScroll.ts b/shared/pubUtils/dictionary/DicHeroScroll.ts index 7d5d0ba67..5d2b96e90 100644 --- a/shared/pubUtils/dictionary/DicHeroScroll.ts +++ b/shared/pubUtils/dictionary/DicHeroScroll.ts @@ -41,7 +41,5 @@ function parseCeAttr(elem) { ceAttr.set(ABI_STAGE.ATK, elem.atk); ceAttr.set(ABI_STAGE.DEF, elem.def); ceAttr.set(ABI_STAGE.MDEF, elem.mdef); - ceAttr.set(ABI_STAGE.AGI, elem.agi); - ceAttr.set(ABI_STAGE.LUK, elem.luk); return ceAttr; } \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicHeroStar.ts b/shared/pubUtils/dictionary/DicHeroStar.ts index 4fdec7f7b..0c5fc18f8 100644 --- a/shared/pubUtils/dictionary/DicHeroStar.ts +++ b/shared/pubUtils/dictionary/DicHeroStar.ts @@ -36,7 +36,6 @@ function parseCeAttr(elem) { ceAttr.set(ABI_STAGE.ATK, elem.atk_up); ceAttr.set(ABI_STAGE.DEF, elem.def_up); ceAttr.set(ABI_STAGE.MDEF, elem.mdef_up); - ceAttr.set(ABI_STAGE.AGI, elem.agi_up); - ceAttr.set(ABI_STAGE.LUK, elem.luk_up); return ceAttr; -} \ No newline at end of file +} +arr = undefined; \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicHeroWake.ts b/shared/pubUtils/dictionary/DicHeroWake.ts index 24e4e56f4..eb71b8523 100644 --- a/shared/pubUtils/dictionary/DicHeroWake.ts +++ b/shared/pubUtils/dictionary/DicHeroWake.ts @@ -40,7 +40,5 @@ function parseCeAttr(elem) { ceAttr.set(ABI_STAGE.ATK, elem.atk_up); ceAttr.set(ABI_STAGE.DEF, elem.def_up); ceAttr.set(ABI_STAGE.MDEF, elem.mdef_up); - ceAttr.set(ABI_STAGE.AGI, elem.agi_up); - ceAttr.set(ABI_STAGE.LUK, elem.luk_up); return ceAttr; } \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicJob.ts b/shared/pubUtils/dictionary/DicJob.ts index 7ed2a6749..32d83989e 100644 --- a/shared/pubUtils/dictionary/DicJob.ts +++ b/shared/pubUtils/dictionary/DicJob.ts @@ -1,6 +1,6 @@ // 兵种表 import {readJsonFile, parseNumberList, parseGoodStr} from '../util' -import { FILENAME } from '../../consts' +import { FILENAME, ABI_STAGE } from '../../consts' import { RewardInter } from '../interface'; const _ = require('lodash'); @@ -23,18 +23,8 @@ export interface DicJob { readonly trainingConsume: Array; // 升阶消耗 readonly upGradeConsume: Array; - // 生命训练提升 - readonly hp: number; - // 攻击力训练提升 - readonly atk: number; - // 防御力训练提升 - readonly def: number; - // 策防训练提升 - readonly mdef: number; - // 敏捷训练提升 - readonly agi: number; - // 幸运训练提升 - readonly luk: number; + // 每阶升级属性 + readonly ceAttr: Map } @@ -42,7 +32,7 @@ const str = readJsonFile(FILENAME.DIC_JOB); let arr = JSON.parse(str); type KeysEnum = { [P in keyof Required]: true }; -const DicJobKeys: KeysEnum = {jobid: true, name: true, grade: true, unlockLevel: true, job_class: true, type: true, seid: true,trainingConsume: true, upGradeConsume: true, hp: true, atk: true, def: true, mdef: true, agi: true, luk: true}; +const DicJobKeys: KeysEnum = {jobid: true, name: true, grade: true, unlockLevel: true, job_class: true, type: true, seid: true,trainingConsume: true, upGradeConsume: true, ceAttr: true}; export const dicJob = new Map(); export const jobClassMaxGrades = new Map(); @@ -52,6 +42,7 @@ arr.forEach(o => { o.seid = parseNumberList(o.seid); o.trainingConsume = parseGoodStr(o.trainingConsume); o.upGradeConsume = parseGoodStr(o.upGradeConsume); + o.ceAttr = parseCeAttr(o); dicJob.set(o.jobid, _.pick(o, Object.keys(DicJobKeys))); let jobClass = jobClassMaxGrades.get(o.job_class); if (!!jobClass && jobClass.grade < o.grade) { @@ -61,4 +52,13 @@ arr.forEach(o => { }); +function parseCeAttr(elem) { + let ceAttr = new Map(); + ceAttr.set(ABI_STAGE.HP, elem.hp); + ceAttr.set(ABI_STAGE.ATK, elem.atk); + ceAttr.set(ABI_STAGE.DEF, elem.def); + ceAttr.set(ABI_STAGE.MDEF, elem.mdef); + return ceAttr; +} + arr = undefined; \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicTeraph.ts b/shared/pubUtils/dictionary/DicTeraph.ts index 341ca53f6..07189fac9 100644 --- a/shared/pubUtils/dictionary/DicTeraph.ts +++ b/shared/pubUtils/dictionary/DicTeraph.ts @@ -1,6 +1,7 @@ // 物品表 import { decodeArrayListStr, readJsonFile, parseGoodStr } from '../util' -import { FILENAME} from '../../consts' +import { FILENAME, ABI_TYPE} from '../../consts' +import { RewardInter } from '../interface'; const _ = require('lodash'); export interface SpecialMaterial { @@ -13,25 +14,16 @@ export interface DicTeraph { readonly id: number; readonly index: number; readonly grade: number; - readonly hpMax: number; - readonly atkMax: number; - readonly defMax: number; - readonly mdefMax: number; - readonly agiMax: number; - readonly lukMax: number; - readonly hp; - readonly atk; - readonly def; - readonly mdef; - readonly agi; - readonly luk; - readonly criRate; - readonly criEffect; - readonly upMaterial:Array<{id: number, number: number}>; + readonly mainAttrMax: Map; // 最大强化加成 id => value 18围内的id + readonly mainAttrUp: Map; // 每次强化加成 id => value 18围内的id + + readonly criRate: number; + readonly criEffect: number; + readonly upMaterial:Array; - readonly assiAttrValue:Array<{id: number, number: number}>; - readonly upGradeMaterial:Array<{id: number, number: number}>; + readonly assiAttrValue:Map; // 次级属性 + readonly upGradeMaterial:Array; } const str = readJsonFile(FILENAME.DIC_TERAPH); @@ -42,18 +34,8 @@ const DicTeraphKeys: KeysEnum = { id: true, index: true, grade: true, - hpMax: true, - atkMax: true, - defMax: true, - mdefMax: true, - agiMax: true, - lukMax: true, - hp: true, - atk: true, - def: true, - mdef: true, - agi: true, - luk: true, + mainAttrMax: true, + mainAttrUp: true, criRate: true, criEffect: true, upMaterial: true, @@ -65,26 +47,40 @@ arr.forEach(o => { o.assiAttrValue = parseAttr(o.assiAttrValue); o.upGradeMaterial = parseGoodStr(o.upGradeMaterial); o.upMaterial = parseGoodStr(o.upMaterial); - o.hp = o.hpUp; - o.atk = o.atkUp; - o.def = o.defUp; - o.mdef = o.mdefUp; - o.agi = o.agiUp; - o.luk = o.lukUp; + o.mainAttrMax = parseMainAttrMax(o); + o.mainAttrUp = parseMainAttrUp(o); dicTeraph.set(o.index + '_' + o.grade, _.pick(o, Object.keys(DicTeraphKeys))); }); arr = undefined; function parseAttr(str: string) { - let result = new Array<{id: number, number: number}>(); + let result = new Map(); if(!str) return result; let decodeArr = decodeArrayListStr(str); for(let [id, number] of decodeArr) { if(isNaN(parseInt(id)) || isNaN(parseInt(number))) { throw new Error('data table format wrong'); } - result.push({id: parseInt(id), number: parseInt(number)}); + result.set(parseInt(id), parseInt(number)); } return result } + +function parseMainAttrMax(elem) { + let result = new Map(); + result.set(ABI_TYPE.ABI_HP, elem.hpMax); + result.set(ABI_TYPE.ABI_ATK, elem.atkMax); + result.set(ABI_TYPE.ABI_DEF, elem.defMax); + result.set(ABI_TYPE.ABI_MDEF, elem.mdefMax); + return result +} + +function parseMainAttrUp(elem) { + let result = new Map(); + result.set(ABI_TYPE.ABI_HP, elem.hpUp); + result.set(ABI_TYPE.ABI_ATK, elem.atkUp); + result.set(ABI_TYPE.ABI_DEF, elem.defUp); + result.set(ABI_TYPE.ABI_MDEF, elem.mdefUp); + return result +} \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicTitle.ts b/shared/pubUtils/dictionary/DicTitle.ts index 79047d65e..b9fd3c5a0 100644 --- a/shared/pubUtils/dictionary/DicTitle.ts +++ b/shared/pubUtils/dictionary/DicTitle.ts @@ -1,6 +1,6 @@ // 物品表 import { decodeArrayListStr, readJsonFile, parseGoodStr } from '../util' -import { FILENAME} from '../../consts' +import { FILENAME, ABI_TYPE} from '../../consts' const _ = require('lodash'); export interface SpecialMaterial { @@ -9,15 +9,10 @@ export interface SpecialMaterial { } export interface DicTitle { - // 等级 readonly id: number; - readonly hp: number; - readonly atk: number; - readonly def: number; - readonly mdef: number; - readonly agi: number; - readonly luk: number; - readonly assiAttrValue: Array<{id: number, number: number}>; + // 等级 + readonly mainAttrValue: Map; // id => value 这里的值是上一级的基础上增加的值 + readonly assiAttrValue: Map; // id => value // 等级现在 readonly lvLimited: number; // 升级消耗 @@ -30,18 +25,14 @@ let arr = JSON.parse(str); type KeysEnum = { [P in keyof Required]: true }; const DicTitleKeys: KeysEnum = { id: true, - hp: true, - atk: true, - def: true, - mdef: true, - agi: true, - luk: true, + mainAttrValue: true, assiAttrValue: true, lvLimited: true, material: true } export const dicTitle = new Map(); arr.forEach(o => { + o.mainAttrValue = parseMainAttr(o); o.assiAttrValue = parseAttr(o.assiAttrValue); o.material = parseGoodStr(o.material); dicTitle.set(o.id, _.pick(o, Object.keys(DicTitleKeys))); @@ -50,14 +41,23 @@ arr.forEach(o => { arr = undefined; function parseAttr(str: string) { - let result = new Array<{id: number, number: number}>(); + let result = new Map(); if(!str) return result; let decodeArr = decodeArrayListStr(str); - for(let [id, number] of decodeArr) { - if(isNaN(parseInt(id)) || isNaN(parseInt(number))) { + for(let [id, value] of decodeArr) { + if(isNaN(parseInt(id)) || isNaN(parseInt(value))) { throw new Error('data table format wrong'); } - result.push({id: parseInt(id), number: parseInt(number)}); + result.set(parseInt(id), parseInt(value)); } return result } + +function parseMainAttr(elem) { + let result = new Map(); + result.set(ABI_TYPE.ABI_HP, elem.hp); + result.set(ABI_TYPE.ABI_ATK, elem.atk); + result.set(ABI_TYPE.ABI_DEF, elem.def); + result.set(ABI_TYPE.ABI_MDEF, elem.mdef); + return result; +} \ No newline at end of file diff --git a/shared/pubUtils/dictionary/DicWarJson.ts b/shared/pubUtils/dictionary/DicWarJson.ts index 0d5a6a4a9..b3df59cb4 100644 --- a/shared/pubUtils/dictionary/DicWarJson.ts +++ b/shared/pubUtils/dictionary/DicWarJson.ts @@ -1,8 +1,5 @@ // 关卡表 import {decodeArrayListStr, readWarJsonFileList} from '../util' -import { ABI_TYPE } from '../../consts'; -import { Attributes } from '../interface'; - export interface DicWarJson { @@ -33,7 +30,7 @@ export interface DicWarJson { // 角色使用的AI类型 readonly initial_ai: number; // 属性 - readonly attribute: Attributes; + readonly attribute: {id: number, val: number}[]; // 武将技能 readonly skill: string; // 武将被动技能 @@ -63,55 +60,15 @@ readWarJsonFileList().forEach(str => { dicWarJson.set(warid, warjson); }) -function parseAttribute(str: string) { - - let attribute: Attributes = {}; - if(!str) return attribute; - - let arr = decodeArrayListStr(str); - for(let [id, value] of arr) { - if(isNaN(parseInt(id)) || isNaN(parseInt(value))) { +export function parseAttribute(str: string) { + let result = new Array<{ id: number, val: number }>(); + if (!str) return result; + let decodeArr = decodeArrayListStr(str); + for (let [id, val] of decodeArr) { + if (isNaN(parseInt(id)) || isNaN(parseInt(val))) { throw new Error('data table format wrong'); } - let _id = parseInt(id), _value = parseInt(value); - switch(_id) { - case ABI_TYPE.ABI_HP: - attribute.hp = _value; break; - case ABI_TYPE.ABI_ATK: - attribute.atk = _value; break; - case ABI_TYPE.ABI_MATK: - attribute.matk = _value; break; - case ABI_TYPE.ABI_DEF: - attribute.def = _value; break; - case ABI_TYPE.ABI_MDEF: - attribute.mdef = _value; break; - case ABI_TYPE.ABI_AGI: - attribute.agi = _value; break; - case ABI_TYPE.ABI_LUK: - attribute.luk = _value; break; - case ABI_TYPE.ABI_SPEED: - attribute.speed = _value; break; - case ABI_TYPE.ABI_HIT: - attribute.hit = _value; break; - case ABI_TYPE.ABI_CRI: - attribute.cri = _value; break; - case ABI_TYPE.ABI_FLEE: - attribute.flee = _value; break; - case ABI_TYPE.ABI_ANT_CRI: - attribute.antCri = _value; break; - case ABI_TYPE.ABI_DAMAGE_INCREASE: - attribute.damageIncrease = _value; break; - case ABI_TYPE.ABI_DAMAGE_DECREASE: - attribute.damageDecrease = _value; break; - case ABI_TYPE.ABI_DEF_IGNORE: - attribute.defIngnore = _value; break; - case ABI_TYPE.ABI_BLOOD_SUCK: - attribute.bloodSuck = _value; break; - case ABI_TYPE.ABI_AP: - attribute.ap = _value; break; - default: - break; - } + result.push({ id: parseInt(id), val: parseInt(val) }); } - return attribute -} \ No newline at end of file + return result +} diff --git a/shared/pubUtils/gamedata.ts b/shared/pubUtils/gamedata.ts index d53e14612..5d5dddd3c 100644 --- a/shared/pubUtils/gamedata.ts +++ b/shared/pubUtils/gamedata.ts @@ -373,8 +373,6 @@ function parseHeroStar() { ceAttr.set(ABI_STAGE.ATK, elem.atk_up); ceAttr.set(ABI_STAGE.DEF, elem.def_up); ceAttr.set(ABI_STAGE.MDEF, elem.mdef_up); - ceAttr.set(ABI_STAGE.AGI, elem.agi_up); - ceAttr.set(ABI_STAGE.LUK, elem.luk_up); heroStarList.set(`${elem.quality}_${elem.star}`,{ceAttr, ...elem}); } @@ -392,8 +390,6 @@ function parseHeroWake() { ceAttr.set(ABI_STAGE.ATK, elem.atk_up); ceAttr.set(ABI_STAGE.DEF, elem.def_up); ceAttr.set(ABI_STAGE.MDEF, elem.mdef_up); - ceAttr.set(ABI_STAGE.AGI, elem.agi_up); - ceAttr.set(ABI_STAGE.LUK, elem.luk_up); heroWakeList.set(`${elem.quality}_${elem.star}`,{ceAttr, ...elem}); } diff --git a/shared/pubUtils/httpUtil.ts b/shared/pubUtils/httpUtil.ts new file mode 100644 index 000000000..bf6b85c87 --- /dev/null +++ b/shared/pubUtils/httpUtil.ts @@ -0,0 +1,103 @@ +import * as request from "request-promise"; +import * as crypto from 'crypto' +import { BANTU_VID_ADDR, BANTU_VID_APP_KEY } from '../consts'; + +/** + * 在线报告 + * @param userCode 账号 + * @param packageName 包名 + */ +export async function reportOnline ( userCode: string, packageName: string) { + if(!packageName || packageName==''){ + packageName = 'com.bantu.nfsg' + } + + let result = await vidHttpRequest(BANTU_VID_ADDR.REPORT_ONLINE, { + account: userCode, + package: packageName + }); + if(result && result.code !== 1) { + console.error(result.msg); + } + + return result; +} + +/** + * 实名认证 + * @param name 真实姓名 + * @param idNum 身份证号 + * @param userCode 账号 + * @param packageName 包名 + */ +export async function authenticate (name: string, idNum: string, userCode: string, packageName: string) { + if(!packageName || packageName==''){ + packageName = 'com.bantu.nfsg' + } + + let result = await vidHttpRequest(BANTU_VID_ADDR.IDCARD, { + account: userCode, + cardno: idNum, + name, + appkey: BANTU_VID_APP_KEY, + package: packageName + }); + if(result && result.code !== 1) { + console.error(result.msg); + } + + return result && result.code == 1; +} + +export async function vidHttpRequest(addr: string, body: any) { + body['sign'] = getObjSign(body); + console.log('body: ', JSON.stringify(body)) + + let options = { + url: BANTU_VID_ADDR.HOST + addr, + method: 'POST', + body:body, + json: true + } + + try { + let res = await request(options); + let check = checkSign(res); + if(!check) return false; + console.log('*****request result*****'); + console.log(JSON.stringify(res)); + return res; + } catch(e) { + console.error(e); + return false + } +} + +export function md5Vid (str: string) { + str = 'vId' + str; + return crypto.createHash('md5').update(str, 'utf8').digest("hex"); +}; + +export function getObjSign (obj: any) { + const str = []; + Object.keys(obj).sort().forEach((key) => { + if (key == 'sign') { + + } else { + str.push(key + '=' + obj[key]); + } + }); + if (str.length == 0) { + console.error('check obj', obj); + } + var strs = str.join(''); + return md5Vid(strs); +} + +export async function checkSign (obj: any) { + if (getObjSign(obj) === obj.sign) { + return true; + } + console.warn('correct sign:', getObjSign(obj), obj.sign); + return false; +} diff --git a/shared/pubUtils/interface.ts b/shared/pubUtils/interface.ts index 7228c5cf2..1e79f7769 100644 --- a/shared/pubUtils/interface.ts +++ b/shared/pubUtils/interface.ts @@ -1,31 +1,12 @@ // 一些通用的interface定义 +import { Attribute } from "../domain/roleField/attribute"; + export interface RewardInter { id: number; count: number; } - -export interface Attributes { - hp?: number; - atk?: number; - matk?: number; - def?: number; - mdef?: number; - agi?: number; - luk?: number; - speed?: number; - hit?: number; - cri?: number; - flee?: number; - antCri?: number; - damageIncrease?: number; - damageDecrease?: number; - defIngnore?: number; - bloodSuck?: number; - ap?: number; -} - export interface EquipInter { id: number; name: string; @@ -82,7 +63,7 @@ export interface oppHeroesDefenseInter { lv: number; // 等级 hide: number; // 是否隐藏 initial_ai: number; // ai类型 - attribute: Attributes; + attribute: Attribute; star: number; // 星级 skill: string|number; // 技能 seid: string; // 技能 diff --git a/shared/pubUtils/playerCe.ts b/shared/pubUtils/playerCe.ts index 202431d98..aea959889 100644 --- a/shared/pubUtils/playerCe.ts +++ b/shared/pubUtils/playerCe.ts @@ -2,213 +2,288 @@ * 体力系统 */ -import { HERO_SYSTEM_TYPE, ABI_TYPE, JEWEL_ATTR } from '../consts'; +import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, HERO_SUB_ATTR_RATIO } from '../consts'; import { deepCopy, getAllAttrStage, reduceCe } from './util'; -import { HeroModel, HeroType } from '../db/Hero'; -import { RoleModel, RoleType } from '../db/Role'; -import { CeAttrData, CeAttr, CeAttrRole, CeAttrNumber, CeAttrDataRole } from '../domain/roleField/attribute'; -import { getAttrNameByJobStage, getAttrCeRatio, getAtrrNameById, ABI_STAGE, SEID_TYPE } from '../consts'; -import { gameData, getJobByGradeAndClass, getHeroWakeByQuality, getHeroStarByQuality, getFriendShipById, getSchoolRateByStar, getScollByStar, getFieldByStage } from './data'; +import { HeroModel, HeroType, HeroUpdate } from '../db/Hero'; +import { RoleModel, RoleType, RoleUpdate } from '../db/Role'; +import { CeAttrData, CeAttrDataRole, Attribute } from '../domain/roleField/attribute'; +import { ABI_STAGE, SEID_TYPE } from '../consts'; +import { gameData, getJobByGradeAndClass, getHeroWakeByQuality, getHeroStarByQuality, getFriendShipById, getSchoolRateByStar, getScollByStar, getTeraph } from './data'; import { DicSe } from './dictionary/DicSe'; import { EquipType } from '../db/Equip'; import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool'; -import { getGoodById } from './gamedata'; import { SchoolModel } from '../db/School'; -import { getTeraphAttr, HEROTARIN } from '../consts/constModules/abilityConst' +import { ABI_TYPE_TO_STAGE, ABI_TYPE_MAIN } from '../consts/constModules/abilityConst' import { PvpDefenseModel } from '../db/PvpDefense'; -const HERO_CE_RATIO = 100; import { findIndex } from 'underscore'; import { GuildModel } from '../db/Guild'; +import { DicJob } from './dictionary/DicJob'; -//战力计算TODO -export function calPlayerCe(globalCeAttr: CeAttrRole, hero: HeroType, type: number, args: Array = []) { - let heroCe = 0; - let reIncAttr: CeAttr = {}; // {"hp": {"base": number, "fixUp": number, "ratioUp": number}} +// 修改并下发战力 +export async function calPlayerCeAndSave(type: number, roleId: string, originHero: HeroType, update: HeroUpdate, args?: Array) { + let role = await RoleModel.findByRoleId(roleId); + + let { attr: roleAttrs = [] } = role; + + let heroAttrs = calPlayerCe(originHero, update, type, args); // 根据操作计算attr的增加 + + let newAttr = new Attribute(); + newAttr.setByDbData(roleAttrs, heroAttrs); + let heroCe = newAttr.calCe(); // 计算最终战力 + let incCe = heroCe - originHero.ce; + + // 更新到武将 + update.attr = heroAttrs; + update.ce = heroCe; + if (originHero.historyCe < heroCe) update.historyCe = heroCe; + let hero = await HeroModel.updateHeroInfo(roleId, originHero.hid, update); // 更新武将 + + // 更新到角色 + let { topLineup, topLineupCe } = await calculatetopLineup(role, originHero.hid, heroCe, originHero._id); // 计算更新最强五人战力 + role = await RoleModel.updateRoleInfo(roleId, { ce: role.ce + incCe, topLineup, topLineupCe }); + + await PvpDefenseModel.updateCe(roleId, originHero.hid, heroCe); // 更新pvp防守阵战力 + await GuildModel.updateCe(roleId, incCe); // 公会更新战力 + + let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>(); + pushHeros.push({ + hid: originHero.hid, + ce: reduceCe(heroCe), + incHeroCe: reduceCe(incCe), + }); + return { pushHeros, role, topLineupCe, hero } +} + +//全局属性加成 +export async function reCalAllHeroCe(type: number, roleId: string, update: RoleUpdate, args?: Array) { + let role = await RoleModel.findByRoleId(roleId); + let heros = await HeroModel.findByRole(roleId); + + let roleAttrs = await reCalRoleAttr(type, heros, role, update, args); + if(!roleAttrs) return {pushHeros: [], ce: role.ce, topLineupCe: role.topLineupCe}; // 无加成 + + let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>(); + + let roleCe = 0; // 总战力加成 + for (let hero of heros) { + let { attr: heroAttrs } = hero; + let newAttr = new Attribute(); + newAttr.setByDbData(roleAttrs, heroAttrs); + let heroCe = newAttr.calCe(); // 计算最终战力 + + let incHeroCe = heroCe - hero.ce; + roleCe += heroCe; + pushHeros.push({ hid: hero.hid, ce: reduceCe(hero.ce), incHeroCe: reduceCe(incHeroCe) }); + await HeroModel.updateHeroInfo(roleId, hero.hid, { ce: heroCe }); + } + let { topLineup, topLineupCe } = await calculatetopLineup(role); // 计算更新最强五人战力 + + update.attr = roleAttrs; + update.ce = roleCe; + update.topLineup = topLineup; + update.topLineupCe = topLineupCe; + + role = await RoleModel.updateRoleInfo(roleId, update); + return { role, pushHeros, ce: role.ce, topLineupCe: role.topLineupCe } +} + +// 计算武将全局战力 +async function reCalRoleAttr(type: number, heros: Array, role: RoleType, update: RoleUpdate, args: Array) { + let { attr: roleAttrs } = role; + switch (type) { + case HERO_SYSTEM_TYPE.ADD_SKIN: + roleAttrs = calHeroAddSkin(role, args); + break; + case HERO_SYSTEM_TYPE.SCHOOL: + roleAttrs = calSchoolAddAttr(role, heros, args[0], args[1], args[2]); + break; + case HERO_SYSTEM_TYPE.SCROLL: + roleAttrs = calScrollAddAttr(role, heros, args[0]); + break; + case HERO_SYSTEM_TYPE.STAR: + case HERO_SYSTEM_TYPE.COLORSTAR: + case HERO_SYSTEM_TYPE.QUALITY: + roleAttrs = await calSchoolStarIncAttr(role, heros, type, args[0], args[1]); + break; + case HERO_SYSTEM_TYPE.TITLE: + roleAttrs = calTitle(role, update); + break; + case HERO_SYSTEM_TYPE.TERAPH: + roleAttrs = calTeraphMainAttr(role, update, args[0]); + break; + case HERO_SYSTEM_TYPE.TERAPH_UP: + roleAttrs = calTeraphAssistAttr(role, update, args[0]); + break; + } + + return roleAttrs; +} + +// 计算单个武将战力 +export function calPlayerCe(hero: HeroType, update: HeroUpdate, type: number, args: Array = []) { + let heroAttrs: CeAttrData[] = []; // {"hp": {"base": number, "fixUp": number, "ratioUp": number}} let addSeidList = new Array(); let removeSeidList = new Array(); switch (type) { case HERO_SYSTEM_TYPE.INIT: - reIncAttr = calHeroInitIncAttr(hero, addSeidList, removeSeidList); // args: 升的星盘 + heroAttrs = calHeroInitIncAttr(hero, addSeidList, removeSeidList); // args: 升的星盘 break; case HERO_SYSTEM_TYPE.STAR: case HERO_SYSTEM_TYPE.LVUP: case HERO_SYSTEM_TYPE.COLORSTAR: case HERO_SYSTEM_TYPE.QUALITY: - reIncAttr = calHeroStarIncAttr(hero, type, args.shift(), args, addSeidList, removeSeidList); // args: 升的星盘 + heroAttrs = calHeroStarIncAttr(hero, update, type, addSeidList, removeSeidList); // args: 升的星盘 break; case HERO_SYSTEM_TYPE.TRAIN: - reIncAttr = calHeroTrainIncAttr(hero); + heroAttrs = calHeroTrainIncAttr(hero, update); break; case HERO_SYSTEM_TYPE.STAGEUP: - reIncAttr = calHeroJobStageUpIncAttr(hero, args, addSeidList, removeSeidList); + heroAttrs = calHeroJobStageUpIncAttr(hero, update, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.SKIN: - reIncAttr = calHeroWearSkinIncAttr(hero, args, addSeidList, removeSeidList); + heroAttrs = calHeroWearSkinIncAttr(hero, args[0], args[1], addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.FAVOUR: - reIncAttr = calHeroFavourUpIncAttr(hero, args); + heroAttrs = calHeroFavourUpIncAttr(hero, update); break; case HERO_SYSTEM_TYPE.CONNECT: - reIncAttr = calHeroConectIncAttr(hero, args); + heroAttrs = calHeroConectIncAttr(hero, update, args[0]); break; case HERO_SYSTEM_TYPE.EQUIP: - reIncAttr = calEquipPutOnOffIncAttr(hero, args, addSeidList, removeSeidList); + heroAttrs = calEquipPutOnOffIncAttr(hero, args, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.EQUIP_BASE: - reIncAttr = calHeroEquipIncAttr(hero); + heroAttrs = calHeroEquipIncAttr(hero); break; case HERO_SYSTEM_TYPE.RESTRENGTHEN: - reIncAttr = calRestrengthenIncAttr(hero, args.shift(), args, addSeidList, removeSeidList); + heroAttrs = calRestrengthenIncAttr(hero, args.shift(), args, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.JEWEL_ON: - reIncAttr = calHeroCeWhenJewelOn(hero, args); + heroAttrs = calHeroCeWhenJewelOn(hero, args[0], args[1]); break; case HERO_SYSTEM_TYPE.JEWEL_OFF: - reIncAttr = calHeroCeWhenJewelOff(hero, args); + heroAttrs = calHeroCeWhenJewelOff(hero, args); break; case HERO_SYSTEM_TYPE.SCROLL: - reIncAttr = calHeroCeScrollIncAttr(hero, args[0], args[1]); + heroAttrs = calHeroCeScrollIncAttr(hero, update); break; default: break; } - addSeidEffect(reIncAttr, hero.ceAttr, addSeidList, removeSeidList); // 处理加值 - if (!hero.ceAttr) hero.ceAttr = new CeAttr(); - for (let attrName in hero.ceAttr) { - if (attrName == '_id') continue; - let globalAttrData: CeAttrDataRole = globalCeAttr[attrName] || new CeAttrDataRole(); - if (!hero.ceAttr[attrName]) hero.ceAttr[attrName] = new CeAttrData(); - if (!!reIncAttr[attrName]) { - for (let attrKey in reIncAttr[attrName]) { - hero.ceAttr[attrName][attrKey] = parseInt(reIncAttr[attrName][attrKey] || 0); - } - } - let attrNumber = (hero.ceAttr[attrName].fixUp + (hero.ceAttr[attrName].equipUp || 0) + globalAttrData.fixUp) * HERO_CE_RATIO + hero.ceAttr[attrName].base * (HERO_CE_RATIO + hero.ceAttr[attrName].ratioUp + globalAttrData.ratioUp); - // console.log(hero.hid, attrNumber, attrName, getAttrCeRatio(attrName)) - heroCe += attrNumber * getAttrCeRatio(attrName); - } - let incCe = heroCe - hero.ce; - hero.ce = heroCe > 0 ? heroCe : 1; - if (hero.historyCe < hero.ce) hero.historyCe = hero.ce; - return incCe; + addSeidEffect(heroAttrs, addSeidList, removeSeidList); // 处理加值 + + return heroAttrs; } -//修改并下发战力 -export async function calPlayerCeAndSave(roleId: string, heros: Array, type?: number, args?: Array) { - if (!heros.length) heros = await HeroModel.findByRole(roleId); - let incPlayerCe = 0; - let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>(); - let role = await RoleModel.findByRoleId(roleId); - if (!role.globalCeAttr) role.globalCeAttr = new CeAttr(); - await reCalRoleAttr(heros, role.globalCeAttr, type, args); - for (let hero of heros) { - let incHeroCe = calPlayerCe(role.globalCeAttr, hero, type, args); - - incPlayerCe += incHeroCe; - await calculatetopLineup(role, hero.hid, hero.ce, hero._id); // 计算更新最强五人战力 - await HeroModel.updateHeroInfo(roleId, hero.hid, hero); - await PvpDefenseModel.updateCe(roleId, hero.hid, hero.ce); // 更新pvp防守阵战力 - pushHeros.push({ - hid: hero.hid, - ce: reduceCe(hero.ce), - incHeroCe: reduceCe(incHeroCe), - }); - } - role.ce += incPlayerCe; - let { topLineup, topLineupCe } = role; - await RoleModel.updateRoleInfo(roleId, { globalCeAttr: role.globalCeAttr, ce: role.ce, topLineup, topLineupCe }); - await GuildModel.updateCe(roleId, incPlayerCe); - return { pushHeros, role, topLineupCe } -} - -export async function calculatetopLineup(role: RoleType, hid: number, ce: number, heroId: string) { +/** + * 计算最强阵容战力 + * @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(); - - topLineup.sort((a, b) => { return b.ce - a.ce }); // 0-6,最大-最小 - let index = topLineup.findIndex(cur => cur.hid == hid); - if(index != -1 && !heroId) { + if(!hid) { // 直接重新排 let heroes = await HeroModel.getTopHero(role.roleId, 6); topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); } else { - if (index == -1) { // 不在最强列表 - if (topLineup.length < 6) { // 不满6人 - topLineup.push({ hid, ce, hero: heroId }); - } else if (topLineup.length == 6) { - if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 - topLineup.pop(); + 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, 6); + topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); + } else { + if (index == -1) { // 不在最强列表 + if (topLineup.length < 6) { // 不满6人 topLineup.push({ hid, ce, hero: heroId }); + } else if (topLineup.length == 6) { + if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 + topLineup.pop(); + topLineup.push({ hid, ce, hero: heroId }); + } + } else { + topLineup.splice(6, topLineup.length - 6); + } + } else { // 原来就是最强6人 + if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 + let heroes = await HeroModel.getTopHero(role.roleId, 6); + topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); + } else { + topLineup[index].ce = ce; } - } else { - topLineup.splice(6, topLineup.length - 6); - } - } else { // 原来就是最强6人 - if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 - let heroes = await HeroModel.getTopHero(role.roleId, 6); - 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); - role.topLineup = topLineup; - role.topLineupCe = topLineupCe; - return role; -} - -// 初始战力 -export function calHeroInitIncAttr(hero: HeroType, addSeidList: Array, removeSeidList: Array) { - let res = calHeroStarIncAttr(hero, HERO_SYSTEM_TYPE.INIT, hero.hid, [], addSeidList, removeSeidList); - let curSkin = hero.skins.find(cur => cur.enable); - calHeroWearSkinIncAttr(hero, [curSkin ? curSkin.id : 0, 0], addSeidList, removeSeidList, true, res); - calHeroJobAttr(hero, res, addSeidList, removeSeidList); - return res; -} - -export function calRoleInitIncAttr(heros: HeroType[], globalCeAttr: CeAttrRole) { - let args = new Array(); - for (let hero of heros) { - for (let skin of hero.skins) { - args.push(skin.id); - } - } - let res = calHeroAddSkin(args, globalCeAttr); - return res; + return { topLineup, topLineupCe }; } /** * - * @param hero HeroType 武将更新后的值 - * @param type number 类型 - * @param hid number 当前武将id - * @param args number[] 当升星时,一个参数,0-是否升了一星;当觉醒时,两个参数,0-是否升了一星,1-是否初次觉醒 - * @param addSeidList number[] 用于更新被动 - * @param removeSeidList number[] 用于更新被动 + * @param {HeroType} hero 武将数据 + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 */ -export function calHeroStarIncAttr(hero: HeroType, type: number, hid: number, args: number[], addSeidList: Array, removeSeidList: Array) { +export function calHeroInitIncAttr(hero: HeroType, addSeidList: Array, removeSeidList: Array) { + try{ + delete hero._id; + let heroAttrs = calHeroStarIncAttr(hero, hero, HERO_SYSTEM_TYPE.INIT, addSeidList, removeSeidList); + let curSkin = hero.skins.find(cur => cur.enable); + heroAttrs = calHeroWearSkinIncAttr(hero, curSkin ? curSkin.id : 0, 0, addSeidList, removeSeidList, true); + heroAttrs = calHeroJobAttr(hero, hero, addSeidList, removeSeidList); + return heroAttrs; + }catch(e) { + console.error(e); + } +} + +/** + * 添加皮肤全局加成 + * @param args + * @param ceAttr + */ +function calHeroAddSkin(role: RoleType, skinIds: Array) { + let { attr: roleAttrs } = role; + + for (let id of skinIds) { + let addSkin = gameData.fashion.get(id); + for (let attr of addSkin.globalAttr) { + let fixUp = attr.number * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, attr.id, { inc: { fixUp } }); + } + } + role.attr = roleAttrs; + return roleAttrs; +} + +/** + * 升星觉醒升品等 + * @param {HeroType} hero 武将更新前的值 + * @param {HeroUpdate} update 更新的值 + * @param {number} type 养成类型 + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + */ +export function calHeroStarIncAttr(originHero: HeroType, update: HeroUpdate, type: number, addSeidList: Array, removeSeidList: Array) { let isInit = type == HERO_SYSTEM_TYPE.INIT; - let { star, starStage, quality, colorStar, colorStarStage, ceAttr, skins } = hero; - let originStar = star, originColorStar = colorStar; + let { hid, star: originStar, starStage: originStarStage, quality: originQuality, colorStar: originColorStar, colorStarStage: originColorStarStage, attr: heroAttrs, skins, lv } = originHero; + let { star = originStar, starStage = originStarStage, quality = originQuality, colorStar = originColorStar, colorStarStage = originColorStarStage } = update; - let res: CeAttr = {}; - if (hero.hid != hid) return res; - - const dicHero = gameData.hero.get(hero.hid); + const dicHero = gameData.hero.get(hid); const isWake = colorStar > 0; // 是否觉醒,只要激活了觉醒,彩星就会 > 1 - if (isWake) { - if (colorStarStage == ABI_STAGE.START) originColorStar = colorStar - 1; - } else { - if (starStage == ABI_STAGE.START) originStar = star - 1; - } + const isFirstWake = colorStar > 0 && originColorStar <= 0; // 是否是初次觉醒 + const isUpStar = originStar != star || originColorStar != colorStar; // 是否有升星 + console.log('*isUpstar', isUpStar, originStar, star, originColorStar, colorStar) + const dicStar = isWake ? getHeroWakeByQuality(dicHero.quality, originColorStar) : getHeroStarByQuality(quality, originStar); // 星级表 let stages = new Array(); // 需要升级的阶 @@ -217,51 +292,97 @@ export function calHeroStarIncAttr(hero: HeroType, type: number, hid: number, ar } else if (type == HERO_SYSTEM_TYPE.LVUP) { stages = getAllAttrStage(); } else if (type == HERO_SYSTEM_TYPE.STAR) { - stages = [args[0] ? ABI_STAGE.END : starStage]; + stages.push(isUpStar? ABI_STAGE.END: starStage); } else if (type == HERO_SYSTEM_TYPE.QUALITY) { stages = getAllAttrStage(); } else if (type = HERO_SYSTEM_TYPE.COLORSTAR) { - if (args[1]) { // 首次觉醒 + if (isFirstWake) { // 首次觉醒 stages = getAllAttrStage(); } else { - stages.push(args[0] ? ABI_STAGE.END : hero.colorStarStage) + stages.push(isUpStar ? ABI_STAGE.END : colorStarStage); } } for (let stage of stages) { - let targetAttrId = getFieldByStage(stage, hero.job); // 转换为17维的属性id + let targetAttrId = ABI_TYPE_TO_STAGE.get(stage); // 转换为18维的属性id let heroAttr = dicHero.baseAbilityArr.get(targetAttrId); // 武将表hp等 let heroUpAttr = dicHero.baseAbilityUpArr.get(targetAttrId); // 武将表hp_up等 - let starUp = 0; + let starUp = 0; // 星级成长 if (!!dicStar && !!dicStar.ceAttr) { starUp = dicStar.ceAttr.get(stage); } - let newBase = (heroAttr + (hero.lv - 1) * (heroUpAttr + starUp)) * HERO_CE_RATIO; - let field = getAtrrNameById(targetAttrId); - let ceAttrData: CeAttrData = ceAttr[field] || new CeAttrData(); // 存表中的属性下的base,fixup,ratioup - let { ratioUp = 0, fixUp = 0 } = ceAttrData; - res[field] = { base: newBase, ratioUp, fixUp }; // base变动,增量为△base * ratio + 0 + let newBase = (heroAttr + (lv - 1) * (heroUpAttr + starUp)) * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, targetAttrId, { set: { base: newBase } }); } // 解锁技能 let curSkin = skins.find(cur => cur.enable); let curSeidList = getSeidListOfFashion(curSkin.id, star, colorStar); let preSeidList = getSeidListOfFashion(curSkin.id, isInit ? 0 : originStar, isInit ? 0 : originColorStar); - for (let [type, seid] of curSeidList) { + + curSeidList.forEach((seid, type) => { if (!preSeidList.has(type)) { addSeidList.push(seid, 0); } - } - for (let [type, seid] of preSeidList) { + }); + preSeidList.forEach((seid, type) => { if (!curSeidList.has(type)) { removeSeidList.push(seid, 0); } - } + }); - return res;//属性增量可以是多个 + originHero.attr = heroAttrs; + return heroAttrs;//属性增量可以是多个 } +type updateCeAttr = Partial; +function updateHeroAttr(heroAttrs: CeAttrData[], id: number, update: { inc?: updateCeAttr, set?: updateCeAttr }) { + let curAttr = heroAttrs.find(cur => cur.id == id); + if(!curAttr) { + curAttr = new CeAttrData(id); + heroAttrs.push(curAttr); + } + if(update.inc) { + let { base, equipUp, fixUp, ratioUp } = update.inc; + if(base) curAttr.base += base; + if(equipUp) curAttr.equipUp += equipUp; + if(fixUp) curAttr.fixUp += fixUp; + if(ratioUp) curAttr.ratioUp += ratioUp; + } + if(update.set) { + let { base, equipUp, fixUp, ratioUp } = update.set; + if(base) curAttr.base = base; + if(equipUp) curAttr.equipUp = equipUp; + if(fixUp) curAttr.fixUp = fixUp; + if(ratioUp) curAttr.ratioUp = ratioUp; + } +} + +type updateCeAttrRole = Partial; +function updateRoleAttr(roleAttrs: CeAttrDataRole[], id: number, update: { inc?: updateCeAttrRole, set?: updateCeAttrRole }) { + let curAttr = roleAttrs.find(cur => cur.id == id); + if(!curAttr) { + curAttr = new CeAttrDataRole(id); + roleAttrs.push(curAttr); + } + if(update.inc) { + let { fixUp, ratioUp } = update.inc; + if(fixUp) curAttr.fixUp += fixUp; + if(ratioUp) curAttr.ratioUp += ratioUp; + } + if(update.set) { + let { fixUp, ratioUp } = update.set; + if(fixUp) curAttr.fixUp = fixUp; + if(ratioUp) curAttr.ratioUp = ratioUp; + } +} +/** + * 获取皮肤上的seid + * @param fashionid + * @param originStar + * @param originColorStar + */ function getSeidListOfFashion(fashionid: number, originStar: number, originColorStar: number) { let seidList = new Map(); // type => seid if (!gameData.fashion.has(fashionid)) return seidList; @@ -281,152 +402,216 @@ function getSeidListOfFashion(fashionid: number, originStar: number, originColor return seidList } -//训练 -export function calHeroTrainIncAttr(hero: HeroType) { - let res: CeAttr = {}; - let attrName: string = getAttrNameByJobStage(hero.jobStage); - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - let currentJob = gameData.job.get(hero.job); - if (currentJob.grade > 1) { - let jobGradeAndClass = getJobByGradeAndClass(currentJob.job_class, currentJob.grade - 1); +/** + * 兵种训练 + * @param {HeroType} originHero 原始武将 + * @param {HeroUpdate} update 更新的数据 + */ +export function calHeroTrainIncAttr(originHero: HeroType, update: HeroUpdate) { + let { attr: heroAttrs, job: oldJob, jobStage: oldJobStage } = originHero; + let { job = oldJob, jobStage = oldJobStage } = update; + + let targetAttrId = ABI_TYPE_TO_STAGE.get(jobStage); // 转换为18维的属性id + + let dicJob = gameData.job.get(job); + if (dicJob.grade > 1) { + let jobGradeAndClass = getJobByGradeAndClass(dicJob.job_class, dicJob.grade - 1); let lastJob = gameData.job.get(jobGradeAndClass.jobid); - res[attrName].fixUp += (currentJob[attrName] - lastJob[attrName]) * HERO_CE_RATIO; + let inc = (dicJob.ceAttr.get(jobStage) - lastJob.ceAttr.get(jobStage)) * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp: inc } }) } else { - res[attrName].fixUp += currentJob[attrName] * HERO_CE_RATIO; + let inc = dicJob.ceAttr.get(jobStage) * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp: inc } }) } - return res; + return heroAttrs; } -//进阶 -export function calHeroJobStageUpIncAttr(hero: HeroType, args: Array, addSeidList: Array, removeSeidList: Array) { - let res: CeAttr = {}; - let lastJob = gameData.job.get(args[0]) || { seid: [] }; - let currentJob = gameData.job.get(hero.job); - for (let seid of currentJob.seid) { - let index = findIndex(lastJob.seid, seid); +/** + * 兵种进阶 + * @param {HeroType} originHero 原始武将 + * @param {HeroUpdate} update 更新内容 + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + */ +export function calHeroJobStageUpIncAttr(originHero: HeroType, update: HeroUpdate, addSeidList: Array, removeSeidList: Array) { + let { job: oldJob, attr: heroAttrs } = originHero; + let { job = oldJob } = update; + + let lastJob = gameData.job.get(oldJob); + let currentJob = gameData.job.get(job); + let lastSeids = lastJob?.seid||new Array(); + let curSeids = currentJob?.seid||new Array(); + + for (let seid of curSeids) { + let index = findIndex(lastSeids, seid); if (index < 0) { addSeidList.push(seid, 0); } } - for (let seid of lastJob.seid) { - let index = findIndex(currentJob.seid, seid); + for (let seid of lastSeids) { + let index = findIndex(curSeids, seid); if (index < 0) { removeSeidList.push(seid, 0); } } - return res; + return heroAttrs; } - -export function calHeroJobAttr(hero: HeroType, res: CeAttr, addSeidList: Array, removeSeidList: Array) { +/** + * 初始计算兵种属性 + * @param {HeroType} originHero 原始武将 + * @param {HeroUpdate} hero 更新后的武将 + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + */ +export function calHeroJobAttr(originHero: HeroType, hero: HeroUpdate, addSeidList: Array, removeSeidList: Array) { + let { attr: heroAttrs } = originHero; let currentJob = gameData.job.get(hero.job); let jobGradeAndClass = getJobByGradeAndClass(currentJob.job_class, currentJob.grade - 1); - let lastJob; + let lastJob: DicJob; if (!!jobGradeAndClass) { lastJob = gameData.job.get(jobGradeAndClass.jobid); } - for (let key in HEROTARIN) { - let attrName: string = HEROTARIN[key]; - res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - if (hero.jobStage >= parseInt(key)) { - res[attrName].fixUp += currentJob[attrName] * HERO_CE_RATIO; + + for (let stage = ABI_STAGE.START + 1; stage <= ABI_STAGE.END; stage++) { + let targetAttrId = ABI_TYPE_TO_STAGE.get(stage); + if(hero.jobStage >= stage) { + let fixUp = currentJob.ceAttr.get(stage) * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp }}) } else { - if (lastJob) - res[attrName].fixUp += lastJob[attrName] * HERO_CE_RATIO; + if(lastJob) { + let fixUp = lastJob.ceAttr.get(stage) * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp } }); + } } - } - calHeroJobStageUpIncAttr(hero, [0], addSeidList, removeSeidList); - return res; + }; + + originHero.attr = heroAttrs; + heroAttrs = calHeroJobStageUpIncAttr(originHero, hero, addSeidList, removeSeidList); + return heroAttrs; } -//穿戴时装 -export function calHeroWearSkinIncAttr(hero: HeroType, args: Array, addSeidList: Array, removeSeidList: Array, isInit = false, heroAttr?: CeAttr) { - let res: CeAttr = heroAttr || {}; - let addSkin = gameData.fashion.get(args[0]); - let delSkin = gameData.fashion.get(args[1]); - let attrName: string; +/** + * 穿戴时装的单武将加成 + * @param {HeroType} originHero 原始武将 + * @param {number} wearSkinId 穿戴的皮肤 + * @param {number} pullSkinId 脱下的皮肤 + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + * @param {boolean} isInit 是否是计算初始战力 + */ +export function calHeroWearSkinIncAttr(originHero: HeroType, wearSkinId: number, pullSkinId: number, addSeidList: number[], removeSeidList: number[], isInit: boolean = false) { + let { attr: heroAttrs } = originHero; + + let addSkin = gameData.fashion.get(wearSkinId); + let delSkin = gameData.fashion.get(pullSkinId); + if (delSkin) { for (let attr of delSkin.actorAttr) { - attrName = getAtrrNameById(attr.id); - res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp -= attr.number * HERO_CE_RATIO; + let fixUp = -1 * attr.number * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } } for (let attr of addSkin.actorAttr) { - attrName = getAtrrNameById(attr.id); - res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp += attr.number * HERO_CE_RATIO; + let fixUp = attr.number * HERO_CE_RATIO; + updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } if (!isInit) { // 初始的时候,这一段技能在calHeroStarIncAttr里计算了,不用重复算 - let { star, colorStar } = hero; + let { star, colorStar } = originHero; - let curSeidList = getSeidListOfFashion(args[0], star, colorStar); - let preSeidList = getSeidListOfFashion(args[1], star, colorStar); - for (let [type, seid] of curSeidList) { + let curSeidList = getSeidListOfFashion(wearSkinId, star, colorStar); + let preSeidList = getSeidListOfFashion(pullSkinId, star, colorStar); + curSeidList.forEach((seid, type) => { if (!preSeidList.has(type)) { removeSeidList.push(seid, 0); } - } - for (let [type, seid] of preSeidList) { + }); + preSeidList.forEach((seid, type) => { if (!curSeidList.has(type)) { addSeidList.push(seid, 0); } - } + }); } - - return res; + originHero.attr = heroAttrs; + return heroAttrs; } -//羁绊解锁 -export function calHeroConectIncAttr(hero: HeroType, args: Array) { - let res: CeAttr = {}; - let fiendShipLevel = gameData.friendShipLevelMap.get(hero.favourLv); - let shipId = args[0];//当前升级的羁绊序号 - let level = args[1];//当前升级的羁绊等级 - let attrName: string; +/** + * 羁绊解锁 + * @param {HeroType} originHero 原始武将 + * @param {HeroUpdate} update 更新数据 + * @param {number} shipId 解锁的那个id + */ +export function calHeroConectIncAttr(originHero: HeroType, update: HeroUpdate, shipId: number) { + let { connections: oldConnections = [], favourLv, attr: heroAttrs } = originHero; + let { connections = oldConnections } = update; + + let oldConnect = oldConnections.find(cur => cur.shipId == shipId); + let connect = connections.find(cur => cur.shipId == shipId); + + let oldLevel = oldConnect?.level||0; + let level = connect?.level||0; + + let fiendShipLevel = gameData.friendShipLevelMap.get(favourLv); let currentShip = getFriendShipById(shipId, level); - for (let attr of currentShip.attributes) { - attrName = getAtrrNameById(attr.id); - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp += attr.number * (HERO_CE_RATIO + fiendShipLevel.add); + if (currentShip) { + for (let attr of currentShip.attributes) { + let fixUp = attr.number * (HERO_CE_RATIO + fiendShipLevel.add); + updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); + } } if (level > 1) { - let lastShip = getFriendShipById(shipId, level - 1); - for (let attr of lastShip.attributes) { - attrName = getAtrrNameById(attr.id); - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp -= attr.number * (HERO_CE_RATIO + fiendShipLevel.add); + let lastShip = getFriendShipById(shipId, oldLevel); + if (lastShip) { + for (let attr of lastShip.attributes) { + let fixUp = -1 * attr.number * (HERO_CE_RATIO + fiendShipLevel.add); + updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }) + } } } - return res; + originHero.attr = heroAttrs; + return heroAttrs; } -//好感升级 -export function calHeroFavourUpIncAttr(hero: HeroType, args: Array) { - let res: CeAttr = {}; - let currentFiendShipLevel = gameData.friendShipLevelMap.get(hero.favourLv); +/** + * 好感度升级,影响羁绊加成 + * + * @param {HeroType} originHero 原始武将数据 + * @param {HeroUpdate} update 更新的数据 + */ +export function calHeroFavourUpIncAttr(originHero: HeroType, update: HeroUpdate) { + let { favourLv: oldFavourLv, attr: heroAttrs } = originHero; + let { favourLv = oldFavourLv } = update; + + let currentFiendShipLevel = gameData.friendShipLevelMap.get(favourLv); let difAdd = currentFiendShipLevel.add; - if (!!args[0]) { - let lastFiendShipLevel = gameData.friendShipLevelMap.get(args[0]); + if (oldFavourLv && oldFavourLv > 0) { // 减上一级好感 + let lastFiendShipLevel = gameData.friendShipLevelMap.get(oldFavourLv); difAdd -= lastFiendShipLevel.add; } - let attrName: string; - for (let connect of hero.connections) { - let heroShip = getFriendShipById(connect.shipId, connect.level); - for (let attr of heroShip.attributes) { - attrName = getAtrrNameById(attr.id); - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp += attr.number * (HERO_CE_RATIO + difAdd); + + for (let {shipId, level} of originHero.connections) { + let dicHeroFriendShip = getFriendShipById(shipId, level); + for (let attr of dicHeroFriendShip.attributes) { + let fixUp = attr.number * (HERO_CE_RATIO + difAdd); + updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } } - return res; + originHero.attr = heroAttrs; + return heroAttrs; } -// 穿脱, removeSeidList原来身上穿着的所有装备的seid,包括套装的 -export function calEquipPutOnOffIncAttr(hero: HeroType, args: Array, addSeidList: Array, removeSeidList: Array) { +/** + * 穿脱, removeSeidList原来身上穿着的所有装备的seid,包括套装的 + * @param {HeroType} hero 武将 + * @param {number[]} seids args 原来穿着的装备的seid + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + */ +export function calEquipPutOnOffIncAttr(hero: HeroType, seids: Array, addSeidList: Array, removeSeidList: Array) { // 计算身上所有装备的战力值(特技相关以外) - let res = calHeroEquipIncAttr(hero); + let heroAttrs = calHeroEquipIncAttr(hero); // 计算被动技能 let { ePlace } = hero; @@ -457,15 +642,19 @@ export function calEquipPutOnOffIncAttr(hero: HeroType, args: Array, add } }); - for (let arg of args) { - removeSeidList.push(arg) + for (let seid of seids) { + removeSeidList.push(seid) } - return res + return heroAttrs } +/** + * 计算一个武将身上的所有被动seid + * @param {HeroType} hero 武将,equip需要populate + */ export function calEquipSeids(hero: HeroType) { - let seids = []; + let seids: number[] = []; // 计算被动技能 let { ePlace } = hero; let suits = new Map(); @@ -498,12 +687,12 @@ export function calEquipSeids(hero: HeroType) { return seids; } -// 装备,装备栏升级,装备精炼等涉及到值的 +/** + * 装备,装备栏升级,装备精炼等涉及到值的 + * @param {HeroType} hero 装备更新过的武将 + */ export function calHeroEquipIncAttr(hero: HeroType) { - let res: CeAttr = {}; - let { ePlace } = hero; - - let attrResult = new CeAttrNumber(); + let { ePlace, attr: heroAttrs } = hero; for (let { equip, lv, refineLv } of ePlace) { if (equip) { @@ -530,8 +719,6 @@ export function calHeroEquipIncAttr(hero: HeroType) { } for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) { - if (i == ABI_TYPE.ABI_SPEED || i == ABI_TYPE.ABI_AP) continue; - let attrName = getAtrrNameById(i); // console.log('***', i, attrName); let value1 = goodsAbility.get(i) || 0 * (HERO_CE_RATIO + e.randRange); // console.log('基础值', value1); @@ -543,25 +730,29 @@ export function calHeroEquipIncAttr(hero: HeroType) { // console.log('jewel', valueJewel); let attr = (value1 + lv * valueup) * (HERO_CE_RATIO + valueRefine) + valueJewel * HERO_CE_RATIO; - attrResult[attrName] += attr; + if(attr > 0) { + console.log('装备战力:', i, attr); + updateHeroAttr(heroAttrs, i, { set: { equipUp: attr } }) + } } } } - for (let attrName in attrResult) { - let originalCe = hero.ceAttr[attrName].equipUp || 0; - console.log('装备战力:', attrName, attrResult[attrName], originalCe); - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp, equipUp: originalCe }; - res[attrName].equipUp += attrResult[attrName] - originalCe; - } - - return res; + hero.attr = heroAttrs; + return heroAttrs; } -// 洗炼 -export function calRestrengthenIncAttr(hero: HeroType, ePaceId: number, args: Array, addSeidList: Array, removeSeidList: Array) { +/** + * 洗炼 + * @param {HeroType} hero 更新过的武将 + * @param {number} ePaceId 更新的栏位id + * @param {number[]} seids 移除的seid + * @param {number[]} addSeidList 用于更新被动 + * @param {number[]} removeSeidList 用于更新被动 + */ +export function calRestrengthenIncAttr(hero: HeroType, ePaceId: number, seids: Array, addSeidList: Array, removeSeidList: Array) { - let res: CeAttr = {}; + let { attr: heroAttrs } = hero; let { ePlace } = hero; let curPlace = ePlace.find(cur => cur.id == ePaceId); @@ -572,13 +763,15 @@ export function calRestrengthenIncAttr(hero: HeroType, ePaceId: number, args: Ar } } - for (let arg of args) { removeSeidList.push(arg) } + for (let seid of seids) { + removeSeidList.push(seid) + } - return res + return heroAttrs } // 添加技能增加的被动属性 -function addSeidEffect(reIncAttr: CeAttr, heroCeAttr: CeAttr, addSeidList: Array, removeSeidList: Array) { +function addSeidEffect(heroAttrs: CeAttrData[], addSeidList: Array, removeSeidList: Array) { console.log('addSeidList', addSeidList) console.log('removeSeidList', removeSeidList) @@ -600,28 +793,14 @@ function addSeidEffect(reIncAttr: CeAttr, heroCeAttr: CeAttr, addSeidList: Array } for (let { type, gainValueArr: [ability, value] } of effectList) { - let attrName = getAtrrNameById(ability); - if (!attrName) continue; if (type == SEID_TYPE.TYPE101) { // 加值 - if (!reIncAttr[attrName]) { - reIncAttr[attrName] = deepCopy(heroCeAttr[attrName]); - } - if (!reIncAttr[attrName]) { - delete reIncAttr[attrName]; - continue; - } - reIncAttr[attrName].fixUp += value * multi * HERO_CE_RATIO; - delete reIncAttr[attrName]._id; + updateHeroAttr(heroAttrs, ability, { inc: {fixUp: value * multi * HERO_CE_RATIO} }); } else if (type == SEID_TYPE.TYPE102) { // 加百分比 - if (!reIncAttr[attrName]) { - reIncAttr[attrName] = deepCopy(heroCeAttr[attrName]); + if(ABI_TYPE_MAIN.includes(ability)) { + updateHeroAttr(heroAttrs, ability, { inc: {ratioUp: value * multi} }); + } else { // 次级属性102特殊处理 + updateHeroAttr(heroAttrs, ability, { inc: {fixUp: value * multi * HERO_SUB_ATTR_RATIO } }); } - if (!reIncAttr[attrName]) { - delete reIncAttr[attrName]; - continue; - } - reIncAttr[attrName].ratioUp += value * multi; - delete reIncAttr[attrName]._id; } } } @@ -649,171 +828,131 @@ function addSeid(effectList: Array, seidId: number, rand: number, seidValue effectList.push(seid); } -function calHeroCeWhenJewelOn(hero: HeroType, args: Array) { - let res: CeAttr = {}; - let id = args[0]; - let oldId = args[1]; - let goodInfo = getGoodById(id); - let oldGoodInfo; - if (!!oldId) - oldGoodInfo = getGoodById(oldId); - for (let attrName in JEWEL_ATTR) { - if (!!goodInfo[attrName]) { - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp += goodInfo[attrName]; - if (oldGoodInfo) - res[attrName].fixUp -= oldGoodInfo[attrName]; - } - } - return res; -} - -function calHeroCeWhenJewelOff(hero: HeroType, args: Array) { - let res: CeAttr = {}; - for (let id of args) { - let goodInfo = getGoodById(id); - for (let attrName in JEWEL_ATTR) { - if (!!goodInfo[attrName]) { - res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp }; - res[attrName].fixUp -= goodInfo[attrName]; +/** + * 带上宝石 + * @param {HeroType} hero 武将数据 + * @param {number} id 带上的宝石 + * @param {number} oldId 脱下的宝石 + */ +function calHeroCeWhenJewelOn(hero: HeroType, id: number, oldId: number) { + let { attr: heroAttrs } = hero; + let goodInfo = gameData.goods.get(id); + let oldGoodInfo = gameData.goods.get(oldId); + + if(goodInfo) { + let jGoods = goodInfo.goodsAbility; + jGoods.forEach((value, key) => { + let equipUp = value; + if(oldGoodInfo && oldGoodInfo.goodsAbility) { + equipUp -= oldGoodInfo.goodsAbility.get(key); } - } + updateHeroAttr(heroAttrs, key, { set: { equipUp } }) + }); } - return res; -} -//全局属性加成 -export async function reCalAllHeroCe(roleId: string, type: number, args: Array) { - let role = await RoleModel.findByRoleId(roleId); - if (!role.globalCeAttr) role.globalCeAttr = new CeAttr(); - let pushHeros: Array<{ hid: number, ce: number, incHeroCe: number }> = [] - let heros = await HeroModel.findByRole(roleId); - await reCalRoleAttr(heros, role.globalCeAttr, type, args); - role.ce = 0; - for (let hero of heros) { - let heroCe = 0; - for (let attrName in role.globalCeAttr) { - if (attrName == '_id') - continue; - let heroAttrData: CeAttrData = hero.ceAttr[attrName] || new CeAttrData(); - let globalAttrData: CeAttrData = role.globalCeAttr[attrName]; - let attrNumber = (heroAttrData.fixUp + (heroAttrData.equipUp || 0) + globalAttrData.fixUp) * HERO_CE_RATIO + heroAttrData.base * (HERO_CE_RATIO + heroAttrData.ratioUp + globalAttrData.ratioUp); - heroCe += attrNumber * getAttrCeRatio(attrName); - } - let incHeroCe = heroCe - hero.ce; - hero.ce = heroCe; - role.ce += hero.ce; - pushHeros.push({ hid: hero.hid, ce: reduceCe(hero.ce), incHeroCe: reduceCe(incHeroCe) }); - await HeroModel.updateHeroInfo(roleId, hero.hid, { ce: hero.ce }); - } - role = await RoleModel.updateRoleInfo(roleId, { globalCeAttr: role.globalCeAttr, ce: role.ce }); - return { pushHeros, ce: role.ce, topLineupCe: role.topLineupCe } + + hero.attr = heroAttrs; + return heroAttrs; } -function calHeroAddSkin(args: Array, ceAttr: CeAttrRole) { - let res: CeAttrRole = {}; - for (let arg of args) { - let addSkin = gameData.fashion.get(arg); - let attrName: string; - for (let attr of addSkin.globalAttr) { - attrName = getAtrrNameById(attr.id); - res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - res[attrName].fixUp += attr.number * HERO_CE_RATIO; +/** + * 脱下宝石 + * @param {HeroType} hero 武将数据 + * @param {number[]} ids 脱下的宝石 + */ +function calHeroCeWhenJewelOff(hero: HeroType, ids: Array) { + let { attr: heroAttrs } = hero; + for (let id of ids) { + let goodInfo = gameData.goods.get(id); + if(goodInfo) { + let jGoods = goodInfo.goodsAbility; + jGoods.forEach((value, key) => { + let equipUp = -1 * value; + updateHeroAttr(heroAttrs, key, { set: { equipUp } }) + }); } } - return res; + hero.attr = heroAttrs; + return heroAttrs; } /** * 全局加成,百家学宫 + * @param role 角色 * @param heros 所有武将 * @param schoolId 学宫学派 * @param hid 换上的武将 * @param preHid 撤下的武将 - * @param ceAttr */ -function calSchoolAddAttr(heros: HeroType[], schoolId: number, hid: number, preHid: number, ceAttr: CeAttrRole) { - let res: CeAttrRole = {}; +function calSchoolAddAttr(role: RoleType, heros: HeroType[], schoolId: number, hid: number, preHid: number) { + let { attr: roleAttrs } = role; let school = gameData.school.get(schoolId); + if (!school) return null; + let preHero = heros.find(cur => cur.hid == preHid); let curHero = heros.find(cur => cur.hid == hid); - if (!school) return res; let defaultPercent = { mainAttrAPerent: 0, assiAttrAddValue: 0 }; let preRate = preHero ? getSchoolRateByStar(preHero.star, preHero.colorStar, preHero.quality) : defaultPercent; let curRate = curHero ? getSchoolRateByStar(curHero.star, curHero.colorStar, curHero.quality) : defaultPercent; - let attrName: string; for (let attrId of school.upAttribute) { - attrName = getAtrrNameById(attrId); - res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - if (attrId < ABI_TYPE.ABI_SPEED) { // 主属性 - res[attrName].ratioUp += curRate.mainAttrAPerent - preRate.mainAttrAPerent; - } else { // 次级属性 - res[attrName].fixUp += (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; + if(ABI_TYPE_MAIN.includes(attrId)) { // 主属性 + let ratioUp = curRate.mainAttrAPerent - preRate.mainAttrAPerent; + updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } }); + } else { + let fixUp = (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); } } - return res; + return roleAttrs; } /** * 升星,觉醒,升品时,百家学宫配置武将会相应修改全局战力 - * @param heros HeroType[] 传入只有一个,如果有全局计算,后面push其他武将 - * @param type number 类型 - * @param args - * @param ceAttr + * @param {HeroType[]} heros 全部武将 + * @param {number} type 类型 HERO_SYSTEM_TYPE + * @param {number} hid 更新的那个武将 + * @param {number} isStarUp 是否升星 */ -async function calSchoolStarIncAttr(heros: HeroType[], type: number, args: number[], ceAttr: CeAttrRole) { - let res: CeAttrRole = {}; - let [hid, isStarUp] = args; // 是否升星,是否初次觉醒 - let needCal = false; - let roleId: string = ''; - for (let hero of heros) { - if (hero.hid != hid) { - continue; - } - if ((type == HERO_SYSTEM_TYPE.STAR || type == HERO_SYSTEM_TYPE.COLORSTAR) && !isStarUp) { - continue; - } - roleId = hero.roleId; - let curHeroInSchool = await SchoolModel.findByHid(roleId, hid); - if (!curHeroInSchool) continue; +async function calSchoolStarIncAttr(role: RoleType, heros: HeroType[], type: number, hid: number, isStarUp: number) { + let { roleId, attr: roleAttrs } = role; - let preStar = hero.star, preColorStar = hero.colorStar, preQuality = hero.quality; - if (type == HERO_SYSTEM_TYPE.STAR && isStarUp) { - preStar--; - } else if (type == HERO_SYSTEM_TYPE.QUALITY) { - preQuality--; - } else if (type == HERO_SYSTEM_TYPE.COLORSTAR) { - preColorStar--; + if ((type == HERO_SYSTEM_TYPE.STAR || type == HERO_SYSTEM_TYPE.COLORSTAR) && !isStarUp) { + return null; + } + + let hero = heros.find(cur => cur.hid == hid); + if(!hero) return null; + + let curHeroInSchool = await SchoolModel.findByHid(roleId, hid); + if (!curHeroInSchool) return null; + + let preStar = hero.star, preColorStar = hero.colorStar, preQuality = hero.quality; + if (type == HERO_SYSTEM_TYPE.STAR && isStarUp) { + preStar--; + } else if (type == HERO_SYSTEM_TYPE.QUALITY) { + preQuality--; + } else if (type == HERO_SYSTEM_TYPE.COLORSTAR) { + preColorStar--; + } else { + return null; + } + let school = gameData.school.get(curHeroInSchool.schoolId); + let preRate = getSchoolRateByStar(preStar, preColorStar, preQuality); + let curRate = getSchoolRateByStar(hero.star, hero.colorStar, hero.quality); + + for (let attrId of school.upAttribute) { + if(ABI_TYPE_MAIN.includes(attrId)) { // 主属性 + let ratioUp = curRate.mainAttrAPerent - preRate.mainAttrAPerent; + updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } }); } else { - continue; - } - let school = gameData.school.get(curHeroInSchool.schoolId); - let preRate = getSchoolRateByStar(preStar, preColorStar, preQuality); - let curRate = getSchoolRateByStar(hero.star, hero.colorStar, hero.quality); - - let attrName: string; - for (let attrId of school.upAttribute) { - attrName = getAtrrNameById(attrId); - res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - if (attrId < ABI_TYPE.ABI_SPEED) { // 主属性 - res[attrName].ratioUp += curRate.mainAttrAPerent - preRate.mainAttrAPerent; - } else { // 次级属性 - res[attrName].fixUp += (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; - } - } - needCal = true; - - } - - if (needCal) { - const allHeros = await HeroModel.findByRole(roleId); - for (let hero of allHeros) { - if (hero.hid != hid) heros.push(hero); + let fixUp = (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); } } - return res; + + return roleAttrs; } /** @@ -822,107 +961,132 @@ async function calSchoolStarIncAttr(heros: HeroType[], type: number, args: numbe * @param hid 激活的武将 * @param ceAttr */ -function calScrollAddAttr(heros: HeroType[], hid: number, ceAttr: CeAttrRole) { - let res: CeAttrRole = {}; +function calScrollAddAttr(role: RoleType,heros: HeroType[], hid: number) { + let { attr: roleAttrs } = role; let curHero = heros.find(cur => cur.hid == hid); let dicHero = gameData.hero.get(hid); - if (!curHero || !dicHero) return res; + if (!curHero || !dicHero) return roleAttrs; let { quality } = dicHero; - let { star, quality: curQuality, colorStar, job } = curHero; + let { star, quality: curQuality, colorStar } = curHero; let heroScroll = getScollByStar(quality, star, curQuality, colorStar); - if (!heroScroll) return res; + if (!heroScroll) return roleAttrs; let preScroll = gameData.preHeroScroll.get(heroScroll.id); heroScroll.ceAttr.forEach((add, id) => { - let attId = getFieldByStage(id, job); - let attrName = getAtrrNameById(attId); + let attrId = ABI_TYPE_TO_STAGE.get(id); let preAdd = preScroll ? preScroll.ceAttr.get(id) : 0; - - res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - res[attrName].fixUp += (add - preAdd) * HERO_CE_RATIO; + let fixUp = (add - preAdd) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); }); - return res; + return roleAttrs; } /** * 名将谱激活增加单个武将好感 - * @param hero 当前武将 - * @param hid 激活武将 - * @param preFavourLv 之前的好感度等级,有提升时才计算加成 + * @param originHero 原始武将 + * @param update 更新数据 */ -function calHeroCeScrollIncAttr(hero: HeroType, hid: number, preFavourLv: number) { - let res: CeAttr = {}; - if (hero.hid == hid && hero.favourLv != preFavourLv) { - res = calHeroFavourUpIncAttr(hero, [preFavourLv]); +function calHeroCeScrollIncAttr(originHero: HeroType, update: HeroUpdate) { + let { attr: heroAttrs, favourLv: oldFavourLv } = originHero; + let { favourLv = oldFavourLv } = update; + if (favourLv != oldFavourLv) { + heroAttrs = calHeroFavourUpIncAttr(originHero, update); } - return res; + return heroAttrs; } -function calTitle(args: Array, ceAttr: CeAttrRole) { - let res: CeAttrRole = {}; - let titleId = args[0]; - let titleInfo = gameData.title.get(titleId); - for (let attrName in getTeraphAttr()) { - res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - res[attrName].fixUp += titleInfo[attrName] * HERO_CE_RATIO; +/** + * 升爵位 + * @param role 角色数据 + * @param titleId 升到哪个爵位 + */ +function calTitle(role: RoleType, update: RoleUpdate) { + let { title: oldTitle, attr: roleAttrs } = role; + let { title: newTitle = oldTitle } = update; + + for(let title = oldTitle; title <= newTitle; title++) { + let dicTitle = gameData.title.get(title); + if(!dicTitle) break; + + for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) { + if(dicTitle.mainAttrValue.has(i)) { + let fixUp = dicTitle.mainAttrValue.get(i) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, i, { inc: { fixUp }}); + } + if(dicTitle.assiAttrValue.has(i)) { + let fixUp = dicTitle.assiAttrValue.get(i) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, i, { inc: { fixUp }}); + } + } } - for (let attr of titleInfo.assiAttrValue) { - let attrName = getAtrrNameById(attr.id); - if (!attrName) continue; - res[attrName] = res[attrName] || { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp }; - res[attrName].ratioUp += attr.number * HERO_CE_RATIO; - } - return res; + + return roleAttrs; } + +/** + * 神像强化,更新主属性加成 + * @param role 角色数据 + * @param update 更新数据 + * @param id 更新哪座神像 + */ +function calTeraphMainAttr(role: RoleType, update: RoleUpdate, id: number) { + let { attr: roleAttrs, teraphs: oldTeraphs = [] } = role; + let { teraphs = oldTeraphs } = update; + + let oldTeraph = oldTeraphs.find(cur => cur.id == id); + let teraph = teraphs.find(cur => cur.id == id); + if(teraph && teraph.attr) { + for(let [attrId, val] of teraph.attr) { + let oldVal = 0; + if(oldTeraph && oldTeraph.attr && oldTeraph.attr.has(attrId)) { + oldVal = oldTeraph.attr.get(attrId); + } + + let fixUp = (val - oldVal) * HERO_CE_RATIO; + updateRoleAttr(roleAttrs, attrId, { inc: {fixUp} }) + } + } + return roleAttrs; +} + + +/** + * 神像进阶,更新次级属性加成 + * @param role 角色数据 + * @param update 更新数据 + * @param id 更新哪座神像 + */ +function calTeraphAssistAttr(role: RoleType, update: RoleUpdate, id: number) { + let { attr: roleAttrs, teraphs: oldTeraphs = [] } = role; + let { teraphs = oldTeraphs } = update; + + let oldTeraph = oldTeraphs.find(cur => cur.id == id); + let teraph = teraphs.find(cur => cur.id == id); + + let dicOldTeraph = getTeraph(id, oldTeraph?.grade); + let dicTeraph = getTeraph(id, teraph?.grade); + if(!dicTeraph) return null; + + dicTeraph.assiAttrValue.forEach((val, attrId) => { + let oldVal = 0; + if(dicOldTeraph && dicOldTeraph.assiAttrValue && dicOldTeraph.assiAttrValue.has(attrId)) { + oldVal = dicOldTeraph.assiAttrValue.get(attrId); + } + + let ratioUp = val - oldVal; + updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } }); + }); + return roleAttrs; +} + +/** + * 全局加成初始化 + * @param role + */ export function initRoleAtrr(role: RoleType) { - if (!role.globalCeAttr) role.globalCeAttr = new CeAttr(); - let titleId = role.title; - let titleInfo = gameData.title.get(titleId); - if (!!titleInfo) { - for (let attrName in getTeraphAttr()) { - if (!attrName) continue; - role.globalCeAttr[attrName].fixUp += titleInfo[attrName] * HERO_CE_RATIO; - } - for (let attr of titleInfo.assiAttrValue) { - let attrName = getAtrrNameById(attr.id); - if (!attrName) continue; - role.globalCeAttr[attrName].ratioUp += attr.number * HERO_CE_RATIO; - } - } - return; + delete role._id; + calTitle({...role, title: 0}, role); // 计算初始爵位带来的全局 } - -async function reCalRoleAttr(heros: Array, ceAttr: CeAttrRole, type: number, args: Array) { - let reIncAttr: CeAttrRole = {}; // role表属性增量 - switch (type) { - case HERO_SYSTEM_TYPE.INIT: - reIncAttr = calRoleInitIncAttr(heros, ceAttr); // 全局变量增 - break; - case HERO_SYSTEM_TYPE.ADD_SKIN: - reIncAttr = calHeroAddSkin(args, ceAttr); - break; - case HERO_SYSTEM_TYPE.SCHOOL: - reIncAttr = calSchoolAddAttr(heros, args[0], args[1], args[2], ceAttr); - break; - case HERO_SYSTEM_TYPE.SCROLL: - reIncAttr = calScrollAddAttr(heros, args[0], ceAttr); - break; - case HERO_SYSTEM_TYPE.STAR: - case HERO_SYSTEM_TYPE.COLORSTAR: - case HERO_SYSTEM_TYPE.QUALITY: - reIncAttr = await calSchoolStarIncAttr(heros, type, args, ceAttr); - break; - case HERO_SYSTEM_TYPE.TITLE: - reIncAttr = calTitle(args, ceAttr); - } - for (let attrName in reIncAttr) { - if (attrName == '_id') continue; - let globalAttrData: CeAttrDataRole = reIncAttr[attrName] || new CeAttrDataRole(); - for (let key in globalAttrData) { - ceAttr[attrName][key] = parseInt(globalAttrData[key] || 0); - } - } -} \ No newline at end of file diff --git a/shared/pubUtils/timeUtil.ts b/shared/pubUtils/timeUtil.ts index d4335bbfd..9723bcc01 100644 --- a/shared/pubUtils/timeUtil.ts +++ b/shared/pubUtils/timeUtil.ts @@ -1,3 +1,4 @@ +import { TIME_FORMAT } from '@consts'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; @@ -93,4 +94,39 @@ export function getTodayZeroDate() { date.setMinutes(0); date.setSeconds(0); return date; +} + +export function getAge(birthday: string) { + let d = new Date(birthday + ' 00:00:00'); + let _year = d.getFullYear(); + let _month = d.getMonth() + 1; + let _day = d.getDate(); + + let age = 0; + let now = new Date(); + let year = now.getFullYear(); + let month = now.getMonth() + 1; + let day = now.getDate(); + + if (year >= _year && month >= _month && day >= _day) { + age = year - _year; + }else{ + age = year - _year - 1; + } + return age +} + +export function formatTime(d: Date, type: number) { + let year = d.getFullYear(); + let month = d.getMonth() + 1; + let day = d.getDate(); + let yearStr = year.toString(); + let monthStr = month.toString(); + let dayStr = day.toString(); + + if(type == TIME_FORMAT.TYPE_SLASH) { + if(day < 10) dayStr = '0' + dayStr; + if(month < 10) monthStr = '0' + monthStr; + return `${yearStr}/${monthStr}/${dayStr}`; + } } \ No newline at end of file diff --git a/shared/resource/jsons/dic_zyz_gk_main.json b/shared/resource/jsons/dic_zyz_gk_main.json index e68e4ebfa..6bb0c73a5 100644 --- a/shared/resource/jsons/dic_zyz_gk_main.json +++ b/shared/resource/jsons/dic_zyz_gk_main.json @@ -751,7 +751,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_1", "recommendedPower": 10031, - "previousGk": 129, + "previousGk": 201, "relatedEliteGk": 0, "movePoint": 95 }, @@ -779,7 +779,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_1", "recommendedPower": 10032, - "previousGk": 130, + "previousGk": 202, "relatedEliteGk": 0, "movePoint": 97 }, @@ -807,7 +807,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_1", "recommendedPower": 10033, - "previousGk": 0, + "previousGk": 203, "relatedEliteGk": 9204, "movePoint": 100 }, @@ -835,7 +835,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_2", "recommendedPower": 10034, - "previousGk": 0, + "previousGk": 204, "relatedEliteGk": 0, "movePoint": 103 }, @@ -863,7 +863,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_2", "recommendedPower": 10035, - "previousGk": 0, + "previousGk": 205, "relatedEliteGk": 0, "movePoint": 109 }, @@ -891,7 +891,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_2", "recommendedPower": 10036, - "previousGk": 0, + "previousGk": 206, "relatedEliteGk": 0, "movePoint": 112 }, @@ -919,7 +919,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_2", "recommendedPower": 10037, - "previousGk": 0, + "previousGk": 207, "relatedEliteGk": 9208, "movePoint": 116 }, @@ -947,7 +947,7 @@ "heroInUI": "1&1001", "detailUIBg": "2_3", "recommendedPower": 10038, - "previousGk": 0, + "previousGk": 208, "relatedEliteGk": 0, "movePoint": 118 }, @@ -975,7 +975,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_3", "recommendedPower": 10039, - "previousGk": 0, + "previousGk": 209, "relatedEliteGk": 0, "movePoint": 120 }, @@ -1003,7 +1003,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_3", "recommendedPower": 10040, - "previousGk": 0, + "previousGk": 210, "relatedEliteGk": 0, "movePoint": 122 }, @@ -1031,7 +1031,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_3", "recommendedPower": 10041, - "previousGk": 0, + "previousGk": 211, "relatedEliteGk": 9212, "movePoint": 124 }, @@ -1059,7 +1059,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_4", "recommendedPower": 10042, - "previousGk": 0, + "previousGk": 212, "relatedEliteGk": 0, "movePoint": 126 }, @@ -1087,7 +1087,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_4", "recommendedPower": 10043, - "previousGk": 0, + "previousGk": 213, "relatedEliteGk": 0, "movePoint": 128 }, @@ -1115,7 +1115,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_4", "recommendedPower": 10044, - "previousGk": 0, + "previousGk": 214, "relatedEliteGk": 0, "movePoint": 130 }, @@ -1143,7 +1143,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_4", "recommendedPower": 10045, - "previousGk": 0, + "previousGk": 215, "relatedEliteGk": 9216, "movePoint": 133 }, @@ -1171,7 +1171,7 @@ "heroInUI": "1&1001", "detailUIBg": "2_5", "recommendedPower": 10046, - "previousGk": 0, + "previousGk": 216, "relatedEliteGk": 0, "movePoint": 135 }, @@ -1199,7 +1199,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_5", "recommendedPower": 10047, - "previousGk": 0, + "previousGk": 217, "relatedEliteGk": 0, "movePoint": 137 }, @@ -1227,7 +1227,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_5", "recommendedPower": 10048, - "previousGk": 0, + "previousGk": 218, "relatedEliteGk": 0, "movePoint": 139 }, @@ -1255,7 +1255,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_5", "recommendedPower": 10049, - "previousGk": 0, + "previousGk": 219, "relatedEliteGk": 9220, "movePoint": 141 }, @@ -1283,7 +1283,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_6", "recommendedPower": 10050, - "previousGk": 0, + "previousGk": 220, "relatedEliteGk": 0, "movePoint": 143 }, @@ -1311,7 +1311,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_6", "recommendedPower": 10051, - "previousGk": 0, + "previousGk": 221, "relatedEliteGk": 0, "movePoint": 146 }, @@ -1339,7 +1339,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "2_6", "recommendedPower": 10052, - "previousGk": 0, + "previousGk": 222, "relatedEliteGk": 0, "movePoint": 148 }, @@ -1367,7 +1367,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "2_6", "recommendedPower": 10053, - "previousGk": 0, + "previousGk": 223, "relatedEliteGk": 9224, "movePoint": 150 }, @@ -1395,7 +1395,7 @@ "heroInUI": "1&1001", "detailUIBg": "3_1", "recommendedPower": 10054, - "previousGk": 0, + "previousGk": 224, "relatedEliteGk": 0, "movePoint": 155 }, @@ -1423,7 +1423,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_1", "recommendedPower": 10055, - "previousGk": 0, + "previousGk": 301, "relatedEliteGk": 0, "movePoint": 159 }, @@ -1451,7 +1451,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_1", "recommendedPower": 10056, - "previousGk": 0, + "previousGk": 302, "relatedEliteGk": 0, "movePoint": 162 }, @@ -1479,7 +1479,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_1", "recommendedPower": 10057, - "previousGk": 0, + "previousGk": 303, "relatedEliteGk": 9304, "movePoint": 166 }, @@ -1507,7 +1507,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_2", "recommendedPower": 10058, - "previousGk": 0, + "previousGk": 304, "relatedEliteGk": 0, "movePoint": 169 }, @@ -1535,7 +1535,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_2", "recommendedPower": 10059, - "previousGk": 0, + "previousGk": 305, "relatedEliteGk": 0, "movePoint": 173 }, @@ -1563,7 +1563,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_2", "recommendedPower": 10060, - "previousGk": 0, + "previousGk": 306, "relatedEliteGk": 0, "movePoint": 176 }, @@ -1591,7 +1591,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_2", "recommendedPower": 10061, - "previousGk": 0, + "previousGk": 307, "relatedEliteGk": 9308, "movePoint": 180 }, @@ -1619,7 +1619,7 @@ "heroInUI": "1&1001", "detailUIBg": "3_3", "recommendedPower": 10062, - "previousGk": 0, + "previousGk": 308, "relatedEliteGk": 0, "movePoint": 184 }, @@ -1647,7 +1647,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_3", "recommendedPower": 10063, - "previousGk": 0, + "previousGk": 309, "relatedEliteGk": 0, "movePoint": 186 }, @@ -1675,7 +1675,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_3", "recommendedPower": 10064, - "previousGk": 0, + "previousGk": 310, "relatedEliteGk": 0, "movePoint": 188 }, @@ -1703,7 +1703,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_3", "recommendedPower": 10065, - "previousGk": 0, + "previousGk": 311, "relatedEliteGk": 9312, "movePoint": 190 }, @@ -1731,7 +1731,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_4", "recommendedPower": 10066, - "previousGk": 0, + "previousGk": 312, "relatedEliteGk": 0, "movePoint": 195 }, @@ -1759,7 +1759,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_4", "recommendedPower": 10067, - "previousGk": 0, + "previousGk": 313, "relatedEliteGk": 0, "movePoint": 197 }, @@ -1787,7 +1787,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_4", "recommendedPower": 10068, - "previousGk": 0, + "previousGk": 314, "relatedEliteGk": 0, "movePoint": 201 }, @@ -1815,7 +1815,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_4", "recommendedPower": 10069, - "previousGk": 0, + "previousGk": 315, "relatedEliteGk": 9316, "movePoint": 204 }, @@ -1843,7 +1843,7 @@ "heroInUI": "1&1001", "detailUIBg": "3_5", "recommendedPower": 10070, - "previousGk": 0, + "previousGk": 316, "relatedEliteGk": 0, "movePoint": 209 }, @@ -1871,7 +1871,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_5", "recommendedPower": 10071, - "previousGk": 0, + "previousGk": 317, "relatedEliteGk": 0, "movePoint": 212 }, @@ -1899,7 +1899,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_5", "recommendedPower": 10072, - "previousGk": 0, + "previousGk": 318, "relatedEliteGk": 0, "movePoint": 215 }, @@ -1927,7 +1927,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_5", "recommendedPower": 10073, - "previousGk": 0, + "previousGk": 319, "relatedEliteGk": 9320, "movePoint": 218 }, @@ -1955,7 +1955,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_6", "recommendedPower": 10074, - "previousGk": 0, + "previousGk": 320, "relatedEliteGk": 0, "movePoint": 221 }, @@ -1983,7 +1983,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_6", "recommendedPower": 10075, - "previousGk": 0, + "previousGk": 321, "relatedEliteGk": 0, "movePoint": 223 }, @@ -2011,7 +2011,7 @@ "heroInUI": "1&1001|1&1004", "detailUIBg": "3_6", "recommendedPower": 10076, - "previousGk": 0, + "previousGk": 322, "relatedEliteGk": 0, "movePoint": 225 }, @@ -2039,7 +2039,7 @@ "heroInUI": "1&1001|1&1004|2&312", "detailUIBg": "3_6", "recommendedPower": 10077, - "previousGk": 0, + "previousGk": 323, "relatedEliteGk": 9324, "movePoint": 227 } diff --git a/shared/resource/jsons/dic_zyz_hero.json b/shared/resource/jsons/dic_zyz_hero.json index 396ad0731..ba08bad4f 100644 --- a/shared/resource/jsons/dic_zyz_hero.json +++ b/shared/resource/jsons/dic_zyz_hero.json @@ -16,14 +16,12 @@ "pieceId": 21001, "hp": 1100, "atk": 420, - "matk": 0, "def": 250, "mdef": 170, "agi": 160, "luk": 110, "hp_up": 110, "atk_up": 42, - "matk_up": 0, "def_up": 25, "mdef_up": 17, "agi_up": 16, @@ -33,7 +31,7 @@ "sound_fight": 1, "kill": "这就是皇天之剑!", "retreat": "复兴汉室的梦想破灭了!", - "info": "魏武帝曹操,字孟德,小名阿瞒东汉末年宰相,太尉曹嵩之子,曹魏政权的奠基者。", + "info": "魏武帝曹操,字孟德,曹魏政权的奠基者,为法家领袖,一生都在为实现霸道之术平定乱世而努力,对刘备坚守的仁义不屑一顾。肉盾型步将,拥有强大的减益光环能力。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-414&-193", @@ -41,11 +39,11 @@ "position": "30&40&30", "initialSkin": 41001, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2, - "spineName": "xiahoudun", + "spineName": "zhaoyun", "rSpineName": "&", "name": "夏侯惇", "face_id": "xiahoudun", @@ -60,14 +58,12 @@ "pieceId": 21002, "hp": 1000, "atk": 540, - "matk": 0, "def": 220, "mdef": 120, "agi": 170, "luk": 120, "hp_up": 100, "atk_up": 54, - "matk_up": 0, "def_up": 22, "mdef_up": 12, "agi_up": 17, @@ -77,7 +73,7 @@ "sound_fight": 0, "kill": "吃我这一记!", "retreat": "失败了,撤退。", - "info": "夏侯惇,字元让,沛国谯县人。汉末三国时期曹魏名将,西汉开国元勋夏侯婴的后代。独眼夏侯。", + "info": "夏侯惇,字元让,曹魏名将,汉初名将兵家夏侯婴的后代,输出型步将,可进行多目标伤害,自带透甲暴击增益。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "693&-138", "imgPosofInfoUI": "-511&-161", @@ -85,7 +81,7 @@ "position": "30&40&30", "initialSkin": 41003, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 3, @@ -104,14 +100,12 @@ "pieceId": 21003, "hp": 1000, "atk": 540, - "matk": 0, "def": 180, "mdef": 100, "agi": 170, "luk": 130, "hp_up": 100, "atk_up": 54, - "matk_up": 0, "def_up": 18, "mdef_up": 10, "agi_up": 17, @@ -121,7 +115,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "撤退也是一种战术。", - "info": "张辽,字文远,雁门马邑人。初为吕布部将,后投降曹操,镇守东南,数次大败孙十万。", + "info": "张辽,字文远,初为吕布部将,后降曹魏,镇守东南,数次大败孙十万,五子良将之一。兵家学派,输出型骑兵将领,能给友军提供辅助增益。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-304&120", @@ -129,7 +123,7 @@ "position": "30&40&30", "initialSkin": 41004, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 4, @@ -148,14 +142,12 @@ "pieceId": 21004, "hp": 980, "atk": 520, - "matk": 0, "def": 190, "mdef": 120, "agi": 180, "luk": 140, "hp_up": 98, "atk_up": 52, - "matk_up": 0, "def_up": 19, "mdef_up": 12, "agi_up": 18, @@ -165,7 +157,7 @@ "sound_fight": 4, "kill": "神力助我!", "retreat": "体力耗尽了。", - "info": "夏侯渊,字妙才,夏侯轻衣的养父。一直敬爱着自己的哥哥夏侯惇。“欧尼酱……”", + "info": "夏侯渊,字妙才,曹魏名将,夏侯惇之弟,夏侯轻衣的父亲。自小就和曹操一起学习法家学术,肉盾型远程输出,可以召唤巨熊帮助作战。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "379&-245", "imgPosofInfoUI": "-292&-143", @@ -173,11 +165,11 @@ "position": "30&40&30", "initialSkin": 41005, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 5, - "spineName": "guojia", + "spineName": "zhaoyun", "rSpineName": "&", "name": "郭嘉", "face_id": "guojia", @@ -191,15 +183,13 @@ "skill": 5, "pieceId": 21005, "hp": 830, - "atk": 0, - "matk": 580, + "atk": 580, "def": 160, "mdef": 190, "agi": 170, "luk": 130, "hp_up": 83, - "atk_up": 0, - "matk_up": 58, + "atk_up": 58, "def_up": 16, "mdef_up": 19, "agi_up": 17, @@ -209,7 +199,7 @@ "sound_fight": 3097, "kill": "全力攻击。", "retreat": "不行了,撤退。", - "info": "郭嘉,字奉孝,曹操帐下著名谋士,被称为“奉孝不死,卧龙不出”。备受现代大众吹捧,主要还是死的早。", + "info": "郭嘉,字奉孝,曹魏著名谋士,法家寒门奇才,深得曹操的信任。输出型策士,战场之上,血量越低伤害越高。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "441&-355", "imgPosofInfoUI": "-204&-176", @@ -217,7 +207,7 @@ "position": "30&40&30", "initialSkin": 41006, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 6, @@ -235,15 +225,13 @@ "skill": 6, "pieceId": 21006, "hp": 980, - "atk": 0, - "matk": 500, + "atk": 500, "def": 190, "mdef": 200, "agi": 170, "luk": 120, "hp_up": 98, - "atk_up": 0, - "matk_up": 50, + "atk_up": 50, "def_up": 19, "mdef_up": 20, "agi_up": 17, @@ -253,7 +241,7 @@ "sound_fight": 3017, "kill": "上啊!", "retreat": "挫折是好男儿的食粮。", - "info": "司马懿,字仲达。人称冢虎、畏蜀如虎、女装仲达、西晋王朝的奠基人之一。", + "info": "司马懿,字仲达。魏之权臣、西晋王朝的奠基人,是贾诩精心培养的阴阳家传人。输出型策士,可以源源不断的释放怒气技,造成巨量伤害。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "623&-335", "imgPosofInfoUI": "-418&-191", @@ -261,7 +249,7 @@ "position": "30&40&30", "initialSkin": 41007, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 7, @@ -280,14 +268,12 @@ "pieceId": 21007, "hp": 1070, "atk": 460, - "matk": 0, "def": 300, "mdef": 60, "agi": 180, "luk": 90, "hp_up": 107, "atk_up": 46, - "matk_up": 0, "def_up": 30, "mdef_up": 6, "agi_up": 18, @@ -297,7 +283,7 @@ "sound_fight": 3065, "kill": "吃我这一箭吧!", "retreat": "暂时撤离战场。", - "info": "典韦,被曹操称赞为“古之恶来”。“凡是被曹操称赞过的人都不得好死的证明之一。”", + "info": "典韦,墨家九侠之一,被曹操赞为“古之恶来”,宛城之战中为保护曹操而被阴阳家遭伏击而死。输出型游侠,可以对敌人快速造成大量伤害。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "562&-212", "imgPosofInfoUI": "-408&-47", @@ -305,7 +291,7 @@ "position": "30&40&30", "initialSkin": 41008, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 8, @@ -324,14 +310,12 @@ "pieceId": 21008, "hp": 960, "atk": 400, - "matk": 0, "def": 200, "mdef": 100, "agi": 160, "luk": 100, "hp_up": 96, "atk_up": 40, - "matk_up": 0, "def_up": 20, "mdef_up": 10, "agi_up": 16, @@ -341,7 +325,7 @@ "sound_fight": 3017, "kill": "呀呀呀呀,沉重的一击!", "retreat": "被包围了,撤退。", - "info": "庞德,字令明,原为马腾部将,后投张鲁,又降曹操,三姓家奴,多曹魏之臣。", + "info": "庞德,字令明,在颜良文丑死后成为新的墨家九侠之一,为替墨侠报仇而被关羽所杀。肉盾型步将,擅长嘲讽,不惧远程物理输出。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "537&-209", "imgPosofInfoUI": "-387&-178", @@ -349,11 +333,11 @@ "position": "30&40&30", "initialSkin": 41009, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 9, - "spineName": "dengai", + "spineName": "zhaoyun", "rSpineName": "&", "name": "邓艾", "face_id": "dengai", @@ -368,14 +352,12 @@ "pieceId": 21009, "hp": 920, "atk": 450, - "matk": 0, "def": 160, "mdef": 120, "agi": 150, "luk": 90, "hp_up": 92, "atk_up": 45, - "matk_up": 0, "def_up": 16, "mdef_up": 12, "agi_up": 15, @@ -385,7 +367,7 @@ "sound_fight": 9, "kill": "挡我者死,让开!", "retreat": "战败了。", - "info": "邓艾,字士载。魏国杰出的军事家。其人文武全才,多次成功击败姜维的入侵,大魏的凉州坚盾。", + "info": "邓艾,字士载。魏之坚盾,受张郃的提携而进入军队,成为兵家天才。肉盾型枪将,不惧策士的攻击。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "625&-243", "imgPosofInfoUI": "-413&-68", @@ -393,11 +375,11 @@ "position": "30&40&30", "initialSkin": 41010, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 10, - "spineName": "xuhuang", + "spineName": "zhaoyun", "rSpineName": "&", "name": "徐晃", "face_id": "xuhuang", @@ -412,14 +394,12 @@ "pieceId": 21010, "hp": 900, "atk": 500, - "matk": 0, "def": 160, "mdef": 60, "agi": 150, "luk": 120, "hp_up": 90, "atk_up": 50, - "matk_up": 0, "def_up": 16, "mdef_up": 6, "agi_up": 15, @@ -429,7 +409,7 @@ "sound_fight": 10, "kill": "神弓开,箭火矢。", "retreat": "失败是成功之母。", - "info": "徐晃,字公明,曹魏名将,五子良将之一,被称赞有“亚夫之风”。", + "info": "徐晃,字公明,五子良将之一,墨家九侠之一,在樊城之战为了死去的墨侠而与关羽一战。输出型枪兵,擅长范围输出,对残血武将有着极强的收割能力。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "408&-183", "imgPosofInfoUI": "-393&-166", @@ -437,7 +417,7 @@ "position": "30&40&30", "initialSkin": 41011, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 11, @@ -456,14 +436,12 @@ "pieceId": 21011, "hp": 860, "atk": 480, - "matk": 0, "def": 210, "mdef": 50, "agi": 160, "luk": 100, "hp_up": 86, "atk_up": 48, - "matk_up": 0, "def_up": 21, "mdef_up": 5, "agi_up": 16, @@ -473,7 +451,7 @@ "sound_fight": 3049, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "曹仁,字子孝,曹魏名将,曹操从弟,宗室之中最为善战,屡次攻克敌军,却因襄阳之战被刻画为善于防守。", + "info": "曹仁,字子孝,曹操堂弟,也曾学习家传的法家学术,是曹操信赖的谨慎之将。肉盾型骑兵,擅于援护友军。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "591&-202", "imgPosofInfoUI": "-269&-118", @@ -481,7 +459,7 @@ "position": "30&40&30", "initialSkin": 41012, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 12, @@ -500,14 +478,12 @@ "pieceId": 21012, "hp": 780, "atk": 540, - "matk": 0, "def": 120, "mdef": 60, "agi": 180, "luk": 120, "hp_up": 78, "atk_up": 54, - "matk_up": 0, "def_up": 12, "mdef_up": 6, "agi_up": 18, @@ -517,7 +493,7 @@ "sound_fight": 3081, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "李典,字曼成,曹魏名将,为人儒雅随和,被称为“曹魏长者”,却英年早逝。", + "info": "李典,字曼成,为人和善亲切,被称为“魏之长者”,法家之人,上蔡李氏之后。远程输出型弓兵将领。擅长连射和怒气获取,可造成范围伤害。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "574&-202", "imgPosofInfoUI": "-443&-52", @@ -525,7 +501,7 @@ "position": "30&40&30", "initialSkin": 41013, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 13, @@ -543,15 +519,13 @@ "skill": 13, "pieceId": 21013, "hp": 700, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 150, "agi": 130, "luk": 80, "hp_up": 70, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 15, "agi_up": 13, @@ -561,15 +535,15 @@ "sound_fight": 3017, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "蔡琰,字昭姬,大儒蔡邕之女。年轻时经历董卓之乱被匈奴掳去,惨遭折磨。", + "info": "蔡琰,字昭姬,大儒蔡邕之女,本为儒门,但因家中巨变父亲惨死而导致性情大变,被贾诩引入阴阳家。辅助治疗型策士。精通怒气回复,擅长治疗策士。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "560&-183", "imgPosofInfoUI": "-387&-85", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41014, - "gender": 1, - "atkSpineEffect": "dunqi" + "gender": 2, + "atkSpineEffect": "faqi" }, { "heroId": 14, @@ -587,15 +561,13 @@ "skill": 14, "pieceId": 21014, "hp": 850, - "atk": 0, - "matk": 420, + "atk": 420, "def": 130, "mdef": 190, "agi": 170, "luk": 110, "hp_up": 85, - "atk_up": 0, - "matk_up": 42, + "atk_up": 42, "def_up": 13, "mdef_up": 19, "agi_up": 17, @@ -605,7 +577,7 @@ "sound_fight": 0, "kill": "吃我这一记!", "retreat": "暂时先避其锋芒。", - "info": "贾诩,字文和,天下毒士。", + "info": "贾诩,字文和,阴阳家当代家主,和张角同为师兄弟,二人一明一暗为实现土德天下,灭百家归一统而努力。输出型道士,擅长群体输出,可造成持续性伤害。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "560&-220", "imgPosofInfoUI": "-413&-161", @@ -613,11 +585,11 @@ "position": "30&40&30", "initialSkin": 41015, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 15, - "spineName": "xuchu", + "spineName": "zhaoyun", "rSpineName": "&", "name": "许褚", "face_id": "xuchu", @@ -632,14 +604,12 @@ "pieceId": 21015, "hp": 1100, "atk": 420, - "matk": 0, "def": 160, "mdef": 30, "agi": 160, "luk": 90, "hp_up": 110, "atk_up": 42, - "matk_up": 0, "def_up": 16, "mdef_up": 3, "agi_up": 16, @@ -649,7 +619,7 @@ "sound_fight": 3001, "kill": "帝王的愤怒。", "retreat": "统一天下可能终究只是美梦了。", - "info": "许褚,字仲康,曹魏猛将。被曹操称赞为“虎痴”,似乎是唯一一个抵挡住曹操称赞而没有死于非命之人。", + "info": "许褚,字仲康,墨家九侠之一,被曹操称赞为“虎痴”,与外表的粗壮不同,实际上是一名无声的刺客。肉盾型游侠,可对目标造成击退和晕眩效果。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "608&-219", "imgPosofInfoUI": "-450&-156", @@ -676,14 +646,12 @@ "pieceId": 21016, "hp": 900, "atk": 320, - "matk": 0, "def": 180, "mdef": 80, "agi": 140, "luk": 60, "hp_up": 90, "atk_up": 32, - "matk_up": 0, "def_up": 18, "mdef_up": 8, "agi_up": 14, @@ -693,7 +661,7 @@ "sound_fight": 3129, "kill": "能吃下这一箭吗?", "retreat": "马革裹尸。", - "info": "乐进,字文谦,曹魏名将,是“五子良将”中最不被人记住的一位。", + "info": "乐进,字文谦,“五子良将”之一,祖先为战国兵家名将乐毅,一生都为了达到祖先的高度而努力着。输出型步兵将领,擅长反击伤害。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "533&-234", "imgPosofInfoUI": "-387&-156", @@ -701,11 +669,11 @@ "position": "30&40&30", "initialSkin": 41017, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 17, - "spineName": "zhangfei", + "spineName": "zhaoyun", "rSpineName": "&", "name": "张飞", "face_id": "zhangfei", @@ -720,14 +688,12 @@ "pieceId": 21017, "hp": 1100, "atk": 500, - "matk": 0, "def": 220, "mdef": 100, "agi": 170, "luk": 110, "hp_up": 110, "atk_up": 50, - "matk_up": 0, "def_up": 22, "mdef_up": 10, "agi_up": 17, @@ -737,7 +703,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "暂时先撤退吧。", - "info": "张飞,字作翼德,蜀汉名将,智勇双全,与兄长关羽一起被称为“万人敌”,是两千年来武将的标杆。", + "info": "张飞,字翼德,“五虎上将”之一,刘备、关羽的结义兄弟,为儒家弟子,虽然外表是个狂野武夫,但却不可思议的能写一手好书画。输出型枪兵,擅长自身回血和消耗目标怒气。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "606&-240", "imgPosofInfoUI": "-424&-213", @@ -745,7 +711,7 @@ "position": "30&40&30", "initialSkin": 41018, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 18, @@ -764,14 +730,12 @@ "pieceId": 21018, "hp": 1050, "atk": 520, - "matk": 0, "def": 220, "mdef": 80, "agi": 160, "luk": 120, "hp_up": 105, "atk_up": 52, - "matk_up": 0, "def_up": 22, "mdef_up": 8, "agi_up": 16, @@ -781,7 +745,7 @@ "sound_fight": 18, "kill": "你觉悟吧!", "retreat": "不行了,恐怕要撤退了。", - "info": "关羽,字云长,蜀汉名将,后世尊为武圣,与义弟张飞一起被视为武将典范,无双国士。", + "info": "关羽,字云长,“五虎上将”之首,是刘备、张飞的结义兄弟,墨家九侠之一,为了天下大义而绝同门小义,因此遭到了天下墨侠的除名。输出型骑兵,擅长连续击杀和怒气回复。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "444&-223", "imgPosofInfoUI": "-297&-158", @@ -789,7 +753,7 @@ "position": "30&40&30", "initialSkin": 41019, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 19, @@ -808,14 +772,12 @@ "pieceId": 21019, "hp": 1020, "atk": 540, - "matk": 0, "def": 180, "mdef": 90, "agi": 180, "luk": 120, "hp_up": 102, "atk_up": 54, - "matk_up": 0, "def_up": 18, "mdef_up": 9, "agi_up": 18, @@ -825,7 +787,7 @@ "sound_fight": 19, "kill": "貂蝉之舞,一闪即逝!", "retreat": "认输。", - "info": "赵云,字子龙,百战常胜。被后世赞为有大臣局量的儒将,甚至被认为是三国时期的完美人物 。", + "info": "赵云,字子龙,是本作的主角,虽然刚刚出山还很年轻,但他的未来不可限量,师从兵家枪王童渊,与夏侯轻衣相互爱慕着。输出型骑兵将领,擅长吸血和穿刺攻击。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "678&-130", "imgPosofInfoUI": "-388&-115", @@ -833,11 +795,11 @@ "position": "30&40&30", "initialSkin": 41020, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 20, - "spineName": "liubei", + "spineName": "zhaoyun", "rSpineName": "&", "name": "刘备", "face_id": "liubei", @@ -852,14 +814,12 @@ "pieceId": 21020, "hp": 1000, "atk": 510, - "matk": 0, "def": 180, "mdef": 130, "agi": 160, "luk": 140, "hp_up": 100, "atk_up": 51, - "matk_up": 0, "def_up": 18, "mdef_up": 13, "agi_up": 16, @@ -869,7 +829,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "暂时的撤退不意味着失败。", - "info": "汉昭烈帝刘备,字玄德,弘毅宽厚,知人待士,百折不挠,与蜀汉名臣们的情意被后世推崇。", + "info": "刘备,字玄德,汉室的继承者,一生都信奉仁义,反对曹操的法家霸道之术,和同伴们为了兴复汉室而奔走努力。治疗辅助型骑兵,擅长多目标治疗,可对蜀国武将有额外增益。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "646&-252", "imgPosofInfoUI": "-385&-120", @@ -877,7 +837,7 @@ "position": "30&40&30", "initialSkin": 41021, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 21, @@ -896,14 +856,12 @@ "pieceId": 21021, "hp": 860, "atk": 680, - "matk": 0, "def": 170, "mdef": 70, "agi": 170, "luk": 130, "hp_up": 86, "atk_up": 68, - "matk_up": 0, "def_up": 17, "mdef_up": 7, "agi_up": 17, @@ -913,7 +871,7 @@ "sound_fight": 3033, "kill": "全力的一刺。", "retreat": "这次恐怕是输了,等我再来。", - "info": "黄忠,字汉升,蜀汉名将。以七旬老将之身,刀劈妙才,力挫曹魏,老当益壮,不输后辈。", + "info": "黄忠,字汉升,“五虎上将”之一,与黄月英为同族,但却走上了兵家之路。远程物理输出型弓兵,拥有超远的射程,并且距离越远,伤害越高。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-199&-118", @@ -921,7 +879,7 @@ "position": "30&40&30", "initialSkin": 41022, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 22, @@ -939,15 +897,13 @@ "skill": 22, "pieceId": 21022, "hp": 950, - "atk": 0, - "matk": 530, + "atk": 530, "def": 190, "mdef": 180, "agi": 170, "luk": 110, "hp_up": 95, - "atk_up": 0, - "matk_up": 53, + "atk_up": 53, "def_up": 19, "mdef_up": 18, "agi_up": 17, @@ -957,7 +913,7 @@ "sound_fight": 22, "kill": "嗯嗯嗯,要你一击毙命!", "retreat": "没吃饱饭,饿肚子了。", - "info": "诸葛亮,字孔明,号卧龙,蜀汉丞相,两千年来天下第一的国士名臣,武侯之名,千载不绝。", + "info": "诸葛亮,字孔明,号卧龙,天下第一的国士,名为法家弟子,实际上却是战国鬼才鬼谷子先生的弟子,通晓百家无所不精。半输出半辅助的策士,擅长范围伤害,自身生存续航能力强。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "405&-243", "imgPosofInfoUI": "-327&-115", @@ -965,7 +921,7 @@ "position": "30&40&30", "initialSkin": 41023, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 23, @@ -983,15 +939,13 @@ "skill": 23, "pieceId": 21023, "hp": 900, - "atk": 0, - "matk": 540, + "atk": 540, "def": 160, "mdef": 190, "agi": 170, "luk": 130, "hp_up": 90, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 16, "mdef_up": 19, "agi_up": 17, @@ -1001,7 +955,7 @@ "sound_fight": 3177, "kill": "投石攻击。", "retreat": "怎么没人来保护我?", - "info": "庞统,字士元,号凤雏,与诸葛亮并称当时双杰,却不幸被张任射杀,出师未捷身先死。", + "info": "庞统,字士元,号凤雏,与诸葛亮并称“天下双杰”。纵横家首领沮授的弟子,为了实现刺杀曹操的谋划而和妹妹庞舞四处奔走。输出型策士,可造成超强的单体伤害,拥有凤凰涅槃的能力。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "589&-77", "imgPosofInfoUI": "-438&-27", @@ -1009,7 +963,7 @@ "position": "30&40&30", "initialSkin": 41024, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 24, @@ -1028,14 +982,12 @@ "pieceId": 21024, "hp": 1050, "atk": 500, - "matk": 0, "def": 220, "mdef": 80, "agi": 180, "luk": 110, "hp_up": 105, "atk_up": 50, - "matk_up": 0, "def_up": 22, "mdef_up": 8, "agi_up": 18, @@ -1045,7 +997,7 @@ "sound_fight": 24, "kill": "一切就看我这一箭吧!", "retreat": "我投降。", - "info": "魏延,字文长,蜀汉名将,深受刘备器重。智勇双全,镇守汉中无人能过。", + "info": "魏延,字文长,在阴阳家中成长,本来是冷酷无情的杀手,却被赵云和刘备所打动折服,成为刘备手下。物理输出型游侠系武将,擅长多段攻击,反杀目标。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "695&-330", "imgPosofInfoUI": "-529&-183", @@ -1072,14 +1024,12 @@ "pieceId": 21025, "hp": 920, "atk": 470, - "matk": 0, "def": 160, "mdef": 70, "agi": 180, "luk": 90, "hp_up": 92, "atk_up": 47, - "matk_up": 0, "def_up": 16, "mdef_up": 7, "agi_up": 18, @@ -1089,7 +1039,7 @@ "sound_fight": 0, "kill": "吃我这一记!", "retreat": "暂时先避其锋芒。", - "info": "陈到,字叔至,蜀汉将领,刘备帐下白毦兵统领,人称小赵云。", + "info": "陈到,字叔至,曾是混迹山野的强盗,在汝南打劫赵云时被其击败,而变得崇拜赵云,成为赵云的追随者。物理输出型枪兵,擅长用毒,攻守兼备。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "606&-181", "imgPosofInfoUI": "-440&-35", @@ -1097,11 +1047,11 @@ "position": "30&40&30", "initialSkin": 41026, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 26, - "spineName": "guanyinping", + "spineName": "zhaoyun", "rSpineName": "&", "name": "关银屏", "face_id": "guanyinping", @@ -1116,14 +1066,12 @@ "pieceId": 21026, "hp": 800, "atk": 540, - "matk": 0, "def": 150, "mdef": 60, "agi": 160, "luk": 100, "hp_up": 80, "atk_up": 54, - "matk_up": 0, "def_up": 15, "mdef_up": 6, "agi_up": 16, @@ -1133,7 +1081,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "看来要先撤退了。", - "info": "关银屏,名将关羽之女。被关羽称之为虎女,武艺甚至超过兄长关平、关兴。", + "info": "关银屏,关羽之女,黄月英的弟子,但却没有继承黄月英的机关之术,反而和其父一样成为了墨侠,与马云禄并称蜀汉双英。肉盾型骑兵,擅长降低敌军命中率,可对敌军造成定身,对男性敌军伤害加深。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "596&-144", "imgPosofInfoUI": "-471&-65", @@ -1141,7 +1089,7 @@ "position": "30&40&30", "initialSkin": 41027, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 27, @@ -1160,14 +1108,12 @@ "pieceId": 21027, "hp": 800, "atk": 550, - "matk": 0, "def": 140, "mdef": 50, "agi": 170, "luk": 100, "hp_up": 80, "atk_up": 55, - "matk_up": 0, "def_up": 14, "mdef_up": 5, "agi_up": 17, @@ -1177,15 +1123,15 @@ "sound_fight": 0, "kill": "吃我这一记!", "retreat": "黄天的梦想覆灭了。", - "info": "马云禄,马腾之女,马超的妹妹,是马腾与西域胡姬所生,自幼习武,女中无双,与关银屏并称为女中英杰。爱上了赵云。", + "info": "马云禄,马超的妹妹,是马腾与西域胡姬所生,因此相貌与众不同,个性率直,第一次进入中原时被赵云打败,因而爱上了赵云。与关银屏并称为女中英杰。物理输出型骑兵,擅长冲锋击退,连续攻击,对女性友军有特殊增益。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "720&-219", "imgPosofInfoUI": "-395&-85", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41028, - "gender": 1, - "atkSpineEffect": "dunqi" + "gender": 2, + "atkSpineEffect": "liqi" }, { "heroId": 28, @@ -1203,15 +1149,13 @@ "skill": 28, "pieceId": 21028, "hp": 720, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 180, "agi": 150, "luk": 120, "hp_up": 72, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 18, "agi_up": 15, @@ -1221,7 +1165,7 @@ "sound_fight": 3145, "kill": "尝尝我的这一拳。", "retreat": "不好,肚子痛,不然不会输。", - "info": "马良,字季常,因眉毛中有白毛,人称白眉马良。“马氏五常,白眉最良。”", + "info": "马良,字季常,本为荆州儒士,因其天生白色眉毛而被称为白眉马良,后来被游历天下的华佗收为弟子,学习医术。治疗型医者,擅长驱散和治疗策系武将", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "683&-278", "imgPosofInfoUI": "-448&-166", @@ -1229,11 +1173,11 @@ "position": "30&40&30", "initialSkin": 41029, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 29, - "spineName": "huangyueying", + "spineName": "zhaoyun", "rSpineName": "&", "name": "黄月英", "face_id": "huangyueying", @@ -1247,15 +1191,13 @@ "skill": 29, "pieceId": 21029, "hp": 800, - "atk": 0, - "matk": 450, + "atk": 450, "def": 130, "mdef": 180, "agi": 160, "luk": 120, "hp_up": 80, - "atk_up": 0, - "matk_up": 45, + "atk_up": 45, "def_up": 13, "mdef_up": 18, "agi_up": 16, @@ -1265,7 +1207,7 @@ "sound_fight": 3033, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "黄月英,诸葛亮之妻,传闻中黑皮黄发的丑妇,但却是貌美无双的奇女子,其才华与诸葛亮相称。", + "info": "黄月英,诸葛亮之妻,传闻中黑皮黄发的丑女,但却是貌美无双的奇女子,才智不输孔明,是墨家中已经罕见的机关术的大师。输出型策士,操纵机关鸟,擅长范围输出,对敌方造成减速控制效果。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "540&-212", "imgPosofInfoUI": "-367&-120", @@ -1273,7 +1215,7 @@ "position": "30&40&30", "initialSkin": 41030, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 30, @@ -1292,14 +1234,12 @@ "pieceId": 21030, "hp": 800, "atk": 550, - "matk": 0, "def": 120, "mdef": 60, "agi": 180, "luk": 110, "hp_up": 80, "atk_up": 55, - "matk_up": 0, "def_up": 12, "mdef_up": 6, "agi_up": 18, @@ -1309,7 +1249,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "撤退吧。", - "info": "王平,字子均,巴西人,汉中之战中觉醒大义而于战场上反正,放弃曹操追随刘备,蜀汉名将。", + "info": "王平,字子均,原为曹操部下,因为被曹操轻视而不满,被刘备招为部下并亲自教其识字开蒙。远程输出型弓兵,擅长狙射和控制,拥有超高的命中率。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "495&-214", "imgPosofInfoUI": "-357&-141", @@ -1317,7 +1257,7 @@ "position": "30&40&30", "initialSkin": 41031, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 31, @@ -1335,15 +1275,13 @@ "skill": 31, "pieceId": 21031, "hp": 700, - "atk": 0, - "matk": 360, + "atk": 360, "def": 120, "mdef": 160, "agi": 140, "luk": 90, "hp_up": 70, - "atk_up": 0, - "matk_up": 36, + "atk_up": 36, "def_up": 12, "mdef_up": 16, "agi_up": 14, @@ -1353,7 +1291,7 @@ "sound_fight": 0, "kill": "来吧致命的一击。", "retreat": "撤退吧。", - "info": "孙乾,字公祐。刘备帐下幕僚,多次代表刘备出使各方势力。", + "info": "孙乾,字公祐,是纵横家首领沮授的弟子,随师父学得一身纵横巧辨之术,多次代表刘备出使各方势力。输出型道士,善用地形之利,精于持续伤害。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "519&-284", "imgPosofInfoUI": "-380&-186", @@ -1361,7 +1299,7 @@ "position": "30&40&30", "initialSkin": 41032, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 32, @@ -1380,14 +1318,12 @@ "pieceId": 21032, "hp": 1150, "atk": 420, - "matk": 0, "def": 280, "mdef": 130, "agi": 160, "luk": 110, "hp_up": 115, "atk_up": 42, - "matk_up": 0, "def_up": 28, "mdef_up": 13, "agi_up": 16, @@ -1397,7 +1333,7 @@ "sound_fight": 3049, "kill": "全力攻击。", "retreat": "撤退。", - "info": "周泰,字幼平,东吴武将。因为孙权总是遇到危险而无能为力,因而多次替孙权挡枪,被称为“江表虎臣”", + "info": "周泰,字幼平,墨家九侠之一,永远以重甲巨盾的形象示人,甚至传言哪怕睡觉的时候也不会脱下盔甲的强悍猛将,是孙权最为信赖的江东之盾。肉盾型步兵,擅长减速控制,在战场上倒地也能再次站起。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "499&-147", "imgPosofInfoUI": "-350&-118", @@ -1424,14 +1360,12 @@ "pieceId": 21033, "hp": 1020, "atk": 540, - "matk": 0, "def": 200, "mdef": 90, "agi": 180, "luk": 120, "hp_up": 102, "atk_up": 54, - "matk_up": 0, "def_up": 20, "mdef_up": 9, "agi_up": 18, @@ -1441,7 +1375,7 @@ "sound_fight": 3033, "kill": "全力攻击。", "retreat": "撤退。", - "info": "孙策,字伯符,孙坚长子,统一江东,和周瑜约为兄弟,一同娶了大小乔。不幸被奸贼刺杀而死。", + "info": "孙策,字伯符,孙权之兄,拥有着孙家代代相传的兵法天赋和孙坚引以为傲的猛烈斗志,永远不停息的为了家族而奋斗着。输出型枪兵,擅长复仇突袭,回复怒气,提升全军物攻。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-511&-90", @@ -1449,7 +1383,7 @@ "position": "30&40&30", "initialSkin": 41034, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 34, @@ -1467,15 +1401,13 @@ "skill": 34, "pieceId": 21034, "hp": 880, - "atk": 0, - "matk": 550, + "atk": 550, "def": 170, "mdef": 180, "agi": 180, "luk": 120, "hp_up": 88, - "atk_up": 0, - "matk_up": 55, + "atk_up": 55, "def_up": 17, "mdef_up": 18, "agi_up": 18, @@ -1485,7 +1417,7 @@ "sound_fight": 3097, "kill": "我可是大将军!", "retreat": "竟然会兵败?", - "info": "周瑜,字公瑾,东吴名将江东有“曲有误,周郎顾”之语。英俊潇洒,江东名士。", + "info": "周瑜,字公瑾,孙策的结义兄弟,自小就被称为江东的天才书生,自诩能力天下第一,被孙策的热情感染而帮助孙策。输出型策士,精通驭火之术,擅于触发暴击伤害,怒气回复。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "722&-284", "imgPosofInfoUI": "-529&-186", @@ -1493,11 +1425,11 @@ "position": "30&40&30", "initialSkin": 41035, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 35, - "spineName": "taishici", + "spineName": "zhaoyun", "rSpineName": "&", "name": "太史慈", "face_id": "taishici", @@ -1512,14 +1444,12 @@ "pieceId": 21035, "hp": 1050, "atk": 520, - "matk": 0, "def": 200, "mdef": 60, "agi": 190, "luk": 110, "hp_up": 105, "atk_up": 52, - "matk_up": 0, "def_up": 20, "mdef_up": 6, "agi_up": 19, @@ -1529,7 +1459,7 @@ "sound_fight": 0, "kill": "吃我这一记!", "retreat": "失败了,撤退。", - "info": "太史慈,字子义,东吴名将。合肥之战,孙权中了张辽计策", + "info": "太史慈,字子义,墨家九侠之一,一生都为信义而战,物理输出型游侠系武将,范围输出机器,破甲提供者。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-503&-123", @@ -1537,11 +1467,11 @@ "position": "30&40&30", "initialSkin": 41036, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 36, - "spineName": "sunquan", + "spineName": "zhaoyun", "rSpineName": "&", "name": "孙权", "face_id": "sunquan", @@ -1556,14 +1486,12 @@ "pieceId": 21036, "hp": 1000, "atk": 400, - "matk": 0, "def": 210, "mdef": 110, "agi": 150, "luk": 90, "hp_up": 100, "atk_up": 40, - "matk_up": 0, "def_up": 21, "mdef_up": 11, "agi_up": 15, @@ -1573,7 +1501,7 @@ "sound_fight": 3001, "kill": "万民的福祉。", "retreat": "放过无辜的百姓吧。", - "info": "我是高玩", + "info": "孙权,字仲谋。孙坚次子,孙策之弟,也是团结东吴英才虎将,创立鼎足之势的少年霸主。辅助治疗型步兵,擅长驱散辅助,单体治疗。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "557&-289", "imgPosofInfoUI": "-448&-153", @@ -1581,11 +1509,11 @@ "position": "30&40&30", "initialSkin": 41037, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 37, - "spineName": "ganning", + "spineName": "zhaoyun", "rSpineName": "&", "name": "甘宁", "face_id": "ganning", @@ -1600,14 +1528,12 @@ "pieceId": 21037, "hp": 920, "atk": 490, - "matk": 0, "def": 150, "mdef": 60, "agi": 180, "luk": 90, "hp_up": 92, "atk_up": 49, - "matk_up": 0, "def_up": 15, "mdef_up": 6, "agi_up": 18, @@ -1617,7 +1543,7 @@ "sound_fight": 3081, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "甘宁,字兴霸。是纵横长江的水贼头目,为人豪爽勇烈,不拘小节而受到将士喜爱,但却也因此总是被孙权说教。物理输出型枪兵,擅长叠加debuff和控制移动", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "790&-272", "imgPosofInfoUI": "-581&-153", @@ -1625,7 +1551,7 @@ "position": "30&40&30", "initialSkin": 41038, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 38, @@ -1644,14 +1570,12 @@ "pieceId": 21038, "hp": 810, "atk": 540, - "matk": 0, "def": 130, "mdef": 60, "agi": 180, "luk": 110, "hp_up": 81, "atk_up": 54, - "matk_up": 0, "def_up": 13, "mdef_up": 6, "agi_up": 18, @@ -1661,19 +1585,19 @@ "sound_fight": 38, "kill": "卑鄙的家伙!", "retreat": "认输。", - "info": "我是高玩", + "info": "孙尚香,孙权之妹。东吴最受宠爱的小公主,自小便表现出不输男儿的气概,和马云禄对于谁是天下最强的女性而争论不休。远程输出型弓兵,擅长群体攻击、回怒回血。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "538&-82", "imgPosofInfoUI": "-387&-37", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41039, - "gender": 1, - "atkSpineEffect": "dunqi" + "gender": 2, + "atkSpineEffect": "gong" }, { "heroId": 39, - "spineName": "luxun", + "spineName": "zhaoyun", "rSpineName": "&", "name": "陆逊", "face_id": "luxun", @@ -1687,15 +1611,13 @@ "skill": 39, "pieceId": 21039, "hp": 800, - "atk": 0, - "matk": 480, + "atk": 480, "def": 130, "mdef": 170, "agi": 160, "luk": 90, "hp_up": 80, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 13, "mdef_up": 17, "agi_up": 16, @@ -1705,7 +1627,7 @@ "sound_fight": 3145, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "陆逊,字伯言,周瑜的弟子,受到周瑜的细心培养,被孙权视为江东的后起之秀,。输出型策士,擅长火攻,可造成范围持续伤害。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "583&-238", "imgPosofInfoUI": "-398&-173", @@ -1713,7 +1635,7 @@ "position": "30&40&30", "initialSkin": 41040, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 40, @@ -1731,15 +1653,13 @@ "skill": 40, "pieceId": 21040, "hp": 840, - "atk": 0, - "matk": 480, + "atk": 480, "def": 140, "mdef": 200, "agi": 170, "luk": 130, "hp_up": 84, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 14, "mdef_up": 20, "agi_up": 17, @@ -1749,7 +1669,7 @@ "sound_fight": 3193, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "小乔,江东二乔中的妹妹,和成熟妩媚的姐姐相比总是活泼跳跃,也因为活跃被于吉仙人传授仙法医术,和周瑜被称为江东仙侣。治疗型医者。擅长范围驱散,群体治疗。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "664&-57", "imgPosofInfoUI": "-458&-108", @@ -1757,11 +1677,11 @@ "position": "30&40&30", "initialSkin": 41041, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 41, - "spineName": "daqiao", + "spineName": "zhaoyun", "rSpineName": "&", "name": "大乔", "face_id": "daqiao", @@ -1775,15 +1695,13 @@ "skill": 41, "pieceId": 21041, "hp": 880, - "atk": 0, - "matk": 540, + "atk": 540, "def": 170, "mdef": 190, "agi": 180, "luk": 120, "hp_up": 88, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 17, "mdef_up": 19, "agi_up": 18, @@ -1793,7 +1711,7 @@ "sound_fight": 3193, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "大乔,江东二乔中的姐姐,成熟稳重,呆在她身边就能够宁静下来,总是可以安稳住过于活跃的孙策,和孙策在一起时就像姐姐和弟弟一般。半输出半辅助型策士,擅长怒气范围输出,怒气回复。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-541&-168", @@ -1801,7 +1719,7 @@ "position": "30&40&30", "initialSkin": 41042, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 42, @@ -1820,14 +1738,12 @@ "pieceId": 21042, "hp": 650, "atk": 480, - "matk": 0, "def": 120, "mdef": 50, "agi": 160, "luk": 80, "hp_up": 65, "atk_up": 48, - "matk_up": 0, "def_up": 12, "mdef_up": 5, "agi_up": 16, @@ -1837,15 +1753,15 @@ "sound_fight": 3193, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "步练师,和孙权是自幼长大的青梅竹马,因遭遇黄巾之乱而与家人失散,被貂蝉抚养,后来返回江东,成为了纵横家在江东留下的一步闲棋。远程物理输出型弓兵,擅长单体暴击伤害。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "604&-217", "imgPosofInfoUI": "-435&-70", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41043, - "gender": 1, - "atkSpineEffect": "dunqi" + "gender": 2, + "atkSpineEffect": "gong" }, { "heroId": 43, @@ -1864,14 +1780,12 @@ "pieceId": 21043, "hp": 1050, "atk": 400, - "matk": 0, "def": 220, "mdef": 250, "agi": 160, "luk": 100, "hp_up": 105, "atk_up": 40, - "matk_up": 0, "def_up": 22, "mdef_up": 25, "agi_up": 16, @@ -1881,7 +1795,7 @@ "sound_fight": 3049, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "左慈,字元放,道号乌角先生,外表虽然年轻但从战国时就已经在民间活跃,面上的头巾之下据说有着一只能够看破生死的眼睛。多次帮助刘备化险为夷,被刘备称为仙人。输出型道士。擅长全图debuff,回合技变形。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-365&-171", @@ -1889,7 +1803,7 @@ "position": "30&40&30", "initialSkin": 41044, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 44, @@ -1908,14 +1822,12 @@ "pieceId": 21044, "hp": 1040, "atk": 570, - "matk": 0, "def": 190, "mdef": 90, "agi": 180, "luk": 110, "hp_up": 104, "atk_up": 57, - "matk_up": 0, "def_up": 19, "mdef_up": 9, "agi_up": 18, @@ -1925,7 +1837,7 @@ "sound_fight": 44, "kill": "哈哈!感受一下青龙偃月刀的力量!", "retreat": "我竟然也会失败吗?", - "info": "我是高玩", + "info": "吕布,字奉先,号称“飞将”,但为人反复,重利轻义。兵家学派代表人物之一,物理输出型枪兵将领,擅长范围伤害,无视格挡。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "657&-193", "imgPosofInfoUI": "-508&-118", @@ -1933,7 +1845,7 @@ "position": "30&40&30", "initialSkin": 41045, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 45, @@ -1952,14 +1864,12 @@ "pieceId": 21045, "hp": 840, "atk": 660, - "matk": 0, "def": 150, "mdef": 80, "agi": 190, "luk": 140, "hp_up": 84, "atk_up": 66, - "matk_up": 0, "def_up": 15, "mdef_up": 8, "agi_up": 19, @@ -1969,7 +1879,7 @@ "sound_fight": 3081, "kill": "谁能与我一战?", "retreat": "没想到竟然会这样。。。", - "info": "我是高玩", + "info": "张任,三国群雄之一,出身贫寒但忠勇刚直,品行高洁。兵家学派代表人物之一,远程物理输出型弓兵将领,对火、冰、雷三元素的控制炉火纯青,可以自主切换元素进行攻击", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-330&-146", @@ -1977,7 +1887,7 @@ "position": "30&40&30", "initialSkin": 41046, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 46, @@ -1995,15 +1905,13 @@ "skill": 46, "pieceId": 21046, "hp": 850, - "atk": 0, - "matk": 480, + "atk": 480, "def": 150, "mdef": 200, "agi": 160, "luk": 120, "hp_up": 85, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 15, "mdef_up": 20, "agi_up": 16, @@ -2013,7 +1921,7 @@ "sound_fight": 3033, "kill": "全力攻击。", "retreat": "撤退。", - "info": "我是高玩", + "info": "华佗,字元化。著名神医,钻研医术而不求功名,擅长外科,精于手术。医家学派代表人物之一,辅助治疗型医者系武将,擅长强力单体治疗和驱散", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-393&-17", @@ -2021,7 +1929,7 @@ "position": "30&40&30", "initialSkin": 41047, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 47, @@ -2039,15 +1947,13 @@ "skill": 47, "pieceId": 21047, "hp": 920, - "atk": 0, - "matk": 540, + "atk": 540, "def": 160, "mdef": 200, "agi": 170, "luk": 130, "hp_up": 92, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 16, "mdef_up": 20, "agi_up": 17, @@ -2057,7 +1963,7 @@ "sound_fight": 3065, "kill": "吃我这一记!", "retreat": "失败了,撤退。", - "info": "我是高玩", + "info": "张角,太平道创始人,黄巾军领袖,自称“天公将军”,利用宗教组织群众发动“黄巾起义”。阴阳家学派代表人物之一,输出型道系武将,擅长操纵雷电进行攻击和控制", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-445&-156", @@ -2065,7 +1971,7 @@ "position": "30&40&30", "initialSkin": 41048, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 48, @@ -2083,15 +1989,13 @@ "skill": 48, "pieceId": 21048, "hp": 980, - "atk": 0, - "matk": 480, + "atk": 480, "def": 180, "mdef": 210, "agi": 170, "luk": 130, "hp_up": 98, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 18, "mdef_up": 21, "agi_up": 17, @@ -2101,7 +2005,7 @@ "sound_fight": 3113, "kill": "斩杀是我的天性。", "retreat": "可惜了,怎么会这样?", - "info": "我是高玩", + "info": "南华,民间被称之为“南华仙人”,外表却是一名小女孩,说话与常人不同,做事与常人不同,没人知道来历,被左慈称为师叔的神秘女子。治疗辅助型道士,可进行无限地形移动,擅长治疗和控制。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-526&-146", @@ -2109,11 +2013,11 @@ "position": "30&40&30", "initialSkin": 41049, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 49, - "spineName": "gaoshun", + "spineName": "zhaoyun", "rSpineName": "&", "name": "高顺", "face_id": "gaoshun", @@ -2128,14 +2032,12 @@ "pieceId": 21049, "hp": 1130, "atk": 450, - "matk": 0, "def": 270, "mdef": 120, "agi": 150, "luk": 110, "hp_up": 113, "atk_up": 45, - "matk_up": 0, "def_up": 27, "mdef_up": 12, "agi_up": 15, @@ -2145,7 +2047,7 @@ "sound_fight": 3081, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "高顺,吕布部将,也是吕布的同乡好友,二人自从五原流落之后,被王家收养,而成长为沉默寡言的兵家传人,对吕布和貂蝉有着家人般的情感。肉盾型步兵将领,擅长群体控制。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "60&-15", @@ -2153,7 +2055,7 @@ "position": "30&40&30", "initialSkin": 41050, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 50, @@ -2171,15 +2073,13 @@ "skill": 50, "pieceId": 21050, "hp": 100, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -2189,7 +2089,7 @@ "sound_fight": 3129, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "麹义,袁绍大将,本来是西凉马家的家将,盗取兵法后叛逃至韩馥帐下,又在冀州之战中刺杀韩馥投靠袁绍,为人狂妄轻敌,但却本领非凡。远程物理输出型弓兵将领,猿臂善射,箭可破甲。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "502&-275", "imgPosofInfoUI": "-299&-141", @@ -2197,7 +2097,7 @@ "position": "30&40&30", "initialSkin": 41051, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 51, @@ -2215,15 +2115,13 @@ "skill": 51, "pieceId": 21051, "hp": 720, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 180, "agi": 150, "luk": 120, "hp_up": 72, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 18, "agi_up": 15, @@ -2233,7 +2131,7 @@ "sound_fight": 51, "kill": "西羌之力!", "retreat": "失败了,愿赌服输。", - "info": "我是高玩", + "info": "李儒,字文优。曾经是华佗的弟子,被华佗称为能超越自己的天才神医,但却在黄巾之乱中和华佗斩断了师徒关系,并将华佗当做了自己的宿敌,既能用医术救人,也能用毒术杀人。半输出半辅助医者,擅长持续伤害和持续治疗。", "actorinfo": "远程职业的法师,菜的一笔。", "imgPosofDialog": "537&-245", "imgPosofInfoUI": "-433&-128", @@ -2241,11 +2139,11 @@ "position": "30&40&30", "initialSkin": 41052, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 52, - "spineName": "pangwu", + "spineName": "zhaoyun", "rSpineName": "&", "name": "庞舞", "face_id": "pangwu", @@ -2260,14 +2158,12 @@ "pieceId": 21052, "hp": 950, "atk": 460, - "matk": 0, "def": 160, "mdef": 30, "agi": 170, "luk": 100, "hp_up": 95, "atk_up": 46, - "matk_up": 0, "def_up": 16, "mdef_up": 3, "agi_up": 17, @@ -2277,7 +2173,7 @@ "sound_fight": 0, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "庞舞,庞统的妹妹,和庞统分别为纵横家貂蝉和沮授的弟子,一纵一横学习修炼,并且和兄长分别以“凤雏”的名号行走于世,由于二人都戴着面具,因此没人能识破他们的身份。输出型游侠,攻守兼备,擅长刺杀和怒气回复。", "actorinfo": "物理职业的步兵,强的一笔。", "imgPosofDialog": "601&-171", "imgPosofInfoUI": "-390&-158", @@ -2285,7 +2181,7 @@ "position": "30&40&30", "initialSkin": 41053, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 53, @@ -2304,14 +2200,12 @@ "pieceId": 21053, "hp": 950, "atk": 470, - "matk": 0, "def": 150, "mdef": 30, "agi": 170, "luk": 100, "hp_up": 95, "atk_up": 47, - "matk_up": 0, "def_up": 15, "mdef_up": 3, "agi_up": 17, @@ -2321,14 +2215,14 @@ "sound_fight": 53, "kill": "能接住我的攻击吗?", "retreat": "认输。", - "info": "我是高玩", + "info": "夏侯轻衣,夏侯渊之女,从小拜师天下第一墨侠王越,以成为天下第一女侠为目标。甜美可爱,性格开朗,善良纯真,和赵云相互爱慕却又互不说出口。肉盾型游侠,擅长分担我军伤害。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "782&-145", "imgPosofInfoUI": "-604&-105", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41054, - "gender": 1, + "gender": 2, "atkSpineEffect": "dunqi" }, { @@ -2348,14 +2242,12 @@ "pieceId": 21054, "hp": 850, "atk": 410, - "matk": 0, "def": 140, "mdef": 40, "agi": 130, "luk": 70, "hp_up": 85, "atk_up": 41, - "matk_up": 0, "def_up": 14, "mdef_up": 4, "agi_up": 13, @@ -2365,15 +2257,15 @@ "sound_fight": 3129, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "文丑,袁绍麾下大将,与颜良同为墨家九侠之一。为人狂放不羁,只有面对大哥颜良和主公袁绍时才能收起性子。物理输出型枪兵,擅长单体暴击伤害。", "actorinfo": "远程职业的法师,菜的一笔。", - "imgPosofDialog": "828&-222", - "imgPosofInfoUI": "-617&-138", + "imgPosofDialog": "721&-56", + "imgPosofInfoUI": "-375&-148", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41055, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 55, @@ -2392,14 +2284,12 @@ "pieceId": 21055, "hp": 700, "atk": 450, - "matk": 0, "def": 140, "mdef": 50, "agi": 120, "luk": 80, "hp_up": 70, "atk_up": 45, - "matk_up": 0, "def_up": 14, "mdef_up": 5, "agi_up": 12, @@ -2409,10 +2299,10 @@ "sound_fight": 0, "kill": "致命一击。", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "颜良,袁绍麾下大将,墨家九侠之一,和文丑情同兄弟,治军严苛,让袁军士兵都十分敬畏。肉盾型骑兵,擅长治疗自身,拥有超强续航能力。", "actorinfo": "物理职业的步兵,强的一笔。", - "imgPosofDialog": "519&-227", - "imgPosofInfoUI": "-410&-136", + "imgPosofDialog": "821&-134", + "imgPosofInfoUI": "-470&-164", "skillScroll": "&", "position": "30&40&30", "initialSkin": 41056, @@ -2436,14 +2326,12 @@ "pieceId": 21056, "hp": 1050, "atk": 500, - "matk": 0, "def": 180, "mdef": 110, "agi": 200, "luk": 110, "hp_up": 105, "atk_up": 50, - "matk_up": 0, "def_up": 18, "mdef_up": 11, "agi_up": 20, @@ -2453,7 +2341,7 @@ "sound_fight": 56, "kill": "我才是皇帝!", "retreat": "撤退吧。", - "info": "我是高玩", + "info": "貂蝉,吕布之妻,人间绝色,和吕布高顺是同乡玩伴,因为五原地震之故分离,后被纵横家收养,成为当代的纵横家之半长。半输出半辅助型策士,擅长治疗和控制。", "actorinfo": "物理职业的弓兵,勉强还行。", "imgPosofDialog": "300&400", "imgPosofInfoUI": "-463&-123", @@ -2461,7 +2349,7 @@ "position": "30&40&30", "initialSkin": 41057, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 57, @@ -2479,15 +2367,13 @@ "skill": 0, "pieceId": 21057, "hp": 100, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -2523,15 +2409,13 @@ "skill": 0, "pieceId": 21058, "hp": 100, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -2568,14 +2452,12 @@ "pieceId": 0, "hp": 60, "atk": 420, - "matk": 0, "def": 250, "mdef": 170, "agi": 160, "luk": 110, "hp_up": 110, "atk_up": 42, - "matk_up": 0, "def_up": 25, "mdef_up": 17, "agi_up": 16, @@ -2593,7 +2475,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 302, @@ -2612,14 +2494,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 220, "mdef": 120, "agi": 170, "luk": 120, "hp_up": 100, "atk_up": 54, - "matk_up": 0, "def_up": 22, "mdef_up": 12, "agi_up": 17, @@ -2637,7 +2517,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 303, @@ -2656,14 +2536,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 180, "mdef": 100, "agi": 170, "luk": 130, "hp_up": 100, "atk_up": 54, - "matk_up": 0, "def_up": 18, "mdef_up": 10, "agi_up": 17, @@ -2681,7 +2559,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 304, @@ -2700,14 +2578,12 @@ "pieceId": 0, "hp": 60, "atk": 520, - "matk": 0, "def": 190, "mdef": 120, "agi": 180, "luk": 140, "hp_up": 98, "atk_up": 52, - "matk_up": 0, "def_up": 19, "mdef_up": 12, "agi_up": 18, @@ -2725,7 +2601,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 305, @@ -2743,15 +2619,13 @@ "skill": 5, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 580, + "atk": 580, "def": 160, "mdef": 190, "agi": 170, "luk": 130, "hp_up": 83, - "atk_up": 0, - "matk_up": 58, + "atk_up": 58, "def_up": 16, "mdef_up": 19, "agi_up": 17, @@ -2769,7 +2643,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 306, @@ -2787,15 +2661,13 @@ "skill": 6, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 500, + "atk": 500, "def": 190, "mdef": 200, "agi": 170, "luk": 120, "hp_up": 98, - "atk_up": 0, - "matk_up": 50, + "atk_up": 50, "def_up": 19, "mdef_up": 20, "agi_up": 17, @@ -2813,7 +2685,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 307, @@ -2832,14 +2704,12 @@ "pieceId": 0, "hp": 60, "atk": 460, - "matk": 0, "def": 300, "mdef": 60, "agi": 180, "luk": 90, "hp_up": 107, "atk_up": 46, - "matk_up": 0, "def_up": 30, "mdef_up": 6, "agi_up": 18, @@ -2857,7 +2727,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 308, @@ -2876,14 +2746,12 @@ "pieceId": 0, "hp": 60, "atk": 400, - "matk": 0, "def": 200, "mdef": 100, "agi": 160, "luk": 100, "hp_up": 96, "atk_up": 40, - "matk_up": 0, "def_up": 20, "mdef_up": 10, "agi_up": 16, @@ -2901,7 +2769,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 309, @@ -2920,14 +2788,12 @@ "pieceId": 0, "hp": 60, "atk": 450, - "matk": 0, "def": 160, "mdef": 120, "agi": 150, "luk": 90, "hp_up": 92, "atk_up": 45, - "matk_up": 0, "def_up": 16, "mdef_up": 12, "agi_up": 15, @@ -2945,7 +2811,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 310, @@ -2964,14 +2830,12 @@ "pieceId": 0, "hp": 60, "atk": 500, - "matk": 0, "def": 160, "mdef": 60, "agi": 150, "luk": 120, "hp_up": 90, "atk_up": 50, - "matk_up": 0, "def_up": 16, "mdef_up": 6, "agi_up": 15, @@ -2989,7 +2853,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 311, @@ -3008,14 +2872,12 @@ "pieceId": 0, "hp": 60, "atk": 480, - "matk": 0, "def": 210, "mdef": 50, "agi": 160, "luk": 100, "hp_up": 86, "atk_up": 48, - "matk_up": 0, "def_up": 21, "mdef_up": 5, "agi_up": 16, @@ -3033,7 +2895,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 312, @@ -3052,14 +2914,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 120, "mdef": 60, "agi": 180, "luk": 120, "hp_up": 78, "atk_up": 54, - "matk_up": 0, "def_up": 12, "mdef_up": 6, "agi_up": 18, @@ -3077,7 +2937,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 313, @@ -3095,15 +2955,13 @@ "skill": 13, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 150, "agi": 130, "luk": 80, "hp_up": 70, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 15, "agi_up": 13, @@ -3121,7 +2979,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 314, @@ -3139,15 +2997,13 @@ "skill": 14, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 420, + "atk": 420, "def": 130, "mdef": 190, "agi": 170, "luk": 110, "hp_up": 85, - "atk_up": 0, - "matk_up": 42, + "atk_up": 42, "def_up": 13, "mdef_up": 19, "agi_up": 17, @@ -3165,7 +3021,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 315, @@ -3184,14 +3040,12 @@ "pieceId": 0, "hp": 60, "atk": 420, - "matk": 0, "def": 160, "mdef": 30, "agi": 160, "luk": 90, "hp_up": 110, "atk_up": 42, - "matk_up": 0, "def_up": 16, "mdef_up": 3, "agi_up": 16, @@ -3228,14 +3082,12 @@ "pieceId": 0, "hp": 60, "atk": 320, - "matk": 0, "def": 180, "mdef": 80, "agi": 140, "luk": 60, "hp_up": 90, "atk_up": 32, - "matk_up": 0, "def_up": 18, "mdef_up": 8, "agi_up": 14, @@ -3253,7 +3105,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 317, @@ -3272,14 +3124,12 @@ "pieceId": 0, "hp": 60, "atk": 500, - "matk": 0, "def": 220, "mdef": 100, "agi": 170, "luk": 110, "hp_up": 110, "atk_up": 50, - "matk_up": 0, "def_up": 22, "mdef_up": 10, "agi_up": 17, @@ -3297,7 +3147,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 318, @@ -3316,14 +3166,12 @@ "pieceId": 0, "hp": 60, "atk": 520, - "matk": 0, "def": 220, "mdef": 80, "agi": 160, "luk": 120, "hp_up": 105, "atk_up": 52, - "matk_up": 0, "def_up": 22, "mdef_up": 8, "agi_up": 16, @@ -3341,7 +3189,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 319, @@ -3360,14 +3208,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 180, "mdef": 90, "agi": 180, "luk": 120, "hp_up": 102, "atk_up": 54, - "matk_up": 0, "def_up": 18, "mdef_up": 9, "agi_up": 18, @@ -3385,7 +3231,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 320, @@ -3404,14 +3250,12 @@ "pieceId": 0, "hp": 60, "atk": 510, - "matk": 0, "def": 180, "mdef": 130, "agi": 160, "luk": 140, "hp_up": 100, "atk_up": 51, - "matk_up": 0, "def_up": 18, "mdef_up": 13, "agi_up": 16, @@ -3429,7 +3273,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 321, @@ -3448,14 +3292,12 @@ "pieceId": 0, "hp": 60, "atk": 680, - "matk": 0, "def": 170, "mdef": 70, "agi": 170, "luk": 130, "hp_up": 86, "atk_up": 68, - "matk_up": 0, "def_up": 17, "mdef_up": 7, "agi_up": 17, @@ -3473,7 +3315,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 322, @@ -3491,15 +3333,13 @@ "skill": 22, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 530, + "atk": 530, "def": 190, "mdef": 180, "agi": 170, "luk": 110, "hp_up": 95, - "atk_up": 0, - "matk_up": 53, + "atk_up": 53, "def_up": 19, "mdef_up": 18, "agi_up": 17, @@ -3517,7 +3357,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 323, @@ -3535,15 +3375,13 @@ "skill": 23, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 540, + "atk": 540, "def": 160, "mdef": 190, "agi": 170, "luk": 130, "hp_up": 90, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 16, "mdef_up": 19, "agi_up": 17, @@ -3561,7 +3399,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 324, @@ -3580,14 +3418,12 @@ "pieceId": 0, "hp": 60, "atk": 500, - "matk": 0, "def": 220, "mdef": 80, "agi": 180, "luk": 110, "hp_up": 105, "atk_up": 50, - "matk_up": 0, "def_up": 22, "mdef_up": 8, "agi_up": 18, @@ -3624,14 +3460,12 @@ "pieceId": 0, "hp": 60, "atk": 470, - "matk": 0, "def": 160, "mdef": 70, "agi": 180, "luk": 90, "hp_up": 92, "atk_up": 47, - "matk_up": 0, "def_up": 16, "mdef_up": 7, "agi_up": 18, @@ -3649,7 +3483,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 326, @@ -3668,14 +3502,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 150, "mdef": 60, "agi": 160, "luk": 100, "hp_up": 80, "atk_up": 54, - "matk_up": 0, "def_up": 15, "mdef_up": 6, "agi_up": 16, @@ -3693,7 +3525,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 327, @@ -3712,14 +3544,12 @@ "pieceId": 0, "hp": 60, "atk": 550, - "matk": 0, "def": 140, "mdef": 50, "agi": 170, "luk": 100, "hp_up": 80, "atk_up": 55, - "matk_up": 0, "def_up": 14, "mdef_up": 5, "agi_up": 17, @@ -3737,7 +3567,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 328, @@ -3755,15 +3585,13 @@ "skill": 28, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 180, "agi": 150, "luk": 120, "hp_up": 72, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 18, "agi_up": 15, @@ -3781,7 +3609,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 329, @@ -3799,15 +3627,13 @@ "skill": 29, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 450, + "atk": 450, "def": 130, "mdef": 180, "agi": 160, "luk": 120, "hp_up": 80, - "atk_up": 0, - "matk_up": 45, + "atk_up": 45, "def_up": 13, "mdef_up": 18, "agi_up": 16, @@ -3825,7 +3651,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 330, @@ -3844,14 +3670,12 @@ "pieceId": 0, "hp": 60, "atk": 550, - "matk": 0, "def": 120, "mdef": 60, "agi": 180, "luk": 110, "hp_up": 80, "atk_up": 55, - "matk_up": 0, "def_up": 12, "mdef_up": 6, "agi_up": 18, @@ -3869,7 +3693,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 331, @@ -3887,15 +3711,13 @@ "skill": 31, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 360, + "atk": 360, "def": 120, "mdef": 160, "agi": 140, "luk": 90, "hp_up": 70, - "atk_up": 0, - "matk_up": 36, + "atk_up": 36, "def_up": 12, "mdef_up": 16, "agi_up": 14, @@ -3913,7 +3735,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 332, @@ -3932,14 +3754,12 @@ "pieceId": 0, "hp": 60, "atk": 420, - "matk": 0, "def": 280, "mdef": 130, "agi": 160, "luk": 110, "hp_up": 115, "atk_up": 42, - "matk_up": 0, "def_up": 28, "mdef_up": 13, "agi_up": 16, @@ -3976,14 +3796,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 200, "mdef": 90, "agi": 180, "luk": 120, "hp_up": 102, "atk_up": 54, - "matk_up": 0, "def_up": 20, "mdef_up": 9, "agi_up": 18, @@ -4001,7 +3819,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 334, @@ -4019,15 +3837,13 @@ "skill": 34, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 550, + "atk": 550, "def": 170, "mdef": 180, "agi": 180, "luk": 120, "hp_up": 88, - "atk_up": 0, - "matk_up": 55, + "atk_up": 55, "def_up": 17, "mdef_up": 18, "agi_up": 18, @@ -4045,7 +3861,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 335, @@ -4064,14 +3880,12 @@ "pieceId": 0, "hp": 60, "atk": 520, - "matk": 0, "def": 200, "mdef": 60, "agi": 190, "luk": 110, "hp_up": 105, "atk_up": 52, - "matk_up": 0, "def_up": 20, "mdef_up": 6, "agi_up": 19, @@ -4089,7 +3903,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 336, @@ -4108,14 +3922,12 @@ "pieceId": 0, "hp": 60, "atk": 400, - "matk": 0, "def": 210, "mdef": 110, "agi": 150, "luk": 90, "hp_up": 100, "atk_up": 40, - "matk_up": 0, "def_up": 21, "mdef_up": 11, "agi_up": 15, @@ -4133,7 +3945,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 337, @@ -4152,14 +3964,12 @@ "pieceId": 0, "hp": 60, "atk": 490, - "matk": 0, "def": 150, "mdef": 60, "agi": 180, "luk": 90, "hp_up": 92, "atk_up": 49, - "matk_up": 0, "def_up": 15, "mdef_up": 6, "agi_up": 18, @@ -4177,7 +3987,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 338, @@ -4196,14 +4006,12 @@ "pieceId": 0, "hp": 60, "atk": 540, - "matk": 0, "def": 130, "mdef": 60, "agi": 180, "luk": 110, "hp_up": 81, "atk_up": 54, - "matk_up": 0, "def_up": 13, "mdef_up": 6, "agi_up": 18, @@ -4221,7 +4029,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 339, @@ -4239,15 +4047,13 @@ "skill": 39, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 480, + "atk": 480, "def": 130, "mdef": 170, "agi": 160, "luk": 90, "hp_up": 80, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 13, "mdef_up": 17, "agi_up": 16, @@ -4265,7 +4071,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 340, @@ -4283,15 +4089,13 @@ "skill": 40, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 480, + "atk": 480, "def": 140, "mdef": 200, "agi": 170, "luk": 130, "hp_up": 84, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 14, "mdef_up": 20, "agi_up": 17, @@ -4309,7 +4113,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 341, @@ -4327,15 +4131,13 @@ "skill": 41, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 540, + "atk": 540, "def": 170, "mdef": 190, "agi": 180, "luk": 120, "hp_up": 88, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 17, "mdef_up": 19, "agi_up": 18, @@ -4353,7 +4155,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 342, @@ -4372,14 +4174,12 @@ "pieceId": 0, "hp": 60, "atk": 480, - "matk": 0, "def": 120, "mdef": 50, "agi": 160, "luk": 80, "hp_up": 65, "atk_up": 48, - "matk_up": 0, "def_up": 12, "mdef_up": 5, "agi_up": 16, @@ -4397,7 +4197,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 343, @@ -4416,14 +4216,12 @@ "pieceId": 0, "hp": 60, "atk": 400, - "matk": 0, "def": 220, "mdef": 250, "agi": 160, "luk": 100, "hp_up": 105, "atk_up": 40, - "matk_up": 0, "def_up": 22, "mdef_up": 25, "agi_up": 16, @@ -4441,7 +4239,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 344, @@ -4460,14 +4258,12 @@ "pieceId": 0, "hp": 60, "atk": 570, - "matk": 0, "def": 190, "mdef": 90, "agi": 180, "luk": 110, "hp_up": 104, "atk_up": 57, - "matk_up": 0, "def_up": 19, "mdef_up": 9, "agi_up": 18, @@ -4485,7 +4281,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 345, @@ -4504,14 +4300,12 @@ "pieceId": 0, "hp": 60, "atk": 660, - "matk": 0, "def": 150, "mdef": 80, "agi": 190, "luk": 140, "hp_up": 84, "atk_up": 66, - "matk_up": 0, "def_up": 15, "mdef_up": 8, "agi_up": 19, @@ -4529,7 +4323,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 346, @@ -4547,15 +4341,13 @@ "skill": 46, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 480, + "atk": 480, "def": 150, "mdef": 200, "agi": 160, "luk": 120, "hp_up": 85, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 15, "mdef_up": 20, "agi_up": 16, @@ -4573,7 +4365,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 347, @@ -4591,15 +4383,13 @@ "skill": 47, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 540, + "atk": 540, "def": 160, "mdef": 200, "agi": 170, "luk": 130, "hp_up": 92, - "atk_up": 0, - "matk_up": 54, + "atk_up": 54, "def_up": 16, "mdef_up": 20, "agi_up": 17, @@ -4617,7 +4407,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 348, @@ -4635,15 +4425,13 @@ "skill": 48, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 480, + "atk": 480, "def": 180, "mdef": 210, "agi": 170, "luk": 130, "hp_up": 98, - "atk_up": 0, - "matk_up": 48, + "atk_up": 48, "def_up": 18, "mdef_up": 21, "agi_up": 17, @@ -4661,7 +4449,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 349, @@ -4680,14 +4468,12 @@ "pieceId": 0, "hp": 60, "atk": 450, - "matk": 0, "def": 270, "mdef": 120, "agi": 150, "luk": 110, "hp_up": 113, "atk_up": 45, - "matk_up": 0, "def_up": 27, "mdef_up": 12, "agi_up": 15, @@ -4705,7 +4491,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 350, @@ -4723,15 +4509,13 @@ "skill": 50, "pieceId": 0, "hp": 60, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -4749,7 +4533,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "gong" }, { "heroId": 351, @@ -4767,15 +4551,13 @@ "skill": 51, "pieceId": 0, "hp": 60, - "atk": 0, - "matk": 400, + "atk": 400, "def": 110, "mdef": 180, "agi": 150, "luk": 120, "hp_up": 72, - "atk_up": 0, - "matk_up": 40, + "atk_up": 40, "def_up": 11, "mdef_up": 18, "agi_up": 15, @@ -4793,7 +4575,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 352, @@ -4812,14 +4594,12 @@ "pieceId": 0, "hp": 60, "atk": 460, - "matk": 0, "def": 160, "mdef": 30, "agi": 170, "luk": 100, "hp_up": 95, "atk_up": 46, - "matk_up": 0, "def_up": 16, "mdef_up": 3, "agi_up": 17, @@ -4837,7 +4617,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 353, @@ -4856,14 +4636,12 @@ "pieceId": 0, "hp": 60, "atk": 470, - "matk": 0, "def": 150, "mdef": 30, "agi": 170, "luk": 100, "hp_up": 95, "atk_up": 47, - "matk_up": 0, "def_up": 15, "mdef_up": 3, "agi_up": 17, @@ -4900,14 +4678,12 @@ "pieceId": 0, "hp": 60, "atk": 410, - "matk": 0, "def": 140, "mdef": 40, "agi": 130, "luk": 70, "hp_up": 85, "atk_up": 41, - "matk_up": 0, "def_up": 14, "mdef_up": 4, "agi_up": 13, @@ -4925,7 +4701,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 355, @@ -4944,14 +4720,12 @@ "pieceId": 0, "hp": 60, "atk": 450, - "matk": 0, "def": 140, "mdef": 50, "agi": 120, "luk": 80, "hp_up": 70, "atk_up": 45, - "matk_up": 0, "def_up": 14, "mdef_up": 5, "agi_up": 12, @@ -4988,14 +4762,12 @@ "pieceId": 0, "hp": 60, "atk": 500, - "matk": 0, "def": 180, "mdef": 110, "agi": 200, "luk": 110, "hp_up": 105, "atk_up": 50, - "matk_up": 0, "def_up": 18, "mdef_up": 11, "agi_up": 20, @@ -5013,7 +4785,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "faqi" }, { "heroId": 357, @@ -5031,15 +4803,13 @@ "skill": 0, "pieceId": 0, "hp": 60, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5075,15 +4845,13 @@ "skill": 0, "pieceId": 0, "hp": 60, - "atk": 20, - "matk": 20, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 10, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5118,16 +4886,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5145,7 +4911,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1002, @@ -5162,16 +4928,14 @@ "jobid": 6, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5189,7 +4953,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1003, @@ -5206,16 +4970,14 @@ "jobid": 11, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5233,7 +4995,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1004, @@ -5250,16 +5012,14 @@ "jobid": 16, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5277,7 +5037,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1005, @@ -5294,16 +5054,14 @@ "jobid": 21, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5321,7 +5079,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1006, @@ -5338,16 +5096,14 @@ "jobid": 26, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5365,7 +5121,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1007, @@ -5382,16 +5138,14 @@ "jobid": 36, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5409,7 +5163,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1008, @@ -5426,16 +5180,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5453,7 +5205,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1009, @@ -5470,16 +5222,14 @@ "jobid": 11, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5497,7 +5247,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1010, @@ -5514,16 +5264,14 @@ "jobid": 11, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5541,7 +5289,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1011, @@ -5558,16 +5306,14 @@ "jobid": 11, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5585,7 +5331,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1012, @@ -5602,16 +5348,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5629,7 +5373,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1013, @@ -5646,16 +5390,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5673,7 +5415,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1014, @@ -5690,16 +5432,14 @@ "jobid": 41, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5717,7 +5457,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1015, @@ -5734,16 +5474,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5761,7 +5499,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1016, @@ -5778,16 +5516,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5805,7 +5541,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1017, @@ -5822,16 +5558,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5849,7 +5583,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1018, @@ -5866,16 +5600,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5893,7 +5625,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1020, @@ -5910,16 +5642,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5937,7 +5667,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1021, @@ -5954,16 +5684,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -5981,7 +5709,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1022, @@ -5998,16 +5726,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6025,7 +5751,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1023, @@ -6042,16 +5768,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6069,7 +5793,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1024, @@ -6086,16 +5810,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6113,7 +5835,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1025, @@ -6130,16 +5852,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6157,7 +5877,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1026, @@ -6174,16 +5894,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6201,7 +5919,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1027, @@ -6218,16 +5936,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6245,7 +5961,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1028, @@ -6262,16 +5978,14 @@ "jobid": 41, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6289,7 +6003,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1029, @@ -6306,16 +6020,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6333,7 +6045,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1030, @@ -6350,16 +6062,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6377,7 +6087,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1031, @@ -6394,16 +6104,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6421,7 +6129,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1032, @@ -6438,16 +6146,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6465,7 +6171,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1033, @@ -6482,16 +6188,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6509,7 +6213,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1034, @@ -6526,16 +6230,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6553,7 +6255,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1035, @@ -6570,16 +6272,14 @@ "jobid": 41, "skill": 0, "pieceId": 0, - "hp": 2400, - "atk": 400, - "matk": 20, + "hp": 5400, + "atk": 420, "def": 120, "mdef": 120, "agi": 60, "luk": 20, "hp_up": 20, - "atk_up": 3, - "matk_up": 1, + "atk_up": 4, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6597,7 +6297,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1036, @@ -6614,16 +6314,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6641,7 +6339,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1037, @@ -6658,16 +6356,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6685,7 +6381,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1038, @@ -6702,16 +6398,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6729,7 +6423,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1039, @@ -6746,16 +6440,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6773,7 +6465,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1040, @@ -6790,16 +6482,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6817,7 +6507,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1041, @@ -6834,16 +6524,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6861,7 +6549,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1042, @@ -6878,16 +6566,14 @@ "jobid": 16, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6905,7 +6591,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1043, @@ -6922,16 +6608,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6949,7 +6633,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1044, @@ -6966,16 +6650,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -6993,7 +6675,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1045, @@ -7010,16 +6692,14 @@ "jobid": 16, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7037,7 +6717,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1046, @@ -7054,16 +6734,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7081,7 +6759,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1047, @@ -7098,16 +6776,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7125,7 +6801,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1048, @@ -7142,16 +6818,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7169,7 +6843,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1049, @@ -7186,16 +6860,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7213,7 +6885,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1050, @@ -7230,16 +6902,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7257,7 +6927,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1051, @@ -7274,16 +6944,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7301,7 +6969,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1052, @@ -7318,16 +6986,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7345,7 +7011,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1053, @@ -7362,16 +7028,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7389,7 +7053,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1054, @@ -7406,16 +7070,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7433,7 +7095,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1055, @@ -7450,16 +7112,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7477,7 +7137,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1056, @@ -7494,16 +7154,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7521,7 +7179,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1057, @@ -7538,16 +7196,14 @@ "jobid": 42, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7565,7 +7221,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1074, @@ -7582,16 +7238,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7609,7 +7263,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1075, @@ -7626,16 +7280,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7653,7 +7305,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1076, @@ -7670,16 +7322,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7697,7 +7347,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1077, @@ -7714,16 +7364,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7741,7 +7389,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1078, @@ -7758,16 +7406,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7785,7 +7431,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1080, @@ -7802,16 +7448,14 @@ "jobid": 2, "skill": 0, "pieceId": 1, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7829,7 +7473,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1502, @@ -7846,16 +7490,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7873,7 +7515,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1503, @@ -7890,16 +7532,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7917,7 +7557,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1504, @@ -7934,16 +7574,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -7961,7 +7599,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1505, @@ -7978,16 +7616,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8005,7 +7641,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1506, @@ -8022,16 +7658,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8049,7 +7683,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1507, @@ -8066,16 +7700,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8093,7 +7725,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1508, @@ -8110,16 +7742,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8137,7 +7767,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1509, @@ -8154,16 +7784,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8181,7 +7809,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1510, @@ -8198,16 +7826,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8225,7 +7851,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1511, @@ -8242,16 +7868,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8269,7 +7893,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1512, @@ -8286,16 +7910,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8313,7 +7935,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 1513, @@ -8330,16 +7952,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8357,7 +7977,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2001, @@ -8374,16 +7994,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8401,7 +8019,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2002, @@ -8418,16 +8036,14 @@ "jobid": 6, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8445,7 +8061,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2003, @@ -8462,16 +8078,14 @@ "jobid": 11, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8489,7 +8103,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2004, @@ -8506,16 +8120,14 @@ "jobid": 16, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8533,7 +8145,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2005, @@ -8550,16 +8162,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8577,7 +8187,7 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" }, { "heroId": 2006, @@ -8594,16 +8204,14 @@ "jobid": 1, "skill": 0, "pieceId": 0, - "hp": 50, - "atk": 20, - "matk": 20, + "hp": 1000, + "atk": 40, "def": 20, "mdef": 20, "agi": 20, "luk": 20, "hp_up": 5, - "atk_up": 1, - "matk_up": 1, + "atk_up": 2, "def_up": 1, "mdef_up": 1, "agi_up": 1, @@ -8621,6 +8229,6 @@ "position": "30&40&30", "initialSkin": 0, "gender": 1, - "atkSpineEffect": "dunqi" + "atkSpineEffect": "liqi" } ] \ No newline at end of file diff --git a/web-server/app/controller/account.ts b/web-server/app/controller/account.ts index d3c2c6041..e31b01653 100644 --- a/web-server/app/controller/account.ts +++ b/web-server/app/controller/account.ts @@ -1,6 +1,13 @@ import { Controller } from 'egg'; export default class AccountController extends Controller { + + public async deviceLogin() { + const { ctx } = this; + const { token, isGuest, deviceId, platform, pkgName, serverType } = ctx.request.body; + ctx.body = await ctx.service.auth.deviceLogin(isGuest, token, deviceId, platform, pkgName, serverType); + } + public async getSms() { const { ctx } = this; const { tel } = ctx.request.body; @@ -9,8 +16,20 @@ export default class AccountController extends Controller { public async smsLogin() { const { ctx } = this; - const { tel, code, platform, pkgName, serverType } = ctx.request.body; - ctx.body = await ctx.service.auth.smsLogin(tel, code, platform, pkgName, serverType); + const { tel, code, platform, pkgName, serverType, deviceId } = ctx.request.body; + ctx.body = await ctx.service.auth.smsLogin(tel, deviceId, code, platform, pkgName, serverType); + } + + public async setPassword() { + const { ctx } = this; + const { password } = ctx.request.body; + ctx.body = await ctx.service.auth.setPassword(password); + } + + public async pwLogin() { + const { ctx } = this; + const { tel, deviceId, password } = ctx.request.body; + ctx.body = await ctx.service.auth.pwLogin(tel, deviceId, password); } public async checkRole() { @@ -24,4 +43,16 @@ export default class AccountController extends Controller { const { serverId, roleName } = ctx.request.body; ctx.body = await ctx.service.auth.createRole(serverId, roleName); } + + public async bind() { + const { ctx } = this; + const { tel, code } = ctx.request.body; + ctx.body = await ctx.service.auth.bind(tel, code); + } + + public async authentication() { + const { ctx } = this; + const { name, idNum } = ctx.request.body; + ctx.body = await ctx.service.auth.authentication(name, idNum); + } } diff --git a/web-server/app/controller/game.ts b/web-server/app/controller/game.ts index adec9aba6..445f3d6c6 100644 --- a/web-server/app/controller/game.ts +++ b/web-server/app/controller/game.ts @@ -1,39 +1,89 @@ import { STATUS } from '@consts'; import { GameModel } from '@db/Game'; import { Controller } from 'egg'; +import { RoleModel } from '@db/Role'; +import { NoticeModel } from '@db/Notice'; +import { ServerParamWithRole, GroupParam } from '../domain/gameField/serverlist'; export default class GameController extends Controller { - public async getServerList() { - const { ctx } = this; - let serverList: Array = []; - let { serverType, auth } = ctx; - if (auth === 1) { - serverList = await GameModel.getAllServerList(); - } else if (!auth) { - serverList = await GameModel.getServerListByType(serverType); - } - if (serverList && serverList.length > 0) { - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { serverList }); - } else { - ctx.body = ctx.service.utils.resResult(STATUS.SERVER_NOT_FOUND); - } - } - public async newServer() { - const { ctx } = this; - const { serverId, serverType, name, host, port, status } = ctx.request.body; - const serverList = await GameModel.getAllServerList(); - for (let { id, host: preHost, port: prePort } of serverList) { - if (preHost === host && prePort === port && id === serverId) { - ctx.body = ctx.service.utils.resResult(STATUS.SERVER_EXISTS); - return; - } + public async getServerList() { + const { ctx } = this; + let { serverType, auth, uid } = ctx; + + let serverList = new Array(); + let loginServerList = new Array(); + + let allServers = await GameModel.getServerList(); + let roles = await RoleModel.findAllByUid(uid); + + allServers.sort((a, b) => { + return b.id - a.id; + }); + for(let server of allServers) { + if(auth === 1 || (!auth && server.serverType == serverType)) { + server['serverStr'] = `S${server.id}`; + let curGroup = serverList.find(cur => cur.groupId == server.groupId); + if(!curGroup) { + curGroup = new GroupParam(server); + serverList.push(curGroup); + } + curGroup.pushServer(server); + + let role = roles.find(role => role.serverId == server.id); + if(!!role) { + let curLoginInfo = new ServerParamWithRole(role, server); + loginServerList.push(curLoginInfo); + } + } + } + + loginServerList.sort((a, b) => { return b.updatedAt.getTime() - a.updatedAt.getTime()}); + + if (serverList && serverList.length > 0) { + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { serverList, loginServerList }); + } else { + ctx.body = ctx.service.utils.resResult(STATUS.SERVER_NOT_FOUND); + } + return } - const gameInfo = await GameModel.newServer(serverId, serverType, name, host, port, status); - if (gameInfo) { - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { gameInfo }); - } else { - ctx.body = ctx.service.utils.resResult(STATUS.NEW_SERVER_ERR); + + public async newServer() { + const { ctx } = this; + const { serverId, serverType, name, host, port, status } = ctx.request.body; + const serverList = await GameModel.getAllServerList(); + for (let { id, host: preHost, port: prePort } of serverList) { + if (preHost === host && prePort === port && id === serverId) { + ctx.body = ctx.service.utils.resResult(STATUS.SERVER_EXISTS); + return; + } + } + const gameInfo = await GameModel.newServer(serverId, serverType, name, host, port, status); + if (gameInfo) { + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { gameInfo }); + } else { + ctx.body = ctx.service.utils.resResult(STATUS.NEW_SERVER_ERR); + } + return } - } + + + public async getnotice() { + const { ctx } = this; + let { serverType } = ctx; + + console.log(serverType); + let notice = await NoticeModel.getAllNotice(serverType); + let result = notice.map(cur => { + let {id, title, tag, type, content, time} = cur; + return { + id, title, tag, type, content, time + } + }) + + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { notice: result }); + return + } + + } diff --git a/web-server/app/middleware/parmsDecode.ts b/web-server/app/middleware/parmsDecode.ts index 3b8eaa215..c593f0021 100644 --- a/web-server/app/middleware/parmsDecode.ts +++ b/web-server/app/middleware/parmsDecode.ts @@ -43,7 +43,7 @@ module.exports = options => { await next(); const resBody = ctx.body; - console.log('return value:', resBody); + console.log('return value:', JSON.stringify(resBody)); if (isJSON(resBody)) { ctx.body = { result: aesEncrypt(JSON.stringify(resBody), ENCRYPT_KEY, ENCRYPT_IV) }; } else { diff --git a/web-server/app/middleware/tokenParser.ts b/web-server/app/middleware/tokenParser.ts index 054ffdb0c..dfb3904db 100644 --- a/web-server/app/middleware/tokenParser.ts +++ b/web-server/app/middleware/tokenParser.ts @@ -17,6 +17,8 @@ module.exports = () => { ctx.uid = user.uid; ctx.serverType = user.serverType; ctx.auth = user.auth; + ctx.userCode = user.userCode; + ctx.pkgName = user.pkgName; await next(); }; }; diff --git a/web-server/app/router.ts b/web-server/app/router.ts index e7c535fb2..cdcf057d0 100644 --- a/web-server/app/router.ts +++ b/web-server/app/router.ts @@ -5,9 +5,15 @@ export default (app: Application) => { const tokenParser = app.middleware.tokenParser(); router.get('/dev', controller.home.dev); router.get('/', controller.home.index); + router.post('/user/devicelogin', controller.account.deviceLogin); router.post('/user/getsms', controller.account.getSms); router.post('/user/smslogin', controller.account.smsLogin); + router.post('/user/setpassword', tokenParser, controller.account.setPassword); + router.post('/user/pwlogin', controller.account.pwLogin); router.post('/user/checkrole', tokenParser, controller.account.checkRole); router.post('/user/createrole', tokenParser, controller.account.createRole); + router.post('/user/bind', tokenParser, controller.account.bind); + router.post('/user/authentication', tokenParser, controller.account.authentication); router.post('/game/getserverlist', tokenParser, controller.game.getServerList); + router.post('/game/getnotice', tokenParser, controller.game.getnotice); }; diff --git a/web-server/app/service/Auth.ts b/web-server/app/service/Auth.ts index ecf4e5391..13abcd97e 100644 --- a/web-server/app/service/Auth.ts +++ b/web-server/app/service/Auth.ts @@ -1,185 +1,389 @@ -import { COUNTER, HERO_SYSTEM_TYPE, DEFAULT_LV, DEFAULT_ITEMS, ITID, DEFAULT_GOLD, DEFAULT_HERO_LV, DEFAULT_EQUIPS, DEFAULT_COIN } from '@consts'; +import { COUNTER, HERO_SYSTEM_TYPE, DEFAULT_LV, DEFAULT_ITEMS, ITID, DEFAULT_GOLD, DEFAULT_HERO_LV, DEFAULT_EQUIPS, DEFAULT_COIN, ADULT_AGE, GUEST_MAX_TIME, GUEST_DAY } from '@consts'; import { DEFAULT_HEROES } from '@consts'; import { HeroModel } from '@db/Hero'; import { RoleModel } from '@db/Role'; -import { UserModel } from '@db/User'; +import { UserModel, UserType } from '@db/User'; import { STATUS } from '@consts'; import { smsModel } from '@db/Sms'; import { Service } from 'egg'; import Counter from '@db/Counter'; import { getHeroInfoById } from 'app/pubUtils/gamedata'; -import { calPlayerCeAndSave } from 'app/pubUtils/playerCe'; +import { calPlayerCeAndSave, reCalAllHeroCe } from 'app/pubUtils/playerCe'; import { getExpByLv, getHeroExpByLv, gameData } from 'app/pubUtils/data'; import { isString } from 'underscore'; +import { getAge } from 'app/pubUtils/timeUtil'; +import { shouldRefresh, resResult } from 'app/pubUtils/util'; +import { authenticate } from 'app/pubUtils/httpUtil'; /** * Test Service */ export default class Auth extends Service { - public checkTelNo(telNo) { - if (!isString(telNo)) { - return { status: 1, data: '参数类型错误' }; - } - if (telNo.length !== 11) { - return { status: 1, data: '手机号长度错误' }; - } - return { status: 0, data: '手机号合法' }; - } + /** + * 设备免密登录 + * @param telNo - 用户手机号 + */ - async sendSmsCodeByGuodu(tel, code) { - const ctx = this.ctx; - const url = `http://221.179.172.68:8000/QxtSms/QxtFirewall?OperID=bantu3&OperPass=c8XcTffG&DesMobile=${tel}&Content=${encodeURIComponent(`【同人游戏】验证码${code},您正在登录赵云传,若非本人操作,请勿泄露`)}&Content_Code=1`; - const result = await ctx.curl(url, { - method: 'GET', - }); - return result.data; - } + public async deviceLogin(isGuest: boolean, token: string, deviceId: string, platform: string, pkgName: string, serverType: string) { + const ctx = this.ctx; - testLimit(sms, interval) { - if (sms.updateTime.getTime() > Date.now() - interval) { - return true; - } - return false; - } + let user = await UserModel.findUserByToken(token); + let loginType = 1; - /** - * 用户获取手机验证码 - * @param telNo - 用户手机号 - */ + if (!user) { + if(isGuest) { + const tel = ctx.service.utils.genCode(10); + const token = ctx.service.utils.generateStr(256); + let lastGuest = await UserModel.getLastDeviceGuest(deviceId); + let { guestTime, createdAt } = lastGuest; + if(shouldRefresh(createdAt, new Date(), 0, GUEST_DAY)) { + guestTime = 0; + } + if(guestTime > GUEST_MAX_TIME) { + loginType = 3; + return this.ctx.service.utils.resResult(STATUS.SUCCESS, { + canLogin: true, + loginType + }); + } else { - public async getSms(tel: string) { + user = await UserModel.createUser(isGuest, tel, token, platform, pkgName, serverType, deviceId, guestTime); + let param = this.getReturnParam(user); - const telVerify = this.checkTelNo(tel); - if (telVerify.status !== 0) { - return telVerify; - } - const sms = await smsModel.findByTel(tel, false); - if (sms) { - if (await sms.timeLimit(10000)) { - return this.ctx.service.utils.resResult(STATUS.SMS_IN_60S); - } - if (await sms.cntLimit(8)) { - return this.ctx.service.utils.resResult(STATUS.SMS_CNT_LIMIT); - } - } + return this.ctx.service.utils.resResult(STATUS.SUCCESS, { + canLogin: true, + loginType, + ...param + }); + } - let code = ''; - if (sms && (!sms.used || sms.isFixed)) { - code = sms.code; - } else { - code = this.ctx.service.utils.generateNum(6); - } - - const smsResult = await this.sendSmsCodeByGuodu(tel, code); - console.log(smsResult); - await smsModel.updateByTel(tel, code, false, new Date(), sms?.hasSendToday() ? sms.countToday + 1 : 1); - return this.ctx.service.utils.resResult(STATUS.SUCCESS); - } - - /** - * 用户获取到手机验证码之后发送验证登录请求 - * @param tel 登录手机号 - * @param code 登录验证码 - * @param platform 平台 - * @param pkgName 包名 - * @param serverType 服务器类型 - */ - public async smsLogin(tel: string, code: string, platform: string, pkgName: string, serverType: string) { - const ctx = this.ctx; - // 参数检查 - const telVerify = this.checkTelNo(tel); - if (telVerify.status !== 0) { - return telVerify; - } - - // ! 测试阶段允许客户端不传验证码,此时不做验证码验证,直接注册或登录账号 - // TODO 上线前改掉或仅保留在测试服 - if (code !== '') { - if (!isString(code) || code.length !== 6) { - return ctx.service.utils.resResult(STATUS.WRONG_PARMS); - } - - // 手机验证码核验 - const smsValid: boolean = await smsModel.validateSms(tel, code); - if (!smsValid) { - const sms = await smsModel.findByTel(tel); - if(sms && sms.isFixed) { // 固定手机号登录 - if (sms.code !== code) { - return ctx.service.utils.resResult(STATUS.SMS_INVALID); - } + } else { + + return this.ctx.service.utils.resResult(STATUS.SUCCESS, { + canLogin: false + }); + } } else { - return ctx.service.utils.resResult(STATUS.SMS_INVALID); + const token = ctx.service.utils.generateStr(256); + user = await UserModel.updateToken(user.tel, token, deviceId); + let param = this.getReturnParam(user); + + if(param.isGuest && param.guestTime > GUEST_MAX_TIME) { + loginType = 2; + } + let canLogin = true; + if(!user.isGuest && !user.hasSetPw) canLogin = false; + return this.ctx.service.utils.resResult(STATUS.SUCCESS, { + canLogin, // 未设置密码等于未创建账号 + loginType, + ...param + }); } - } + } - // 用户注册登录 - const token = ctx.service.utils.generateStr(256); - const user = await UserModel.updateToken(tel, token, platform, pkgName, serverType); - return ctx.service.utils.resResult(STATUS.SUCCESS, { token, userCode: user?.userCode }); - } - - public async checkRole(serverId: number) { - const ctx = this.ctx; - const { uid } = ctx; - const role = await RoleModel.findByUid(uid, serverId); - if (role) { - return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId }); + private getReturnParam(user: UserType) { + let age = getAge(user.birthday); + let isAdult = age >= ADULT_AGE; + let todayPlayTime = user.todayPlayTime; + if(shouldRefresh(user.reportTime, new Date(), 0)) { + todayPlayTime = 0; + } + return { + tel: user.tel, + isGuest: !!user.isGuest, + guestTime: user.guestTime, // 游客已体验时间 + hasAuthenticated: !!user.hasAuthenticated, // 是否进行过实名认证 + isAdult, // 是否已成年 + todayPlayTime, // 今天已游戏时长 + + hasSetPw: user.hasSetPw, // 是否设置了密码 + token: user.token, // 用户token + userCode: user.userCode // 用户标识 + } } - return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND); - } - public async createRole(serverId: number, roleName: string) { - console.log('enter Auth createRole'); - const ctx = this.ctx; - const { uid } = ctx; - const roleId = ctx.service.utils.genCode(10); - const code = ctx.service.utils.genCode(6); - const seqId = await Counter.getNewCounter(COUNTER.ROLE) || -1; - const role = await RoleModel.createRole(uid, serverId, { roleId, code, roleName, seqId, lv: DEFAULT_LV, exp: (getExpByLv(DEFAULT_LV - 1)||{sum:0}).sum||0 }); - if (role) { - for (let hid of DEFAULT_HEROES) { - let hero = await HeroModel.findByHidAndRole(hid, roleId); - if(hero) { - continue; + public checkTelNo(telNo) { + if (!isString(telNo)) { + return { status: 1, resResult: resResult(STATUS.WRONG_PARMS) }; } - - let dicHero = getHeroInfoById(hid); - if(!dicHero) { - break; + if (telNo.length !== 11) { + return { status: 1, resResult: resResult(STATUS.TEL_LEN_ERR) }; } - let {quality, initialStars: star, jobid: job, name: hName, initialSkin} = dicHero; + return { status: 0 }; + } - hero = await HeroModel.createHero({ - roleId, roleName: role.roleName, hid, hName, star, quality, job, serverId: role.serverId, - skins:[{id: initialSkin, enable: true}], lv: DEFAULT_HERO_LV, exp: getHeroExpByLv(DEFAULT_HERO_LV - 1)||0 + async sendSmsCodeByGuodu(tel, code) { + const ctx = this.ctx; + const url = `http://221.179.172.68:8000/QxtSms/QxtFirewall?OperID=bantu3&OperPass=c8XcTffG&DesMobile=${tel}&Content=${encodeURIComponent(`【同人游戏】验证码${code},您正在登录赵云传,若非本人操作,请勿泄露`)}&Content_Code=1`; + const result = await ctx.curl(url, { + method: 'GET', }); - await calPlayerCeAndSave(roleId, [hero], HERO_SYSTEM_TYPE.INIT); - - } - - for(let {id, count} of DEFAULT_ITEMS) { - let dicGoods = gameData.goods.get(id); - if(!dicGoods) continue; - let itidObj = ITID.get(dicGoods.itid); - if(!itidObj) continue; - await ctx.service.utils.addBags(roleId, role.roleName, {id, itemName: dicGoods.name, count, type: itidObj.type, hid: 0}); - } - - for(let {id, count} of DEFAULT_EQUIPS) { - for(let j = 0; j < count; j++) { - let dicGoods = gameData.goods.get(id); - if(!dicGoods) continue; - - await ctx.service.utils.addEquips(roleId, role.roleName, {id, ...dicGoods, hid: 0}); - } - } - await RoleModel.addGoldFree(roleId, DEFAULT_GOLD); - await RoleModel.addCoin(roleId, DEFAULT_COIN); - - return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId }); + return result.data; + } + + testLimit(sms, interval) { + if (sms.updateTime.getTime() > Date.now() - interval) { + return true; + } + return false; + } + + /** + * 用户获取手机验证码 + * @param telNo - 用户手机号 + */ + + public async getSms(tel: string) { + + const telVerify = this.checkTelNo(tel); + if (telVerify.status !== 0) { + return telVerify.resResult; + } + const sms = await smsModel.findByTel(tel, false); + if (sms) { + if (await sms.timeLimit(10000)) { + return this.ctx.service.utils.resResult(STATUS.SMS_IN_60S); + } + if (await sms.cntLimit(8)) { + return this.ctx.service.utils.resResult(STATUS.SMS_CNT_LIMIT); + } + } + + let code = ''; + if (sms && (!sms.used || sms.isFixed)) { + code = sms.code; + } else { + code = this.ctx.service.utils.generateNum(6); + } + + const smsResult = await this.sendSmsCodeByGuodu(tel, code); + console.log(smsResult); + await smsModel.updateByTel(tel, code, false, new Date(), sms?.hasSendToday() ? sms.countToday + 1 : 1); + + let user = await UserModel.findUserByTel(tel); + return this.ctx.service.utils.resResult(STATUS.SUCCESS, { + hasAccount: !!user && !!user.hasSetPw + }); + } + + /** + * 用户获取到手机验证码之后发送验证登录请求 + * @param tel 登录手机号 + * @param code 登录验证码 + * @param platform 平台 + * @param pkgName 包名 + * @param serverType 服务器类型 + */ + public async smsLogin(tel: string, deviceId: string, code: string, platform: string, pkgName: string, serverType: string) { + const ctx = this.ctx; + // 参数检查 + const telVerify = this.checkTelNo(tel); + if (telVerify.status !== 0) { + return telVerify.resResult; + } + + // ! 测试阶段允许客户端不传验证码,此时不做验证码验证,直接注册或登录账号 + // TODO 上线前改掉或仅保留在测试服 + if (code !== '') { + if (!isString(code) || code.length !== 6) { + return ctx.service.utils.resResult(STATUS.WRONG_PARMS); + } + + // 手机验证码核验 + const smsValid: boolean = await smsModel.validateSms(tel, code); + if (!smsValid) { + const sms = await smsModel.findByTel(tel); + if (sms && sms.isFixed) { // 固定手机号登录 + if (sms.code !== code) { + return ctx.service.utils.resResult(STATUS.SMS_INVALID); + } + } else { + return ctx.service.utils.resResult(STATUS.SMS_INVALID); + } + } + } + + // 用户注册登录 + const token = ctx.service.utils.generateStr(256); + const user = await UserModel.createOrUpdate(false, tel, token, platform, pkgName, serverType, deviceId); + let param = this.getReturnParam(user); + return ctx.service.utils.resResult(STATUS.SUCCESS, param); + } + + /** + * 设置密码 + * @param password 密码 + */ + public async setPassword(password: string) { + const { ctx } = this; + const { uid } = ctx; + if(!password) return ctx.service.utils.resResult(STATUS.PASSWORD_ILLEGEL); + + let user = await UserModel.setPass(uid, password); + if (user) { + let param = this.getReturnParam(user); + return ctx.service.utils.resResult(STATUS.SUCCESS, param); + } else { + return ctx.service.utils.resResult(STATUS.INTERNAL_ERR); + } + } + + /** + * 密码登录 + * @param tel 登录手机号 + * @param code 登录验证码 + * @param platform 平台 + * @param pkgName 包名 + * @param serverType 服务器类型 + */ + public async pwLogin(tel: string, deviceId: string, pw: string) { + const ctx = this.ctx; + // 参数检查 + const telVerify = this.checkTelNo(tel); + if (telVerify.status !== 0) { + return telVerify.resResult; + } + + + // 用户注册登录 + const token = ctx.service.utils.generateStr(256); + const user = await UserModel.checkPass(tel, pw, token, deviceId); + if(!user) return ctx.service.utils.resResult(STATUS.PASSWORD_ERR); + + let param = this.getReturnParam(user); + return ctx.service.utils.resResult(STATUS.SUCCESS, { ...param }); + } + + public async checkRole(serverId: number) { + const ctx = this.ctx; + const { uid } = ctx; + const role = await RoleModel.findByUid(uid, serverId); + if (role) { + return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId }); + } + return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND); + } + + public async createRole(serverId: number, roleName: string) { + console.log('enter Auth createRole'); + const ctx = this.ctx; + const { uid } = ctx; + const roleId = ctx.service.utils.genCode(10); + const code = ctx.service.utils.genCode(6); + const seqId = await Counter.getNewCounter(COUNTER.ROLE) || -1; + const role = await RoleModel.createRole(uid, serverId, { roleId, code, roleName, seqId, lv: DEFAULT_LV, exp: (getExpByLv(DEFAULT_LV - 1) || { sum: 0 }).sum || 0 }); + if (role) { + let skinIds = new Array(); + for (let hid of DEFAULT_HEROES) { + let hero = await HeroModel.findByHidAndRole(hid, roleId); + if (hero) { + continue; + } + + let dicHero = getHeroInfoById(hid); + if (!dicHero) { + break; + } + let { quality, initialStars: star, jobid: job, name: hName, initialSkin } = dicHero; + + hero = await HeroModel.createHero({ + roleId, roleName: role.roleName, hid, hName, star, quality, job, serverId: role.serverId, + skins: [{ id: initialSkin, enable: true }], lv: DEFAULT_HERO_LV, exp: getHeroExpByLv(DEFAULT_HERO_LV - 1) || 0 + }); + skinIds.push(initialSkin); + await calPlayerCeAndSave(HERO_SYSTEM_TYPE.INIT, roleId, hero, {}); + + } + await reCalAllHeroCe(HERO_SYSTEM_TYPE.ADD_SKIN, roleId, {}, skinIds) + + for (let { id, count } of DEFAULT_ITEMS) { + let dicGoods = gameData.goods.get(id); + if (!dicGoods) continue; + let itidObj = ITID.get(dicGoods.itid); + if (!itidObj) continue; + await ctx.service.utils.addBags(roleId, role.roleName, { id, itemName: dicGoods.name, count, type: itidObj.type, hid: 0 }); + } + + for (let { id, count } of DEFAULT_EQUIPS) { + for (let j = 0; j < count; j++) { + let dicGoods = gameData.goods.get(id); + if (!dicGoods) continue; + + await ctx.service.utils.addEquips(roleId, role.roleName, { id, ...dicGoods, hid: 0 }); + } + } + await RoleModel.addGoldFree(roleId, DEFAULT_GOLD); + await RoleModel.addCoin(roleId, DEFAULT_COIN); + + return ctx.service.utils.resResult(STATUS.SUCCESS, { roleId: role.roleId }); + } + return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND); + } + + /** + * 绑定账号 + * @param tel 手机号 + * @param code 验证码 + */ + public async bind(tel: string, code: string) { + const ctx = this.ctx; + // 参数检查 + const telVerify = this.checkTelNo(tel); + if (telVerify.status !== 0) { + return telVerify.resResult; + } + + if (!isString(code) || code.length !== 6) { + return ctx.service.utils.resResult(STATUS.WRONG_PARMS); + } + + // 手机验证码核验 + const smsValid: boolean = await smsModel.validateSms(tel, code); + if (!smsValid) { + const sms = await smsModel.findByTel(tel); + if (sms && sms.isFixed) { // 固定手机号登录 + if (sms.code !== code) { + return ctx.service.utils.resResult(STATUS.SMS_INVALID); + } + } else { + return ctx.service.utils.resResult(STATUS.SMS_INVALID); + } + } + + let telUser = await UserModel.findUserByTel(tel); + if(telUser && telUser.uid != ctx.uid) { + return ctx.service.utils.resResult(STATUS.TEL_HAS_USED); + } + + let user = await UserModel.bindTel(ctx.uid, tel); + if(!user) return ctx.service.utils.resResult(STATUS.ACCOUNT_NOT_GUEST); + let param = this.getReturnParam(user); + return ctx.service.utils.resResult(STATUS.SUCCESS, param); + } + + /** + * 实名认证 + * @param password 密码 + */ + public async authentication(name: string, idNum: string) { + const ctx = this.ctx; + // TODO 接SDK + console.log(name, idNum); + let result = await authenticate(name, idNum, ctx.userCode, ctx.pkgName); + if(!result) return ctx.service.utils.resResult(STATUS.AUTHEN_FAIL); + + let birthday = this.getBirthdayByIdCard(idNum); + let user = await UserModel.authentication(ctx.uid, birthday, ''); + let param = this.getReturnParam(user); + return ctx.service.utils.resResult(STATUS.SUCCESS, param); + } + + private getBirthdayByIdCard(idNum: string) { + let year = idNum.slice(6,10); + let month = idNum.slice(10,12); + let date = idNum.slice(12,14); + return `${year}-${month}-${date}`; } - return ctx.service.utils.resResult(STATUS.ROLE_NOT_FOUND); - } } diff --git a/web-server/app/service/Utils.ts b/web-server/app/service/Utils.ts index 9f80ed6a6..241d4ae30 100644 --- a/web-server/app/service/Utils.ts +++ b/web-server/app/service/Utils.ts @@ -1,7 +1,5 @@ import { Service } from 'egg'; import { resResult as pubResult } from '../pubUtils/util'; -import { calPlayerCeAndSave } from 'app/pubUtils/playerCe'; -import { HeroType } from '@db/Hero'; import { addSkins, addBags, addEquips } from 'app/pubUtils/itemUtils'; import { BagInter, EquipInter } from 'app/pubUtils/interface'; const csprng = require('csprng'); @@ -44,10 +42,6 @@ export default class Utils extends Service { return pubResult(status, data, customMsg); } - public calPlayerCeAndSave(roleId: string, heros: HeroType[], type: number, args: number[]) { - return calPlayerCeAndSave(roleId, heros, type, args) - } - public addSkins(roleId: string, id: number) { return addSkins(roleId, id); } diff --git a/web-server/config/config.isbn.ts b/web-server/config/config.isbn.ts new file mode 100644 index 000000000..120a2ac63 --- /dev/null +++ b/web-server/config/config.isbn.ts @@ -0,0 +1,59 @@ +import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; +const path = require('path'); + +export default (appInfo: EggAppInfo) => { + const config = {} as PowerPartial; + + // override config from framework / plugin + // use for cookie sign key, should change to your own and keep security + config.keys = appInfo.name + '_1597499383757_3508'; + config.security = { + csrf: { + enable: false, + }, + domainWhiteList: [ '*' ], + }; + config.cors = { + origin: '*', // 匹配规则 域名+端口 *则为全匹配 + allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH', + }; + // add your egg config in here + config.middleware = [ 'parmsDecode' ]; + + config.mongoose = { + url: 'mongodb://root:Bantus123@dds-8vb74337eab84d641.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vb74337eab84d642.mongodb.zhangbei.rds.aliyuncs.com:3717/admin?replicaSet=mgset-504694158', // 内网 + options: { useNewUrlParser: true, useUnifiedTopology: true }, + }; + + config.alinode = { + appid: '86043', + secret: '54ef0364995b0c4f2ab42150e29ad30df8327a3a', + error_log: [ '/root/logs/zyz/zyz-web.log', '/root/logs/zyz/common-error.log', '/root/logs/zyz/egg-agent.log' ], + packages: [ '/root/zyz/web-server/package.json' ], + }; + + config.view = { + root: path.join(appInfo.baseDir, '/app/public'), + defaultViewEngine: 'nunjucks', + mapping: { + '.html': 'nunjucks' //左边写成.html后缀,会自动渲染.html文件 + }, + }; + + config.static = { + prefix: '/', + dir: path.join(appInfo.baseDir, '/app/public'), + }; + + + // add your special config in here + const bizConfig = { + sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`, + }; + + // the return config will combines to EggAppConfig + return { + ...config, + ...bizConfig, + }; +}; diff --git a/web-server/package-lock.json b/web-server/package-lock.json index 0f45c84ca..157038d46 100644 --- a/web-server/package-lock.json +++ b/web-server/package-lock.json @@ -269,6 +269,12 @@ } } }, + "@types/bluebird": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.33.tgz", + "integrity": "sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==", + "dev": true + }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -285,6 +291,12 @@ } } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -544,6 +556,28 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/request-promise": { + "version": "4.1.47", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.47.tgz", + "integrity": "sha512-eRSZhAS8SMsrWOM8vbhxFGVZhTbWSJvaRKyufJTdIf4gscUouQvOBlfotPSPHbMR3S7kfkyKbhb1SWPmQdy3KQ==", + "dev": true, + "requires": { + "@types/bluebird": "*", + "@types/request": "*" + } + }, "@types/serve-static": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz", @@ -572,6 +606,12 @@ "@types/superagent": "*" } }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "@types/yargs": { "version": "12.0.18", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.18.tgz", diff --git a/web-server/package.json b/web-server/package.json index 92edb6a53..b40322247 100644 --- a/web-server/package.json +++ b/web-server/package.json @@ -20,7 +20,8 @@ "autod": "autod", "lint": "eslint . --ext .ts", "clean": "ets clean", - "local": "cross-env EGG_SERVER_ENV=local npm run dev" + "local": "cross-env EGG_SERVER_ENV=local npm run dev", + "isbn": "cross-env EGG_SERVER_ENV=isbn npm run dev" }, "dependencies": { "cross-env": "^7.0.3", @@ -37,6 +38,7 @@ "devDependencies": { "@types/mocha": "^2.2.40", "@types/node": "^7.0.12", + "@types/request-promise": "^4.1.47", "@types/supertest": "^2.0.0", "autod": "^3.0.1", "autod-egg": "^1.1.0",