Merge origin/main into feature/gen-modularization (생성기 모듈화)

main의 5개 PR(#62 exhaust+tooltip, #66 dex/thorns, #67 캐릭터 덱버튼 제거,
#68 스크롤바, #69 표창카드)을 모듈화 브랜치에 병합.

충돌은 tools/deck/gen-slaydeck.mjs 한 파일 — main이 그 단일체를 콘텐츠 변경
(구조/emit/top-level 상수는 불변)한 반면 본 브랜치는 모듈로 재구조화.
해결: main 버전(theirs)을 취해 **콘텐츠 마커 기반으로 재모듈화**(라인인덱스 X,
이름 자동 파생) → lib/data·lib/ui-helpers + hud/*.mjs 16종 재생성.

검증(손실 0): 재모듈화 생성기 출력이 origin/main 산출물과 **바이트 동일**
(diffcheck: ui/DefaultGroup.ui·SlayDeckController.codeblock IDENTICAL).
common.gamelogic은 origin/main 그대로 채택(유일 차이는 main의 stale `.0` 정수표기
— origin/main 원본 생성기도 정수를 만듦을 확인). 미러 테스트 sim-balance·rogue-map 통과.
RULES.md는 §1(모듈구조)+§4/§7(main) 자동 병합.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-16 07:38:54 +09:00
26 changed files with 1009 additions and 882 deletions

View File

@@ -156,6 +156,8 @@ function luaCardsTable(cards) {
if (c.damage != null) fields.push(`damage = ${c.damage}`);
if (c.block != null) fields.push(`block = ${c.block}`);
if (c.strength != null) fields.push(`strength = ${c.strength}`);
if (c.dex != null) fields.push(`dex = ${c.dex}`);
if (c.thorns != null) fields.push(`thorns = ${c.thorns}`);
if (c.weak != null) fields.push(`weak = ${c.weak}`);
if (c.vuln != null) fields.push(`vuln = ${c.vuln}`);
if (c.powerEffect != null) fields.push(`powerEffect = ${luaStr(c.powerEffect)}`);
@@ -171,11 +173,16 @@ function luaCardsTable(cards) {
if (c.poison != null) fields.push(`poison = ${c.poison}`);
if (c.discard != null) fields.push(`discard = ${c.discard}`);
if (c.discardAll === true) fields.push('discardAll = true');
if (c.addShiv != null) fields.push(`addShiv = ${c.addShiv}`);
if (c.turnStartShiv != null) fields.push(`turnStartShiv = ${c.turnStartShiv}`);
if (c.addShivPerDiscard === true) fields.push('addShivPerDiscard = true');
if (c.sly === true) fields.push('sly = true');
if (c.retain === true) fields.push('retain = true');
if (c.exhaust === true || String(c.desc || '').includes('소멸.')) fields.push('exhaust = true');
if (c.aoe === true) fields.push('aoe = true');
if (c.unplayable === true) fields.push('unplayable = true');
if (c.curse === true) fields.push('curse = true');
if (c.token === true) fields.push('token = true');
if (c.endTurnDamage != null) fields.push(`endTurnDamage = ${c.endTurnDamage}`);
if (c.fx != null) fields.push(`fx = ${luaStr(c.fx)}`);
if (c.image != null) fields.push(`image = ${luaStr(c.image)}`);
@@ -187,4 +194,4 @@ function luaDeckTable(deck) {
return `self.DrawPile = { ${deck.map(luaStr).join(', ')} }`;
}
export { CARDS, ENEMIES, CLASSES, JOBS, SOUL_UNLOCKS, CARDFRAMES, RARITIES, MAP_ROWS, MAP_COLS, CHEST_CLOSED_RUID, CHEST_OPEN_RUID, NODEICONS, CHARS, CAM, RELICS, POTIONS, luaSoulShopTable, frameRuid, luaFramesTable, luaNodeIconsTable, luaRelicsTable, luaPotionsTable, luaIntentsArray, luaEnemiesTable, luaStr, luaJobsTable, luaCardsTable, luaDeckTable };
export { CARDS, ENEMIES, CLASSES, JOBS, SOUL_UNLOCKS, luaSoulShopTable, CARDFRAMES, RARITIES, frameRuid, luaFramesTable, luaNodeIconsTable, MAP_ROWS, MAP_COLS, CHEST_CLOSED_RUID, CHEST_OPEN_RUID, NODEICONS, CHARS, CAM, RELICS, luaRelicsTable, POTIONS, luaPotionsTable, luaIntentsArray, luaEnemiesTable, luaStr, luaJobsTable, luaCardsTable, luaDeckTable };

View File

@@ -233,7 +233,7 @@ function scrollLayoutGroup({ cellSize, spacing, columns }) {
ScrollBarHandleColor: { r: 0.94, g: 0.74, b: 0.26, a: 0.9 },
ScrollBarHandleImageRUID: { DataId: '' },
ScrollBarThickness: 12,
ScrollBarVisible: 1,
ScrollBarVisible: 2,
SortingLayer: 'UI',
Spacing: 0,
StartAxis: 0,
@@ -337,5 +337,4 @@ function appendUiSection(ui, section, entities) {
ui.ContentProto.Entities.push(...entities);
}
export { UI_FILE, COMMON_FILE, UI_ROOT, GENERATED_UI_SECTIONS, UI_APPEND_ORDER, DISABLED_STOCK_CONTROLS, TRANSPARENT, DARK, GOLD, ATTACK, DEFEND, SKILL, DAMAGE_DIGIT_RUIDS, DAMAGE_POP_MAX_DIGITS, DAMAGE_POP_DIGIT_W, DAMAGE_POP_DIGIT_H, DAMAGE_POP_DIGIT_SPACING, MAX_MONSTERS, HEAD_OFFSET_Y, HP_BAR_W, WHITE, CARD_NAME_TEXT, CARD_DESC_TEXT, cardFaceLayout, CARD_W, CARD_H, CARD_SPACING, CARD_XS, ALIGN_CENTER, ALIGN_BOTTOM_CENTER, guid, transform, sprite, button, text, scrollLayoutGroup, popupLayerFor, uiOrderFor, displayOrderFor, applySortingOverride, entity, uiPath, sectionRoot, isGeneratedUiEntity, appendUiSection };