feedback5 WM: merge feedback4 (896dd5d, the coming 0.1.4) — PRs #150 #66 #146 #74 #72 #103 #149 #109 #160 ported into the split layout
Ported by hand: - #109 kit hunks → kits/ops (the tier files stay re-export shims): 宴 chess_char_1_18-utage.js, 野鬃 chess_char_1_19-wildmn.js, 砾 chess_char_2_12-gravel.js, 斯卡蒂 chess_char_3_05-skadi.js, 伊内丝 chess_char_4_04-ines.js, 缄默德克萨斯 chess_char_4_16-texas2.js, 耀骑士临光 chess_char_6_17-nearl2.js. The +/- lines are identical to #109's tier1/2/3/4/6 diffs. - #109 generic.js against W5D's own-duration passives (一击即退): the deployment window is computed where #109 computes it, with W5D's case included. Both forms run #109's duration lifecycle (activateOnDeploy, spType 'none', the skill's own mods), and W5D's 冲锋号令 DP start effect is kept. - #103 room.js through i18n phase 1: t('{name}邀请你加入卫戍协议:盟约【{difficulty}】') with the translated difficulty name (the Chinese text is the PR's), plus its English line in public/i18n/en.json. - data/assets.json: feedback5's manifest plus #72's audio.bgm.combatAlts (after boss, the plan order). files +3 and bytes +5 037 595 as measured on feedback4; the hash is recomputed with the generator's contentHash. No other data/ file changed. - docs: DESIGN §5.6 (#109's timed deployment paragraph before feedback5's trigger rules; "Permanent passive skills are always on"), SIM §7.4 (both generic passive cases). - Auto-merged and checked: #149 bond-bar fold (still in screens/game.js), #160 skills.js / spine.js, #109 skills.js / snapshot.js, #66 addon/battle.js (restTile / isDown live in sim/battle/tiles.js), #150 units.js, #72 audio.js / plan.mjs, #74 plan.mjs / docs. Where the PRs met feedback5 work: - 突袭 (W5L, GitHub #49): raidPoll counts a skill that needs no SP while it is on. That is a passive, as before, or a #109 deploy-timed skill while its window runs. Once the window has ended only the idle trigger is left. Without this change 缄默德克萨斯 / 宴 lost #49. research 02 §3.18 says so. - Tests changed to #109's representation: bonds_addon #49 test (kind 'duration', activateOnDeploy) plus a new test (window over → idle trigger only), and standin.test.js's 预备干员 PASSIVE branch (the skill's mods instead of the generic:passive buff). Golden regenerated on the merged code. Attribution: each PR's gameplay change was reverted alone in a scratch copy, and all three together. With all three reverted the digests equal feedback5's exactly. Every moved scenario was replayed and fields the unit that explains it. - #160 only (0.5 s skill events of deploy passives; events.skill only): roster-001/006/025/049, bond-arcaneShip-low, bond-emptyShip-high, bond-investShip-high, bond-kjeragShip-low, bond-siracusaShip-low/high, bond-victoriaShip-low, bond-yanShip-high, boss-boss_2/4/6-solo, hidden-boss_8/10-solo, standin-03/05/08/10, diy-005/006 (普罗旺斯 S1, 琳琅诗怀雅 S1/S2, 星熊 S2, 凯瑟琳 S1, Misery S3 as stand-in / 自选 prototype). - #109 only (deploy-timed skill state and lifecycle; 突袭 技能就绪 limited to the window; generic 一击即退): roster-003/004/005/021/023/024/039/041/042/046/047, bond-egirShip-high, bond-indomShip-high, bond-kazimierzShip-low/high, hidden-boss_8-pair, standin-01, coop4-FUNNY-6, coop2-NORMAL-8-serverrun. - #66 only (灵巧's aura stays only for a killed member, from its body tile): roster-028, coop2-NORMAL-3, coop3-ABYSS-5, coop4-ABYSS-7, solo-HARD-9-boosted. - #109 + #160: roster-002, roster-029, bond-investShip-low, bond-raidShip-low/high, bond-suntShip-low, bond-visiShip-high. - #66 + #160: roster-008, roster-027. - #66 + #109: roster-022, roster-040, bond-indomShip-low, boss-boss_2/4/6-pair, hidden-boss_10-pair, standin-06, coop2-HARD-4, coop2-NORMAL-14-standins. - all three: roster-010, roster-012, roster-031. 69 scenarios. Every other digest is unchanged.
This commit is contained in:
commit
a0a7660287
55 files changed
+2140
-736
No files matched your search
@@ -444,6 +444,8 @@ test('1_18 宴 S1 分神: no attacks, block 0 (releases), DEF +def, regenerates
|
||||
assert.equal(u.s.blockCnt, 0);
|
||||
assert.equal(u.blocking.length, 0);
|
||||
assert.equal(e.blockedBy, null, 'blocked enemy released');
|
||||
h.b.dealDamage(u, e, { amount: 100, type: 'phys', isAttack: true });
|
||||
assert.equal(dealt(h, u).at(-1).type, 'phys', 'active S1 does not inherit S2 arts conversion');
|
||||
approx(u.s.def, u.base.def * (1 + bb.def), `${id} DEF`);
|
||||
approx(u.s.hpRegen, u.s.maxHp * bb.hp_recovery_per_sec_by_max_hp_ratio, 'regen');
|
||||
u.hp = u.s.maxHp * 0.3;
|
||||
@@ -462,23 +464,71 @@ test('1_18 宴 S1 分神: no attacks, block 0 (releases), DEF +def, regenerates
|
||||
}
|
||||
});
|
||||
|
||||
test('1_19 野鬃 S1 骑枪刺击 (PASSIVE): ASPD +attack_speed for `duration` s after every deployment', () => {
|
||||
test('1_18 宴 S2: deployment loses current HP once; ATK and normal-attack arts conversion end with the duration', () => {
|
||||
for (const id of pair('18')) {
|
||||
const s = rec(id, 'skchr_utage_2'), bb = s.bb;
|
||||
const h = run({ defs: { chess: noGarrison(id), enemies: { e: dummy('e') } },
|
||||
units: [entry(id, s.skillId, { row: 10, col: 4, carryState: { hpPct: 0.5, skillActive: true } })] });
|
||||
h.b.start();
|
||||
const u = h.unit(id);
|
||||
assert.equal(u.skill.kind, 'duration');
|
||||
assert.equal(u.skill.activations, 1);
|
||||
assert.equal(u.skill.charges, 0);
|
||||
approx(u.hp, u.s.maxHp * 0.5 * (1 - bb.hp_ratio), 'one loss from carried current HP');
|
||||
approx(u.s.atk, u.base.atk * (1 + bb.atk));
|
||||
const e = h.spawn('e', { pos: [10, 8] });
|
||||
const hit = () => { h.b.dealDamage(u, e, { amount: 100, type: 'phys', isAttack: true }); return dealt(h, u).at(-1); };
|
||||
assert.equal(hit().type, 'arts');
|
||||
assert.ok(!hit().dmg.isSkill, 'normal attack marker retained');
|
||||
h.run(bb.duration / 2);
|
||||
approx(u.skill.timeLeft, bb.duration / 2);
|
||||
h.run(bb.duration / 2 + 0.1);
|
||||
assert.equal(u.skill.active, false);
|
||||
assert.equal(u.skill.ready, false);
|
||||
approx(u.s.atk, u.base.atk);
|
||||
assert.equal(hit().type, 'phys');
|
||||
assert.deepEqual(ended(h, u).map((c) => c.reason), ['duration']);
|
||||
const hp = u.hp;
|
||||
h.run(3);
|
||||
approx(u.hp, hp, 'no second loss while staying deployed');
|
||||
h.b.retreat(u);
|
||||
assert.ok(h.b.redeploy(u, { free: true }));
|
||||
assert.equal(u.skill.activations, 2);
|
||||
approx(u.hp, u.s.maxHp * (1 - bb.hp_ratio), 'new deployment loses current HP once');
|
||||
done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('1_19 野鬃 S1 骑枪刺击: ASPD +attack_speed for `duration` s after every deployment', () => {
|
||||
for (const id of pair('19')) {
|
||||
const s = rec(id, 'skchr_wildmn_1');
|
||||
const h = run({ defs: { chess: noGarrison(id) }, units: [entry(id, s.skillId, { row: 9, col: 5 })] });
|
||||
const u = sel(h, id, s.skillId);
|
||||
assert.equal(u.skill.kind, 'passive');
|
||||
h.step();
|
||||
h.b.start();
|
||||
assert.equal(u.skill.kind, 'duration');
|
||||
assert.equal(u.skill.active, true);
|
||||
assert.equal(u.skill.activations, 1);
|
||||
assert.equal(u.skill.charges, 0);
|
||||
assert.equal(u.skill.ready, false);
|
||||
assert.equal(started(h, u)[0].reason, 'deploy');
|
||||
approx(u.s.aspd, u.base.aspd + s.bb.attack_speed, `${id} ASPD after deployment`);
|
||||
h.run(s.duration - 0.5);
|
||||
h.run(s.duration / 2);
|
||||
approx(u.skill.timeLeft, s.duration / 2);
|
||||
assert.deepEqual(h.snapshot().units.find((t) => t[0] === u.id).slice(5, 7), [s.duration / 2, s.duration]);
|
||||
h.run(s.duration / 2 - 0.5);
|
||||
approx(u.s.aspd, u.base.aspd + s.bb.attack_speed, 'still up');
|
||||
h.run(1);
|
||||
approx(u.s.aspd, u.base.aspd, `expired after ${s.duration} s`);
|
||||
assert.equal(u.skill.active, false);
|
||||
assert.equal(u.skill.ready, false);
|
||||
assert.deepEqual(ended(h, u).map((c) => c.reason), ['duration']);
|
||||
h.b.kill(u, null);
|
||||
h.step();
|
||||
assert.ok(h.b.redeploy(u, { free: true }));
|
||||
h.step();
|
||||
approx(u.s.aspd, u.base.aspd + s.bb.attack_speed, 'again after the redeployment');
|
||||
assert.equal(u.skill.activations, 2);
|
||||
assert.equal(ended(h, u).length, 1, 'expired skill does not end again on death');
|
||||
done(h);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user