diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index 40cc42bde..115d5d070 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -46,7 +46,6 @@ export class EntryHandler { } let role = await RoleModel.findByUid(user.uid, serverId, ROLE_SELECT.ENTRY, true); - console.log('****', role.heads, role.head) if (!role) { return resResult(STATUS.ROLE_NOT_FOUND); } diff --git a/game-server/app/servers/role/handler/friendHandler.ts b/game-server/app/servers/role/handler/friendHandler.ts index b7fa27c91..3291d0a08 100644 --- a/game-server/app/servers/role/handler/friendHandler.ts +++ b/game-server/app/servers/role/handler/friendHandler.ts @@ -647,16 +647,26 @@ export class FriendHandler { let dbHeroes = await HeroModel.findByRole(oppoRoleId); let role = await RoleModel.findByRoleId(oppoRoleId, null, true); - let { topLineup, topLineupCe, towerLv } = role; + let { topLineup, topLineupCe, towerLv, showLineup } = role; let heroes = new Array(); for(let {hid, lv, star, colorStar, quality } of dbHeroes) { - let hasHero = topLineup.find(cur => cur.hid == hid); - if(hasHero) { - heroes.push({ - actorId: hid, lv, star, colorStar, quality, - score: 0 - }); + if(showLineup) { // 设置过展示阵容 + let hasHero = showLineup.includes(hid); + if(hasHero) { + heroes.push({ + actorId: hid, lv, star, colorStar, quality, + score: 0 + }); + } + } else { + let hasHero = topLineup.find(cur => cur.hid == hid); + if(hasHero) { + heroes.push({ + actorId: hid, lv, star, colorStar, quality, + score: 0 + }); + } } } let rank = await getMyRank(REDIS_KEY.PVP_RANK, 0, oppoRoleId);//去redis中获取排名 diff --git a/game-server/app/servers/role/handler/roleHandler.ts b/game-server/app/servers/role/handler/roleHandler.ts index d05cd9f06..d85e142a1 100644 --- a/game-server/app/servers/role/handler/roleHandler.ts +++ b/game-server/app/servers/role/handler/roleHandler.ts @@ -12,7 +12,8 @@ import { SclResultInter, SclPosInter } from '../../../pubUtils/interface'; import { SchoolModel } from '../../../db/School'; import { checkTeraphMaterialEnough } from '../../../services/roleService' import { calPlayerCeAndSave, calAllHeroCe } from '../../../services/playerCeService'; -import { HERO_SYSTEM_TYPE } from '../../../consts'; +import { HERO_SYSTEM_TYPE, LINEUP_NUM, ROLE_SELECT } from '../../../consts'; +import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; export default function(app: Application) { return new RoleHandler(app); @@ -358,7 +359,7 @@ export class RoleHandler { }); } - + // 防沉迷调试用,推送窗口 async debugPlayerTime(msg: { type: number }, session: BackendSession) { let { type } = msg; let roleId = session.get('roleId'); @@ -404,4 +405,91 @@ export class RoleHandler { return resResult(STATUS.SUCCESS); } + + // 保存展示阵容 + async saveShowLineup(msg: { showLineup: number[] }, session: BackendSession) { + let { showLineup } = msg; + let roleId = session.get('roleId'); + + let checkHeroes = await checkBattleHeroesByHid(roleId, showLineup); + if(!checkHeroes) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); + + if(showLineup.length > LINEUP_NUM) { + return resResult(STATUS.LINEUP_MAX); + } + + let role = await RoleModel.updateRoleInfo(roleId, { showLineup }); + + return resResult(STATUS.SUCCESS, { showLineup: role.showLineup }); + } + + // 更换头像 + async setHead(msg: { id: number }, session: BackendSession) { + let { id } = msg; + let roleId = session.get('roleId'); + let role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_HEADS); + if(!role) return resResult(STATUS.ROLE_NOT_FOUND); + + let { heads } = role; + let curHead = heads.find(cur => cur.id == id); + if(!curHead) return resResult(STATUS.HEAD_NOT_FOUND); + if(curHead.enable) return resResult(STATUS.HEAD_IS_WEARING); + if(!curHead.status) return resResult(STATUS.HEAD_IS_LOCKED); + + let oldHead = heads.find(cur => cur.enable); // 穿戴中的头像 + if(oldHead) { + oldHead.enable = false; + } + curHead.enable = true; + + role = await RoleModel.updateRoleInfo(roleId, { heads }); + + return resResult(STATUS.SUCCESS, { heads: role.heads, head: role.head }); + } + + // 更换相框 + async setFrame(msg: { id: number }, session: BackendSession) { + let { id } = msg; + let roleId = session.get('roleId'); + let role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_HEADS); + if(!role) return resResult(STATUS.ROLE_NOT_FOUND); + + let { frames } = role; + let curFrame = frames.find(cur => cur.id == id); + if(!curFrame) return resResult(STATUS.HEAD_NOT_FOUND); + if(curFrame.enable) return resResult(STATUS.HEAD_IS_WEARING); + if(!curFrame.status) return resResult(STATUS.HEAD_IS_LOCKED); + + let oldHead = frames.find(cur => cur.enable); // 穿戴中的头像 + if(oldHead) { + oldHead.enable = false; + } + curFrame.enable = true; + + role = await RoleModel.updateRoleInfo(roleId, { frames }); + + return resResult(STATUS.SUCCESS, { frames: role.frames, frame: role.frame }); + } + + // 更换形象 + async setSpine(msg: { id: number }, session: BackendSession) { + let { id } = msg; + let roleId = session.get('roleId'); + let role = await RoleModel.findByRoleId(roleId, ROLE_SELECT.GET_HEADS); + if(!role) return resResult(STATUS.ROLE_NOT_FOUND); + + let { spine } = role; + + if(spine == id) { + return resResult(STATUS.SPINE_IS_WEARING); + } + let checkSkinResult = await HeroModel.checkSkin(roleId, spine); + if(!checkSkinResult) { + return resResult(STATUS.SPINE_NOT_FOUND); + } + + role = await RoleModel.updateRoleInfo(roleId, { spine: id }); + + return resResult(STATUS.SUCCESS, { spine: role.spine }); + } } diff --git a/shared/consts/constModules/selectConst.ts b/shared/consts/constModules/selectConst.ts index 36a4e5456..395b0bcbd 100644 --- a/shared/consts/constModules/selectConst.ts +++ b/shared/consts/constModules/selectConst.ts @@ -1,7 +1,7 @@ export enum ROLE_SELECT { // 初始登录数据 - ENTRY = 'serverId userInfo.uid userInfo.tel userInfo.serverType ce topLineupCe teraphs roleId roleName tili lv exp gold coin vLv title hasGuild funcs eventStatus heads head frames frame spine guildCode', + ENTRY = 'serverId userInfo.uid userInfo.tel userInfo.serverType ce topLineupCe teraphs roleId roleName tili lv exp gold coin vLv title hasGuild funcs eventStatus heads head frames frame spine guildCode frdCnt', // 玩家列表显示基础数据 SHOW_SIMPLE = 'roleId roleName ce head frame spine lv title job quitTime vLv guildName serverId userInfo.serverType', // 显示申请需要的信息 @@ -11,7 +11,8 @@ export enum ROLE_SELECT { GET_LV = 'lv', GET_ROLE_ID = 'roleId', GET_MY_SERVER = 'lv serverId userInfo.serverType', - COM_BATTLE = 'lv head frame spine topLineupCe' + COM_BATTLE = 'lv head frame spine topLineupCe', + GET_HEADS = 'heads head frames frame spine' }; export enum HERO_SELECT { diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index d67cf2f56..81fa853a5 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -422,4 +422,5 @@ export enum DEFAULT_DEVICE_ID { PC = 'pc' } +// 阵容人数限制 export const LINEUP_NUM = 6; \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index bd978932b..f808041a8 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -270,6 +270,17 @@ export const STATUS = { FRIEND_HAS_SENT: { code: 30712, simStr: '赠送达到上限' }, FRIEND_HAS_RECEIVE: { code: 30713, simStr: '领取达到上限' }, + // 形象相关 + LINEUP_MAX: { code: 30801, simStr: '阵容武将数达到上限' }, + HEAD_NOT_FOUND: { code: 30802, simStr: '未找到头像' }, + HEAD_IS_WEARING: { code: 30803, simStr: '头像已设置中' }, + HEAD_IS_LOCKED: { code: 30804, simStr: '头像未解锁' }, + FRAME_NOT_FOUND: { code: 30805, simStr: '未找到相框' }, + FRAME_IS_WEARING: { code: 30806, simStr: '相框已设置中' }, + FRAME_IS_LOCKED: { code: 30807, simStr: '相框未解锁' }, + SPINE_IS_WEARING: { code: 30808, simStr: '形象已设置中' }, + SPINE_NOT_FOUND: { code: 30809, simStr: '形象未解锁' }, + // 社交相关状态 40000 - 49999 SYS_CHANNEL_AUTH_NOT_ENOUGH: {code: 40000, simStr: '无法在系统频道发送消息'}, UPDATE_PRIVATE_MSG_READ_TIME_ERR: {code: 40001, simStr: '更新私聊阅读时间失败'}, diff --git a/shared/db/Hero.ts b/shared/db/Hero.ts index 50f11e841..b452a3c6c 100644 --- a/shared/db/Hero.ts +++ b/shared/db/Hero.ts @@ -266,6 +266,11 @@ export default class Hero extends BaseModel { const user: HeroType[] = await HeroModel.find(searchObj).lean(lean); return user; } + + public static async checkSkin(roleId: string, skinId: number) { + let hero = await HeroModel.findOne({ roleId, 'skins.id': skinId }).lean(); + return !!hero; + } } export const HeroModel = getModelForClass(Hero); diff --git a/shared/db/Role.ts b/shared/db/Role.ts index 1f635454a..a3566d603 100644 --- a/shared/db/Role.ts +++ b/shared/db/Role.ts @@ -5,7 +5,7 @@ import User from './User'; import { shouldRefresh, reduceCe } from '../pubUtils/util'; import { initRoleAtrr } from '../pubUtils/playerCe'; import { nowSeconds } from '../pubUtils/timeUtil'; -import { Head, Frame } from '../domain/dbGeneral'; +import { Figure } from '../domain/dbGeneral'; import { FIGURE } from '../pubUtils/dicParam'; import Hero from './Hero'; @@ -121,13 +121,13 @@ export default class Role extends BaseModel { @prop({ required: true }) code: string; // 邀请码 - @prop({ required: true, type: Number, default: [] }) + @prop({ required: true, type: Number }) showLineup: number[]; // 展示阵容 - @prop({ required: true, type: Head, default: [] }) - heads: Head[]; // 拥有头像列表 - @prop({ required: true, type: Head, default: [] }) - frames: Frame[]; // 拥有相框列表 + @prop({ required: true, type: Figure, default: [] }) + heads: Figure[]; // 拥有头像列表 + @prop({ required: true, type: Figure, default: [] }) + frames: Figure[]; // 拥有相框列表 @prop({ required: true, default: FIGURE.DEFAULT_SPINE }) spine: number; // 显示形象 @@ -260,7 +260,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 headHid sHid lv updatedAt').lean(lean); + const role: RoleType[] = await RoleModel.find({ 'userInfo.uid': uid }).select('roleId roleName serverId head frame spine lv updatedAt').lean(lean); return role; } @@ -459,9 +459,9 @@ 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, getters = false, virtuals = true) { delete roleUpdate._id; - let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$set:roleUpdate}, {new: true}).lean(lean); + let result: RoleType = await RoleModel.findOneAndUpdate({roleId}, {$set:roleUpdate}, {new: true}).lean({ getters, virtuals }); return result; } diff --git a/shared/domain/dbGeneral.ts b/shared/domain/dbGeneral.ts index 9efeffa98..694d0490b 100644 --- a/shared/domain/dbGeneral.ts +++ b/shared/domain/dbGeneral.ts @@ -2,7 +2,8 @@ import { prop, mongoose, Ref } from '@typegoose/typegoose'; import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; import { Attribute } from './roleField/attribute'; import Hero, { HeroType } from '../db/Hero'; -import { FIGURE } from '../pubUtils/dicParam'; +import { gameData } from '../pubUtils/data'; +import { nowSeconds, getBeforeDaySeconds } from '../pubUtils/timeUtil'; // 从玩家数据中覆盖warjson的部分字段 export class PvpHeroInfo { @@ -202,20 +203,51 @@ export class Teraph { luk: number; } -export class Head { - @prop({ required: true, default: FIGURE.DEFAULT_HEAD }) +export class Figure { + @prop({ required: true, default: 0 }) id: number; // 头像id @prop({ required: true, default: false }) - enable: boolean; // 是否启用 - @prop({ required: true }) - time: number; // 到期时间 -} + enable: boolean = false; // 是否启用 + @prop({ required: false, default: 0 }) + time?: number; // 到期时间 + @prop({ required: true, default: [] }) + unlockedType: number[] = []; // 当前已经解锁了的type -export class Frame { - @prop({ required: true, default: FIGURE.DEFAULT_FRAME }) - id: number; // 相框id - @prop({ required: true, default: false }) - enable: boolean; // 是否启用 - @prop({ required: true }) - time: number; // 到期时间 -} \ No newline at end of file + public get status () { // 虚拟字段status,当前头像是否已经解锁 + let dicGoods = gameData.goods.get(this.id); + if(!dicGoods) return false; + + let hasUnlockedAll = true; + for(let {type} of dicGoods.condition) { + if(!this.unlockedType.includes(type)) { + hasUnlockedAll = false; break; + } + } + if(!hasUnlockedAll) return true; + + if(dicGoods.timeLimit) { // 超时 + if(this.time < nowSeconds()) return false; + } + return true; + } + + constructor(id: number, unlockedType?: number[]) { + let dicGoods = gameData.goods.get(id); + if(dicGoods) { + this.id = id; + if(!unlockedType) unlockedType = dicGoods.condition.map(cur => cur.type); + this.unlockedType = unlockedType; + + let hasUnlockedAll = true; + for(let {type} of dicGoods.condition) { + if(!this.unlockedType.includes(type)) { + hasUnlockedAll = false; break; + } + } + if(hasUnlockedAll && dicGoods.timeLimit) { + this.time = getBeforeDaySeconds(-1 * dicGoods.timeLimit); // timeLimit天以后 + } + } + } + +} diff --git a/shared/domain/gameField/serverlist.ts b/shared/domain/gameField/serverlist.ts index 230d39f57..b2ddde656 100644 --- a/shared/domain/gameField/serverlist.ts +++ b/shared/domain/gameField/serverlist.ts @@ -49,8 +49,9 @@ export class ServerParamWithRole extends ServerParam { roleId: string; // 玩家账号 roleName: string; // 玩家名 - headHid: number; // 头像 - sHid: number; // 形象 + head: number; // 头像 + frame: number; // 相框 + spine: number; // 形象 lv: number; // 等级 updatedAt: Date; @@ -61,8 +62,9 @@ export class ServerParamWithRole extends ServerParam { this.roleId = role.roleId; this.roleName = role.roleName; - this.headHid = role.headHid; - this.sHid = role.sHid; + this.head = role.head; + this.frame = role.frame; + this.spine = role.spine; this.lv = role.lv; this.updatedAt = role.updatedAt; } diff --git a/shared/pubUtils/dictionary/DicGoods.ts b/shared/pubUtils/dictionary/DicGoods.ts index f3bf45fd7..380040da6 100644 --- a/shared/pubUtils/dictionary/DicGoods.ts +++ b/shared/pubUtils/dictionary/DicGoods.ts @@ -56,8 +56,12 @@ export interface DicGoods { readonly nextJewelId?: number; readonly specialCount?: number; readonly nextSpecialId?: number; - // 对应的装备id - readonly equipId?: number; + // 对应的装备id + readonly equipId?: number; + // 解锁条件 + readonly condition: {type: number, param: number}[]; + // 时间限制 + readonly timeLimit: number; } const str = readJsonFile(FILENAME.DIC_GOODS); @@ -88,11 +92,15 @@ const DicGoodsKeys: KeysEnum = { nextJewelId: true, specialCount: true, nextSpecialId: true, - equipId: true + equipId: true, + condition: true, + timeLimit: true } export const dicJewel = new Map(); export const dicGoods = new Map(); export const blueprt = new Map>(); +export const figureCondition = new Map(); // type => {param, id} + arr.forEach(o => { o.goodsAbility = parseAbility(o); o.goodsAbilityUp = parseAbilityUp(o); @@ -106,6 +114,13 @@ arr.forEach(o => { if (!!good) o.equipId = good.good_id; } + let condition = parseConditionStr(o.condition); + for(let {type, param} of condition) { + let mapArr = figureCondition.get(type)||new Array<{param: number, id: number}>(); + mapArr.push({ param, id: o.good_id}); + figureCondition.set(type, mapArr); + } + o.condition = condition; dicGoods.set(o.good_id, _.pick(o, Object.keys(DicGoodsKeys))); if (o.itid == IT_TYPE.BLUEPRT) { @@ -183,4 +198,18 @@ function parseSpecialMaterial(str: string) { specialAttr.count = count; } return specialAttr; -} \ No newline at end of file +} + +// 解析物品 {"type": number, "param": number} 格式 +export function parseConditionStr(str: string) { + let result = new Array<{ type: number, param: number }>(); + if (!str) return result; + let decodeArr = decodeArrayListStr(str); + for (let [type, param] of decodeArr) { + if (isNaN(parseInt(type)) || isNaN(parseInt(param))) { + throw new Error('data table format wrong'); + } + result.push({ type: parseInt(type), param: parseInt(param) }); + } + return result +}