From 650b96059d0e005049573c1bf50fd403c81c39ac Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 15 Sep 2026 17:02:57 +0800 Subject: [PATCH] fix(07-01): #06-01-3 abandon the battle only when before returns false - read the before result into proceed and abandon only on falsy, matching the ICombatScript.before contract in types.ts - un-skip the correct-expectation case and correct the three existing cases that encoded the inverted semantics (explicit truthy beforeResult, complementary truthy-branch assertion, synced FakeScript comment) --- .../data-system/src/combat/combat.test.ts | 25 +++++++++++-------- .../data-system/src/combat/combat.ts | 4 +-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages-user/data-system/src/combat/combat.test.ts b/packages-user/data-system/src/combat/combat.test.ts index 5064322..26c14a3 100644 --- a/packages-user/data-system/src/combat/combat.test.ts +++ b/packages-user/data-system/src/combat/combat.test.ts @@ -111,7 +111,7 @@ class FakeScript implements ICombatScript { readonly label: string; /** 共享的调用顺序记录 */ readonly calls: string[]; - /** before 的返回值,真值表示短路 */ + /** before 的返回值,假值表示放弃战斗 */ beforeResult: boolean; /** before 需要等待的异步闸门 */ gate: Deferred | null = null; @@ -289,9 +289,9 @@ describe('CombatFlow scripts and guards', () => { it('sorts scripts by descending priority and rejects duplicates', async () => { const fixture = createFixture(); bindAll(fixture); - const low = new FakeScript(1, 'low', fixture.calls); - const high = new FakeScript(2, 'high', fixture.calls); - const duplicate = new FakeScript(1, 'duplicate', fixture.calls); + const low = new FakeScript(1, 'low', fixture.calls, true); + const high = new FakeScript(2, 'high', fixture.calls, true); + const duplicate = new FakeScript(1, 'duplicate', fixture.calls, true); fixture.flow.addCombatScript(low); fixture.flow.addCombatScript(high); @@ -427,7 +427,7 @@ describe('CombatFlow async ordering', () => { const fixture = createFixture(); bindAll(fixture); const gate = createDeferred(); - const script = new FakeScript(1, 'script', fixture.calls); + const script = new FakeScript(1, 'script', fixture.calls, true); script.gate = gate; fixture.flow.addCombatScript(script); fixture.flow @@ -456,8 +456,8 @@ describe('CombatFlow async ordering', () => { ]); }); - // 验证战前脚本返回真值时短路,不再执行钩子与战后脚本 - it('short-circuits hooks and after scripts when before returns truthy', async () => { + // 验证战前脚本返回真值时仍会执行战前钩子、战后脚本与战后钩子 + it('runs hooks and after scripts when before returns truthy', async () => { const fixture = createFixture(); bindAll(fixture); const script = new FakeScript(1, 'script', fixture.calls, true); @@ -476,11 +476,16 @@ describe('CombatFlow async ordering', () => { const info = await fixture.flow.battle(fixture.view); expect(info).toBe(fixture.info); - expect(fixture.calls).toEqual(['script.before']); + expect(fixture.calls).toEqual([ + 'script.before', + 'hooks.onBeforeCombat', + 'script.after', + 'hooks.onAfterCombat' + ]); }); - // 疑似 bug:接口约定战前脚本返回 false 应放弃战斗,详见 06-TEST-FINDINGS.md #06-01-3,修复后取消 skip - it.skip('abandons the battle when the before script returns false', async () => { + // 验证战前脚本返回 false 时会放弃战斗,不再执行钩子与战后脚本 + it('abandons the battle when the before script returns false', async () => { const fixture = createFixture(); bindAll(fixture); const script = new FakeScript(1, 'script', fixture.calls, false); diff --git a/packages-user/data-system/src/combat/combat.ts b/packages-user/data-system/src/combat/combat.ts index fa5909c..364947a 100644 --- a/packages-user/data-system/src/combat/combat.ts +++ b/packages-user/data-system/src/combat/combat.ts @@ -176,8 +176,8 @@ export class CombatFlow } for (const script of this.scriptList) { - const skip = await script.before(damage, handler); - if (skip) return damage; + const proceed = await script.before(damage, handler); + if (!proceed) return damage; } await Promise.all( this.forEachHook(hook => hook.onBeforeCombat?.(damage))