Playtest #6 follow-up (v2.5.1): leader HP review — 直接乘算, one debuff instance, 999 layer cap, 限伤; elite to the board; 假想敌:胄 kit

- co-op leaders died within seconds: leader HP is the official data (40 values pinned); bond / strategy / item /
  机变 / 特质 "+X%" bonuses now add up (PRTS 直接乘算) instead of compounding; a same-named enemy debuff keeps one
  (strongest) instance per target (奥术 across a pair field); leader parts pass damage 1:1; fixed co-op pool (the user's call)
- official limits read from the client: each bond stops at 999 layers (MAX_GARRISON_STACK); a leader hit of 300000+ in
  boss / hidden battles is cancelled (MAX_BATTLE_DAMAGE, 限伤) — shared/constants.js switches, research 11
- a merge that consumes a deployed copy puts the elite on that tile and facing (user-confirmed); gold target highlight,
  promotion effect
- 假想敌:胄 per PRTS: one shell, shells within range, any drone death costs 2 % max HP, 剑/锤 sorties and 瘫痪
- DESIGN §20.10–§20.14; 2842 unit tests, all 28 browser suites green; Chrome = Node on boss fields
This commit is contained in:
sganggs committed 2026-10-02 04:19:28 +08:00
1 parent 6464e4b46a
commit 620f88c0d8
81 files changed
+4194 -447

No files matched your search

+15 -5
View File
@@ -17,13 +17,23 @@ test('pairing by seat: (1,2), (3,4); an odd player alone', () => {
assert.deepEqual(pairPlayers([p(3), p(1), p(0), p(2)]).map((g) => g.map((x) => x.seat)), [[0, 1], [2, 3]]);
});
test('boss pool = bloodPoint[difficulty] in co-op whatever the alive count (solo × 0.25) × tuning; shared and never negative', () => {
// research numbers (data/tuning.json left out); research 08 §6 #7: "敌方领袖的总生命值不变" — no alive-player factor
test('boss pool = bloodPoint[difficulty] in co-op whatever the alive count (× alive / 4 only with aliveScaling; solo × 0.25) × tuning; shared and never negative', () => {
// research numbers (data/tuning.json left out); DESIGN §20.10: notice 5114's "敌方领袖的总生命值不变" is about the
// mirrored copies, the one note on player count (巴哈姆特 12294 "聯機隊友(撤退/死掉)變少,最後boss血條也會變少") has no
// proportion — config bossHpScale.aliveScaling (off) would apply × alive / 4
const { tuning, ...RAW } = DATA; // eslint-disable-line no-unused-vars
const gd = new GameData(RAW, 'mode_multi_hard');
assert.equal(bossPoolHp(gd, 'boss_1', 4), 1800000);
assert.equal(bossPoolHp(gd, 'boss_1', 2), 1800000);
assert.equal(bossPoolHp(gd, 'boss_1', 1), 1800000);
for (const n of [4, 3, 2, 1, undefined, 9]) assert.equal(bossPoolHp(gd, 'boss_1', n), 1800000, `${n} alive`);
assert.equal(gd.bossPoolHp('boss_1', 2), bossPoolHp(gd, 'boss_1', 2), 'GameData agrees');
// the flip: config bossHpScale.aliveScaling true scales the pool by alive / 4
const scaled = new GameData({ ...RAW, config: { ...RAW.config, bossHpScale: { ...RAW.config.bossHpScale, aliveScaling: true },
modes: { ...RAW.config.modes, mode_multi_hard: { ...RAW.config.modes.mode_multi_hard, bossHpScale: { ...RAW.config.modes.mode_multi_hard.bossHpScale, aliveScaling: true } } } } }, 'mode_multi_hard');
assert.equal(bossPoolHp(scaled, 'boss_1', 4), 1800000);
assert.equal(bossPoolHp(scaled, 'boss_1', 3), 1350000);
assert.equal(bossPoolHp(scaled, 'boss_1', 2), 900000);
assert.equal(bossPoolHp(scaled, 'boss_1', 1), 450000);
assert.equal(bossPoolHp(scaled, 'boss_1'), 1800000, 'no count given: a full team');
assert.equal(bossPoolHp(scaled, 'boss_1', 9), 1800000, 'never above the data value');
assert.equal(bossPoolHp(new GameData(RAW, 'mode_single_abyss'), 'boss_5', 1), 750000);
assert.equal(bossPoolHp(new GameData(RAW, 'mode_single_funny'), 'boss_2', 1), 56250);
// the balance layer multiplies the pool (docs/BALANCE.md)