feedback1 WE: 鸭爵 strategy enemies follow the official rules

- 圆仔 is unblockable (PRTS 天赋 "无法攻击/被阻挡"); it was blocked like any
  ground enemy because its kit only had the front guard.
- 鸭爵 runs at move speed x(1 + run.attack@move_speed) once hurt: +300 % for
  the strategy version, +400 % for the original (PRTS); it was x3 / x4.
- The swap also applies in the Final Assault and the Hidden Core (PRTS
  下半/PRTS盟约记录 鸭爵 备注 "在最终回合和隐秘核心回合中仍然生效"): any
  ground wave enemy but the leader, its parts, bounties and uncounted units
  can be swapped (the leader rounds' escorts are elites); each player of a
  boss field gets its own 0-2.
- The four swapped-in enemies cost 1 LP at the protection point
  ("但进入保护目标点将减少1点目标生命值"): build-data sets their lpr to 1
  instead of the database's roguelike 0 (Final Assault LP, detail card).
This commit is contained in:
sganggs committed 2026-10-03 01:45:54 +08:00
1 parent 7f134737ce
commit f1e7f7da1a
10 files changed
+262 -19

No files matched your search

+19
View File
@@ -1673,12 +1673,30 @@ const MODEL_SCALES = new Map([
const MODEL_SCALE_BY_PREFAB = new Map();
for (const [v, list] of MODEL_SCALES) for (const k of list) MODEL_SCALE_BY_PREFAB.set(`enemy_${k}`, Math.round((v / MODEL_SCALE_STANDARD) * 1e4) / 1e4);
/**
* The 鸭爵 strategy's swapped-in enemies (`round_start_all_player_change_enemy_2` enemylist — the act2 versions, *_2)
* cost BAND_SWAP_LPR at the protection point, not the database's lifePointReduce 0 (the roguelike 宝藏 rule): PRTS
* 卫戍协议:盟约 下半/PRTS盟约记录 §策略 鸭爵 备注 "…但进入保护目标点将减少1点目标生命值,且在最终回合和隐秘核心回合中仍然生效"
* (player feedback after 0.1.0, #7). Normal rounds count leaks whatever their `lpr`; the Final Assault / Hidden Core
* LP and the detail card's 目标价值 read it.
*/
const BAND_SWAP_LPR = 1;
function bandSwapEnemyKeys(act) {
const out = new Set();
for (const buffs of Object.values(act.effectBuffInfoDataDict || {})) for (const b of buffs || []) {
if (b?.key !== 'round_start_all_player_change_enemy_2') continue;
for (const kv of b.blackboard || []) if (kv.key === 'enemylist') for (const k of String(kv.valueStr || '').split(',')) if (k.trim()) out.add(k.trim());
}
return out;
}
/**
* Build data/enemies.json: base stats at the season level (randomEnemyAttributeDict.level, 0 for
* all), with the season-wide override level (level_autochess_enemy_data) applied.
*/
function buildEnemies(ctx) {
const { ac, act, handbook } = ctx;
const swapKeys = bandSwapEnemyKeys(act);
const c = ac.constData;
const hpF = c.enemyMaxHpFactor ?? 1, atkF = c.enemyAtkFactor ?? 5, defF = c.enemyDefFactor ?? 3, resF = c.enemyMagicResistanceFactor ?? 3;
const globalOverrides = new Map();
@@ -1736,6 +1754,7 @@ function buildEnemies(ctx) {
otherImmunities: ['disarmedCombat', 'feared', 'palsy', 'attract', 'teleport', 'groundBound'].filter((k) => !!mv(at[`${k}Immune`], false)),
tauntLevel: mv(at.tauntLevel, 0),
};
if (swapKeys.has(key)) stats.lpr = BAND_SWAP_LPR;
const beFactor = rand?.enemyBattleEffectivenessFactor ?? 1;
const be = beFactor > 0 ? Math.round((stats.maxHp * hpF + stats.atk * atkF + stats.def * defF + stats.res * resF) / beFactor) : null;
const talents = flattenBB(data.talentBlackboard, `enemy ${key} talents`);