Module:Sandbox/Aurelain/ArtifactsOverview

From Heroes of Might and Magic: Olden Era Official Wiki

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:

idnameX
ambassadors_word_ambassadors_sash_artifactAmbassador's SashAmbassador's Sash
ambassadors_word_diplomatic_gifts_artifactDiplomatic GiftsDiplomatic Gifts
ancient_idol_artifactAncient IdolAncient Idol
angelic_alliance_armor_of_wonder_artifactArmor of WonderArmor of Wonder
angelic_alliance_celestial_sash_of_bliss_artifactCelestial Sash of BlissCelestial Sash of Bliss
angelic_alliance_helm_of_heavenly_enlightenment_artifactHelm of Heavenly EnlightenmentHelm of Heavenly Enlightenment
angelic_alliance_lions_shield_of_courage_artifactLion's Shield of CourageLion's Shield of Courage
angelic_alliance_sandals_of_the_saint_artifactSandals of the SaintSandals of the Saint
angelic_alliance_sword_of_judgement_artifactSword of JudgementSword of Judgement
banner_of_four_winds_artifactBanner of Six WindsBanner of Six Winds
beelzebubs_blessing_chitinous_shield_artifactChitinous ShieldChitinous Shield
beelzebubs_blessing_demon_claw_artifactDemon ClawDemon Claw
beelzebubs_blessing_demon_crest_artifactBeelzebub's BoonBeelzebub's Boon
beelzebubs_blessing_heartbeat_artifactHeartbeatHeartbeat
boreolos_foot_artifactBoreoloth's TailBoreoloth's Tail
boreolos_hand_artifactBoreoloth's HandBoreoloth's Hand
boreolos_head_artifactBoreoloth's HeadBoreoloth's Head
boreolos_heart_artifactBoreoloth's HeartBoreoloth's Heart
caduceus_artifactCaduceusCaduceus
campaign_M3_captured_priestesses_itemChained PriestessesChained Priestesses
campaign_M3_freed_priestesses_itemInjured PriestessesInjured Priestesses
campaign_M9_phoenix_egg_itemPhoenix EggPhoenix Egg
campaign_ichor_itemBlob of RedBlob of Red
cards_deck_artifactDeck of SpellsDeck of Spells
chain_link_artifactChain LinkChain Link
chain_mail_artifactChain MailChain Mail
clothes_of_enlightenment_artifactRobe of EnlightenmentRobe of Enlightenment
crown_of_the_supreme_magi_artifactCrown of the Supreme MagiCrown of the Supreme Magi
demonic_heart_artifactDemonic HeartDemonic Heart
duelists_pride_brass_knuckles_artifactBrass KnucklesBrass Knuckles
duelists_pride_buckler_artifactBucklerBuckler
duelists_pride_rapier_artifactRapierRapier
eagle_armor_artifactEagle ArmorEagle Armor
elixir_of_life_flask_of_oblivion_artifactFlask of OblivionFlask of Oblivion
elixir_of_life_lifeblood_fairy_artifactLifeblood FaeLifeblood Fae
elixir_of_life_ring_of_life_artifactRing of LifeRing of Life
enchanted_magic_scroll_artifact_day_3_magic_hasteEnchanted Magic ScrollEnchanted Magic Scroll
endless_bag_artifactEndless BagEndless Bag
ethereal_knowledge_glass_dagger_artifactCrescent DaggerCrescent Dagger
ethereal_knowledge_mirror_shoes_artifactMagic SlippersMagic Slippers
ethereal_knowledge_third_eye_artifactSeven EyesSeven Eyes
ethereal_knowledge_vortex_dress_artifactVortex RobeVortex Robe
excalibur_artifactExcaliburExcalibur
fallen_angel_wings_artifactFallen Angel WingsFallen Angel Wings
fine_wand_artifactFine WandFine Wand
flag_of_truce_artifactFlag of TruceFlag of Truce
garotte_artifactGarotteGarotte
gifts_of_dwarven_lords_crimson_resonance_controller_artifactCrimson Resonance ControllerCrimson Resonance Controller
gifts_of_dwarven_lords_emerald_resonance_controller_artifactEmerald Resonance ControllerEmerald Resonance Controller
gifts_of_dwarven_lords_protective_belt_artifactProtective BeltProtective Belt
golden_goose_egg_artifactGolden Goose EggGolden Goose Egg
head_torch_artifactHead TorchHead Torch
holy_sigil_of_eridore_artifactHoly Sigil of EridoreHoly Sigil of Eridore
holy_sigil_of_insara_artifactHoly Sigil of InsaraHoly Sigil of Insara
holy_sigil_of_mearea_artifactHoly Sigil of MeareaHoly Sigil of Mearea
holy_sigil_of_quix_artifactHoly Sigil of QuixHoly Sigil of Quix
holy_sigil_of_roph_artifactHoly Sigil of RophHoly Sigil of Roph
holy_sigil_of_the_second_man_artifactHoly Sigil of The Second ManHoly Sigil of The Second Man
holy_sigil_of_the_seven_magi_artifactHoly Sigil of The Seven MagiHoly Sigil of The Seven Magi
holy_sigil_of_uurdt_artifactHoly Sigil of UurdtHoly Sigil of Uurdt
hourglass_of_protection_artifactPelagic HourglassPelagic Hourglass
inner_song_fancy_mask_artifactFancy MaskFancy Mask
inner_song_music_sheet_artifactMusic SheetMusic Sheet
inner_song_singing_pan_pipe_artifactSinging Pan-PipeSinging Pan-Pipe
keepers_fortitude_keepers_oberegus_artifactKeeper's AmuletKeeper's Amulet
keepers_fortitude_keepers_ring_artifactKeeper's RingKeeper's Ring
knights_honor_armet_artifactArmetArmet
knights_honor_drums_of_war_artifactDrum of WarDrum of War
knights_honor_lance_artifactLanceLance
knights_honor_misericorde_artifactMisericordeMisericorde
knights_honor_plate_armor_artifactPlate ArmorPlate Armor
legions_step_artifactLegion's LegLegion's Leg
living_arrows_light_and_shade_cloak_artifactLight-and-Shade CloakLight-and-Shade Cloak
living_arrows_quivering_quiver_artifactQuivering QuiverQuivering Quiver
living_arrows_shroomwood_bow_artifactShroomwood BowShroomwood Bow
lords_ring_artifactLord's RingLord's Ring
magic_key_ring_artifactMagic Key RingMagic Key Ring
magic_scroll_artifact_day_3_magic_hasteMagic ScrollMagic Scroll
milos_curse_golden_moth_artifactGolden MothGolden Moth
milos_curse_golden_pig_artifactGolden PigGolden Pig
milos_curse_skull_of_milos_artifactSkull of MilosSkull of Milos
monster_head_artifactMonster HeadMonster Head
ogres_club_of_havoc_artifactOgre's Club of HavocOgre's Club of Havoc
omencaller_artifactOmencallerOmencaller
orb_of_destruction_artifactOrb of DestructionOrb of Destruction
orb_of_inhibition_artifactOrb of InhibitionOrb of Inhibition
paupers_glory_dumb_club_artifactFish-to-the-FaceFish-to-the-Face
paupers_glory_last_coin_artifactLast CoinLast Coin
paupers_glory_rags_artifactRagsRags
paupers_glory_rope_belt_artifactRope BeltRope Belt
paupers_glory_straw_hat_artifactStraw HatStraw Hat
paupers_glory_wooden_ring_artifactWooden RingWooden Ring
pole_star_artifactPole StarPole Star
power_of_the_dragon_father_dragon_crest_artifactCrown of DragontoothCrown of Dragontooth
power_of_the_dragon_father_dragon_scale_armor_artifactDragon Scale ArmorDragon Scale Armor
power_of_the_dragon_father_dragon_scale_shield_artifactDragon Scale ShieldDragon Scale Shield
power_of_the_dragon_father_dragon_wing_artifactDragon Wing TabardDragon Wing Tabard
power_of_the_dragon_father_dragonbone_greaves_artifactDragonbone GreavesDragonbone Greaves
power_of_the_dragon_father_piercing_eye_of_a_dragon_artifactQuiet Eye of a DragonQuiet Eye of a Dragon
power_of_the_dragon_father_red_dragon_flame_tongue_artifactRed Dragon Flame TongueRed Dragon Flame Tongue
power_of_the_dragon_father_slithering_sash_artifactSlithering SashSlithering Sash
resonant_sphere_orb_of_daylight_artifactOrb of DawnOrb of Dawn
resonant_sphere_orb_of_eternity_artifactOrb of EternityOrb of Eternity
resonant_sphere_orb_of_twilight_artifactOrb of TwilightOrb of Twilight
resonant_sphere_primal_orb_artifactPrimordial OrbPrimordial Orb
ring_of_neutrality_artifactRing of NeutralityRing of Neutrality
rule_of_shadow_liquid_silence_artifactLiquid SilenceLiquid Silence
rule_of_shadow_nostrias_gaze_artifactAmelchia's LawAmelchia's Law
rule_of_shadow_the_truthmaker_artifactTruthmakerTruthmaker
rule_of_shadow_the_truthseeker_artifactTruthseekerTruthseeker
runestone_shards_artifactRunestone ShardsRunestone Shards
scholars_wisdom_scholars_oberegus_artifactScholar's AmuletScholar's Amulet
scholars_wisdom_scholars_tiara_artifactScholar's TiaraScholar's Tiara
seal_of_silence_artifactSeal of SilenceSeal of Silence
seven_league_boots_artifactSeven-League BootsSeven-League Boots
shackles_of_war_artifactShackles of WarShackles of War
shadow_of_death_bone_boots_artifactBone BootsBone Boots
shadow_of_death_cursed_armor_artifactRibcage ArmorRibcage Armor
shadow_of_death_dark_hatchet_artifactDark HatchetDark Hatchet
shadow_of_death_second_shade_artifactSecond ShadeSecond Shade
shamaniac_soul_clutching_ring_artifactClenching RingClenching Ring
shamaniac_soul_gemwood_mask_artifactSirin MaskSirin Mask
shamaniac_soul_iridescent_cloak_artifactIridescent CloakIridescent Cloak
shamaniac_soul_shaman_staff_artifactShaman StaffShaman Staff
shoddy_shield_artifactShoddy ShieldShoddy Shield
sixth_finger_artifactSixth FingerSixth Finger
soulless_sash_artifactSoulless SashSoulless Sash
soulscaller_ring_artifactSoulcaller RingSoulcaller Ring
spellbinders_hat_artifactSpellbinder's HatSpellbinder's Hat
spells_in_a_bottle_artifactSpells in BottlesSpells in Bottles
spyglass_artifactSpyglassSpyglass
swamp_boots_artifactSwamp BootsSwamp Boots
tactical_guide_artifactTactical GuideTactical Guide
tarq_of_the_rampaging_ogre_artifactShield of the Rampaging OgreShield of the Rampaging Ogre
tranquility_brightmind_tiara_artifactMirror TiaraMirror Tiara
tranquility_ring_of_serenity_artifactShard of SerenityShard of Serenity
tunic_of_the_cyclops_king_artifactTunic of the Cyclops KingTunic of the Cyclops King
two_faced_mask_artifactTwo-faced MaskTwo-faced Mask
ukhtabar_seal_tabar_seal_artifactTabar Signet-RingTabar Signet-Ring
ukhtabar_seal_ukh_seal_artifactUkh SignetUkh Signet
voodoosh_doll_artifactVoodoo DollVoodoo Doll
wanderers_way_backpack_artifactBackpackBackpack
wanderers_way_boots_of_travel_artifactBoots of TravelBoots of Travel
warlord_boots_artifactWarlord BootsWarlord Boots
warriors_strength_warriors_belt_artifactWarrior's BeltWarrior's Belt
warriors_strength_warriors_oberegus_artifactWarrior's AmuletWarrior's Amulet
wizards_might_wizards_cloak_artifactWizard's CloakWizard's Cloak
wizards_might_wizards_oberegus_artifactWizard's AmuletWizard's Amulet

-- 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'
}

-- 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 .. '[[Data:WikiTranslations/' .. lang .. '#' .. key .. '|💬]]'
        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, 'T.name = name');
    table.insert(fields, 'T.language = language');

    -- where:
    local where = {}
    table.insert(where, '(A.id NOT LIKE "%_magic_%" OR A.id LIKE "%_magic_haste")')
    table.insert(where, 'T.type = "artifact"')
    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 all Cargo results into a single dictionary:
------------------------------------------------------------------------------------------------------------------------
local function consolidate(lang, results)
    local hub = {}
    for _, row in ipairs(results) do
        local id = row.id
        local entry = hub[id]
        if not entry then
            entry = {}
            entry.id = id or ''
            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 ''
        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

------------------------------------------------------------------------------------------------------------------------
local function createHeader(htmlTable)
    local tr = htmlTable:tag('tr')
    addTh(tr, 'id'):attr('colspan', 2)
    addTh(tr, 'nameX'):attr('colspan', 2)
end

------------------------------------------------------------------------------------------------------------------------
local function createBody(htmlTable, list)
    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, item.nameEn)
        addTd(tr, item.name)
    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)
    createBody(htmlTable, list)

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

return p