# 시스템 갭 보완 (P5) 구현 계획 > **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. T3·T5는 컨트롤러 직접. **Goal:** 경제 밸런스(첫 상점 구매 가능), 신규 카드 2종+복합 효과, 적 패턴 보강, 런 종료 후 메뉴 복귀. --- ## Task 1: 데이터+상수 (경제·적 패턴·신규 카드 골격) **Files:** `data/enemies.json`, `data/cards.json`, `tools/deck/gen-slaydeck.mjs`(상수·elite 골드) - [ ] enemies.json 의도 패턴 교체(스펙 §2.C 표 그대로; slime 3종·king_slime 유지). - [ ] cards.json에 추가(이미지는 T3에서 채움 — 일단 필드 생략): ```json "WarLeap": { "name": "워 리프", "cost": 1, "kind": "Attack", "damage": 4, "block": 3, "desc": "피해 4, 방어도 3" }, "Brandish": { "name": "브랜디시", "cost": 2, "kind": "Attack", "damage": 13, "desc": "피해 13" } ``` - [ ] gen-slaydeck: `GOLD_PER_WIN = 15` → `25`; CheckCombatEnd elite 분기(AddRelic 줄 옆)에 `self.Gold = self.Gold + 15` 추가. - [ ] 검증: JSON 파스, gen-slaydeck 실행 OK(산출물 복원), sim 통과(기존 fixture 무관). - [ ] Commit: `feat(system-gaps): 경제 상향(승리25·엘리트+15)·적 패턴 보강·신규 카드 2종 데이터` ## Task 2: 복합 카드 로직 + EndRun 복귀 + sim **Files:** `tools/deck/gen-slaydeck.mjs`, `tools/balance/sim-balance.mjs`, `tools/balance/sim-balance.test.mjs` - [ ] **sim 테스트 먼저** (test 파일에 추가): ```js test('simulateCombat: Attack 카드의 block 필드도 적용(복합 카드)', () => { const data = { cards: { Combo: { name: '콤보', cost: 1, kind: 'Attack', damage: 4, block: 3 } }, starterDeck: ['Combo', 'Combo', 'Combo', 'Combo', 'Combo'], monsters: [{ name: '적', maxHp: 9, intents: [{ kind: 'Attack', value: 5 }] }], }; const r = simulateCombat(data, mulberry32(1)); assert.equal(r.win, true); // 3코스트 내 3장: 12딤>9 → 1턴 승리(블록 적용 여부와 무관하게 승리하지만) assert.equal(r.playerHpRemaining, 80); // 피해 받기 전 승리 — 블록 검증은 아래 시나리오로 }); test('simulateCombat: 복합 카드 블록이 적 공격을 흡수', () => { const data = { cards: { Combo: { name: '콤보', cost: 1, kind: 'Attack', damage: 1, block: 3 } }, starterDeck: ['Combo', 'Combo', 'Combo', 'Combo', 'Combo'], monsters: [{ name: '적', maxHp: 100, intents: [{ kind: 'Attack', value: 9 }] }], }; const r = simulateCombat(data, mulberry32(1)); // 1턴: 3장 사용 → 블록 9 → 적 공격 9 전부 흡수 → 2턴 시작 HP 80 유지 확인 위해 2턴 후 비교 불가(루프) — 간접: MAX_TURNS 도달 draw, hp가 (80 - 0*몇턴)... // 단순 명제: 블록 미적용이면 매턴 -9 → 100/9≈11턴 내 사망. 블록 적용이면 매턴 9블록=무피해 → draw. assert.equal(r.draw, true); assert.equal(r.playerHpRemaining, 80); }); ``` - [ ] sim 구현: simulateCombat Attack 분기에 `if (c.block) pBlock += c.block;` 추가(스탯 bump의 block 합산도 `c.block || 0`로). 테스트 통과. - [ ] gen-slaydeck PlayCard Attack 분기에 추가(PlayAttackFx 호출 다음 줄): ``` if c.block ~= nil then self.PlayerBlock = self.PlayerBlock + c.block end ``` - [ ] gen-slaydeck EndRun: 신규 메서드 + CheckCombatEnd 두 지점 교체: ```js method('EndRun', `self:ShowResult(text) self.RunActive = false _TimerService:SetTimerOnce(function() self:ShowMainMenu() end, 4)`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'text' }]), ``` 교체: `self:ShowResult("런 클리어!")` + `self.RunActive = false` → `self:EndRun("런 클리어!")`; `self:ShowResult("패배...")` + `self.RunActive = false` → `self:EndRun("패배...")`. - [ ] 검증: sim 전체 통과(16개), gen 실행·심볼 확인 후 산출물 복원. - [ ] Commit: `feat(system-gaps): 복합 카드(피해+방어)·런 종료 후 메뉴 복귀(EndRun)` ## Task 3 (컨트롤러 직접): 신규 카드 이미지 수확 - "워 리프"/"브랜디시" 검색→메이커 선별→cards.json image 채움→커밋. ## Task 4: 재생성·검증·산출물 커밋 (T3 이후) - 표준 절차 + `node tools/balance/sim-balance.mjs 2000` 결과 기록(참고). ## Task 5 (컨트롤러 직접): 메이커 검증+푸시+PR+머지 - 보상/상점 신규 카드(이미지)·복합 카드 효과·엘리트 골드·패배→4s 메뉴 복귀. 스크린샷. ## Self-Review - §2.A→T1, §2.B→T1(데이터)+T2(로직)+T3(이미지), §2.C→T1, §2.D→T2. 시그니처 일관(EndRun(text)). 복합 카드 sim 테스트는 블록 적용을 draw/hp로 결정적으로 판별.