StartRun이 run마다 BindButtons를 호출하는데 앞 7개 핸들러만
disconnect 가드돼 있고 reward/skip/map/shop/monster/relic/potion/job
등 ~30개 ConnectEvent는 미가드라, 2회차+ 런에서 핸들러가 누적된다.
특히 PickReward는 RewardChoices·CombatOver를 클리어하지 않아 중복
핸들러로 두 번 불리면 같은 보상 카드가 RunDeck에 2번 추가된다.
BindLobbyButtons/BindSoulShopButtons와 동일하게 self.ButtonsBound
1회 가드를 추가(런 UI 엔티티는 영속이라 1회 바인드로 충분).
신규 prop ButtonsBound 선언. 산출물 재생성 포함.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UUvHKjrt8jqLzDeCsRRGmj
`DiscardPostDraw`·`DiscardDrawPerPick`가 hand.mjs(BeginDiscardSelection·
AutoDiscardHand·FinishDiscardSelection·SelectDiscardSlot)에서 대입되는데
gen-slaydeck.mjs prop 목록에 선언되지 않아 런타임 "cannot set DiscardPostDraw,
no such field"로 BeginDiscardSelection이 중단됨. 그 직전 DiscardSelectRemaining/
Total이 이미 set되어 게임이 버리기-선택 모드에 갇혀, 이후 모든 카드(공중제비 포함)
클릭이 버리기 픽으로 처리됨("2장 버린다 표시 + 동작 없음").
근본 원인: 형제 prop DiscardPostShiv·DiscardShivPerPick는 선언됐으나
draw 변형 2개가 누락. 선언만 추가(병렬 패턴).
신규 가드 tools/verify/cbprops.mjs: cb의 `self.X =` 대입 ↔ 선언 prop 대조,
미선언 = no such field 후보 검출. 수정 전 2개 누락→후 0.
검증: cbprops 0·cbgap GAP 0·테스트 93/93. 산출물(codeblock) 재생성 포함.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
구현 기능 표에 "도적 카드 공용 효과" 행 추가 — 카드명 하드코딩 대신
data/cards.json 공용 필드로 효과 표현(불가침·x-cost·드로우 비례·다음 스킬
반복·처치 보상·키워드 하이라이트·독 버스트 등), Lua+JS 미러 양쪽 구현,
필드 사전 docs/card-effect-fields.md. 밸런스 시뮬 단위테스트 현 84종 명시.
(codex PRs #82~#89로 main 반영된 내용 README 동기화)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
지금까지 main 머지분(#76~#79)을 README에 반영하고 stale 수치/문구 정리:
- 적 12종 → 18종, 카드 122장 → 121장(도적 86), Silent 88 → 86
- 구현 PR 범위 #34~#57 → #34~#79
- 게임 시작 시 MainMenu 없이 로비 직행(MainMenu 추후 재지정) 명시
- 캐릭터 선택: 초상화·직업 설명·선택 테두리 강조 UI 반영
- 향후 계획: 로비 직행·캐릭터 선택 UI·디버그 치트·map01 로스터 [x],
도적 카드 아이콘 완료 반영(TODO는 카드명 재서사·한글화로 정정)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OnBeginPlay에서 UI 로드 후 self:ShowMainMenu() 대신 self:ShowLobby() 호출.
게임 시작하면 MainMenu를 거치지 않고 곧장 로비 맵(LobbyUIGroup)으로 진입한다.
ShowState("lobby")가 MainMenu를 숨기므로 메뉴는 표시되지 않음.
MainMenu는 한동안 비활성이지만 ShowMainMenu 메서드·BindMenuButtons·
DefaultGroup/MainMenu UI는 그대로 유지 — 추후 싱글/멀티/게임 종료 선택
메뉴가 필요할 때 OnBeginPlay를 self:ShowMainMenu()로 되돌리면 복구된다.
산출물 재생성: SlayDeckController.codeblock. 검증: cbgap GAP 0, JS 41/41.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
메이커 저작(964cf7c)에서 map01에 수작업 배치한 몬스터
octopus·kapa_drake·junior_neki·junior_bugi(combat) / dile·mano(elite)의
EnemyId가 enemies.json에 미등록 상태였다. 전투 시 BuildMonsters가
self.Enemies[id]=nil → fallback {maxHp=10, intents={{Attack,5}}}(단일 intent)
으로 떨어져, EnemyActStep의 math.random(1,#intents)가 random(1,1)이 되어
항상 "공격 5"만 반복 → 행동 랜덤화 불가·이름 raw id·HP 10 고정.
수정: 6종을 기존 티어 밸런스(combat HP15~24/elite HP65~80, 다중 intent)에
맞춰 enemies.json에 등록하고 SlayDeckController.codeblock 재생성(산출물).
맵은 이미 해당 id를 참조하므로 맵 재생성 불필요(수작업 배치 유지).
검증: 전 맵 EnemyId 매핑 OK 33/MISSING 0, JS 미러 테스트 41/41.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>