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

+8 -7
View File
@@ -7,8 +7,8 @@
// matches (stage, factions, bans, boss and lineups all vary with the seed), simulates the real wave of that round with
// the real Battle and FULL content (kits, talents, bonds incl. layers, IN_BATTLE garrisons, items, bands, tokens) and
// reports the leak distribution and clear time. Boss rounds (R14 / solo 标准 R9) and the Hidden Core (R15) run the
// real Final Assault fields (pairs, `_s` template for a lone player, shared boss HP pool = bloodPoint (co-op; solo
// ×0.25 [ASSUMED]) — GameData.bossPoolHp —, team LP, overtime drain) and report the pool damage by 150 s, the kill time and the team LP spent.
// real Final Assault fields (pairs, `_s` template for a lone player, shared boss HP pool = bloodPoint (co-op; × alive / 4
// only with config bossHpScale.aliveScaling; solo ×0.25 [ASSUMED]) — GameData.bossPoolHp —, team LP, overtime drain) and report the pool damage by 150 s, the kill time and the team LP spent.
//
// The competent board of round r (curves below, profile-scaled): shop level, deployed units, elites (精锐), equipment,
// 2–3 active bonds built around a core bond (3 members early, 6 from R11 when the pool allows it) and the layers those
@@ -31,7 +31,8 @@
// --group N boards per multi match (default 4; 1 = no 联防)
// --boss-samples N sampled matches per boss / hidden round (default 8)
// --rehearsal N layout variants a board rehearses (default 5 = every bot variant; 0 = heuristic planner only)
// --profile curve multiplier for elites, items and layers (weak 0.6, competent 1, strong 1.4, or a number)
// --profile curve multiplier for elites, items and layers (weak 0.6, competent 1, strong 1.4, or a number;
// a bond's layers stop at BOND_LAYER_CAP, 999)
// --tuning off ignore data/tuning.json (it only holds title rules now: no effect on the numbers)
// --legacy-time read the combat limits as game seconds (the reading before the fix of docs/BALANCE.md §2.1)
// --boss-lp N team LP per alive player entering the Final Assault (default 15)
@@ -54,7 +55,7 @@ import { positionClass } from '../server/match/board.js';
import { pairPlayers, bossPoolHp, SharedBossPool } from '../server/match/finalAssault.js';
import { planUnite, uniteBattleOpts, uniteSurvivors } from '../server/match/unite.js';
import { createRng, deriveSeed } from '../server/sim/rng.js';
import { GEO, PHASE } from '../shared/constants.js';
import { GEO, PHASE, layerGainRoom } from '../shared/constants.js';
import { TICK } from '../server/sim/constants.js';
export const DIFFS = ['FUNNY', 'NORMAL', 'HARD', 'ABYSS'];
@@ -270,7 +271,7 @@ export function applyBoard(m, ps, plan, r, rng, { profile = 1 } = {}) {
for (const [id, b] of Object.entries(planned)) {
if (!b.active) continue;
const base = id === plan.core ? curve('coreLayers', r) : curve('addonLayers', r);
const v = Math.round(base * profile * jit());
const v = layerGainRoom(0, Math.round(base * profile * jit())); // ≤ BOND_LAYER_CAP (999) for any --profile
if (v > 0) ps.layers[id] = v;
}
ps.recompute();
@@ -376,8 +377,8 @@ export function runBoss({ data, mode, difficulty, round, seed, profile = 1, boss
}
}
const alive = m.alivePlayers();
// the official pool (co-op = bloodPoint, no alive scaling) — finalAssault.bossPoolHp until the match adopts it
const pool = new SharedBossPool(typeof gd.bossPoolHp === 'function' ? gd.bossPoolHp(id) : bossPoolHp(gd, id, alive.length));
// the official pool (co-op = bloodPoint, × alive / 4 only with aliveScaling, DESIGN §20.10; solo ×0.25) — the match's own rule
const pool = new SharedBossPool(bossPoolHp(gd, id, alive.length));
let teamLp = alive.reduce((s, p) => s + p.lp, 0);
const teamLp0 = teamLp;
let leakLp = 0;