Module:StreetBrawlAbilities: Difference between revisions

Add report() to list Street Brawl ability changes grouped by hero (with help from vergir-bot LLM)
Vergir (talk | contribs)
Add hero_has_changes checker for the Street Brawl hero category (with help from vergir-bot LLM)
 
(3 intermediate revisions by 2 users not shown)
Line 20: Line 20:
if type(card) == "table" and hero and hero.Name and hero.IsDisabled ~= true then
if type(card) == "table" and hero and hero.Name and hero.IsDisabled ~= true then
for slot = 1, 8 do
for slot = 1, 8 do
local ability = card[tostring(slot)]
-- The card's slot keys decode as numbers, so index with one.
local ability = card[slot] or card[tostring(slot)]
if type(ability) == "table" and ability.Key then
if type(ability) == "table" and ability.Key then
map[ability.Key] = { hero = hero.Name, slot = slot, name = ability.Name }
map[ability.Key] = { hero = hero.Name, slot = slot, name = ability.Name }
Line 46: Line 47:
local na, nb = tonumber(a), tonumber(b)
local na, nb = tonumber(a), tonumber(b)
if na and nb then return na < nb end
if na and nb then return na < nb end
return a < b
-- Upgrade tiers arrive as numbers, so never compare a number with a string.
return tostring(a) < tostring(b)
end)
end)
return keys
return keys
Line 55: Line 57:
for _, key in ipairs(sorted_keys(node, top)) do
for _, key in ipairs(sorted_keys(node, top)) do
local value = node[key]
local value = node[key]
local path = prefix and (prefix .. "." .. key) or key
local path = prefix and (prefix .. "." .. key) or tostring(key)
if type(value) == "table" then
if type(value) == "table" then
flatten(value, path, out, false)
flatten(value, path, out, false)
Line 62: Line 64:
end
end
end
end
end
-- Reads a property both ways, returning its Street Brawl value and its normal one.
local function both_values(frame, ability, prop)
local sb  = frame:expandTemplate{ title = "DataProp", args = { ability, prop, "streetbrawl" } }
local base = frame:expandTemplate{ title = "DataProp", args = { ability, prop } }
return tonumber(sb), tonumber(base)
end
end


Line 72: Line 81:
return "* <code>" .. mw.text.nowiki(call) .. "</code> &rarr; '''" .. sb
return "* <code>" .. mw.text.nowiki(call) .. "</code> &rarr; '''" .. sb
.. "''' ''(default " .. base .. ")''"
.. "''' ''(default " .. base .. ")''"
end
-- True when Street Brawl changes at least one of this hero's abilities. Accepts a
-- hero_* key or the hero's English name, so callers may pass whichever they hold.
function p.hero_has_changes(hero)
if hero == nil or hero == "" then return false end
local record  = mw.loadJsonData(HERO_PAGE)[hero]
local name    = (record and record.Name) or hero
local owners  = build_owner_map()
local changes = mw.loadJsonData(SB_PAGE)["ability-changes"]
for key in pairs(changes) do
local owner = owners[key]
if owner and owner.hero == name then return true end
end
return false
end
-- {{#invoke:StreetBrawlAbilities|hasChanges|HERO}} exposes the same check to wikitext,
-- answering "1" or the empty string so #if can branch on it.
function p.hasChanges(frame)
return p.hero_has_changes(mw.text.trim(frame.args[1] or "")) and "1" or ""
end
-- {{#invoke:StreetBrawlAbilities|change|ABILITY|PROP}} describes how far a property moved
-- in Street Brawl, as "reduced by 45%" or "increased by ~40%".
function p.change(frame)
local ability = mw.text.trim(frame.args[1] or "")
local prop    = mw.text.trim(frame.args[2] or "")
local sb, base = both_values(frame, ability, prop)
-- DataProp answers a failed lookup with a red notice rather than a number.
if not sb or not base or base == 0 then
return '<span style="color:red;">No change for ' .. ability .. '/' .. prop .. '</span>'
end
-- Properties Street Brawl leaves alone fall back to the base value, so two equal
-- numbers mean this property was never in the overlay.
if sb == base then
return '<span style="color:red;">Street Brawl does not change ' .. ability .. '/' .. prop .. '</span>'
end
-- Purely a comparison of the two numbers; whether that helps or hurts the hero is
-- for the surrounding prose to say.
local direction = sb > base and "increased" or "reduced"
local percent = math.abs(sb - base) / math.abs(base) * 100
-- Rounded to the nearest 5% so the prose reads as a round figure; when that rounding
-- moves the number by more than 1.5 points, "~" marks it as approximate.
local rounded = math.floor(percent / 5 + 0.5) * 5
local approx = math.abs(percent - rounded) > 1.5 and "~" or ""
return direction .. " by " .. approx .. string.format("%.0f", rounded) .. "%"
end
end