import { method, RUN_LENGTH, GOLD_PER_WIN, CARD_PRICE, REST_HEAL, RELIC_PRICE, ACT_COUNT, ACT_MAPS, LOBBY_MAP, LOBBY_SPAWN } from '../lib/codeblock.mjs'; import { 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 } from '../lib/data.mjs'; 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'; export const mapMethods = [ method('ShowMap', `self:ShowState("map") self:RenderMap()`), method('GenerateMap', `-- 절차 생성 — tools/map/rogue-map.mjs(JS 미러)와 로직 동기화 유지 self.MapNodes = {} self.MapStart = {} self.VisitedNodes = {} self.Depth = 0 self.MapNodes["boss"] = { type = "boss", row = ${MAP_ROWS} + 1, col = 0, next = {} } local cols = { 1, 2, 3, 4 } for i = #cols, 2, -1 do local j = math.random(1, i) cols[i], cols[j] = cols[j], cols[i] end local starts = { cols[1], cols[2], math.random(1, ${MAP_COLS}), math.random(1, ${MAP_COLS}) } for p = 1, 4 do local c = starts[p] local sid = "r1c" .. tostring(c) if self.MapNodes[sid] == nil then self.MapNodes[sid] = { type = "combat", row = 1, col = c, next = {} } end local found = false for i = 1, #self.MapStart do if self.MapStart[i] == sid then found = true end end if found == false then table.insert(self.MapStart, sid) end for r = 1, ${MAP_ROWS} - 1 do local nc = c + math.random(-1, 1) if nc < 1 then nc = 1 end if nc > ${MAP_COLS} then nc = ${MAP_COLS} end local nid = "r" .. tostring(r + 1) .. "c" .. tostring(nc) if self.MapNodes[nid] == nil then self.MapNodes[nid] = { type = "combat", row = r + 1, col = nc, next = {} } end local fid = "r" .. tostring(r) .. "c" .. tostring(c) local dup = false for i = 1, #self.MapNodes[fid].next do if self.MapNodes[fid].next[i] == nid then dup = true end end if dup == false then table.insert(self.MapNodes[fid].next, nid) end c = nc end local lid = "r" .. tostring(${MAP_ROWS}) .. "c" .. tostring(c) local bdup = false for i = 1, #self.MapNodes[lid].next do if self.MapNodes[lid].next[i] == "boss" then bdup = true end end if bdup == false then table.insert(self.MapNodes[lid].next, "boss") end end for r = 3, ${MAP_ROWS} do for c = 1, ${MAP_COLS} do local id = "r" .. tostring(r) .. "c" .. tostring(c) local node = self.MapNodes[id] if node ~= nil then -- 부모 노드 타입 수집 (rest/shop/elite 는 부모와 같은 타입 연속 금지) local parentTypes = {} for pid, pn in pairs(self.MapNodes) do if pn.row == r - 1 then for i = 1, #pn.next do if pn.next[i] == id then parentTypes[pn.type] = true end end end end local w if r == ${MAP_ROWS} then w = { { "rest", 50 }, { "combat", 25 }, { "shop", 10 }, { "elite", 8 }, { "treasure", 7 } } elseif r >= 4 then w = { { "combat", 45 }, { "elite", 16 }, { "shop", 12 }, { "rest", 12 }, { "treasure", 15 } } else w = { { "combat", 45 }, { "shop", 12 }, { "rest", 12 } } end local total = 0 for i = 1, #w do local t = w[i][1] if (t == "elite" or t == "rest" or t == "shop") and parentTypes[t] == true then w[i][2] = 0 end total = total + w[i][2] end local roll = math.random() * total local acc = 0 for i = 1, #w do acc = acc + w[i][2] if roll <= acc then node.type = w[i][1] break end end end end end`), method('IsReachable', `local list if self.CurrentNodeId == "" then list = self.MapStart else local node = self.MapNodes[self.CurrentNodeId] if node == nil then return false end list = node.next end for i = 1, #list do if list[i] == id then return true end end return false`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }], 0, 'boolean'), method('RenderMapNode', `local base = "/ui/DefaultGroup/MapHud/Node_" .. id local e = _EntityService:GetEntityByPath(base) if e == nil then return end local node = self.MapNodes[id] if node == nil then e.Enable = false return end e.Enable = true local ruid = self.NodeIcons[node.type] if ruid == nil then ruid = self.NodeIcons["combat"] end if e.SpriteGUIRendererComponent ~= nil and ruid ~= nil then e.SpriteGUIRendererComponent.ImageRUID = ruid end local reachable = self:IsReachable(id) local visited = false if self.VisitedNodes ~= nil then for i = 1, #self.VisitedNodes do if self.VisitedNodes[i] == id then visited = true end end end if e.SpriteGUIRendererComponent ~= nil then if id == self.CurrentNodeId then e.SpriteGUIRendererComponent.Color = Color(1, 0.82, 0.3, 1) elseif visited == true then e.SpriteGUIRendererComponent.Color = Color(0.5, 0.5, 0.55, 0.9) elseif reachable == true then e.SpriteGUIRendererComponent.Color = Color(1, 1, 1, 1) else e.SpriteGUIRendererComponent.Color = Color(0.68, 0.68, 0.72, 0.85) end end if e.ButtonComponent ~= nil then e.ButtonComponent.Enable = reachable end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }]), method('RenderMapDots', `local node = self.MapNodes[fromId] local has = false if node ~= nil then for i = 1, #node.next do if node.next[i] == toId then has = true end end end for k = 1, 3 do local d = _EntityService:GetEntityByPath("/ui/DefaultGroup/MapHud/Dot_" .. dotId .. "_" .. tostring(k)) if d ~= nil then d.Enable = has if has == true and d.SpriteGUIRendererComponent ~= nil then if fromId == self.CurrentNodeId then d.SpriteGUIRendererComponent.Color = Color(0.95, 0.8, 0.3, 1) else d.SpriteGUIRendererComponent.Color = Color(0.5, 0.5, 0.55, 0.8) end end end end`, [ { Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'dotId' }, { Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'fromId' }, { Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'toId' }, ]), method('RenderMap', `for r = 1, ${MAP_ROWS} do for c = 1, ${MAP_COLS} do self:RenderMapNode("r" .. tostring(r) .. "c" .. tostring(c)) end end self:RenderMapNode("boss") for r = 1, ${MAP_ROWS} - 1 do for c = 1, ${MAP_COLS} do local fid = "r" .. tostring(r) .. "c" .. tostring(c) for c2 = c - 1, c + 1 do if c2 >= 1 and c2 <= ${MAP_COLS} then self:RenderMapDots(fid .. "_" .. tostring(c2), fid, "r" .. tostring(r + 1) .. "c" .. tostring(c2)) end end end end for c = 1, ${MAP_COLS} do local fid = "r" .. tostring(${MAP_ROWS}) .. "c" .. tostring(c) self:RenderMapDots(fid .. "_b", fid, "boss") end `), method('PickNode', `if self.RunActive ~= true then return end if self:IsReachable(id) ~= true then return end self.CurrentNodeId = id if self.VisitedNodes == nil then self.VisitedNodes = {} end table.insert(self.VisitedNodes, id) local hud = _EntityService:GetEntityByPath("/ui/DefaultGroup/MapHud") if hud ~= nil then hud.Enable = false end local node = self.MapNodes[id] self.Depth = node.row self:RenderRun() if node.type == "shop" then self:ShowShop() elseif node.type == "rest" then self:ShowRest() elseif node.type == "treasure" then self:ShowTreasure() else self.CurrentEnemyId = "" self:StartCombat() end`, [{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'id' }]), ];