diff --git a/tools/balance/sim-balance.mjs b/tools/balance/sim-balance.mjs index c783ac6..789f074 100644 --- a/tools/balance/sim-balance.mjs +++ b/tools/balance/sim-balance.mjs @@ -423,6 +423,9 @@ export function simulateCombat(data, rng, stats) { const hitN = (c.hits || 1) + bonusHits; let useAoe = c.aoe === true; if (c.class === 'shiv' && shivAoeThisCombat === true) useAoe = true; + if (c.class === 'shiv' && !shivFirstDamageBonusUsed && powerFieldTotal('firstShivDamageBonus') > 0) { + shivFirstDamageBonusUsed = true; + } const perHit = calcAttack(baseDamage || 0, pStr, pWeak, 0) * turnAttackMultiplier; const dealToTarget = (target, amount) => { if (!target || !target.alive) return { killed: false, dealt: 0 }; @@ -516,9 +519,6 @@ export function simulateCombat(data, rng, stats) { } } } - if (c.class === 'shiv' && !shivFirstDamageBonusUsed && powerFieldTotal('firstShivDamageBonus') > 0) { - shivFirstDamageBonusUsed = true; - } } } if (c.strength) pStr += c.strength; diff --git a/tools/balance/sim-balance.test.mjs b/tools/balance/sim-balance.test.mjs index fe44e5e..3583a11 100644 --- a/tools/balance/sim-balance.test.mjs +++ b/tools/balance/sim-balance.test.mjs @@ -902,6 +902,22 @@ test("calcEnemyAttack: 힘 손실이 base 아래로 공격을 낮춘다 (음수 assert.equal(calcEnemyAttack(5, 0, 0, 0, 6), 0); // 5-6=-1 → 0 클램프 }); +test('simulateCombat: firstShivDamageBonus는 턴당 첫 Shiv에만 적용 (Lua 동기화)', () => { + // PhantomBlades(firstShivDamageBonus 9) 활성. 턴당 3 Shiv 사용(에너지3·cost1). + // 정답(첫 Shiv만 +9): 턴1 = 10+1+1=12 → 13HP에 1 남김 → 2턴. + // 버그(모든 Shiv +9): 턴1 = 10*3=30 → 1턴. + const data = { + cards: { + PhantomBlades: { name: '환영검', cost: 0, kind: 'Power', firstShivDamageBonus: 9 }, + Shiv: { name: '시브', cost: 1, kind: 'Attack', class: 'shiv', damage: 1 }, + }, + starterDeck: ['PhantomBlades', 'Shiv', 'Shiv', 'Shiv', 'Shiv'], + monsters: [{ name: '적', maxHp: 13, intents: [{ kind: 'Attack', value: 0 }] }], + }; + const r = simulateCombat(data, mulberry32(1)); + assert.equal(r.turns, 2); +}); + test("simulateCombat: repeatOnKill repeats an attack until no kill occurs", () => { const shared = { cards: {