import { 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 } from '../../lib/ui-helpers.mjs'; import { 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 } from '../../lib/data.mjs'; export function buildShop() { const shop = []; const shopHud = entity({ id: guid('shp', 0), path: '/ui/DefaultGroup/ShopHud', modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', displayOrder: 8, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 1920, y: 1080 }, pos: { x: 0, y: 0 }, align: ALIGN_CENTER }), sprite({ color: { r: 0.05, g: 0.06, b: 0.09, a: 0.92 }, type: 1, raycast: true }), ], }); shopHud.jsonString.enable = false; shop.push(shopHud); shop.push(entity({ id: guid('shp', 1), path: '/ui/DefaultGroup/ShopHud/Title', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 0, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 700, y: 60 }, pos: { x: 0, y: 400 } }), sprite({ color: TRANSPARENT }), text({ value: '상점', fontSize: 44, bold: true, color: GOLD, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', 2), path: '/ui/DefaultGroup/ShopHud/Gold', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 1, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 300, y: 44 }, pos: { x: 0, y: 330 } }), sprite({ color: TRANSPARENT }), text({ value: '메소 0', fontSize: 28, bold: true, color: { r: 0.98, g: 0.85, b: 0.4, a: 1 }, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', 3), path: '/ui/DefaultGroup/ShopHud/MesoIcon', modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', displayOrder: 1, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 30, y: 30 }, pos: { x: -86, y: 330 } }), sprite({ color: { r: 1, g: 0.82, b: 0.2, a: 1 }, type: 1 }), ], })); const shopXs = [-300, 0, 300]; // 카드 단위 엔티티 v2 네임스페이스 (stride 8: Price 포함) — DeckInspectHud 주석 참조 for (let i = 1; i <= 3; i++) { const shpBase = 3 + (i - 1) * 8; const cardPath = `/ui/DefaultGroup/ShopHud/Card${i}`; shop.push(entity({ id: guid('shp2', shpBase), path: cardPath, modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent,MOD.Core.UITouchReceiveComponent', displayOrder: i, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: CARD_W, y: CARD_H }, pos: { x: shopXs[i - 1], y: 20 } }), sprite({ dataId: CARDFRAMES.frames.warrior.normal, color: WHITE, type: 0, raycast: true }), button(), { '@type': 'MOD.Core.UITouchReceiveComponent', Enable: true }, ], })); const shopLayout = cardFaceLayout(CARD_W); const shopTexts = shopLayout.texts.map(([sfx, c]) => [sfx, { ...c, value: sfx === 'Cost' ? '1' : sfx === 'Name' ? '카드' : '' }]); shopTexts.push(['Price', { size: { x: 160, y: 40 }, pos: { x: 0, y: -135 }, value: '30 메소', fontSize: 22, bold: true, color: { r: 0.98, g: 0.85, b: 0.4, a: 1 } }]); for (const [tIdx, [suffix, cfg]] of shopTexts.entries()) { const dOrder = suffix === 'Cost' ? 7 : suffix === 'Name' ? 6 : suffix === 'Desc' ? 8 : 9; shop.push(entity({ id: guid('shp2', shpBase + 1 + tIdx), path: `${cardPath}/${suffix}`, modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: dOrder, components: [ transform({ parentW: CARD_W, parentH: CARD_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: cfg.size, pos: cfg.pos }), sprite({ color: TRANSPARENT }), text({ value: cfg.value, fontSize: cfg.fontSize, bold: cfg.bold, color: cfg.color, dropShadow: cfg.dropShadow, outlineWidth: cfg.outlineWidth }), ], })); } shop.push(entity({ id: guid('shp2', shpBase + 7), path: `${cardPath}/Art`, modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent', displayOrder: 5, components: [ transform({ parentW: CARD_W, parentH: CARD_H, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: shopLayout.art.size, pos: shopLayout.art.pos }), sprite({ color: WHITE, type: 0, raycast: false }), ], })); } let shpN = 3 + 3 * 8; // 구 시퀀스의 루프 종료 시점 값(27) 보존 — Relic 등 후속 id 불변 shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Relic', modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent', displayOrder: 9, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 560, y: 76 }, pos: { x: 0, y: -190 } }), sprite({ color: { r: 0.7, g: 0.55, b: 0.85, a: 1 }, type: 1, raycast: true }), button(), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Relic/Label', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 0, components: [ transform({ parentW: 560, parentH: 76, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 540, y: 40 }, pos: { x: 0, y: 12 } }), sprite({ color: TRANSPARENT }), text({ value: '유물', fontSize: 22, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Relic/Price', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 1, components: [ transform({ parentW: 560, parentH: 76, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 540, y: 30 }, pos: { x: 0, y: -22 } }), sprite({ color: TRANSPARENT }), text({ value: '60 메소', fontSize: 20, bold: true, color: { r: 0.98, g: 0.85, b: 0.4, a: 1 }, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Potion', modelId: 'uisprite', entryId: 'UISprite', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent', displayOrder: 11, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 560, y: 76 }, pos: { x: 0, y: -278 } }), sprite({ color: { r: 0.45, g: 0.7, b: 0.55, a: 1 }, type: 1, raycast: true }), button(), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Potion/Label', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 0, components: [ transform({ parentW: 560, parentH: 76, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 540, y: 40 }, pos: { x: 0, y: 12 } }), sprite({ color: TRANSPARENT }), text({ value: '물약', fontSize: 22, bold: true, color: { r: 1, g: 1, b: 1, a: 1 }, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Potion/Price', modelId: 'uitext', entryId: 'UIText', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.TextComponent', displayOrder: 1, components: [ transform({ parentW: 560, parentH: 76, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 540, y: 30 }, pos: { x: 0, y: -22 } }), sprite({ color: TRANSPARENT }), text({ value: '20 메소', fontSize: 20, bold: true, color: { r: 0.98, g: 0.85, b: 0.4, a: 1 }, alignment: 4 }), ], })); shop.push(entity({ id: guid('shp', shpN++), path: '/ui/DefaultGroup/ShopHud/Leave', modelId: 'uibutton', entryId: 'UIButton', componentNames: 'MOD.Core.UITransformComponent,MOD.Core.SpriteGUIRendererComponent,MOD.Core.ButtonComponent,MOD.Core.TextComponent', displayOrder: 10, components: [ transform({ parentW: 1920, parentH: 1080, anchor: { x: 0.5, y: 0.5 }, pivot: { x: 0.5, y: 0.5 }, size: { x: 200, y: 60 }, pos: { x: 0, y: -380 } }), sprite({ color: DARK, type: 1, raycast: true }), button(), text({ value: '나가기', fontSize: 26, bold: true, color: GOLD, alignment: 4 }), ], })); return shop; }