Module:SubSkillsTable: Difference between revisions

From Heroes of Might and Magic: Olden Era Official Wiki
No edit summary
No edit summary
Line 27: Line 27:
-- Fonction pour remplacer les noms de skills par des liens wiki
-- Fonction pour remplacer les noms de skills par des liens wiki
local function linkSkillsInText(text, lang, linkMap)
local function linkSkillsInText(text, lang, linkMap)
     -- 1. On crée une table inversée en minuscules pour la recherche
     -- On crée une table pour le remplacement sensible à la casse
     -- map["chance"] = { id = "skill_luck", display = "Chance" }
     -- On trie les noms par longueur décroissante pour traiter "Advanced Offense" avant "Offense"
     local searchMap = {}
     local sortedNames = {}
     for name, id in pairs(linkMap) do
     for name, id in pairs(linkMap) do
         searchMap[mw.ustring.lower(name)] = { id = id, display = name }
         table.insert(sortedNames, name)
     end
     end
    -- 2. On trie les clés (noms) par longueur décroissante pour éviter les conflits
    local sortedNames = {}
    for name, _ in pairs(searchMap) do table.insert(sortedNames, name) end
     table.sort(sortedNames, function(a, b) return #a > #b end)
     table.sort(sortedNames, function(a, b) return #a > #b end)
      
      
     -- 3. On remplace dynamiquement
     -- On utilise un remplacement global en une seule passe
     for _, nameLower in ipairs(sortedNames) do
     for _, name in ipairs(sortedNames) do
         local info = searchMap[nameLower]
         local id = linkMap[name]
         local replacement = "[[" .. info.id .. "/" .. lang .. "|" .. info.display .. "]]"
         local replacement = "[[" .. id .. "/" .. lang .. "|" .. name .. "]]"
          
          
         -- Le pattern utilise le modificateur (?i) pour ignorer la casse
         -- Pattern : %f[%a] (frontière de mot), ensuite le nom, puis %f[%A]
        -- %f[%a] : frontière de mot
        -- On utilise mw.ustring.gsub
         local pattern = "(%f[%a])" .. mw.ustring.escapePattern(nameLower) .. "(%f[%A])"
        -- Le flag '1' dans le gsub précédent était le problème : il n'en remplaçait qu'un seul.
        -- Ici, on fait un remplacement global sans le '1'.
         local pattern = "(%f[%a])" .. mw.ustring.escapePattern(name) .. "(%f[%A])"
          
          
         -- On utilise une fonction pour remplacer tout en gardant la casse originale du texte
         -- On ajoute une condition pour ne pas remplacer si le nom est DÉJÀ dans un lien
         text = mw.ustring.gsub(text, pattern, function(prefix, suffix)
        -- On cherche si le texte n'est pas précédé de "[[".
             return prefix .. replacement .. suffix
         text = mw.ustring.gsub(text, "([^%[])" .. pattern, function(prefix, p1, p2)
         end, 1) -- '1' pour ne remplacer que la première occurrence si nécessaire, ou enlève le 1 pour tout remplacer
            -- prefix est le caractère avant, p1 la frontière, p2 la frontière après
             return prefix .. p1 .. replacement .. p2
         end)
     end
     end
   
     return text
     return text
end
end

Revision as of 12:49, 7 June 2026

Documentation for this module may be created at Module:SubSkillsTable/doc

local p = {}

-- Fonction utilitaire robuste avec valeur par défaut
local function getTrans(target_id, type, lang, field, variant, default)
    local query_where = string.format("target_id = '%s' AND type = '%s' AND language = '%s'", target_id, type, lang)
    if variant then query_where = query_where .. string.format(" AND variant = '%s'", variant) end
    
    local res = mw.ext.cargo.query("Translation", field, { where = query_where, limit = 1 })
    local result = (res and #res > 0) and res[1][field] or ""
    
    return (result ~= "") and result or (default or "")
end

-- Fonction pour créer la carte des liens (Nom -> ID)
local function getSkillLinkMap(lang)
    local results = mw.ext.cargo.query('Translation', 'target_id, name', {
        where = "type = 'skill' AND language = '" .. lang .. "' AND variant = 'production'",
        limit = 500
    })
    local map = {}
    for _, row in ipairs(results) do
        map[row.name] = row.target_id
    end
    return map
end

-- Fonction pour remplacer les noms de skills par des liens wiki
local function linkSkillsInText(text, lang, linkMap)
    -- On crée une table pour le remplacement sensible à la casse
    -- On trie les noms par longueur décroissante pour traiter "Advanced Offense" avant "Offense"
    local sortedNames = {}
    for name, id in pairs(linkMap) do
        table.insert(sortedNames, name)
    end
    table.sort(sortedNames, function(a, b) return #a > #b end)
    
    -- On utilise un remplacement global en une seule passe
    for _, name in ipairs(sortedNames) do
        local id = linkMap[name]
        local replacement = "[[" .. id .. "/" .. lang .. "|" .. name .. "]]"
        
        -- Pattern : %f[%a] (frontière de mot), ensuite le nom, puis %f[%A]
        -- On utilise mw.ustring.gsub
        -- Le flag '1' dans le gsub précédent était le problème : il n'en remplaçait qu'un seul.
        -- Ici, on fait un remplacement global sans le '1'.
        local pattern = "(%f[%a])" .. mw.ustring.escapePattern(name) .. "(%f[%A])"
        
        -- On ajoute une condition pour ne pas remplacer si le nom est DÉJÀ dans un lien
        -- On cherche si le texte n'est pas précédé de "[[".
        text = mw.ustring.gsub(text, "([^%[])" .. pattern, function(prefix, p1, p2)
            -- prefix est le caractère avant, p1 la frontière, p2 la frontière après
            return prefix .. p1 .. replacement .. p2
        end)
    end
    
    return text
end

-- Fonction pour récupérer les infos d'un SubSkill
local function getSubSkillInfo(sub_id, lang, linkMap)
    local sub_def = mw.ext.cargo.query("SubSkill", "icon", { where = string.format("id = '%s'", sub_id), limit = 1 })
    local icon = (sub_def and #sub_def > 0) and sub_def[1].icon or "Placeholder"
    local name = getTrans(sub_id, "sub_skill", lang, "name")
    local desc = getTrans(sub_id, "sub_skill", lang, "description")
    -- Application des liens
    desc = linkSkillsInText(desc, lang, linkMap)
    return { name = name, desc = desc, icon = icon }
end

function p.display(frame)
    local skill_id = frame.args["id"] or frame.args[1]
    if not skill_id then return "ID requis" end
    local lang = frame.args.language or "en"
    
    -- Préparation de la carte des liens
    local linkMap = getSkillLinkMap(lang)
    
    local hSkill = getTrans("wiki_skills", "wiki", lang, "name", nil, "Skills")
    local hSub = getTrans("wiki_sub_skills", "wiki", lang, "name", nil, "Subskills")
    
    local levels = mw.ext.cargo.query("SkillLevel", "level, icon, offered_sub_skills", {
        where = string.format("skill_id = '%s'", skill_id),
        orderBy = "level ASC"
    })
    
    if not levels or #levels == 0 then return "Aucun niveau trouvé." end
    
    local html = {'{| class="wikitable" style="width:100%; border-collapse:collapse;"'}
    table.insert(html, '! colspan=2 | ' .. hSkill .. ' !! colspan=6 | ' .. hSub)

    for _, lvl in ipairs(levels) do
        local name = getTrans(skill_id, "skill_level", lang, "name", lvl.level)
        local desc = getTrans(skill_id, "skill_level", lang, "description", lvl.level)
        -- Application des liens sur la description principale
        desc = linkSkillsInText(desc, lang, linkMap)
        
        local icon = (lvl.icon and lvl.icon ~= "") and lvl.icon or "Placeholder"
        
        table.insert(html, '|- style="vertical-align:top;"')
        table.insert(html, '| style="width:70px; border-right:0px;" | [[File:' .. icon .. '.png|70px]]')
        table.insert(html, '| style="border-left:0px; width:200px;" | \'\'\'' .. name .. '\'\'\' <br /><br />' .. desc .. '')
        
        local subs = {}
        if lvl.offered_sub_skills then
            for s in string.gmatch(lvl.offered_sub_skills, "([^,]+)") do table.insert(subs, s) end
        end
        
        for i = 1, 3 do
            if subs[i] then
                local info = getSubSkillInfo(subs[i], lang, linkMap)
                table.insert(html, '| style="width:30px; border-right:0px; padding-left:10px;" | [[File:' .. info.icon .. '.png|30px]]')
                table.insert(html, '| style="width:180px; border-left:0px;" | \'\'\'' .. info.name .. '\'\'\'<br /><br />' .. info.desc .. '')
            else
                table.insert(html, '| colspan=2 style="border-left:1px solid #ccc;" | &nbsp;')
            end
        end
    end
    
    table.insert(html, "|}")
    return table.concat(html, "\n")
end

return p