diff --git a/game-server/app/servers/role/handler/heroHandler.ts b/game-server/app/servers/role/handler/heroHandler.ts index a07c4b0be..b8787b476 100644 --- a/game-server/app/servers/role/handler/heroHandler.ts +++ b/game-server/app/servers/role/handler/heroHandler.ts @@ -26,6 +26,8 @@ import { SkinModel } from '../../../db/Skin'; import { RoleCeModel } from '../../../db/RoleCe'; import { saveRebirthLog } from '../../../pubUtils/logUtil'; import { isGoodsHidden, isHeroHidden } from '../../../services/dataService'; +import { LadderMatchModel } from '../../../db/LadderMatch'; +import { PvpSaveDataModel } from '../../../db/PvpSaveData'; export default function (app: Application) { new HandlerService(app, {}); @@ -749,6 +751,42 @@ export class HeroHandler { return resResult(STATUS.SUCCESS, { curHero: {...pick(heroResult, ['hid', 'talent', 'usedTalentPoint', 'totalTalentPoint']) }}); } + + // 设置副将 + async setSubHero(msg: { hid: number, subHid: number }, session: BackendSession) { + let roleId = session.get('roleId'); + let { hid, subHid: subSkinId } = msg; + + let dicHero = gameData.hero.get(hid); + if(!dicHero || dicHero.urType != 1) return resResult(STATUS.HERO_CAN_NOT_SET_SUB); + + let hero = await HeroModel.findByHidAndRole(hid, roleId); + if(!hero) return resResult(STATUS.HERO_NOT_FIND); + + let subHid = 0; + if(subSkinId > 0) { // 设置上 + if(hero.subHid == subSkinId) return resResult(STATUS.HERO_SUB_DUPLICATE); + let dicHero = gameData.hero.get(subSkinId); + if(!dicHero || dicHero.urType == 1) return resResult(STATUS.HERO_CAN_NOT_BE_SET_SUB); + subHid = dicHero.actorId; + + let subHero = await HeroModel.findByHidAndRole(subHid, roleId); + if(!subHero) return resResult(STATUS.HERO_NOT_FIND); + + await LadderMatchModel.removeBySub(roleId, subHid); + await PvpSaveDataModel.removeBySub(roleId, subHid); + await PvpDefenseModel.removeBySub(roleId, subHid); + + } else { // 卸下 + if(!hero.subHid) return resResult(STATUS.HERO_CAN_NOT_REMOVE_SUB); + } + + // 设置副将 + const { preHid, curHero } = await HeroModel.setSubHero(roleId, hid, subSkinId, subHid); + + return resResult(STATUS.SUCCESS, { preHid, curHero: pick(curHero, ['hid', 'subHid']) }); + } + // ! debug接口 一键全武将 public async debugGetAllHeroes(msg: { magicWord: string }, session: BackendSession) { let roleId: string = session.get('roleId'); diff --git a/game-server/app/servers/role/handler/roleHandler.ts b/game-server/app/servers/role/handler/roleHandler.ts index 433cc1565..132f7b00b 100644 --- a/game-server/app/servers/role/handler/roleHandler.ts +++ b/game-server/app/servers/role/handler/roleHandler.ts @@ -17,9 +17,6 @@ import { Rank } from '../../../services/rankService'; import { updateUserInfo } from '../../../services/redisService'; import { checkTask, checkTaskInActiveScroll } from '../../../services/task/taskService'; import { RScriptRecordModel } from '../../../db/RScriptRecord'; -import { SkinModel, SkinUpdate } from '../../../db/Skin'; -import { Figure } from '../../../domain/dbGeneral'; -import { getActivities } from '../../../services/activity/activityService'; import * as dicParam from '../../../pubUtils/dicParam'; import Counter from '../../../db/Counter'; import { UserModel } from '../../../db/User'; diff --git a/shared/consts/constModules/selectConst.ts b/shared/consts/constModules/selectConst.ts index 9182cfccb..e3e0f0f6b 100644 --- a/shared/consts/constModules/selectConst.ts +++ b/shared/consts/constModules/selectConst.ts @@ -19,7 +19,7 @@ export enum ROLE_SELECT { export enum HERO_SELECT { ENTRY = '-_id -attr -__v', - HERO_DETAIL = 'roleId roleName hid hName ce lv star colorStar quality job skins attr ePlace skinId connections', + HERO_DETAIL = 'roleId roleName hid hName ce lv star colorStar quality job skins attr ePlace skinId connections subHid', // 排行榜中lineup字段 RANK_LINEUP = 'seqId roleId hid star colorStar lv quality job ce updatedAt skinId' } diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index c5d894c0e..ea260e5ce 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -333,6 +333,10 @@ export const STATUS = { HERO_IS_HIDDEN: { code: 30316, simStr: '未找到该武将' }, FASHION_IS_HIDDEN: { code: 30317, simStr: '未找到该时装' }, ITEM_IS_HIDDEN: { code: 30318, simStr: '未找到该道具' }, + HERO_CAN_NOT_SET_SUB: { code: 30319, simStr: '该武将不可设置副将' }, + HERO_CAN_NOT_BE_SET_SUB: { code: 30320, simStr: '该武将不可被设置为副将' }, + HERO_CAN_NOT_REMOVE_SUB: { code: 30321, simStr: '该武将未设置过副将,无法卸下' }, + HERO_SUB_DUPLICATE: { code: 30322, simStr: '请勿重复设置副将' }, // 装备养成 30400-30499 ROLE_EQUIP_PLACE_NOT_ENOUGH: { code: 30400, simStr: '装备栏未装备或无可强化' }, diff --git a/shared/db/Hero.ts b/shared/db/Hero.ts index 1bd54e543..1d303af62 100644 --- a/shared/db/Hero.ts +++ b/shared/db/Hero.ts @@ -163,6 +163,12 @@ export default class Hero extends BaseModel { @prop({ required: true, type: Reward, default: [], _id: false }) consumes: Reward[]; // 武将装备引用数组 + @prop({ required: true, default: 0 }) + subHid: number; // 副将 + + @prop({ required: true, default: 0 }) + subActorId: number; // 副将 + public static async findByRole(roleId: string, sort: { field: string, sortBy: number }[] = [], select?: string, getters = false) { let sortParam = {}; for (let { field, sortBy } of sort) { @@ -205,6 +211,18 @@ export default class Hero extends BaseModel { return hero; } + public static async findSubHero(roleId: string, subHid: number) { + const hero: HeroType = await HeroModel.findOne({ roleId, subHid }).lean(); + return hero; + } + + // 设置副将 + public static async setSubHero(roleId: string, hid: number, subSkinId: number, subActorId: number) { + const preHero = subActorId > 0? await HeroModel.findOneAndUpdate({ roleId, subActorId }, { $set: { subActorId: 0, subHid: 0 } }, { new: true }).lean(): null; + const curHero: HeroType = await HeroModel.findOneAndUpdate({ roleId, hid }, { $set: { subHid: subSkinId, subActorId } }, { new: true }).lean(); + return { preHid: preHero?.hid||0, curHero }; + } + public static async addEquip(roleId: string, hid: number, ePlaceId: number, equipId: string) { const hero: HeroType = await HeroModel.findOneAndUpdate( { roleId, hid, 'ePlace.id': ePlaceId }, diff --git a/shared/db/LadderMatch.ts b/shared/db/LadderMatch.ts index 1e2532402..5a6fc63eb 100644 --- a/shared/db/LadderMatch.ts +++ b/shared/db/LadderMatch.ts @@ -56,7 +56,7 @@ export default class LadderMatch extends BaseModel { public static async findByRoleIdAndInclude(roleId: string) { const result: LadderMatchType = await LadderMatchModel.findOne({ roleId }) .populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt') - .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job') + .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job subHid') .lean(); return result; } @@ -78,7 +78,7 @@ export default class LadderMatch extends BaseModel { public static async updateByRoleIdAndInclude(roleId: string, params: LadderUpdateInter) { const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ roleId }, { $set: params}, { new: true }) .populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt') - .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job') + .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job subHid') .lean(); return defense; } @@ -98,7 +98,7 @@ export default class LadderMatch extends BaseModel { public static async lock(serverId: number, roleId: string, rank: number) { const defense: LadderMatchType = await LadderMatchModel.findOneAndUpdate({ serverId, roleId, rank, locked: 0 }, { $set: { locked: 1 }}, { new: true }) .populate('role', 'roleId roleName head frame spine heads frames spines title lv updatedAt') - .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job') + .populate('defense.heroes.hero', 'hid skinId quality star colorStar lv skins job subHid') .lean(); return defense; } @@ -154,6 +154,10 @@ export default class LadderMatch extends BaseModel { { arrayFilters: [{"t.actorId": hid}] }).lean(); return rec } + + public static async removeBySub(roleId: string, subHid: number) { + await LadderMatchModel.updateMany({ roleId, hasDefense: true }, { $pull: { 'defense.heroes': { actorId: subHid } } }); + } } export const LadderMatchModel = getModelForClass(LadderMatch); diff --git a/shared/db/PvpDefense.ts b/shared/db/PvpDefense.ts index da2a43b91..f3b05d967 100644 --- a/shared/db/PvpDefense.ts +++ b/shared/db/PvpDefense.ts @@ -189,6 +189,11 @@ export default class PvpDefense extends BaseModel { public static async resetDefense() { await PvpDefenseModel.updateMany({}, { $set: { hasDefense: false, defense: null } }); } + + public static async removeBySub(roleId: string, subHid: number) { + await PvpDefenseModel.updateMany({ roleId, hasDefense: true }, { $pull: { 'defense.heroes': { actorId: subHid } } }); + await PvpDefenseModel.updateMany({ roleId, 'attack.heroes': { $exists: true } }, { $pull: { 'attack.heroes': { actorId: subHid } } }); + } } export const PvpDefenseModel = getModelForClass(PvpDefense); diff --git a/shared/db/PvpSaveData.ts b/shared/db/PvpSaveData.ts index 97cf81f04..1ac67bc2e 100644 --- a/shared/db/PvpSaveData.ts +++ b/shared/db/PvpSaveData.ts @@ -26,6 +26,10 @@ export default class PvpSaveData extends BaseModel { const result: PvpSaveDataType[] = await PvpSaveDataModel.find({ roleId }).lean(); return result; } + + public static async removeBySub(roleId: string, subHid: number) { + await PvpSaveDataModel.updateMany({ roleId }, { $pull: { heroes: { actorId: subHid } } }); + } } diff --git a/shared/domain/battleField/ladder.ts b/shared/domain/battleField/ladder.ts index 49e6de25a..86747c5ca 100644 --- a/shared/domain/battleField/ladder.ts +++ b/shared/domain/battleField/ladder.ts @@ -342,6 +342,7 @@ export class LadderOppDetailHeroReturn { seid: string = ''; // 技能 spine: string = ''; // 动画 talent: Talent[] = []; + subHid: number = 0; // 副将 constructor(warJson: DicWarJson, defensHero: LadderDefenseHero) { this.dataId = warJson.dataId; @@ -371,6 +372,7 @@ export class LadderOppDetailHeroReturn { let skin = hero.skins.find(cur => cur.enable); if(skin) this.talent = skin.talent; this.job = hero.job; + this.subHid = hero.subHid; } } } diff --git a/shared/domain/dbGeneral.ts b/shared/domain/dbGeneral.ts index 7fea42024..406839a55 100644 --- a/shared/domain/dbGeneral.ts +++ b/shared/domain/dbGeneral.ts @@ -39,6 +39,8 @@ export class PvpHeroInfo { quality?: number = 0; // 品质 @prop({ required: false, type: Talent, _id: false }) talent?: Talent[] = []; // 品质 + @prop({ required: false }) + subHid?: number = 0; // 副将 @prop({ required: true, _id: false }) attribute?: string; // 属性 @@ -54,6 +56,7 @@ export class PvpHeroInfo { this.quality = hero.quality; let skin = hero.skins?.find(cur => cur.enable); if(skin) this.talent = skin.talent; + this.subHid = hero.subHid; } setRobotInfo(dicHero: DicHero, lv: number) { @@ -145,6 +148,8 @@ export class PvpEnemies extends Enemies { score: number; @prop({ required: true, type: () => Talent, _id: false }) talent: Talent[]; + @prop({ required: true }) + subHid: number; // score: 这个武将的军功 constructor(warjson: DicWarJson, heroInfo: PvpHeroInfo, score: number, ce: number) { @@ -156,6 +161,7 @@ export class PvpEnemies extends Enemies { this.score = score; this.talent = heroInfo.talent; this.job = heroInfo.job; + this.subHid = heroInfo.subHid; } } diff --git a/shared/domain/roleField/friend.ts b/shared/domain/roleField/friend.ts index 7481b8d57..d2f441a92 100644 --- a/shared/domain/roleField/friend.ts +++ b/shared/domain/roleField/friend.ts @@ -200,6 +200,7 @@ export class HeroDetailParam { teraph: number; school: number; }; + subHid: number = 0; constructor(hero: HeroType) { this.roleId = hero.roleId; @@ -220,6 +221,7 @@ export class HeroDetailParam { } } this.connections = hero.connections; + this.subHid = hero.subHid; } setAttributes(attributes: {hp: number, atk: number, def: number, mdef: number}) { diff --git a/shared/pubUtils/dictionary/DicHero.ts b/shared/pubUtils/dictionary/DicHero.ts index 82dd2939d..78ff3cf05 100644 --- a/shared/pubUtils/dictionary/DicHero.ts +++ b/shared/pubUtils/dictionary/DicHero.ts @@ -37,10 +37,14 @@ export interface DicHero { readonly face_id: string; // 天赋树id readonly talentId: number; + // 是否是ur武将 + readonly urType: number; + // 武将id + readonly actorId: number; } type KeysEnum = { [P in keyof Required]: true }; -const DicHeroKeys: KeysEnum = {heroId: true, name: true, quality: true, camp: true, jobClass: true, jobid: true, skill: true, pieceId: true, initialStar: true, initialColorStar: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true, talentId: true}; +const DicHeroKeys: KeysEnum = {heroId: true, name: true, quality: true, camp: true, jobClass: true, jobid: true, skill: true, pieceId: true, initialStar: true, initialColorStar: true, pieceCount: true, baseAbilityArr: true, baseAbilityUpArr: true, initialSkin: true, recruit: true, face_id: true, talentId: true, urType: true, actorId: true }; export const dicHero = new Map(); export function loadHero() { dicHero.clear();