Module:Sandbox/Aurelain/ArtifactsOverview: Difference between revisions

From Heroes of Might and Magic: Olden Era Official Wiki
No edit summary
No edit summary
Line 81: Line 81:
     local fields = {}
     local fields = {}
     table.insert(fields, 'A.id = id');
     table.insert(fields, 'A.id = id');
    table.insert(fields, 'A.slot = slot');
    table.insert(fields, 'A.rarity = rarity');
    table.insert(fields, 'A.artifact_set_id = artifact_set_id');
    table.insert(fields, 'A.goods_value = goods_value');
    table.insert(fields, 'A.max_level = max_level');
    table.insert(fields, 'A.cost_base = cost_base');
    table.insert(fields, 'A.cost_per_level = cost_per_level');
     table.insert(fields, 'T.language = language');
     table.insert(fields, 'T.language = language');
     table.insert(fields, 'T.name = name');
     table.insert(fields, 'T.name = name');
     table.insert(fields, 'T.description = description');
     table.insert(fields, 'T.description = description');
    table.insert(fields, 'T.type = type');


     -- where:
     -- where:
     local where = {}
     local where = {}
     table.insert(where, 'A.id NOT LIKE "campaign_%"')
     table.insert(where, 'A.id NOT LIKE "campaign_%"')
    table.insert(where, 'T.type = "artifact"')
     table.insert(where, '(T.language = "en" OR T.language = "' .. lang .. '")')
     table.insert(where, '(T.language = "en" OR T.language = "' .. lang .. '")')


Line 120: Line 127:
                 entry.id = id or ''
                 entry.id = id or ''
                 entry.spells = {}
                 entry.spells = {}
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                 hub[id] = entry
                 hub[id] = entry
             end
             end
             if row.language == lang then
             if row.language == lang then
                 entry.name = row.name or ''
                 entry.name = row.name or ''
                entry.description = row.description or ''
             end
             end
             if row.language == 'en' then
             if row.language == 'en' then
Line 147: Line 160:
                 entry = {}
                 entry = {}
                 entry.id = id or ''
                 entry.id = id or ''
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                 hub[id] = entry
                 hub[id] = entry
             end
             end
             if row.language == lang then
             if row.language == lang then
                 entry.name = row.name or ''
                 entry.name = row.name or ''
                 entry.description = row.description or ''
                 if row.type == 'artifact' then
                    entry.description = row.description or ''
                end
                if row.type == 'artifact_upgrade' then
                    entry.upgrade = row.description or ''
                end
                if row.type == 'artifact_narrative' then
                    entry.narrative = row.description or ''
                end
             end
             end
             if row.language == 'en' then
             if row.language == 'en' then
Line 191: Line 219:
end
end


-- TABLE HEADER
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
local function createHeader(htmlTable, words)
local function createHeader(htmlTable, words)
Line 196: Line 225:
     --addTh(tr, 'id')
     --addTh(tr, 'id')
     addTh(tr, words.wiki_artifact):attr('colspan', 2)
     addTh(tr, words.wiki_artifact):attr('colspan', 2)
     addTh(tr, 'description'):attr('colspan', 2)
     addTh(tr, words.unit_window_narrative)
    addTh(tr, 'upgrade')
    addTh(tr, 'narrative')
    addTh(tr, 'slot')
    addTh(tr, 'rarity')
    addTh(tr, 'artifact_set_id')
    addTh(tr, 'goods_value')
    addTh(tr, 'max_level')
    addTh(tr, 'cost_base')
    addTh(tr, 'cost_per_level')
end
end


Line 211: Line 249:
end
end


-- TABLE BODY
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
local function createBody(htmlTable, list, lang)
local function createBody(htmlTable, list, lang)
Line 231: Line 270:
         addTd(tr, renderName(item.name, item.nameEn, lang))
         addTd(tr, renderName(item.name, item.nameEn, lang))
         addTd(tr, item.description)
         addTd(tr, item.description)
        addTd(tr, item.description)
        addTd(tr, item.upgrade)
        addTd(tr, item.narrative)
        addTd(tr, item.slot)
        addTd(tr, item.rarity)
        addTd(tr, item.artifact_set_id)
        addTd(tr, item.goods_value)
        addTd(tr, item.max_level)
        addTd(tr, item.cost_base)
        addTd(tr, item.cost_per_level)
     end
     end
end
end

Revision as of 10:55, 29 June 2026

This module renders a giant table with all artifacts. Scroll artifacts are consolidated into 3 generic scroll artifacts (normal, enchanted and mythic). Campaign artifacts are excluded.

A hyper parameter is supported. For more information, see Module:UtilHyper/doc.

Usage

Input: {{#invoke:Sandbox/Aurelain/ArtifactsOverview|display | lang=en | hyper=Attack=Hero_Basics#Attributes}}

Output:

Artifact🗯️Descriptionupgradenarrativeslotrarityartifact_set_idgoods_valuemax_levelcost_basecost_per_level
[[|]]+10% to Persuasion Power in Diplomacy.+10% to Persuasion Power in Diplomacy.Upgrade: +5% more Persuasion Power in Diplomacy.They’ll follow you if you look pretty!backlegendaryambassadors_word_item_set2400026040
[[|]]+10% to Persuasion Power in Diplomacy.+10% to Persuasion Power in Diplomacy.Upgrade: +5% more Persuasion Power in Diplomacy.No desire for independence can withstand the power of goodies.item_slotlegendaryambassadors_word_item_set2400026040
[[|]]The hero ignores the restriction on using the same Magic School twice.The hero ignores the restriction on using the same Magic School twice.Cannot be upgraded.Power flows from the idol’s stone eyes, coursing into the body of its owner.item_slotrare600013020
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.This armor was worn by ancient warriors of the Church of the Sun when it was still in its infancy.armorlegendaryangelic_alliance_item_set2400026040
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.The sentinels have withdrawn from the pact, but the artifact remains.beltlegendaryangelic_alliance_item_set2400026040
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.Many say this is the helm of Erathia’s founder, but could it be possible for it to have ended up on Jadame?headlegendaryangelic_alliance_item_set2400026040
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.In Jadame, the Alliance’s effect extends to all creatures, not just those part of the initial pact.right_handlegendaryangelic_alliance_item_set2400026040
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.Many are the pilgrims of the Light who wear these sandals as a gesture of humility.bootslegendaryangelic_alliance_item_set2400026040
[[|]]+2 Attack, Defense, Spell Power, and Knowledge.+2 Attack, Defense, Spell Power, and Knowledge.Upgrade: +1 more to every attribute.The Angelic Alliance was formed as a symbol of unity between sentinels of glory and mortals. Rumor has is that other such alliances exist in far away lands.left_handlegendaryangelic_alliance_item_set2400026040
[[|]]+1 Speed to friendly creatures.+1 Speed to friendly creatures.Cannot be upgraded.There used to be a seventh wind, but he displeased Arina. And then there were six.backepic1200014530
[[|]]+12 Defense, but –4 Attack.+12 Defense, but –4 Attack.Upgrade: +4 more Defense.Their shells are as hard as crystal.right_handlegendarybeelzebubs_blessing_item_set2400026040
[[|]]+12 Attack, but –4 Defense.+12 Attack, but –4 Defense.Upgrade: +4 more Attack.They say Beelzebub’s hands are soft as silk, but not those of his minions.left_handlegendarybeelzebubs_blessing_item_set2400026040
[[|]]+12 Knowledge, but –4 Spell Power.+12 Knowledge, but –4 Spell Power.Upgrade: +4 more Knowledge.A new force in this world, Beelzebub sought a way to ensure his summoning would never end.headlegendarybeelzebubs_blessing_item_set2400026040
[[|]]+12 Spell Power, but –4 Knowledge.+12 Spell Power, but –4 Knowledge.Upgrade: +4 more Spell Power.Just feel the rhythm of the Chorus.armorlegendarybeelzebubs_blessing_item_set2400026040
[[|]]+1 Defense.+1 Defense.Upgrade: +1 more Defense. Can be upgraded an unlimited number of times.Born into a clutch of ordinary dragons, Boreoloth spent his life striving for the greatness he was denied at birth. Even in death, his remains still hold the spark of endless self-improvement.item_slotcommon30009991515
[[|]]+1 Attack.+1 Attack.Upgrade: +1 more Attack. Can be upgraded an unlimited number of times.Born into a clutch of ordinary dragons, Boreoloth spent his life striving for the greatness he was denied at birth. Even in death, his remains still hold the spark of endless self-improvement.item_slotcommon30009991515
[[|]]+1 Knowledge.+1 Knowledge.Upgrade: +1 more Knowledge. Can be upgraded an unlimited number of times.Born into a clutch of ordinary dragons, Boreoloth spent his life striving for the greatness he was denied at birth. Even in death, his remains still hold the spark of endless self-improvement.item_slotcommon30009991515
[[|]]+1 Spell Power.+1 Spell Power.Upgrade: +1 more Spell Power. Can be upgraded an unlimited number of times.Born into a clutch of ordinary dragons, Boreoloth spent his life striving for the greatness he was denied at birth. Even in death, his remains still hold the spark of endless self-improvement.item_slotcommon30009991515
[[|]]Heroic Strike restores 4 mana.Heroic Strike restores 4 mana.Upgrade: +4 more mana.With this, blood can become magic, and matter can become spirit.right_handrarelegendary_hero_item_set600023020
[[|]]Makes all tier-1 spells available to the hero.Makes all tier-1 spells available to the hero.Cannot be upgraded.Some wizards enjoyed games and gambling a bit too much. This is the result.item_slotrare600013020
[[|]]Allows the hero to cast all Daylight spells.Allows the hero to cast all Daylight spells.Cannot be upgraded.“Arina the Brave, Justice of the Heavens, Sister of Sunlight that reveals all and strikes true…”item_slotlegendary2400016040
[[|]]Allows the hero to cast all Nightshade spells.Allows the hero to cast all Nightshade spells.Cannot be upgraded.“Naira the True, the Gentle, Knower of Secrets, Muffler of Steps: wrap me in your wings of silence…”item_slotlegendary2400016040
[[|]]Allows the hero to cast all Primal spells.Allows the hero to cast all Primal spells.Cannot be upgraded.“Hksmilla, World’s Rage, Primal Eye; unlike any other scholar, with your thousand claws and multiple heads...”item_slotlegendary2400016040
[[|]]Allows the hero to cast all Arcane spells.Allows the hero to cast all Arcane spells.Cannot be upgraded.“Doreath the Pure, Weaver of the world’s clearest essence, Master of Time, Space, and Solitude…”item_slotlegendary2400016040
[[|]]Forbids the wearer and the enemy hero to cast tier-1 and 2 spells in combat.Forbids the wearer and the enemy hero to cast tier-1 and 2 spells in combat.Cannot be upgraded.A link from a Concubus chain worn around the finger. It’s seen a lot.ringrare600013020
[[|]]+3 Defense.+3 Defense.Cannot be upgraded.Basic torso protection. Takes way too long to make for its mediocre defense.armorcommon300011510
[[|]]Makes all tier-3 spells available to the hero.Makes all tier-3 spells available to the hero.Cannot be upgraded.A wizard once noticed an odd resemblance between weaving and spellcraft. As a result, these robes were created.armorepic1200014530
[[|]]+4 Knowledge.+4 Knowledge.Upgrade: +2 more Knowledge. Can be upgraded an unlimited number of times.They say it drives the wearer mad over time.headrare60009996060
[[|]]Replaces all the hero’s spells with their Masterful versions (if they exist).Replaces all the hero’s spells with their Masterful versions (if they exist).Cannot be upgraded.Everyone has all the power of the world in their heart. You just need to tune to the Chorus’s buzz to find it.item_slotlegendary2400016040
[[|]]Friendly creatures take –30% counterattack Damage.Friendly creatures take –30% counterattack Damage.Upgrade: –15% less counterattack Damage.Well, technically it’s four rings.ringepicduelists_pride_item_set1200024530
[[|]]Friendly creatures can counterattack even if the attacking enemy has “Swift Strike.”Friendly creatures can counterattack even if the attacking enemy has “Swift Strike.”Upgrade: Friendly creatures deal +5% Melee Damage.Made not for defense, but to better position yourself for counterattacking.right_handcommonduelists_pride_item_set300021510
[[|]]Friendly creatures deal +10% Melee DamageFriendly creatures deal +10% Melee DamageUpgrade: +5% more Melee Damage.A light, stinging weapon. A tool for elegant fighters.left_handrareduelists_pride_item_set600023020
[[|]]+2 Morale and Luck.+2 Morale and Luck.Cannot be upgraded.Spirits and birds soar together.armorrare600013020
[[|]]All negative effects on friendly creatures last for –1 round(s).All negative effects on friendly creatures last for –1 round(s).Upgrade: –1 fewer round(s).Water brings oblivion. It can erase memories of pain and trouble.beltrareelixir_of_life_item_set600023020
[[|]]Friendly creatures have +2 HP.Friendly creatures have +2 HP.Upgrade: +1 more HP.The fae know unique blood magic. They also remember the face of everyone who has ever held them captive.item_slotlegendaryelixir_of_life_item_set1200024530
[[|]]All positive effects on friendly creatures last for +1 round(s).All positive effects on friendly creatures last for +1 round(s).Upgrade: +1 more round(s).Made of silverwort, a unique herb that feels like metal.ringrareelixir_of_life_item_set600023020
[[|]]item_slotrare5500100
[[|]]Produces +1 Gem, Crystal, or Mercury daily. (The resource depends on the bearer’s faction.)Produces +1 Gem, Crystal, or Mercury daily. (The resource depends on the bearer’s faction.)Cannot be upgraded.Adventurers all over the world throw their possessions into these bags. It’s about time someone began to fish them out.beltrare600013020
[[|]]Spells and creature abilities ignore 40% of enemy magic resistance.Spells and creature abilities ignore 40% of enemy magic resistance.Upgrade: Ignore +20% more magic resistance.If spells are written in the stars, the crescent moon is there to cut them to pieces.right_handrareethereal_knowledge_item_set600023020
[[|]]Spells cost 2 less mana.Spells cost 2 less mana.Upgrade: 1 less mana.Not the most comfortable, but definitely very magical.bootscommonethereal_knowledge_item_set300021510
[[|]]+1 level(s) to all spells while worn.+1 level(s) to all spells while worn.Upgrade: +1 more spell level(s).Connecting directly to the brain, these eyes access an entirely new layer of knowledge.headlegendaryethereal_knowledge_item_set2400026040
[[|]]Whenever the opponent casts a spell, restores 40% of its cost as mana to the wearer.Whenever the opponent casts a spell, restores 40% of its cost as mana to the wearer.Upgrade: Restores 60% of the spell’s cost.If you look at it for too long, you’ll feel as though it’s sucking you in.armorrareethereal_knowledge_item_set600023020
[[|]]Heroic Strike kills +1 unit(s). Works on creatures up to tier 7.Heroic Strike kills +1 unit(s). Works on creatures up to tier 7.Upgrade: +1 more unit(s).No scale, armor, or shield can offer protection against this blade.left_handlegendarylegendary_hero_item_set2400026040
[[|]]Grants constant flight.Grants constant flight.Cannot be upgraded.They whisper that the true angels abandoned the Temple of the Sun. Was it the Templars’ zealotry — or the angels’ hubris?backlegendary2400016040
[[|]]+1 level to all spells.+1 level to all spells.Cannot be upgraded.Wands are used to focus mental projections, just as crystals focus light into beams.right_handrare600013020
[[|]]The wearer keeps their army whenever they flee from battle.The wearer keeps their army whenever they flee from battle.Cannot be upgraded.No matter how powerful you are on the battlefield, in the end all disputes are solved politically.item_slotepic1200014530
[[|]]–1 Speed to all enemies.–1 Speed to all enemies.Cannot be upgraded.Can’t do much when you’re choking.left_handepic1200014530
[[|]]–10% Magic Damage taken. Friendly creatures are immune to the effects of “Berserk.”–10% Magic Damage taken. Friendly creatures are immune to the effects of “Berserk.”Upgrade: –5% less Magic Damage taken.Dwarves deal with the elements so much, they’ve automated their defenses.backraregifts_of_dwarven_lords_item_set600023020
[[|]]–20% to enemy hero Spell Power. Friendly creatures are immune to effects that prevent them from attacking.–20% to enemy hero Spell Power. Friendly creatures are immune to effects that prevent them from attacking.Upgrade: –10% more to enemy Spell Power.Magic is the art of resonance — which means discordant vibration can dampen it.ringepicgifts_of_dwarven_lords_item_set1200024530
[[|]]–10% to enemy hero Spell Power. Friendly creatures are immune to the effects that kill additional units.–10% to enemy hero Spell Power. Friendly creatures are immune to the effects that kill additional units.Upgrade: –5% more.Magic is the art of resonance — which means discordant vibration can dampen it.ringraregifts_of_dwarven_lords_item_set600023020
[[|]]–10% Magic Damage taken. Friendly creatures are immune to the effects of “Sleep.”–10% Magic Damage taken. Friendly creatures are immune to the effects of “Sleep.”Upgrade: –5% less Magic Damage taken.Not to be confused with conveyor belts. (Unless…)beltepicgifts_of_dwarven_lords_item_set1200024530
[[|]]Grants a random wondrous reward after a random number of upgrades.Grants a random wondrous reward after a random number of upgrades.Can have unlimited upgrades.If we knew for certain how golden geese are hatched, we’d live like kings. But there doesn’t seem to be a pattern.item_slotepic120009999600
[[|]]+1 sight radius.+1 sight radius.Cannot be upgraded.Surprisingly, it was the templars who invented it, not the dwarves. They required even more of the guiding light.headcommon300011510
[[|]]While worn, grants all unlearned Subskills of the following Skills: Logistics, Battle Magic, Wisdom.While worn, grants all unlearned Subskills of the following Skills: Logistics, Battle Magic, Wisdom.Cannot be upgraded.A fictional deity invented by pixies as a prank, Eridore would later be worshipped by many seeking to bless their messages.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Leadership, Insight, Diplomacy, Tactics.While worn, grants all unlearned Subskills of the following Skills: Leadership, Insight, Diplomacy, Tactics.Cannot be upgraded.Legend speaks of an oracle who could foresee the outcomes of wars and battles. Over time, generals began to revere her name.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Luck, Economy, Daylight Magic.While worn, grants all unlearned Subskills of the following Skills: Luck, Economy, Daylight Magic.Cannot be upgraded.The golden dragon of myth is said to bring wealth so great that it eventually became a symbol of worship.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Arcane Magic, Scouting, Battlecraft, Thaumaturgy.While worn, grants all unlearned Subskills of the following Skills: Arcane Magic, Scouting, Battlecraft, Thaumaturgy.Cannot be upgraded.A conqueror who was said to have never died, but instead ventured to conquer new worlds beyond this one, Quix exists now only in legend.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Righteousness, Necromancy, Murmuring, Triumvirate’s Strength, Abyssal Communion, Summon Swarm.While worn, grants all unlearned Subskills of the following Skills: Righteousness, Necromancy, Murmuring, Triumvirate’s Strength, Abyssal Communion, Summon Swarm.Cannot be upgraded.No one remembers who Roph once served, but he did so with unwavering loyalty. In time, he became a local saint, embodying the ideals of steadfast devotion to one’s sovereign, one’s faction, and oneself.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Offense, Summon Avatar, Siegecraft, Combat.While worn, grants all unlearned Subskills of the following Skills: Offense, Summon Avatar, Siegecraft, Combat.Cannot be upgraded.The First Man in existence is said to have found death, conquered by the power of the Second. At least, that is what the legends tell.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Sorcery, Nightshade Magic, Resistance.While worn, grants all unlearned Subskills of the following Skills: Sorcery, Nightshade Magic, Resistance.Cannot be upgraded.Seven powerful mages formed a secret coven. It’s no longer in existence, but their Sigil endures.unic_slotepic2100014530
[[|]]While worn, grants all unlearned Subskills of the following Skills: Defense, Primal Magic, Recruitment.While worn, grants all unlearned Subskills of the following Skills: Defense, Primal Magic, Recruitment.Cannot be upgraded.“Where blood spills, plants grow.” This was the motto of an ancient druidic cult, and only their sigil remains to tell their tale.unic_slotepic2100014530
[[|]]The cooldowns of all spells are reduced by 1 round(s).The cooldowns of all spells are reduced by 1 round(s).Cannot be upgraded.Water flows upwards, rewinding time.right_handrare600013020
[[|]]Generates 2 Focus Point(s) at the start of the battle.Generates 2 Focus Point(s) at the start of the battle.Upgrade: +2 more Focus Point(s).Tell me what mask you wear, and I will tell you who you want to be.headcommoninner_song_item_set300021510
[[|]]Friendly creatures’ abilities deal +40% Damage.Friendly creatures’ abilities deal +40% Damage.Upgrade: +20% more Damage.Music helps one articulate themselves — and sets the battle rhythm.item_slotcommoninner_song_item_set300021510
[[|]]All effects applied by friendly creatures last +1 round(s).All effects applied by friendly creatures last +1 round(s).Upgrade: +1 more round(s).Spells linger like notes.right_handcommoninner_song_item_set300021510
[[|]]+2 Defense.+2 Defense.Upgrade: +1 more Defense.This amulet allows the wearer to survive against all odds — though sadly, it’s worn by cowards who never intend to face such dangers.item_slotrarekeepers_fortitude_item_set600023020
[[|]]+2 Defense.+2 Defense.Upgrade: +1 more Defense.City guards often wear these rings to help them react to danger one or two seconds faster.ringrarekeepers_fortitude_item_set600023020
[[|]]+2 Defense.+2 Defense.Upgrade: +1 more Defense.A modern classic.headcommonknights_honor_item_set300021510
[[|]]Friendly creatures deal +1 Damage.Friendly creatures deal +1 Damage.Upgrade: +1 more Damage.Without cause or purpose.item_slotepicknights_honor_item_set1200023020
[[|]]+3 Attack.+3 Attack.Upgrade: +2 more Attack.Charge!left_handrareknights_honor_item_set600023020
[[|]]+2 Attack.+2 Attack.Upgrade: +1 more Attack.Ending an opponent’s suffering swiftly is a mercy.right_handcommonknights_honor_item_set300021510
[[|]]+3 Defense.+3 Defense.Upgrade: +2 more Defense.Sticks and stones may break bones, but not through full armor.armorrareknights_honor_item_set600023020
[[|]]+50% to all creature growth in all your cities.+50% to all creature growth in all your cities.Cannot be upgraded.Somewhere, a legless statue is waiting sorrowfully.bootsepic1200014530
[[|]]Friendly creatures can still use Ranged attacks while adjacent to enemy creatures.Friendly creatures can still use Ranged attacks while adjacent to enemy creatures.Upgrade: Friendly creatures deal +5% Ranged Damage.Makes the wearer dissolve into the dance of light and shade.backepicliving_arrows_item_set1200024530
[[|]]Friendly creatures deal +10% Ranged Damage.Friendly creatures deal +10% Ranged Damage.Upgrade: +5% more Ranged Damage.Grows magic arrows, bolts, darts, shuriken, javelins, and any throwing item imaginable. (Thank the woods.)item_slotrareliving_arrows_item_set600023020
[[|]]Eliminates Ranged Damage penalty for friendly creatures.Eliminates Ranged Damage penalty for friendly creatures.Upgrade: Friendly creatures deal +5% Ranged Damage.This living bow grows new arrows itself.left_handepicliving_arrows_item_set1200024530
[[|]]Friendly creatures have +1 Initiative.Friendly creatures have +1 Initiative.Cannot be upgraded.When your lord commands, you get up and go. Simple as that.ringepic1200014530
[[|]]Negates all effects that restrict creature rearrangement, surrendering, fleeing, and using the Spellbook and hero abilities in battle.Negates all effects that restrict creature rearrangement, surrendering, fleeing, and using the Spellbook and hero abilities in battle.Cannot be upgraded.Can unlock the Shackles of War.beltlegendary2400016040
Magic Scrollitem_slotcommon2750100

-- Usage: {{#invoke:ArtifactsOverview|display | lang=en}}
local p = {}
local f = mw.ustring.format

-- Note: The right side is just a fallback, it will seldom be used.
local TRANSLATION_IDS = {
    wiki_none = 'None',
    wiki_artifact = 'Artifact',
    unit_window_narrative = 'Description'
}

-- Displays a variable
------------------------------------------------------------------------------------------------------------------------
local function dump(target)
    return '<pre>' .. mw.dumpObject(target) .. '</pre>'
end

-- Spawns a safe robotic url from an English name, fit for adding it before the visible name
------------------------------------------------------------------------------------------------------------------------
local function getUrl(nameEn, lang)
    if not nameEn then
        return ''
    end
    local url = nameEn
    if lang ~= 'en' then
        url = url .. '/' .. lang
    end
    return url
end

-- Retrieves the text for some specific ids from Cargo Translations.
------------------------------------------------------------------------------------------------------------------------
local function translateIds(ids, lang, extra)
    -- Key list
    local list = {}
    for key, _ in pairs(ids) do
        list[#list + 1] = key
    end
    local idListString = '"' .. table.concat(list, '", "') .. '"'

    -- Cargo
    local where = {}
    table.insert(where, 'target_id IN (' .. idListString .. ')')
    table.insert(where, 'language = "' .. lang .. '"')
    if extra then
        table.insert(where, extra)
    end
    local results = mw.ext.cargo.query('Translation', 'target_id, name', {
        where = table.concat(where, ' AND '),
        limit = 100
    })

    -- Dictionary
    local dictionary = mw.clone(ids)
    for key, value in pairs(dictionary) do
        dictionary[key] = value .. '🗯️'
    end
    for _, row in ipairs(results) do
        local name = row['name']
        if name and name ~= '' then
            dictionary[row['target_id']] = name
        end
    end
    return dictionary
end

-- Converts a dictionary into a linear array
------------------------------------------------------------------------------------------------------------------------
local function flatten(hub)
    local list = {}
    for _, entry in pairs(hub) do
        list[#list + 1] = entry
    end
    return list
end

-- Interrogates the main Cargo table
------------------------------------------------------------------------------------------------------------------------
local function queryMain(lang)
    -- fields:
    local fields = {}
    table.insert(fields, 'A.id = id');
    table.insert(fields, 'A.slot = slot');
    table.insert(fields, 'A.rarity = rarity');
    table.insert(fields, 'A.artifact_set_id = artifact_set_id');
    table.insert(fields, 'A.goods_value = goods_value');
    table.insert(fields, 'A.max_level = max_level');
    table.insert(fields, 'A.cost_base = cost_base');
    table.insert(fields, 'A.cost_per_level = cost_per_level');
    table.insert(fields, 'T.language = language');
    table.insert(fields, 'T.name = name');
    table.insert(fields, 'T.description = description');
    table.insert(fields, 'T.type = type');

    -- where:
    local where = {}
    table.insert(where, 'A.id NOT LIKE "campaign_%"')
    table.insert(where, '(T.language = "en" OR T.language = "' .. lang .. '")')

    -- query:
    return mw.ext.cargo.query('Artifact=A, Translation=T', table.concat(fields, ','), {
        join = 'A.id = T.target_id',
        where = table.concat(where, ' AND '),
        limit = 500
    })
end

-- Folds magic scrolls into 3 artifacts (normal, enchanted and mythic):
------------------------------------------------------------------------------------------------------------------------
local function consolidateScrolls(lang, results)
    local hub = {}
    for _, row in ipairs(results) do
        local id = row.id
        if id:find('magic_scroll') then
            if id:find('mythic') then
                id = 'mythic_scroll_box_artifact'
            else
                if id:find('enchanted') then
                    id = 'enchanted_magic_scroll_artifact'
                else
                    id = 'magic_scroll_artifact'
                end
            end
            local entry = hub[id]
            if not entry then
                entry = {}
                entry.id = id or ''
                entry.spells = {}
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                hub[id] = entry
            end
            if row.language == lang then
                entry.name = row.name or ''
            end
            if row.language == 'en' then
                entry.nameEn = row.name or ''
                local spellId = row.id:gsub('.*artifact_', '')
                table.insert(entry.spells, spellId)
            end
        end
    end
    return hub
end

-- Folds all Cargo results into a single dictionary:
------------------------------------------------------------------------------------------------------------------------
local function consolidate(lang, results)
    local hub = consolidateScrolls(lang, results)
    for _, row in ipairs(results) do
        local id = row.id
        if not id:find('magic_scroll') then
            local entry = hub[id]
            if not entry then
                entry = {}
                entry.id = id or ''
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                hub[id] = entry
            end
            if row.language == lang then
                entry.name = row.name or ''
                if row.type == 'artifact' then
                    entry.description = row.description or ''
                end
                if row.type == 'artifact_upgrade' then
                    entry.upgrade = row.description or ''
                end
                if row.type == 'artifact_narrative' then
                    entry.narrative = row.description or ''
                end
            end
            if row.language == 'en' then
                entry.nameEn = row.name or ''
            end
        end
    end
    return hub
end

------------------------------------------------------------------------------------------------------------------------
local function sortList(a, b)
    return a.id < b.id
end

-- Boilerplate for the header cells
------------------------------------------------------------------------------------------------------------------------
local function addTh(tr, text)
    return tr:tag('th'):wikitext(text)
end

-- Boilerplate for the body cells
------------------------------------------------------------------------------------------------------------------------
local function addTd(tr, content)
    if type(content) == "string" then
        return tr:tag('td'):wikitext(content)
    else
        return tr:tag('td'):node(content)
    end
end

-- Boilerplate for the separator rows
------------------------------------------------------------------------------------------------------------------------
local function addSeparator(htmlTable, className, content)
    htmlTable:tag('tr')
        :addClass('separator')
        :addClass(className)
        :tag('td'):attr('data-sort-value', ''):attr('colspan', 100):wikitext(content):done()
end

-- TABLE HEADER
------------------------------------------------------------------------------------------------------------------------
local function createHeader(htmlTable, words)
    local tr = htmlTable:tag('tr')
    --addTh(tr, 'id')
    addTh(tr, words.wiki_artifact):attr('colspan', 2)
    addTh(tr, words.unit_window_narrative)
    addTh(tr, 'upgrade')
    addTh(tr, 'narrative')
    addTh(tr, 'slot')
    addTh(tr, 'rarity')
    addTh(tr, 'artifact_set_id')
    addTh(tr, 'goods_value')
    addTh(tr, 'max_level')
    addTh(tr, 'cost_base')
    addTh(tr, 'cost_per_level')
end

------------------------------------------------------------------------------------------------------------------------
local function renderIcon(id, nameEn, lang)
    local url = getUrl(nameEn, lang)
    return f('[[File:%s.png|64px|link=%s]]', id, url)
end

------------------------------------------------------------------------------------------------------------------------
local function renderName(name, nameEn, lang)
    local url = getUrl(nameEn, lang)
    return f('[[%s|%s]]', url, name)
end

-- TABLE BODY
------------------------------------------------------------------------------------------------------------------------
local function createBody(htmlTable, list, lang)
    local currentType = list[1].param1
    local currentFaction = list[1].faction
    for _, item in ipairs(list) do
        -- separators
        if item.faction ~= currentFaction then
            currentFaction = item.faction
            currentType = item.class_type
            addSeparator(htmlTable, 'separator-large', '')
        elseif item.class_type ~= currentType then
            currentType = item.class_type
            addSeparator(htmlTable, 'separator-tiny', '')
        end

        local tr = htmlTable:tag('tr'):addClass('artifact')
        --addTd(tr, item.id)
        addTd(tr, renderIcon(item.id, item.nameEn, lang))
        addTd(tr, renderName(item.name, item.nameEn, lang))
        addTd(tr, item.description)
        addTd(tr, item.description)
        addTd(tr, item.upgrade)
        addTd(tr, item.narrative)
        addTd(tr, item.slot)
        addTd(tr, item.rarity)
        addTd(tr, item.artifact_set_id)
        addTd(tr, item.goods_value)
        addTd(tr, item.max_level)
        addTd(tr, item.cost_base)
        addTd(tr, item.cost_per_level)
    end
end

-- M A I N
------------------------------------------------------------------------------------------------------------------------
function p.display(frame)
    --do return dump(frame) end

    -- Args
    local args = frame.args
    local lang = args.lang ~= '' and args.lang or 'en'
    --lang = 'ja'

    -- Language
    local words = translateIds(TRANSLATION_IDS, lang)

    -- Cargo
    local results = queryMain(lang)
    local hub = consolidate(lang, results)
    local list = flatten(hub);
    if #list == 0 then return words.wiki_none end

    -- Various manipulations
    table.sort(list, sortList)

    -- Table
    local htmlTable = mw.html.create('table')
    htmlTable:addClass('wikitable sortable')
    createHeader(htmlTable, words)
    createBody(htmlTable, list, lang)

    -- Output
    local styleTag = frame:extensionTag('templatestyles', '', { src = frame:getTitle() .. '/styles.css' })
    return '<div class="artifacts-overview">' .. styleTag .. tostring(htmlTable) .. '</div>'
end

return p