Files
maplecontest/docs/superpowers/specs/2026-06-09-run-loop-core-design.md
2026-06-09 02:27:38 +09:00

69 lines
4.1 KiB
Markdown

# 런 루프 코어 (TODO E1+E2) — 설계
> 작성: 2026-06-09 / 상태: 승인됨 / 근거: TODO.md 항목 E(분해) + SlayDeckController 분석.
> E(로그라이크 메타)의 첫 하위 프로젝트. 선행: B·D 완료. 후속: E3(맵)·E4(상점)·E5(유물)·E6(보스/저장).
## 문제
단일 전투(B)는 닫혔으나 승리 후 보상·다음 전투·덱 성장이 없다(보상 훅 자리만 비어 있음).
전투를 한 "런"으로 확장해야 덱빌딩 로그라이크가 된다.
## 범위 (이 슬라이스)
전투를 **연속 N전투 런**으로 확장: 런 상태 영속(HP/골드/덱) + 승리 후 카드 1택 보상 +
다음 전투 연결 + 고정 N전투 후 "런 클리어". **맵 노드·상점·유물·보스·저장은 범위 밖**(후속 E3~E6).
아키텍처: 기존 `SlayDeckController` 확장(별도 RunState 분리는 후속).
## 설계
### 런 파라미터 (생성기 상수 — 향후 외부화)
- `RUN_LENGTH = 3` (런당 전투 수), `GOLD_PER_WIN = 15`.
### 새 상태 (SlayDeckController 속성)
- `RunDeck`(any) — 보유 카드 id 누적 배열(영속).
- `Gold`(number) — 누적 골드.
- `Floor`(number) — 현재 전투 번호(1-base).
- `RunLength`(number) — 런당 전투 수.
- `RewardChoices`(any) — 현재 제시 중인 보상 카드 id 3개.
- `RunActive`(boolean) — 런 진행 중.
- 플레이어 HP는 전투 간 **유지**(StartCombat에서 리셋 안 함).
### 메서드
- `OnBeginPlay``self:StartRun()`.
- **`StartRun`**(신규): `PlayerMaxHp=80`, `PlayerHp=PlayerMaxHp`, `Gold=0`, `Floor=0`,
`RunLength=RUN_LENGTH`, `RunDeck = starterDeck 복사`, `RunActive=true``BindButtons()`(1회) → `StartCombat()`.
- **`StartCombat`**(수정): `Floor += 1`; 적 데이터(activeEnemy) 세팅; 전투별 리셋(Energy/Turn/Block/
EnemyHp/EnemyBlock/EnemyIntentIndex/DiscardPile/Hand/CombatOver); `DrawPile = RunDeck 복사` → Shuffle;
`Cards` 테이블 세팅. **HP·Gold·RunDeck 보존, BindButtons 호출 제거.** → RenderCombat → StartPlayerTurn.
- **`BindButtons`**(수정): EndTurn·카드5·**보상카드3·건너뛰기** 버튼을 1회 바인딩(StartRun에서 호출).
- **`CheckCombatEnd`**(수정):
- 적 HP≤0(승리): `Gold += GOLD_PER_WIN`; `CombatOver=true`;
`Floor >= RunLength`이면 `ShowResult("런 클리어!")` + `RunActive=false`;
아니면 `self:OfferReward()`.
- 플레이어 HP≤0(패배): `CombatOver=true`; `ShowResult("패배...")`; `RunActive=false`.
- **`OfferReward`**(신규): `RewardChoices = 카드풀에서 3개 무작위`(math.random); 각 보상 카드 UI 갱신
(이름/코스트/설명/색); RewardHud 표시(Enable).
- **`PickReward(slot)`**(신규): `slot`(1~3)이면 `RewardChoices[slot]``RunDeck`에 추가; `slot=0`(건너뛰기)이면 추가 안 함;
RewardHud 숨김 → `StartCombat()`(다음 층).
- **`RenderRun`**(신규): `층 Floor/RunLength`·`골드 Gold` 텍스트 갱신. RenderCombat에서 호출.
### UI (생성기 신규)
- `RewardHud`(평소 숨김): 제목 "보상 카드 선택" + 보상 카드 3장(UISprite+버튼, 이름/코스트/설명 자식) + "건너뛰기" 버튼.
- HUD 표시 추가: `/ui/DefaultGroup/CombatHud/Floor`("층 1/3"), `/Gold`("골드 0").
- 보상 카드 클릭 → `PickReward(slot)`, 건너뛰기 → `PickReward(0)`.
### 버그 예방
- `BindButtons`가 매 전투(StartCombat)마다 카드 버튼에 `ConnectEvent` → 런에서 핸들러 중첩.
**StartRun에서 1회만 바인딩**으로 이동(StartCombat의 BindButtons 호출 제거).
## 검증 (메이커 Play)
- 전투 승리 → RewardHud에 카드 3장 표시; 골드 +15·층 표시.
- 보상 1택 → RunDeck +1(다음 전투 손패/덱에 등장 가능), RewardHud 숨김, 다음 전투 시작(HP 유지).
- 건너뛰기 → 덱 변화 없이 다음 전투.
- 3전투째 승리 → "런 클리어!"·런 종료. 도중 패배 → "패배..."·런 종료.
- 카드/보상 버튼 클릭은 런타임(MCP는 `PlayCard`/`EndPlayerTurn`/`PickReward` 직접 호출로 검증).
- 생성기 결정적, JSON 유효.
## 범위 밖 (금지)
- 맵 노드(E3)·상점/휴식(E4)·유물(E5)·보스/층전환/저장(E6). 골드 소비(E4). 보상 풀 확장(메이플 IP 추후).