feedback5: merge W5AA — community reports of 2026-10-06: the 孤岛风云 prisoners leave the gate confined (grey) and change model as their prefabs do, the 4th attack hits freed; a bounty enemy that dies with no operator behind it pays in 联防 too (the helper whose half it fell on); 忍冬's trigger and 枯朽之种's bounty were already fixed (pinned by tests); DESIGN §25.14 after round 18's §25.13; data/enemies.json regenerated offline on the merged code (round 18's model quirks + the prisoners' clips); golden: vs feedback5 exactly W5AA's moves (26 battles, solo-ABYSS-2, coop2-NORMAL-3, coop3-ABYSS-5, solo-HARD-9-boosted), vs W5AA exactly round 18's boss-pool moves

This commit is contained in:
sganggs committed 2026-10-06 22:35:10 +08:00
commit 714af994fc
26 files changed
+1081 -366

No files matched your search

+2 -2
View File
@@ -85,8 +85,8 @@
// kind, tiles?, id?, form?} (delayed strikes, charges, 'reborn' with form 'reborn') · 'beam' {from, to, kind} ·
// 'summon' {id, key} · 'ember' {id, hits, dur, form: 'husk'} · 'revive' {id, kind?, form: 'form2' | 'revived' | 'fly'}
// · 'stone' {id, dur, form: 'stone'} · 'blink' {id, fx, fy} · 'charge' {id, tx, ty} · 'expose' {id} · 'shieldBreak'
// {id} · 'liberate' {id} · 'phase' {id, kind, dur?, form?} (form changes — 掠海漂移体 'crawl', 暴鸰 'bombed',
// translator_* — and barrier / charge states) · 'lpLoss' {value, reason} · 'steal' · 'ignite'. Forms go through
// {id} · 'liberate' {id, form: 'liberty'} · 'phase' {id, kind, dur?, form?} (form changes — 掠海漂移体 'crawl', 暴鸰
// 'bombed', translator_*, a prisoner's 'warning' — and barrier / charge states) · 'lpLoss' {value, reason} · 'steal' · 'ignite'. Forms go through
// setForm(): the unit keeps it (`e.form`, UnitInfo `form`) and the fx's `form` is the model's clip set from then on
// (render/app.js → UnitView.setForm, units.js FORMS); the client keeps every fx with a `form` through catch-ups and
// hidden tabs (shared/protocol.js fxForm).
+19 -3
View File
@@ -232,16 +232,28 @@ const selfFear = (ab) => ({
},
});
/** Prisoners (禁锢 → 解放). */
/**
* Prisoners (孤岛风云: 禁锢 → 解放). The official battle prefabs (local client battle/enm_pfb_*.ab) have three modes and the
* buff templates (buff_template_data enemy_confinement, enemy_confinement[atk_cnt], enemy_liberty_listener[warning]) move
* between them: the 禁锢终端 starts with `confinement.times` charges; before each attack (ON_BEFORE_ATTACK — here the
* `before` hook: an attack 麻痹 interrupts never gets there, PRTS 拳师囚犯 "在持有麻痹的情况下,攻击不计数") one is spent, and
* the one that leaves a single charge switches it to mode R, the warning — still confined, its collar light blinking
* orange; before the next attack it switches to mode L, 【解放】, so the times-th attack already hits freed (PRTS
* "进行第4次攻击前,切换至解放状态"; until 0.2.0 it was freed after that attack's damage). The model follows the mode
* (setForm: UnitInfo `form`, render/units.js FORMS): the manifest's clips are the grey confined set, 'warning' the orange
* set, 'liberty' the red one — the 'liberate' fx carries it (a community report of 2026-10-06: they came out of the gate
* drawn freed and never changed).
*/
function prisoner(ab, { freeAll = false } = {}) {
const t = (k) => T(ab, k) ?? 0;
const times = Math.max(1, Math.round(T(ab, 'confinement.times') ?? 4));
const liberate = (b, e, a) => {
if (a.free || !e.alive) return;
a.free = true;
b.removeBuff(e, 'ab:confined');
b.addBuff(e, { key: 'ab:liberty', persist: true, visible: true, mods: {
atkPct: t('liberty.atk'), defIgnorePct: t('liberty.def_penetrate'), resFlat: t('liberty.magic_resistance'), hpRegen: t('liberty.hp_recovery_per_sec') } });
b.fx('liberate', { x: e.x, y: e.y, id: e.id });
setForm(b, e, 'liberty', 'liberate');
if (freeAll && !stOf(b).freedAll) {
// "第一次解放时同时解放全场敌人"
stOf(b).freedAll = true;
@@ -254,7 +266,11 @@ function prisoner(ab, { freeAll = false } = {}) {
a.n = 0; a.free = false;
b.addBuff(e, { key: 'ab:confined', persist: true, visible: true, mods: { aspd: t('confinement.attack_speed'), defFlat: t('confinement.def') } });
},
attack(c, b, e, a) { if (!a.free && ++a.n >= (T(ab, 'confinement.times') ?? 4)) liberate(b, e, a); },
before(c, b, e, a) {
if (a.free) return;
if (++a.n >= times) liberate(b, e, a);
else if (a.n === times - 1) setForm(b, e, 'warning');
},
};
}