| Latest revision |
Your text |
| 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 |
| -- The card's slot keys decode as numbers, so index with one.
| | local ability = card[tostring(slot)] |
| 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 47: |
Line 46: |
| 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 |
| -- Upgrade tiers arrive as numbers, so never compare a number with a string.
| | return a < b |
| return tostring(a) < tostring(b) | |
| end) | | end) |
| return keys | | return keys |
| Line 57: |
Line 55: |
| 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 tostring(key) | | local path = prefix and (prefix .. "." .. key) or key |
| if type(value) == "table" then | | if type(value) == "table" then |
| flatten(value, path, out, false) | | flatten(value, path, out, false) |
| Line 64: |
Line 62: |
| 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 81: |
Line 72: |
| return "* <code>" .. mw.text.nowiki(call) .. "</code> → '''" .. sb | | return "* <code>" .. mw.text.nowiki(call) .. "</code> → '''" .. 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 |
|
| |
|