diff --git a/assets/script/game/hero/Mon.ts b/assets/script/game/hero/Mon.ts index 7797be92..c01e9b81 100644 --- a/assets/script/game/hero/Mon.ts +++ b/assets/script/game/hero/Mon.ts @@ -194,6 +194,29 @@ export class Monster extends ecs.Entity { // 最终技能等级 = 初始技能等级 + 怪物等级增量,且下限为 0 model.skills[skill.uuid] = { ...skill, lv: Math.max(0,skill.lv + mon_lv - 2), ccd: 0 }; } + // 【测试模式专属】如果有覆盖技能配置则应用 + const testSkills = (this as any)._testSkills; + if (testSkills) { + if (testSkills.skill !== undefined) { + // 如果是替换普攻,通常是修改 hero.skill 字段或从 model.skills 里清除并注入 + model.skills = {}; + if (testSkills.skill) { + model.skills[testSkills.skill.s_uuid] = { + uuid: testSkills.skill.s_uuid, + cd: testSkills.skill.cd ?? 0, + lv: 1, + ccd: 0, + overrides: testSkills.skill.overrides + }; + } + } + if (testSkills.atking !== undefined) model.atking = testSkills.atking; + if (testSkills.atked !== undefined) model.atked = testSkills.atked; + if (testSkills.dead !== undefined) model.dead = testSkills.dead; + if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart; + if (testSkills.fend !== undefined) model.fend = testSkills.fend; + } + // 缓存技能射程等派生数据,减少战斗帧内重复计算 model.updateSkillDistanceCache(); diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index 6ebd6dc2..f5a0e21a 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -311,12 +311,16 @@ export class MissionMonCompComp extends CCComp { let scale = -1; // 获取硬编码的占位点坐标,不再使用随机偏移 - const basePos = MissionMonCompComp.MON_POSITIONS[posIndex]; + const basePos = MissionMonCompComp.MON_POSITIONS[posIndex % MissionMonCompComp.MON_POSITIONS.length]; const spawnX = basePos.x; const landingY = basePos.y + (monData.isBoss ? 6 : 0); const spawnPos: Vec3 = v3(spawnX, landingY + MissionMonCompComp.MON_DROP_HEIGHT, 0); this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999; + // 如果存在测试技能覆盖,则传递下去(修改 mon.load 逻辑或者通过预存) + // 为了避免侵入 Mon.ts 的原有逻辑,我们先预存 + (mon as any)._testSkills = monData.testSkills; + mon.load(spawnPos, scale, monData.uuid, monData.isBoss, landingY, monLv, posIndex); // 设置渲染排序 diff --git a/assets/script/game/map/RogueConfig.ts b/assets/script/game/map/RogueConfig.ts index 03646d54..ff98f241 100644 --- a/assets/script/game/map/RogueConfig.ts +++ b/assets/script/game/map/RogueConfig.ts @@ -554,7 +554,21 @@ export const TestModeConfig = { /** 固定的测试怪物类型 */ monType: MonType.Melee, /** 固定的测试怪物 UUID (如 6001 兽人战士) */ - monUuid: 6001 + monUuid: 6001, + /** 测试模式中生成怪物是否携带特定词缀(为空则不带) */ + affixes: [] as AffixType[], + /** 每次刷新的怪物数量 */ + spawnCount: 1, + + // ===== 附加技能测试覆盖配置 ===== + /** 替换普攻技能(清除旧技能,添加新技能) */ + skill: undefined as { s_uuid: number; cd?: number; overrides?: any } | undefined, + /** 覆盖触发技能(完全替换该类型的触发配置) */ + atking: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined, + atked: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined, + dead: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined, + fstart: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined, + fend: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined, } // ======================== 向后兼容接口 ======================== @@ -606,6 +620,15 @@ export interface GeneratedMonster { affixes: AffixType[] isBoss: boolean spawnIndex: number + /** 测试模式专属:临时覆盖怪物技能配置 */ + testSkills?: { + skill?: { s_uuid: number; cd?: number; overrides?: any }; + atking?: { s_uuid: number; t_num: number; overrides?: any }[]; + atked?: { s_uuid: number; t_num: number; overrides?: any }[]; + dead?: { s_uuid: number; t_num: number; overrides?: any }[]; + fstart?: { s_uuid: number; t_num: number; overrides?: any }[]; + fend?: { s_uuid: number; t_num: number; overrides?: any }[]; + } } // ======================== 生成引擎 ======================== @@ -670,15 +693,37 @@ export class RogueSpawningEngine { // 测试模式拦截 if (TestModeConfig.enable) { const growth = 1 + (waveNumber - 1) * TestModeConfig.growthRatePerWave; - return [{ - uuid: TestModeConfig.monUuid, - type: TestModeConfig.monType, - hp: Math.round(TestModeConfig.baseHp * growth), - ap: Math.round(TestModeConfig.baseAp * growth), - affixes: [], - isBoss: false, - spawnIndex: 0 - }]; + + // 提取词缀加成 + const affixHpMul = 1.0 + TestModeConfig.affixes.reduce( + (sum, a) => sum + (AffixConfigs[a].hpMultiplier - 1.0), 0 + ); + const affixApMul = 1.0 + TestModeConfig.affixes.reduce( + (sum, a) => sum + (AffixConfigs[a].apMultiplier - 1.0), 0 + ); + + const count = Math.max(1, TestModeConfig.spawnCount || 1); + const monsters: GeneratedMonster[] = []; + for (let i = 0; i < count; i++) { + monsters.push({ + uuid: TestModeConfig.monUuid, + type: TestModeConfig.monType, + hp: Math.round(TestModeConfig.baseHp * growth * affixHpMul), + ap: Math.round(TestModeConfig.baseAp * growth * affixApMul), + affixes: [...TestModeConfig.affixes], + isBoss: false, + spawnIndex: i, + testSkills: { + skill: TestModeConfig.skill, + atking: TestModeConfig.atking, + atked: TestModeConfig.atked, + dead: TestModeConfig.dead, + fstart: TestModeConfig.fstart, + fend: TestModeConfig.fend + } + }); + } + return monsters; } const tier = Math.ceil(waveNumber / 3)