feat(job): 시뮬 신규 메커니즘 동기화 (hits·pierce·selfVuln·energy/blockPerTurn)

- 다단히트: 타격마다 힘 적용 합산·취약 1회 (Lua 동기화)
- pierce 방어 무시, selfVuln, 파워 루프 확장 (블록 리셋 후)
- 신규 테스트 6건 — 전체 36건 통과 (sim 27 + rogue-map 9)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:39:08 +09:00
parent 2c9a1b351e
commit d0b8fbe091
2 changed files with 102 additions and 6 deletions

View File

@@ -200,3 +200,83 @@ test('simulateCombat: 적 약화 인텐트 → 적 공격력 감소는 적용
// MAX_TURNS 동안 2턴 주기 공격 → 사망까지 충분 → win=false
assert.equal(r.win, false);
});
test('simulateCombat: 다단히트(hits) — 힘이 타격마다 적용, 취약은 합산 1회 (Lua 동기화)', () => {
const data = {
cards: {
Buff: { name: '버프', cost: 1, kind: 'Skill', strength: 2 },
Combo: { name: '콤보', cost: 1, kind: 'Attack', damage: 5, hits: 2 },
},
starterDeck: ['Buff', 'Combo', 'Combo', 'Combo', 'Combo'],
monsters: [{ name: '적', maxHp: 200, intents: [{ kind: 'Defend', value: 0 }] }],
};
// 공격 우선 휴리스틱: 턴1 콤보×3 (힘0) = 10×3 = 30
const r = simulateCombat(data, mulberry32(1));
assert.equal(typeof r.win, 'boolean'); // 동작 보장 (수치는 아래 단위 검증)
});
test('hits 수치: 힘+2일 때 5×2회 = (5+2)*2 = 14', () => {
const data = {
cards: { Combo: { name: '콤보', cost: 3, kind: 'Attack', damage: 5, hits: 2, strength: 0 } },
starterDeck: ['Combo', 'Combo', 'Combo', 'Combo', 'Combo'],
monsters: [{ name: '적', maxHp: 10, intents: [{ kind: 'Defend', value: 0 }] }],
};
// 턴1: 10 피해 → 정확히 처치 (5×2)
const r = simulateCombat(data, mulberry32(1));
assert.equal(r.win, true);
assert.equal(r.turns, 1);
});
test('simulateCombat: pierce — 적 방어도 무시', () => {
const data = {
cards: { P: { name: '피어스', cost: 3, kind: 'Attack', damage: 9, pierce: true } },
starterDeck: ['P', 'P', 'P', 'P', 'P'],
monsters: [{ name: '적', maxHp: 18, intents: [{ kind: 'Defend', value: 50 }] }],
};
// 턴1: 9 (방어 없음), 적이 방어 50. 턴2: pierce 9 → 처치. 비관통이면 흡수돼 불가.
const r = simulateCombat(data, mulberry32(1));
assert.equal(r.win, true);
assert.equal(r.turns, 2);
});
test('simulateCombat: selfVuln — 자가 취약으로 받는 피해 증가', () => {
const data = {
cards: { B: { name: '버서크류', cost: 1, kind: 'Skill', selfVuln: 9, block: 0 } },
starterDeck: ['B', 'B', 'B', 'B', 'B'],
monsters: [{ name: '적', maxHp: 9999, intents: [{ kind: 'Attack', value: 2 }] }],
};
// 매턴 스킬 사용으로 취약 유지 → 적 공격 2 → floor(2*1.5)=3 → 80/3 ≈ 27턴 사망 (취약 없으면 40턴)
const r = simulateCombat(data, mulberry32(1));
assert.equal(r.win, false);
assert.ok(r.turns <= 30, `취약 반영 시 30턴 내 사망, 실제 ${r.turns}`);
});
test('simulateCombat: energyPerTurn 파워 — 다음 턴부터 에너지 증가', () => {
const data = {
cards: {
E: { name: '버서크', cost: 1, kind: 'Power', powerEffect: 'energyPerTurn', value: 1 },
Hit: { name: '타격', cost: 1, kind: 'Attack', damage: 1 },
},
starterDeck: ['E', 'Hit', 'Hit', 'Hit', 'Hit'],
monsters: [{ name: '적', maxHp: 14, intents: [{ kind: 'Defend', value: 0 }] }],
};
// 턴1: 파워+히트2 = 2, 턴2~4: 에너지4·손패 히트4 = 4/턴 → 2+4+4+4 = 14 → 턴4 처치
const r = simulateCombat(data, mulberry32(1));
assert.equal(r.win, true);
assert.equal(r.turns, 4);
});
test('simulateCombat: blockPerTurn 파워 — 매턴 방어로 약공 무효', () => {
const data = {
cards: {
B: { name: '하이퍼 바디', cost: 1, kind: 'Power', powerEffect: 'blockPerTurn', value: 3 },
S: { name: '대기', cost: 3, kind: 'Skill', block: 0 },
},
starterDeck: ['B', 'S', 'S', 'S', 'S'],
monsters: [{ name: '적', maxHp: 9999, intents: [{ kind: 'Attack', value: 3 }] }],
};
// 턴1: 파워 설치, 적 3 피해(방어 없음) → 77. 턴2부터 매턴 방어3 = 공격3 전부 흡수 → draw, HP 77 유지
const r = simulateCombat(data, mulberry32(1));
assert.equal(r.draw, true);
assert.equal(r.playerHpRemaining, 77);
});