Files
maplecontest/docs/superpowers/plans/2026-06-11-system-gaps.md

4.6 KiB

시스템 갭 보완 (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에서 채움 — 일단 필드 생략):
    "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 = 1525; 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 파일에 추가):
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 두 지점 교체:
    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 = falseself:EndRun("런 클리어!"); self:ShowResult("패배...") + self.RunActive = falseself: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로 결정적으로 판별.