refactor(map): 重构rogue战斗数值生成逻辑

重构了Rogue模式的怪物数值计算方式,移除了基于英雄实时强度的动态缩放算法,改为统一使用基础属性乘以可调系数的固定缩放方案:
1.  更新了怪物配置基础属性,对齐1级英雄面板作为基准
2.  简化了数值公式,仅保留三个可调节的全局系数用于平衡难度
3.  删除了冗余的ECS查询、强度计算和类型系数逻辑
4.  更新了全部注释文档,明确数值校准目标和调整方式
This commit is contained in:
panFD
2026-08-13 14:12:05 +08:00
parent 9da3e2d9fd
commit cb2a72da52
2 changed files with 56 additions and 128 deletions

View File

@@ -11,23 +11,19 @@
* 设计层次:
* 1. BossComboLibrary - Boss 组合库(小怪构成 + Boss/小怪技能池 + 抽取权重)
* 2. MonSkillPool/BossSkillPool - 怪物技能池atking / atked / dead 等全触发类型)
* 3. RogueSpawningEngine - 生成引擎(按英雄强度反推怪物强度
* 3. RogueSpawningEngine - 生成引擎(基础属性 × 可调系数
*
* 核心公式:
* heroPower = Σ calcHeroPower(HeroInfo[uuid], lv) (场上存活英雄
* targetPower = heroPower × BOSS_TYPE_RATIO × FINAL_HP_MUL × MON_POWER_MUL
* hpScale = targetPower ÷ Σ 怪物基础强度
* 怪物 hp = base_hp × hpScale (走总强度框架,自动匹配玩家)
*
* 怪物 ap 独立挂钩玩家输出(不走总强度,避免被 hp 挤占):
* 怪物 ap = 玩家平均攻击 × AP_GROWTH_FINAL × AP_RELATIVE × 类型系数
* 核心公式(基础属性 × 可调系数)
* 怪物 hp = HeroInfo 基础hp × MON_HP_MULBoss 额外 × BOSS_HP_BONUS_MUL
* 怪物 ap = HeroInfo 基础ap × MON_AP_MUL
* 怪物基础面板与 1 级英雄持平(近战镜像 hp300/ap22/cd1.8),默认系数校准为
* 整场战斗3 英雄 vs 4 小怪 + 1 Boss双方对砍 ≈ WAVE_DURATION(30s)。
* 手感微调只改 MON_HP_MUL / MON_AP_MUL / BOSS_HP_BONUS_MUL 三个系数即可。
*/
import { HeroInfo, MonType, MonTypeName, calcHeroPower, TriggerGrouped, LvReviveEntry } from "../common/config/heroSet";
import { HeroInfo, MonType, MonTypeName, TriggerGrouped, LvReviveEntry } from "../common/config/heroSet";
import { SkillOverrides } from "../common/config/SkillSet";
import { FacSet } from "../common/config/GameSet";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
// ======================== 1. 战斗常量 ========================
@@ -38,17 +34,13 @@ export const WAVE_DURATION = 30;
export const BOSS_COUNT = 1;
export const MINION_COUNT = 4;
/** Boss 战强度系数(原压力回合系数) */
export const BOSS_TYPE_RATIO = 1.2;
/** 最终 Boss 战 HP 乘区(原 wave 20 配置) */
export const FINAL_HP_MUL = 1.8;
/** 全局怪物强度系数1 = 怪物强度与英雄能力持平,同时作用于 hp 缩放与 ap 挂钩公式 */
export const MON_POWER_MUL = 1;
/** 怪物 ap 最终递进系数(原 wave 20 满档 3.0 */
export const AP_GROWTH_FINAL = 3.0;
/** 怪物 ap 相对玩家平均攻击的基础系数(<1 保证单怪不至于一击致命,由 Boss/精英类型再上浮) */
export const AP_RELATIVE = 0.6;
/** Boss 血量加成(原 wave 20 bossBonusHpMul = 1.6 */
/** 怪物血量可调系数:最终 hp = HeroInfo 基础hp × MON_HP_MUL。
* 2.6 = 校准后怪物总血量 / 3 英雄 30s 输出≈30 DPS双方对砍 ≈ 30s 分胜负 */
export const MON_HP_MUL = 2.6;
/** 怪物攻击可调系数:最终 ap = HeroInfo 基础ap × MON_AP_MUL。
* 0.9 使 4 小怪+1 Boss 的总 DPS ≈ 2030s 恰好磨光 3 英雄总血量≈600 */
export const MON_AP_MUL = 0.9;
/** Boss 血量额外加成(在 MON_HP_MUL 之上乘算,突出压场定位 */
export const BOSS_HP_BONUS_MUL = 1.6;
/** 战斗超时(秒):超过后强制结算整局(残留怪销毁并扣留存分) */
export const BATTLE_TIMEOUT = 90;
@@ -371,12 +363,12 @@ export const TestModeConfig = {
/**
* Boss 组合生成引擎
* 随机抽一组 Boss 组合,按英雄强度反推怪物强度(最终 Boss 战档位)
* 随机抽一组 Boss 组合,怪物最终属性 = HeroInfo 基础属性 × 可调系数
*/
export class RogueSpawningEngine {
/**
* 生成一场战斗的怪物列表:随机一组 Boss 组合1 Boss + 组合小怪)。
* 生成一场战斗的怪物列表:随机一组 Boss 组合1 Boss + 4 小怪,属性走基础×系数)。
* Boss 压队尾(登场时由 MissionMonComp 统一布位)。
* @returns 怪物列表小怪在前、Boss 在尾)
*/
@@ -406,21 +398,10 @@ export class RogueSpawningEngine {
monsters.push(this.makeBoss());
}
// 属性缩放:直接取最终 Boss 战档位系数
const heroPower = this.getCurrentHeroPower();
const targetPower = heroPower * BOSS_TYPE_RATIO * MON_POWER_MUL;
const totalBasePower = monsters.reduce((sum, m) => {
const info = HeroInfo[m.uuid];
return sum + (info ? calcHeroPower(info, 1) : m.hp + m.ap);
}, 0);
if (totalBasePower > 0 && targetPower > 0) {
const hpScale = (targetPower * FINAL_HP_MUL) / totalBasePower;
const heroAvgAp = this.getCurrentHeroAttack();
for (const m of monsters) {
m.hp = Math.max(1, Math.round(m.hp * hpScale));
// ap = 玩家平均攻击 × 最终递进 × 基础系数 × 全局强度系数 × 类型系数
m.ap = Math.max(1, Math.round(heroAvgAp * AP_GROWTH_FINAL * AP_RELATIVE * MON_POWER_MUL * this.getApTypeFactor(m)));
}
// 属性缩放:基础属性 × 可调系数Boss 血量额外加成),校准目标双方对砍 ≈ 30s
for (const m of monsters) {
m.hp = Math.max(1, Math.round(m.hp * MON_HP_MUL * (m.isBoss ? BOSS_HP_BONUS_MUL : 1)));
m.ap = Math.max(1, Math.round(m.ap * MON_AP_MUL));
}
// 挂载组合技能Boss 专属池 / 小怪普通池)
@@ -443,45 +424,6 @@ export class RogueSpawningEngine {
reset(): void {
}
// ======================== 私有生成子算法 ========================
/**
* 计算场上存活英雄的总强度
* 通过 ECS 查询所有 HeroAttrsComp累加 calcHeroPower
*/
private getCurrentHeroPower(): number {
let total = 0;
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
const attrs = entity.get(HeroAttrsComp);
if (!attrs || attrs.is_dead || attrs.fac !== FacSet.HERO) return;
const info = HeroInfo[attrs.hero_uuid];
if (!info) return;
// 使用英雄当前等级(升级卡驱动),保证强度评估与实战一致
const lv = Math.max(1, attrs.lv || 1);
total += calcHeroPower(info, lv);
});
// 兜底:无英雄时返回基准强度,避免除零
return Math.max(total, 100);
}
/**
* 计算场上存活英雄的输出强度(用于怪物 ap 挂钩玩家,独立于总强度框架)。
* 取玩家英雄的"实时 ap 平均",怪物 ap 以此为锚,保证玩家输出越高、被反击越痛。
*/
private getCurrentHeroAttack(): number {
let totalAp = 0;
let count = 0;
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
const attrs = entity.get(HeroAttrsComp);
if (!attrs || attrs.is_dead || attrs.fac !== FacSet.HERO) return;
totalAp += Math.max(1, attrs.ap || 1);
count++;
});
// 兜底:无英雄时返回基准攻击,避免除零
if (count === 0) return 30;
return totalAp / count; // 平均单英雄攻击
}
/** 测试模式:完全绕过引擎逻辑 */
private generateTestWave(): GeneratedMonster[] {
const count = Math.max(1, TestModeConfig.spawnCount || 1);
@@ -536,20 +478,6 @@ export class RogueSpawningEngine {
};
}
/**
* 怪物 ap 类型系数Boss 上浮,远程/召唤稍降(避免玻璃大炮互秒),近战/重甲基准。
*/
private getApTypeFactor(m: GeneratedMonster): number {
if (m.isBoss) return 2.2; // Boss 单发重,符合"压场"定位
if (m.isBossGuard) return 1.2; // 护卫略高于杂鱼
switch (m.type) {
case MonType.Long: return 0.9;
case MonType.Summoner: return 0.7;
case MonType.Assassin: return 1.1;
default: return 1.0; // Melee / Heavy
}
}
/** 生成普通怪物 */
private makeMonster(type: MonType, spawnIndex: number): GeneratedMonster {
let uuids = MonList[type];