Module:AbilityHints: Difference between revisionsGive feedback
Jump to navigation
Jump to search
Revert groups/combinations: reactivebarrier and indomitable are plain separate icons again (with help from vergir-bot LLM) |
Use the standard interacts text for the enhanced state (with help from vergir-bot LLM) |
||
| (22 intermediate revisions by 6 users not shown) | |||
| Line 1: | Line 1: | ||
-- | -- Small item icons on ability cards showing how an ability interacts with items (dispellable, reduced, blocked, etc.). | ||
-- Used by Template:AbilitySection. Styles are there too. | |||
-- | |||
-- | -- label_dict_key names the [[Data:Dictionary]] entry holding the tooltip text. It is | ||
-- resolved at render time rather than here, so the tooltip follows the page language | |||
-- and so no frame is needed while the module is still loading. | |||
local CONFIG = { | |||
{ list = "melee", file = "Melee Lifesteal.png", label_dict_key = "AbilityHintsMelee" }, | |||
{ list = "dontbreakstealth", file = "Veil Walker.png", label_dict_key = "AbilityHintsDontBreakStealth" }, | |||
{ list = "movementbased", file = "Slowing Hex.png", label_dict_key = "AbilityHintsMovementBased" }, | |||
{ list = "debuffresist", file = "Debuff Reducer.png", label_dict_key = "AbilityHintsDebuffResist" }, | |||
{ list = "heal", file = "Healing Booster.png", label_dict_key = "AbilityHintsHeal" }, | |||
{ list = "healingtempo", file = "Healing Tempo.png", label_dict_key = "AbilityHintsHealingTempo" }, | |||
{ list = "reactivebarrier", file = "Reactive Barrier.png", label_dict_key = "AbilityHintsReactiveBarrier" }, | |||
{ list = "dispelmagic", file = "Dispel Magic.png", label_dict_key = "AbilityHintsDispelMagic" }, | |||
{ list = "indomitable", file = "Indomitable.png", label_dict_key = "AbilityHintsIndomitable" }, | |||
{ list = "unstoppable", file = "Unstoppable.png", label_dict_key = "AbilityHintsUnstoppable" }, | |||
{ list = "platedarmor", file = "Plated Armor.png", label_dict_key = "AbilityHintsPlatedArmor" }, | |||
{ list = "summons", file = "Monster Rounds.png", label_dict_key = "AbilityHintsSummons" }, | |||
} | |||
-- Tooltip wording for a manually placed icon, keyed by its iconbox state. Each entry | |||
-- takes the item title as {{{1}}}, so translations can put the object where their | |||
-- grammar wants it rather than always after the verb. The enhanced state has no entry | |||
-- of its own: the glow already marks it, so it falls through to the normal wording. | |||
local STATE_DICT_KEYS = { | |||
normal = "AbilityHintsInteracts", | |||
disabled = "AbilityHintsInteractsNot", | |||
partial = "AbilityHintsInteractsPartial", | |||
} | |||
local AbilityTable = require("Module:AbilityTable") | local AbilityTable = require("Module:AbilityTable") | ||
local | local dictionary = require("Module:Dictionary") | ||
local | local resource_lookup = mw.loadJsonData("Data:ResourceLookup.json") | ||
local item_data = mw.loadJsonData("Data:ItemData.json") | |||
local p = {} | local p = {} | ||
-- Display order | -- Display order: item type (Weapon => Vitality => Spirit), then cost, then name. | ||
local function sort_key(file) | |||
local | local base = mw.ustring.lower((file:gsub('%.%w+$', ''))) | ||
local entry = resource_lookup[base] | |||
local item = (entry ~= nil and entry.type == 'item') and item_data[entry.key] or nil | |||
if item == nil then | |||
return { 99, math.huge, base } | |||
end | |||
{ | local slot = item["Slot"] | ||
local slot_rank = (slot == "Weapon" and 1) or (slot == "Armor" and 2) or (slot == "Tech" and 3) or 98 | |||
return { | |||
slot_rank, | |||
tonumber(item["Cost"]) or math.huge, | |||
mw.ustring.lower(item["Name"] or base), | |||
} | |||
end | |||
local function compare(a, b) | |||
for i = 1, 3 do | |||
if a.sort[i] ~= b.sort[i] then return a.sort[i] < b.sort[i] end | |||
end | |||
return false | |||
end | |||
-- partial: split the icon so the top-left half is grayscale (mirrors the iconbox-partial box icon). | |||
-- An empty link makes the icon non-clickable; automatic hints link from their tooltip text instead. | |||
local function icon_img(file, link, partial) | |||
link = link or '' | |||
if partial then | |||
return '<span class="ability-hint-icon"><span class="ability-hint-split">' | |||
.. '[[File:' .. file .. '|24px|link=' .. link .. ']]' | |||
.. '<span class="ability-hint-split-gray">[[File:' .. file .. '|24px|link=]]</span>' | |||
.. '</span></span>' | |||
end | |||
return '<span class="ability-hint-icon">[[File:' .. file .. '|24px|link=' .. link .. ']]</span>' | |||
end | |||
local function hint_icon(def) | |||
return '<span class="ability-hint">' .. icon_img(def.file) | |||
local function | .. '<span class="ability-hint-tip">' .. dictionary.translate(def.label_dict_key) .. '</span></span>' | ||
end | end | ||
-- | local function manual_icon(m) | ||
local | local cls = 'ability-hint' | ||
return '<span class=" | local dict_key = STATE_DICT_KEYS.normal | ||
local partial = false | |||
if m.state == 'disabled' then | |||
cls = cls .. ' ability-hint--disabled' | |||
dict_key = STATE_DICT_KEYS.disabled | |||
elseif m.state == 'partial' then | |||
dict_key = STATE_DICT_KEYS.partial | |||
partial = true | |||
elseif m.state == 'enhanced' then | |||
cls = cls .. ' ability-hint--enhanced' | |||
end | |||
local tip = dictionary.translate(dict_key, nil, nil, { m.title }) | |||
.. '<br>' .. dictionary.translate('AbilityHintsClickReveal') | |||
return '<span class="' .. cls .. '">' .. icon_img(m.file, '#' .. m.anchor, partial) | |||
.. '<span class="ability-hint-tip">' .. tip .. '</span></span>' | .. '<span class="ability-hint-tip">' .. tip .. '</span></span>' | ||
end | end | ||
function p.get_icons(ability_key, ability_num, manual) | |||
manual = manual or {} | |||
local manual_by_file = {} | |||
function p.get_icons(ability_key, ability_num) | for _, m in ipairs(manual) do | ||
local | manual_by_file[mw.ustring.lower(m.file)] = m | ||
end | |||
local entries = {} | |||
local placed = {} | |||
local num = tonumber(ability_num) | local num = tonumber(ability_num) | ||
for _, def in ipairs(CONFIG) do | |||
if AbilityTable.is_member(def.list, ability_key, num) then | |||
local key = mw.ustring.lower(def.file) | |||
local m = manual_by_file[key] | |||
if m ~= nil then | |||
table.insert(entries, { file = m.file, html = manual_icon(m) }) | |||
placed[key] = true | |||
else | |||
table.insert(entries, { file = def.file, html = hint_icon(def) }) | |||
end | |||
end | |||
end | |||
for _, m in ipairs(manual) do | |||
for _, | if not placed[mw.ustring.lower(m.file)] then | ||
if | table.insert(entries, { file = m.file, html = manual_icon(m) }) | ||
table.insert( | |||
end | end | ||
end | end | ||
if # | if #entries == 0 then return '' end | ||
for _, e in ipairs(entries) do e.sort = sort_key(e.file) end | |||
table.sort(entries, compare) | |||
local icons = {} | |||
for _, e in ipairs(entries) do table.insert(icons, e.html) end | |||
return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>' | return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>' | ||
end | end | ||
return p | return p | ||
Latest revision as of 11:29, 2 August 2026
Overview
[edit source]Renders a small strip of item icons showing how an ability interacts with items and used by Module:AbilitySection. Each icon displays a configured image and has a hover tooltip.
Hints can be "automatic" and "manual".
- Automatic come from Module:AbilityTable/Lists. If an ability is part of 'debuffresist' list, then it will show automatic debuff resist hint. List of enabled automatic hints is configured through CONFIG in this module. Clicking on an icon does nothing, however tooltip often will have a link to relevant item/mechanic.
- Manual hints come from
{{AbilityInteraction}}blocks used on AbilitySection. Whenetever an editor describes an interaction using that block a hint will be displayed. Clicking on a hint reveals that hand-written block.
Entry point
[edit source]p.get_icons(ability_key, ability_num)
[edit source]Returns the rail HTML for one ability, or an empty string when the ability matches no lists.
Configuration
[edit source]CONFIG
[edit source]List of the icons the rail can show. Order within CONFIG does not affect the rendered output — see Display order. Each entry:
| Field | Description |
|---|---|
list |
List name in Module:AbilityTable/Lists whose membership triggers the icon. |
file |
Image file to display, e.g. Reactive Barrier.png. Also determines the icon's position in the rail.
|
tip |
Hover tooltip text. May contain wikilinks and simple HTML (<br>, <b>).
|
To add an icon, add a CONFIG row: pick the triggering list, the display file, and the tip. To re-scope which abilities an icon covers, edit the list in Module:AbilityTable/Lists.
-- Small item icons on ability cards showing how an ability interacts with items (dispellable, reduced, blocked, etc.).
-- Used by Template:AbilitySection. Styles are there too.
-- label_dict_key names the [[Data:Dictionary]] entry holding the tooltip text. It is
-- resolved at render time rather than here, so the tooltip follows the page language
-- and so no frame is needed while the module is still loading.
local CONFIG = {
{ list = "melee", file = "Melee Lifesteal.png", label_dict_key = "AbilityHintsMelee" },
{ list = "dontbreakstealth", file = "Veil Walker.png", label_dict_key = "AbilityHintsDontBreakStealth" },
{ list = "movementbased", file = "Slowing Hex.png", label_dict_key = "AbilityHintsMovementBased" },
{ list = "debuffresist", file = "Debuff Reducer.png", label_dict_key = "AbilityHintsDebuffResist" },
{ list = "heal", file = "Healing Booster.png", label_dict_key = "AbilityHintsHeal" },
{ list = "healingtempo", file = "Healing Tempo.png", label_dict_key = "AbilityHintsHealingTempo" },
{ list = "reactivebarrier", file = "Reactive Barrier.png", label_dict_key = "AbilityHintsReactiveBarrier" },
{ list = "dispelmagic", file = "Dispel Magic.png", label_dict_key = "AbilityHintsDispelMagic" },
{ list = "indomitable", file = "Indomitable.png", label_dict_key = "AbilityHintsIndomitable" },
{ list = "unstoppable", file = "Unstoppable.png", label_dict_key = "AbilityHintsUnstoppable" },
{ list = "platedarmor", file = "Plated Armor.png", label_dict_key = "AbilityHintsPlatedArmor" },
{ list = "summons", file = "Monster Rounds.png", label_dict_key = "AbilityHintsSummons" },
}
-- Tooltip wording for a manually placed icon, keyed by its iconbox state. Each entry
-- takes the item title as {{{1}}}, so translations can put the object where their
-- grammar wants it rather than always after the verb. The enhanced state has no entry
-- of its own: the glow already marks it, so it falls through to the normal wording.
local STATE_DICT_KEYS = {
normal = "AbilityHintsInteracts",
disabled = "AbilityHintsInteractsNot",
partial = "AbilityHintsInteractsPartial",
}
local AbilityTable = require("Module:AbilityTable")
local dictionary = require("Module:Dictionary")
local resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")
local item_data = mw.loadJsonData("Data:ItemData.json")
local p = {}
-- Display order: item type (Weapon => Vitality => Spirit), then cost, then name.
local function sort_key(file)
local base = mw.ustring.lower((file:gsub('%.%w+$', '')))
local entry = resource_lookup[base]
local item = (entry ~= nil and entry.type == 'item') and item_data[entry.key] or nil
if item == nil then
return { 99, math.huge, base }
end
local slot = item["Slot"]
local slot_rank = (slot == "Weapon" and 1) or (slot == "Armor" and 2) or (slot == "Tech" and 3) or 98
return {
slot_rank,
tonumber(item["Cost"]) or math.huge,
mw.ustring.lower(item["Name"] or base),
}
end
local function compare(a, b)
for i = 1, 3 do
if a.sort[i] ~= b.sort[i] then return a.sort[i] < b.sort[i] end
end
return false
end
-- partial: split the icon so the top-left half is grayscale (mirrors the iconbox-partial box icon).
-- An empty link makes the icon non-clickable; automatic hints link from their tooltip text instead.
local function icon_img(file, link, partial)
link = link or ''
if partial then
return '<span class="ability-hint-icon"><span class="ability-hint-split">'
.. '[[File:' .. file .. '|24px|link=' .. link .. ']]'
.. '<span class="ability-hint-split-gray">[[File:' .. file .. '|24px|link=]]</span>'
.. '</span></span>'
end
return '<span class="ability-hint-icon">[[File:' .. file .. '|24px|link=' .. link .. ']]</span>'
end
local function hint_icon(def)
return '<span class="ability-hint">' .. icon_img(def.file)
.. '<span class="ability-hint-tip">' .. dictionary.translate(def.label_dict_key) .. '</span></span>'
end
local function manual_icon(m)
local cls = 'ability-hint'
local dict_key = STATE_DICT_KEYS.normal
local partial = false
if m.state == 'disabled' then
cls = cls .. ' ability-hint--disabled'
dict_key = STATE_DICT_KEYS.disabled
elseif m.state == 'partial' then
dict_key = STATE_DICT_KEYS.partial
partial = true
elseif m.state == 'enhanced' then
cls = cls .. ' ability-hint--enhanced'
end
local tip = dictionary.translate(dict_key, nil, nil, { m.title })
.. '<br>' .. dictionary.translate('AbilityHintsClickReveal')
return '<span class="' .. cls .. '">' .. icon_img(m.file, '#' .. m.anchor, partial)
.. '<span class="ability-hint-tip">' .. tip .. '</span></span>'
end
function p.get_icons(ability_key, ability_num, manual)
manual = manual or {}
local manual_by_file = {}
for _, m in ipairs(manual) do
manual_by_file[mw.ustring.lower(m.file)] = m
end
local entries = {}
local placed = {}
local num = tonumber(ability_num)
for _, def in ipairs(CONFIG) do
if AbilityTable.is_member(def.list, ability_key, num) then
local key = mw.ustring.lower(def.file)
local m = manual_by_file[key]
if m ~= nil then
table.insert(entries, { file = m.file, html = manual_icon(m) })
placed[key] = true
else
table.insert(entries, { file = def.file, html = hint_icon(def) })
end
end
end
for _, m in ipairs(manual) do
if not placed[mw.ustring.lower(m.file)] then
table.insert(entries, { file = m.file, html = manual_icon(m) })
end
end
if #entries == 0 then return '' end
for _, e in ipairs(entries) do e.sort = sort_key(e.file) end
table.sort(entries, compare)
local icons = {}
for _, e in ipairs(entries) do table.insert(icons, e.html) end
return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>'
end
return p