모듈:LoL

게임세상운영 (토론 | 기여)님의 2026년 6월 3일 (수) 19:03 판 (Importing missing module)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

이 모듈에 대한 설명문서는 모듈:LoL/설명문서에서 만들 수 있습니다

local p = {}

-- Faction/Region mapping from Korean to English
local factionMap = {
    ["녹서스"] = "Noxus",
    ["데마시아"] = "Demacia",
    ["아이오니아"] = "Ionia",
    ["이오니아"] = "Ionia",
    ["킨코우 결사단"] = "Kinkou_Order",
    ["킨코우"] = "Kinkou_Order",
    ["킨쿠 결사단"] = "Ionia",
    ["킨쿠"] = "Ionia",
    ["빌지워터"] = "Bilgewater",
    ["그림자 군도"] = "Shadow_Isles",
    ["슈리마"] = "Shurima",
    ["타곤"] = "Mount_Targon",
    ["타곤 산"] = "Mount_Targon",
    ["타곤산"] = "Mount_Targon",
    ["라코어"] = "Mount_Targon",
    ["공허"] = "Void",
    ["자운"] = "Zaun",
    ["필트오버"] = "Piltover",
    ["밴들 시티"] = "Bandle_City",
    ["밴들시티"] = "Bandle_City",
    ["축복의 빛 군도"] = "Blessed_Isles",
    ["카마보르"] = "Camavor",
    ["이쉬탈"] = "Ixtal",
    ["룬테라"] = "Runeterra",
    ["빛의 감시자"] = "Sentinels_of_Light",
    ["크라운가드 가문"] = "Crownguard_House",
    ["크라운가드"] = "Crownguard_House",
    ["빛방패 가문"] = "Lightshield_House",
    ["빛의 방패"] = "Lightshield_House",
    ["빛의 방패 가문"] = "Lightshield_House",
    ["페로스 가문"] = "Ferros_Clan",
    ["키라만 가문"] = "Kiramman_House",
    ["프렐요드"] = "Freljord",
    ["겨울 발톱"] = "Freljord",
    ["아바로사"] = "Freljord",
}

-- Skill/Ability mapping from Korean to English
local skillMap = {
    ["만트라"] = "Mantra",
    ["무형의 검"] = "Formless_Blade",
    ["액체 칼날"] = "Formless_Blade",
    ["환희의 장막"] = "Jubilant_Veil",
    ["급류"] = "Slipstream",
    ["요동치는 인도"] = "Apotheosis",
    ["운명의 장난"] = "New_Destiny",
}

-- Champion mapping from Korean to English (parsed from wiki templates)
local champMap = {
        ['Card infobox'] = '{{{1}}}',
    ['MOONGTANGYEE'] = '뭉탱이',
    ['가렌'] = 'Garen',
    ['갈리오'] = 'Galio',
    ['갱플랭크'] = 'Gangplank',
    ['그라가스'] = 'Gragas',
    ['그레이브즈'] = 'Graves',
    ['길에서 보지 쳐팔고 다니는 하코 저주짤'] = '좆코뒤짐 와',
    ['나르'] = 'Gnar',
    ['나미'] = 'Nami',
    ['나서스'] = 'Nasus',
    ['노틸러스'] = 'Nautilus',
    ['녹턴'] = 'Nocturne',
    ['누누'] = 'Nunu',
    ['뉴튼 룩'] = 'portrait_Newton1',
    ['니달리'] = 'Nidalee',
    ['닉 밴드'] = 'portrait_Nick1',
    ['다리우스'] = 'Darius',
    ['다이애나'] = 'Diana',
    ['드레이븐'] = 'Draven',
    ['라이즈'] = 'Ryze',
    ['랄스턴 판슬리'] = 'portrait_Ralston1',
    ['랄스톤 판슬리'] = 'portrait_Ralston1',
    ['람머스'] = 'Rammus',
    ['램 스티드'] = 'portrait_Ram1',
    ['럭스'] = 'Lux',
    ['럼블'] = 'Rumble',
    ['레넥톤'] = 'Renekton',
    ['레오나'] = 'Leona',
    ['레이라 카슐드'] = 'portrait_Reira1',
    ['레이라 캐슐드'] = 'portrait_Reira1',
    ['레이라 케슐드'] = 'portrait_Reira1',
    ['렉사이'] = 'RekSai',
    ['렝가'] = 'Rengar',
    ['루시안'] = 'Lucian',
    ['룰루'] = 'Lulu',
    ['르블랑'] = 'Leblanc',
    ['리 신'] = 'LeeSin',
    ['리븐'] = 'Riven',
    ['리산드라'] = 'Lissandra',
    ['리쳐 에보니'] = 'portrait_Richor1',
    ['마스터 이'] = 'MasterYi',
    ['마오카이'] = 'Maokai',
    ['말자하'] = 'Malzahar',
    ['말파이트'] = 'Malphite',
    ['모건 래켐'] = 'portrait_CptMorgan1',
    ['모데카이저'] = 'Mordekaiser',
    ['모르가나'] = 'Morgana',
    ['문도 박사'] = 'DrMundo',
    ['미스 포츈'] = 'MissFortune',
    ['바드'] = 'Bard',
    ['바루스'] = 'Varus',
    ['바이'] = 'Vi',
    ['밥 나샤하고'] = 'portrait_Bob1',
    ['베이가'] = 'Veigar',
    ['베인'] = 'Vayne',
    ['벨코즈'] = 'Velkoz',
    ['볼리베어'] = 'Volibear',
    ['브라움'] = 'Braum',
    ['브랜드'] = 'Brand',
    ['브리스크스'] = 'portrait_LB1',
    ['브리스키스'] = 'portrait_LB1',
    ['블라디미르'] = 'Vladimir',
    ['블리츠크랭크'] = 'Blitzcrank',
    ['빅토르'] = 'Viktor',
    ['뽀삐'] = 'Poppy',
    ['사용자 상자:레스터 시티(GTA)'] = 'Leicester City FC',
    ['사이온'] = 'Sion',
    ['샤코'] = 'Shaco',
    ['세주아니'] = 'Sejuani',
    ['섹드립'] = '좆코를 강간하자',
    ['소나'] = 'Sona',
    ['소라카'] = 'Soraka',
    ['쉔'] = 'Shen',
    ['쉬바나'] = 'Shyvana',
    ['스웨인'] = 'Swain',
    ['스카너'] = 'Skarner',
    ['시비르'] = 'Sivir',
    ['신 짜오'] = 'XinZhao',
    ['신드라'] = 'Syndra',
    ['신지드'] = 'Singed',
    ['쓰레쉬'] = 'Thresh',
    ['아리'] = 'Ahri',
    ['아리아 브레커'] = 'portrait_Aria1',
    ['아무무'] = 'Amumu',
    ['아우라스 램'] = 'portrait_Auras1',
    ['아우러스 램'] = 'portrait_Ram1',
    ['아우렐리온 솔'] = 'AurelionSol',
    ['아지르'] = 'Azir',
    ['아칼리'] = 'Akali',
    ['아트록스'] = 'Aatrox',
    ['알리스타'] = 'Alistar',
    ['애니'] = 'Annie',
    ['애니비아'] = 'Anivia',
    ['애쉬'] = 'Ashe',
    ['야스오'] = 'Yasuo',
    ['에코'] = 'Ekko',
    ['엘리스'] = 'Elise',
    ['오공'] = 'MonkeyKing',
    ['오리아나'] = 'Orianna',
    ['올라프'] = 'Olaf',
    ['요릭'] = 'Yorick',
    ['우디르'] = 'Udyr',
    ['우르곳'] = 'Urgot',
    ['워윅'] = 'Warwick',
    ['유저박스:1000편집(GTA)'] = 'Silver_award',
    ['유저박스:Loud(GTA)'] = 'TheJewelStoreJob-GTAV-LoudApproachEscape',
    ['유저박스:채널 X(GTA)'] = 'ChannelXTee-GTAO-Advert',
    ['응 해봐'] = '광대드플',
    ['이렐리아'] = 'Irelia',
    ['이블린'] = 'Evelynn',
    ['이즈리얼'] = 'Ezreal',
    ['일라오이'] = 'Illaoi',
    ['자르반 4세'] = 'JarvanIV',
    ['자이라'] = 'Zyra',
    ['자전거의 종류'] = 'cycle',
    ['자크'] = 'Zac',
    ['잔나'] = 'Janna',
    ['잭스'] = 'Jax',
    ['제드'] = 'Zed',
    ['제라스'] = 'Xerath',
    ['제이스'] = 'Jayce',
    ['직스'] = 'Ziggs',
    ['진'] = 'Jhin',
    ['질리언'] = 'Zilean',
    ['징크스'] = 'Jinx',
    ['초가스'] = 'Chogath',
    ['카르마'] = 'Karma',
    ['카사딘'] = 'Kassadin',
    ['카서스'] = 'Karthus',
    ['카시오페아'] = 'Cassiopeia',
    ['카직스'] = 'Khazix',
    ['카타리나'] = 'Katarina',
    ['칼리스타'] = 'Kalista',
    ['케넨'] = 'Kennen',
    ['케이틀린'] = 'Caitlyn',
    ['케일'] = 'Kayle',
    ['코그모'] = 'KogMaw',
    ['코르키'] = 'Corki',
    ['퀸'] = 'Quinn',
    ['퀸톤 그로트'] = 'portrait_Quinton1',
    ['퀸튼 그로트'] = 'portrait_Quinton1',
    ['킨드레드'] = 'Kindred',
    ['타릭'] = 'Taric',
    ['탈론'] = 'Talon',
    ['탐 켄치'] = 'TahmKench',
    ['토비아스 드럼'] = 'portrait_Tobias1',
    ['톰 타룸카'] = 'portrait_Tom1',
    ['툼 타룸카'] = 'portrait_Tom1',
    ['트런들'] = 'Trundle',
    ['트리스타나'] = 'Tristana',
    ['트린다미어'] = 'Tryndamere',
    ['트위스티드 페이트'] = 'TwistedFate',
    ['트위치'] = 'Twitch',
    ['티모'] = 'Teemo',
    ['판테온'] = 'Pantheon',
    ['프레스트'] = 'portrait_Jace1',
    ['피들스틱'] = 'FiddleSticks',
    ['피오라'] = 'Fiora',
    ['피즈'] = 'Fizz',
    ['하이머딩거'] = 'Heimerdinger',
    ['헤카림'] = 'Hecarim',
    ['헨릴 드레빙'] = 'Portrait Henril1',
}

-- Manual fallback/update champion map for missing ones
local fallbackMap = {
    ["닐라"] = "Nilah",
    ["비에고"] = "Viego",
    ["그웬"] = "Gwen",
    ["세나"] = "Senna",
    ["피들스틱"] = "FiddleSticks",
    ["일라오이"] = "Illaoi",
    ["볼리베어"] = "Volibear",
    ["잔나"] = "Janna",
    ["모르가나"] = "Morgana",
    ["모데카이저"] = "Mordekaiser",
}

local function cleanName(name)
    if not name then return "" end
    name = mw.text.trim(name)
    -- Remove namespace if present (e.g. "틀:" or "Template:")
    name = string.gsub(name, "^[^:]+:", "")
    -- Remove parentheses suffix like (LEAGUEOFLEGENDS)
    name = string.gsub(name, "%s*%([^)]*%)$", "")
    return name
end

-- Helper for ui and cbi rendering
local function renderIconLink(name, display, link, file, defaultSuffix)
    if name == "" then
        return ""
    end
    
    if display == "" then
        display = name
    end
    
    local cleanNameVal = cleanName(name)
    
    -- Determine target page link
    if link == "" then
        link = cleanNameVal .. "(LEAGUEOFLEGENDS)"
    end
    
    -- Determine file name
    if file == "" then
        local engName = champMap[cleanNameVal] or fallbackMap[cleanNameVal] or cleanNameVal
        engName = string.gsub(engName, "%s", "_")
        file = engName .. defaultSuffix
    end
    
    -- Check if file exists in MediaWiki
    local fileTitle = mw.title.new("File:" .. file)
    local imgHtml = ""
    if fileTitle and fileTitle.exists then
        imgHtml = "[[File:" .. file .. "|20px|link=" .. link .. "|alt=]] "
    else
        -- Fallback to checking without suffix if it fails
        local baseFile = string.gsub(file, "Square%.png$", ".png")
        local baseTitle = mw.title.new("File:" .. baseFile)
        if baseTitle and baseTitle.exists then
            imgHtml = "[[File:" .. baseFile .. "|20px|link=" .. link .. "|alt=]] "
        end
    end
    
    return '<span class="unit-icon" style="white-space:nowrap;">' .. imgHtml .. '[[' .. link .. '|' .. display .. ']]</span>'
end

-- Unit Icon
function p.ui(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    
    local name = args[1] or ""
    local display = args[2] or ""
    local link = args["link"] or args["링크"] or ""
    local file = args["file"] or args["image"] or args["파일"] or args["이미지"] or ""
    
    return renderIconLink(name, display, link, file, "Square.png")
end

-- Champion Biography Icon
function p.cbi(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    
    local name = args[1] or ""
    local display = args[2] or ""
    local link = args["link"] or args["링크"] or ""
    local file = args["file"] or args["image"] or args["파일"] or args["이미지"] or ""
    
    return renderIconLink(name, display, link, file, "Square.png")
end

-- Faction/Region Icon
function p.fi(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    
    local name = args[1] or ""
    local display = args[2] or ""
    
    if name == "" then
        return ""
    end
    
    if display == "" then
        display = name
    end
    
    local cleanFaction = cleanName(name)
    local engFaction = factionMap[cleanFaction] or cleanFaction
    local fileBase = string.gsub(engFaction, "%s", "_")
    
    -- Check multiple crest/icon patterns
    local patterns = {
        "%s_Crest_icon.png",
        "%s_Crest_icon.svg",
        "%s_Crest.png",
        "%s_icon.png",
        "%sSquare.png",
        "%s_Crest_icon.PNG",
        "%s_Crest.PNG",
        "%s_icon.PNG",
    }
    
    local foundFile = ""
    for _, pattern in ipairs(patterns) do
        local file = string.format(pattern, fileBase)
        local fileTitle = mw.title.new("File:" .. file)
        if fileTitle and fileTitle.exists then
            foundFile = file
            break
        end
    end
    
    -- Form default link
    local link = cleanFaction .. "(LEAGUEOFLEGENDS)"
    
    local imgHtml = ""
    if foundFile ~= "" then
        imgHtml = "[[File:" .. foundFile .. "|20px|link=" .. link .. "|alt=]] "
    end
    
    return '<span class="faction-icon" style="white-space:nowrap;">' .. imgHtml .. '[[' .. link .. '|' .. display .. ']]</span>'
end

-- Ability Icon
function p.ai(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    
    local skillName = args[1] or ""
    local champName = args[2] or ""
    local display = args[3] or ""
    
    if skillName == "" then
        return ""
    end
    
    if display == "" then
        display = skillName
    end
    
    local cleanChamp = cleanName(champName)
    local cleanSkill = cleanName(skillName)
    
    local engChamp = champMap[cleanChamp] or fallbackMap[cleanChamp] or cleanChamp
    local engSkill = skillMap[cleanSkill] or cleanSkill
    
    local champBase = string.gsub(engChamp, "%s", "_")
    local skillBase = string.gsub(engSkill, "%s", "_")
    
    -- Check patterns for ability icons:
    -- 1. [ChampName]_[SkillName].png
    -- 2. [SkillName].png
    local file1 = champBase .. "_" .. skillBase .. ".png"
    local file2 = skillBase .. ".png"
    
    local foundFile = ""
    if mw.title.new("File:" .. file1).exists then
        foundFile = file1
    elseif mw.title.new("File:" .. file2).exists then
        foundFile = file2
    end
    
    local link = cleanChamp .. "(LEAGUEOFLEGENDS)#" .. cleanSkill
    
    local imgHtml = ""
    if foundFile ~= "" then
        imgHtml = "[[File:" .. foundFile .. "|20px|link=" .. link .. "|alt=]] "
    end
    
    return '<span class="ability-icon" style="white-space:nowrap;">' .. imgHtml .. '[[' .. link .. '|' .. display .. ']]</span>'
end

-- Passive progression (evaluates math in values like "1.2*12 ~ 2.4*12")
function p.pp(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    local val = args[1] or ""
    
    local function eval(expr)
        expr = mw.text.trim(expr)
        local success, result = pcall(function()
            return frame:preprocess("{{#expr: " .. expr .. "}}")
        end)
        if success and result and not string.find(result, "Expression error") then
            local num = tonumber(result)
            if num then
                if num == math.floor(num) then
                    return string.format("%d", num)
                else
                    local formatted = string.format("%.2f", num)
                    formatted = string.gsub(formatted, "0+$", "")
                    formatted = string.gsub(formatted, "%.$", "")
                    return formatted
                end
            end
            return result
        end
        return expr
    end

    local parts = {}
    local sep = " ~ "
    if string.find(val, "~") then
        sep = " ~ "
        for part in string.gmatch(val, "[^~]+") do
            table.insert(parts, eval(part))
        end
    elseif string.find(val, "–") then
        sep = " – "
        for part in string.gmatch(val, "[^–]+") do
            table.insert(parts, eval(part))
        end
    else
        return eval(val)
    end

    return table.concat(parts, sep)
end

-- Adaptive Force conversion
function p.adaptive(frame)
    local args = frame:getParent().args
    if not args[1] then
        args = frame.args
    end
    local val = args[1] or "0"
    
    local sep = nil
    if string.find(val, "~") then
        sep = "~"
    elseif string.find(val, "–") then
        sep = "–"
    end
    
    if sep then
        local parts_ad = {}
        local parts_ap = {}
        for part in string.gmatch(val, "[^" .. sep .. "]+") do
            part = mw.text.trim(part)
            table.insert(parts_ad, "0.6*(" .. part .. ")")
            table.insert(parts_ap, part)
        end
        local expr_ad = table.concat(parts_ad, sep)
        local expr_ap = table.concat(parts_ap, sep)
        return "(" .. p.pp(frame:newChild{args={expr_ad}}) .. " '''추가''' 공격력 또는 " .. p.pp(frame:newChild{args={expr_ap}}) .. " 주문력)"
    else
        local num = tonumber(val) or 0
        local ad = num * 0.6
        local ap = num
        local ad_str = string.format("%.2f", ad):gsub("0+$", ""):gsub("%.$", "")
        local ap_str = string.format("%.2f", ap):gsub("0+$", ""):gsub("%.$", "")
        return "(" .. ad_str .. " '''추가''' 공격력 또는 " .. ap_str .. " 주문력)"
    end
end

return p