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

+26 -7
View File
@@ -97,7 +97,7 @@ export class GameData {
/**
* Leader HP pool multiplier — always 1 (no custom balance). Kept for callers written against the old tuning layer
* (finalAssault.bossPoolHp); use `bossPoolHp` for the official pool.
* (finalAssault.bossPoolHp); use `bossPoolHp` / `bossPoolShare` for the official pool.
* @deprecated
*/
bossHpMul(bossId) { // eslint-disable-line no-unused-vars
@@ -105,23 +105,42 @@ export class GameData {
}
/**
* Official shared leader HP pool (research 08 §6 #7): co-op = bloodPoint[difficulty] as is — split leaders share one
* pool, "敌方领袖的总生命值不变", no alive-player scaling; solo = bloodPoint × config bossHpScale.solo (0.25,
* [ASSUMED], flagged in data). Leaders are never scaled by enemyScale.
* Official shared leader HP pool (DESIGN §20.10): ONE pool for every boss field of the match (official tip "最终攻势中,
* 所有人将一起对敌方领袖造成伤害"; the mirrored copies of a pair field share it — notice 5114 "两侧的敌方领袖共享生命值
* (敌方领袖的总生命值不变)", which is about those copies, not about the number of players). Co-op = bloodPoint
* [difficulty]; with config bossHpScale.aliveScaling (default false) × alive / aliveFull (4) — 巴哈姆特 12294 "聯機隊友
* (撤退/死掉)變少,最後boss血條也會變少" is one community note without a proportion, kept off until confirmed (it would
* shorten fights after eliminations, the opposite of the playtest report); `aliveCount` omitted ⇒ a full team. Solo = bloodPoint ×
* bossHpScale.solo (0.25 = one player of four, [ASSUMED]). Leaders are never scaled by enemyScale ("领袖单位于服务器的
* 生命值加成不受上述加成影响").
* @param {string} bossId
* @param {number} [aliveCount] alive players at the Final Assault / Hidden Core start (co-op)
* @returns {number}
*/
bossPoolHp(bossId) {
bossPoolHp(bossId, aliveCount) {
const boss = this.boss(bossId);
const diff = this.difficulty;
let base = boss && boss.bloodPoint && Number.isFinite(boss.bloodPoint[diff]) ? boss.bloodPoint[diff] : null;
if (base == null && boss && boss.bloodPoint) base = Object.values(boss.bloodPoint).find((v) => Number.isFinite(v)) ?? null;
if (base == null) base = 500000;
return Math.max(1, Math.round(base * this.bossPoolShare(aliveCount)));
}
/**
* Multiplier of bloodPoint for the leader pool (see bossPoolHp): solo = bossHpScale.solo (0.25); co-op = coop (1) ×
* min(alive, aliveFull) / aliveFull when bossHpScale.aliveScaling (mode entry first, then the global one).
* @param {number} [aliveCount]
*/
bossPoolShare(aliveCount) {
const ms = this.mode.bossHpScale && typeof this.mode.bossHpScale === 'object' ? this.mode.bossHpScale : {};
const cs = this.config.bossHpScale && typeof this.config.bossHpScale === 'object' ? this.config.bossHpScale : {};
const pick = (k, d) => (Number.isFinite(ms[k]) && ms[k] > 0 ? ms[k] : Number.isFinite(cs[k]) && cs[k] > 0 ? cs[k] : d);
const mul = this.isSolo ? pick('solo', 0.25) : pick('coop', 1);
return Math.max(1, Math.round(base * mul));
if (this.isSolo) return pick('solo', 0.25);
const scaling = typeof ms.aliveScaling === 'boolean' ? ms.aliveScaling : cs.aliveScaling === true;
const full = Math.max(1, Math.floor(pick('aliveFull', 4)));
const n = Number(aliveCount);
const alive = scaling && Number.isFinite(n) && n >= 1 ? Math.min(full, Math.floor(n)) : full;
return pick('coop', 1) * (alive / full);
}
/** config.titles with the tuning overrides (stat / rule per title id) merged in. */