Files
ark-stronghold-protocol/test/sim/feedback5-kjerag-cold.test.js
sganggs e47b098d43 feedback5 CB1: a pair of colds on an enemy becomes the freeze, no cold is left — the 谢拉格 wind no longer freezes for good from 51 layers on (community reports 「谢拉格盟约冰冻时间没有随层数正确成长」 and 「…被在无法被任何干员攻击到的地方永控」, items 7 and 8)
PRTS 术语释义 寒冷 「友方寒冷始终需要两两一对产生友方冻结,持续时间取双方之中最高」, 异常效果 COLD 「在特定条件下转变为冻结」:
applyStatus kept the older cold on for as long as the freeze, so every later cold froze again; the wind (every 25 s,
20 + 0.1 x layers s of cold) froze an enemy anywhere for the rest of the battle once its cold outlasted 25 s, never
below. Now the pair turns into the freeze (max of the two, as before) and leaves no cold on an enemy; a cold on an
operator (敌方寒冷) keeps the old rule. The wind alone now freezes 20 + 0.1 x L s of every 50 s from 51 layers (all of
it from 300). Tests: test/sim/feedback5-kjerag-cold.test.js (fails on the parent); feedback3-cold-freeze and 灵知 S2
(kits_t4) updated to the pairing. Docs: SIM.md cold row, design/engine.md.

Golden: every scenario where a second cold met an enemy still cold (灵知, 初雪, 雪猎, 耶拉, 圣聆初雪, 凛御银灰, items,
the 谢拉格 wind) — the pair no longer leaves a cold: roster-005 / 009 / 010 / 012 / 014 / 015 / 016 / 018 / 026 / 029 /
031 / 036 / 040 / 042 / 046 / 047 / 049; bond-egirShip-high, bond-indomShip-low, bond-kjeragShip-high,
bond-maniShip-high, bond-raidShip-low, bond-steadShip-high, bond-suntShip-low; boss-boss_2-pair / boss_3-pair /
boss_4-pair / boss_6-pair, hidden-boss_8-pair / boss_10-pair; matches solo-HARD-1, solo-ABYSS-1, coop3-ABYSS-5,
coop4-FUNNY-6, coop4-ABYSS-7.
2026-10-07 01:39:50 +08:00

87 lines
5.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Community reports of 2026-10-06 「谢拉格盟约冰冻时间没有随层数正确成长」 and 「谢拉格盟约冰冻敌人有概率在未受到后续干员施加
// 寒冷的情况下,被在无法被任何干员攻击到的地方永控」 (items 7 / 8): the 6-member wind (every 25 s, 寒冷 20 + 0.1 × layers s,
// data/bonds.json kjeragShip) froze an enemy for the rest of the battle from 51 layers on and never below: a second cold
// froze for max(remaining, incoming) and the older cold stayed on for as long, so the next gust always found a cold.
// PRTS 术语释义 寒冷: 「友方寒冷始终需要两两一对产生友方冻结,持续时间取双方之中最高」; 异常效果 COLD 「在特定条件下转变为冻结」 —
// the pair becomes the freeze, no cold is left. A 敌方 cold (on an operator) keeps the old rule.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec } from '../helpers/battleHarness.js';
import { hasGeneratedData } from '../../server/sim/simdata.js';
const REAL = { skip: !hasGeneratedData() };
const close = (a, b, eps, msg = '') => assert.ok(Math.abs(a - b) <= eps, `${msg} expected ${b} ± ${eps}, got ${a}`);
/** One harmless enemy parked at the gate, out of every operator's reach; 谢拉格 6 at `layers`; seconds frozen per window. */
function windTimeline(layers, until = 200) {
const h = makeBattle({
units: [{ chessId: 'chess_char_4_22_a', row: 11, col: 3 }],
bonds: { kjeragShip: { count: 6, layers, active: true, tier: 2 } },
enemies: [{ key: 'enemy_park', time: 0, route: 0 }],
defs: { enemies: { enemy_park: enemyRec({ key: 'enemy_park', hp: 1e9, atk: 0, speed: 0.00001 }) } },
timeLimit: until, seed: 1, hooks: ['statusApplied'],
});
const frozenAt = [];
while (!h.b.finished && h.b.time < until - 0.1) {
h.step();
const e = h.b.enemies[0];
frozenAt.push([h.b.time, !!(e && e.s.flags.freeze), !!(e && e.findBuff('cold'))]);
}
const frozenBetween = (t0, t1) => frozenAt.filter(([t, f]) => t >= t0 && t < t1 && f).length * h.TICK;
return { h, frozenAt, frozenBetween, at: (t) => frozenAt.find(([x]) => x >= t) };
}
test('谢拉格 wind alone: below 50 layers it never freezes (each 20 + 0.1·L s cold ends before the next gust)', REAL, () => {
const { frozenBetween } = windTimeline(40, 160);
assert.equal(frozenBetween(0, 160), 0);
});
test('谢拉格 wind alone at 60 layers: frozen 26 s out of every 50 s, not for the rest of the battle', REAL, () => {
const { frozenBetween, at } = windTimeline(60);
// gust 1 (25 s): cold 26 s; gust 2 (50 s): the pair → 26 s freeze, no cold left; gust 3 (75 s): a lone cold, still frozen
// to 76 s; gust 4 (100 s): the pair again …
close(frozenBetween(50, 100), 26, 0.2, 'the first freeze lasts the wind cold');
assert.equal(at(80)[1], false, 'free at 80 s (the parent kept it frozen from 50 s to the end)');
assert.equal(at(80)[2], true, 'with gust 3\'s lone cold on it');
assert.equal(at(101)[1], true, 'gust 4 pairs that cold: frozen again');
close(frozenBetween(100, 150), 26, 0.2);
});
test('谢拉格 wind alone: the frozen share grows with the layers (60 → 26 s, 200 → 40 s per 50 s), all of it from 300 on', REAL, () => {
close(windTimeline(60).frozenBetween(100, 150), 26, 0.2, '60 layers');
close(windTimeline(200).frozenBetween(100, 150), 40, 0.2, '200 layers');
close(windTimeline(300).frozenBetween(100, 150), 50, 0.2, '300 layers: 50 s of cold covers the 50 s cycle');
});
test('友方寒冷: the pair becomes the freeze; a lone cold on a frozen enemy is a cold and does not extend the freeze', () => {
const h = makeBattle({
defs: { enemies: { enemy_dummy: enemyRec({ key: 'enemy_dummy', hp: 1e6, speed: 0 }) } },
enemies: [{ key: 'enemy_dummy', pos: [11, 8] }], content: 'none', autoFinish: false, timeLimit: 60, hooks: ['statusApplied'],
});
h.step();
const e = h.enemy('enemy_dummy');
h.b.applyStatus(e, 'cold', { duration: 6 });
h.b.applyStatus(e, 'cold', { duration: 4 });
close(e.findBuff('freeze').timeLeft, 6, 1e-6, 'max of the pair');
assert.equal(e.findBuff('cold'), null, 'no cold left');
h.run(1);
h.b.applyStatus(e, 'cold', { duration: 10 });
close(e.findBuff('freeze').timeLeft, 5, 0.05, 'a third cold does not freeze again (it has no partner)');
close(e.findBuff('cold').timeLeft, 10, 1e-6, 'it waits as a cold');
h.b.applyStatus(e, 'cold', { duration: 2 });
close(e.findBuff('freeze').timeLeft, 10, 1e-6, 'a fourth one pairs with it: max(10, 2)');
assert.equal(e.findBuff('cold'), null);
assert.equal(h.hooksOf('statusApplied').filter((c) => c.status === 'freeze').length, 2, 'two pairs, two freezes');
});
test('敌方寒冷 on an operator keeps the old rule: the freeze and the longer cold both stay', () => {
const h = makeBattle({ units: [{ chessId: 'chess_char_1_02_a', row: 10, col: 4 }], content: 'none', autoFinish: false, timeLimit: 60 });
h.step();
const u = h.unit('chess_char_1_02_a');
h.b.applyStatus(u, 'cold', { duration: 6 });
h.b.applyStatus(u, 'cold', { duration: 4 });
close(u.findBuff('freeze').timeLeft, 6, 1e-6);
close(u.findBuff('cold').timeLeft, 6, 1e-6);
});