Editing Module:StreetBrawlItems

Jump to navigation Jump to search
Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision Your text
Line 7: Line 7:
-- Slot display order: Weapon -> Vitality (Armor) -> Spirit (Tech)
-- Slot display order: Weapon -> Vitality (Armor) -> Spirit (Tech)
local SLOT_RANK = { Weapon = 1, Armor = 2, Tech = 3 }
local SLOT_RANK = { Weapon = 1, Armor = 2, Tech = 3 }
-- Card scale passed to ItemBox.
-- Default card scale passed to ItemBox (tier columns and counter cards).
local CARD_SIZE = "0.7"
local CARD_SIZE = "0.75"


local NAME_TO_KEY = {}
local NAME_TO_KEY, KEY_TO_NAME, RELEASED = {}, {}, {}
for key, h in pairs(heroes) do
for key, h in pairs(heroes) do
if type(h) == "table" and h.Name then
if type(h) == "table" and h.Name then
KEY_TO_NAME[key] = h.Name
NAME_TO_KEY[mw.ustring.lower(h.Name)] = key
NAME_TO_KEY[mw.ustring.lower(h.Name)] = key
if not h.InDevelopment and not h.IsDisabled then RELEASED[key] = true end
end
end
end
end
Line 52: Line 54:
end
end


local function render_item(frame, code)
local function render_item(frame, code, style, size)
local name = iname(code); if not name then return nil end
local name = iname(code); if not name then return nil end
-- These hero pages place hundreds of cards at once, so the cards render in
if style == "icon" then return frame:expandTemplate{title = "ItemIcon", args = {name}} end
-- lowGraphics mode: ItemBox swaps its paper texture for a single cacheable
local args = { name, size = size or CARD_SIZE }
-- overlay, which keeps scrolling smooth. See [[Template:ItemBox]].
local args = { name, size = CARD_SIZE, lowGraphics = "true" }
-- Legendary (tier 5) cards omit the tier badge; it is redundant in the Legendary tier.
-- Legendary (tier 5) cards omit the tier badge; it is redundant in the Legendary tier.
if itier(code) ~= 5 then args.showTierTag = "true" end
if itier(code) ~= 5 then args.showTierTag = "true" end
return frame:expandTemplate{title = "ItemBox", args = args}
return frame:expandTemplate{title = "ItemBox", args = args}
end
local function render_hero(frame, key)
local name = KEY_TO_NAME[key]; if not name then return nil end
return frame:expandTemplate{title = "HeroIcon", args = {name}}
end
end


Line 67: Line 71:
if #parts == 0 then return "" end
if #parts == 0 then return "" end
return '<div class="' .. class .. '">' .. table.concat(parts) .. '</div>'
return '<div class="' .. class .. '">' .. table.concat(parts) .. '</div>'
end
-- A tier/section heading: a plain div carrying the skin's own heading wrapper
-- classes, so it inherits real heading styling while staying out of the table
-- of contents (and can be hidden inside the gate).
local function heading_div(label)
return '<div class="mw-heading mw-heading4 sb-tier-head">' .. label .. '</div>'
end
end


local function hero_sets(hkey)
local function hero_sets(hkey)
local favored, unfavored, counter = {}, {}, {}
local favored, unfavored, special, counter = {}, {}, {}, {}
for _, o in ipairs(sb.Outliers) do
for _, o in ipairs(sb.Outliers) do
if o.Hero == hkey then
if o.Hero == hkey then
if o.Bucket == "Good" then favored[o.Item] = true
if o.Bucket == "Good" then favored[o.Item] = true; special[o.Item] = true
elseif type(o.Weight) == "number" and o.Weight < 1 then unfavored[o.Item] = true end
elseif type(o.Weight) == "number" and o.Weight < 1 then unfavored[o.Item] = true; special[o.Item] = true end
if o.Counter ~= nil then counter[#counter + 1] = o.Item end
if o.Counter ~= nil then counter[#counter + 1] = o.Item end
end
end
end
end
return favored, unfavored, counter
return favored, unfavored, special, counter
end
end


-- Returns sorted high (favored), average (pool), low (unfavored) item-code lists for a tier.
-- Returns sorted high (favored), normal (pool), low (unfavored) item-code lists for a tier.
local function collect(hkey, tier)
local function collect(hkey, tier)
local favored, unfavored = hero_sets(hkey)
local favored, unfavored = hero_sets(hkey)
local high, average, low = {}, {}, {}
local high, normal, low = {}, {}, {}
for _, c in ipairs(sb.AvailableItems) do
for _, c in ipairs(sb.AvailableItems) do
if iok(c) and (tier == nil or itier(c) == tier) then
if iok(c) and (tier == nil or itier(c) == tier) then
if favored[c] then high[#high + 1] = c
if favored[c] then high[#high + 1] = c
elseif unfavored[c] then low[#low + 1] = c
elseif unfavored[c] then low[#low + 1] = c
else average[#average + 1] = c end
else normal[#normal + 1] = c end
end
end
end
end
table.sort(high, item_less)
table.sort(high, item_less)
table.sort(average, item_less)
table.sort(normal, item_less)
table.sort(low, item_less)
table.sort(low, item_less)
return high, average, low
return high, normal, low
end
 
local function item_code(input)
input = mw.text.trim(input or "")
if input == "" then return nil end
if items[input] then return input end
for k, v in pairs(items) do
if type(v) == "table" and v.Name == input and v.IsDisabled ~= true then return k end
end
for k, v in pairs(items) do
if type(v) == "table" and v.Name == input then return k end
end
return nil
end
end


-- Builds one tier as conditional columns:
-- Builds one tier as conditional columns:
--  High chance (favored) takes 35%, the average column fills the rest.
--  High chance (favored) 35% and Middle chance (pool) fill the rest.
--  Low chance (unfavored) is dropped when empty; a narrow column on the right when
--  Low chance (unfavored) is dropped when empty; a narrow one-card column on the right
--  High is present; a fit-content column on the right when High is absent.
--  when High is present; a fit-content column on the right when High is absent.
local function tier_columns(frame, hkey, tier, hi, avg, lo)
local function tier_columns(frame, hkey, tier, style, size, theme, hi, mid, lo)
local high, average, low = collect(hkey, tier)
local high, normal, low = collect(hkey, tier)
local body_class = (style == "card") and "sb-col-body sb-col-cards" or "sb-col-body"
local sep = (style == "card") and "" or "<br>"


local function col(codes, cls, head)
local function col(codes, cls, head)
local parts = {}
local parts = {}
for _, c in ipairs(codes) do local r = render_item(frame, c); if r then parts[#parts + 1] = r end end
for _, c in ipairs(codes) do local r = render_item(frame, c, style, size); if r then parts[#parts + 1] = r end end
return '<div class="sb-col ' .. cls .. '">'
return '<div class="sb-col ' .. cls .. '">'
.. '<div class="sb-col-head">' .. head .. '</div>'
.. '<div class="sb-col-head">' .. head .. '</div>'
.. '<div class="sb-col-body sb-col-cards">' .. table.concat(parts) .. '</div>'
.. '<div class="' .. body_class .. '">' .. table.concat(parts, sep) .. '</div>'
.. '</div>'
.. '</div>'
end
end
local cls = "sb-tier"
if theme ~= "" then cls = cls .. " " .. theme end


local out = {}
local out = {}
Line 125: Line 140:
out[#out + 1] = col(high, "sb-col-high sb-w-high", hi)
out[#out + 1] = col(high, "sb-col-high sb-w-high", hi)
end
end
out[#out + 1] = col(average, "sb-col-average sb-w-fill", avg)
out[#out + 1] = col(normal, "sb-col-normal sb-w-fill", mid)
if #low > 0 then
if #low > 0 then
local low_w = (#high > 0) and "sb-low-narrow" or "sb-low-wide"
local low_w = (#high > 0) and "sb-low-narrow" or "sb-low-wide"
out[#out + 1] = col(low, "sb-col-low " .. low_w, lo)
out[#out + 1] = col(low, "sb-col-low " .. low_w, lo)
end
end
return '<div class="sb-tier">' .. table.concat(out) .. '</div>'
return '<div class="' .. cls .. '">' .. table.concat(out) .. '</div>'
end
end


-- {{#invoke:StreetBrawlItems|tiers|HERO|gate=ID|high=..|average=..|low=..|tier1=..|...|tier5=..}}
-- {{#invoke:StreetBrawlItems|hero|HERO|GROUP|TIER|label=..|collapse=yes|style=card|icon}}
-- All five tiers under styled (non-TOC) headings. All display text is supplied by the
-- Legacy: superseded by p.tier, kept for reference.
-- caller. With gate=ID, the Tier 1 heading and everything after it is wrapped in an open
function p.hero(frame)
-- <div id=ID class="sb-gate">, whose inner <div class="sb-gate-body"> the caller must
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
-- close after any trailing content. The id sits on the outer wrapper so following the
local group = mw.text.trim(frame.args[2] or "")
-- anchor lands on the Tier 1 heading rather than the columns below it.
local tier = tonumber(frame.args[3])
local style = frame.args.style
if not style or style == "" then style = (group == "common") and "icon" or "card" end
local label = frame.args.label or ""
 
local favored, unfavored, special = hero_sets(hkey)
local pred
if group == "favored" then pred = function(c) return favored[c] end
elseif group == "unfavored" then pred = function(c) return unfavored[c] end
elseif group == "common" then pred = function(c) return not special[c] end
else return "" end
 
local codes = {}
for _, c in ipairs(sb.AvailableItems) do
if iok(c) and (tier == nil or itier(c) == tier) and pred(c) then codes[#codes + 1] = c end
end
table.sort(codes, item_less)
 
local parts = {}
for _, c in ipairs(codes) do local r = render_item(frame, c, style); if r then parts[#parts + 1] = r end end
if #parts == 0 then return "" end
 
local row_class = (style == "icon") and "sb-icons" or "sb-cards"
local out = '<div class="sb-group">'
if label ~= "" then out = out .. '<div class="sb-label">' .. label .. '</div>' end
return out .. classdiv(parts, row_class) .. '</div>'
end
 
-- {{#invoke:StreetBrawlItems|tier|HERO|TIER|style=icon|card|size=..|theme=..|layout=grid|high=..|middle=..|low=..}}
function p.tier(frame)
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
local tier = tonumber(frame.args[2])
local style = (frame.args.style == "card") and "card" or "icon"
local size = frame.args.size
local theme = frame.args.theme or ""
local hi = frame.args.high or "High chance"
local mid = frame.args.middle or "Average chance"
local lo = frame.args.low or "Low chance"
 
if frame.args.layout == "grid" then
local high, normal, low = collect(hkey, tier)
local function chips(codes, chance)
local out = {}
for _, c in ipairs(codes) do
local r = render_item(frame, c, "card", size)
if r then out[#out + 1] = '<span class="sb-chip ' .. chance .. '">' .. r .. '</span>' end
end
return table.concat(out)
end
return '<div class="sb-grid">'
.. chips(high, "sb-chip-high")
.. chips(normal, "sb-chip-normal")
.. chips(low, "sb-chip-low")
.. '</div>'
end
 
return tier_columns(frame, hkey, tier, style, size, theme, hi, mid, lo)
end
 
-- {{#invoke:StreetBrawlItems|tiers|HERO|style=..|size=..|theme=..}} -> all five tiers, each with a heading.
function p.tiers(frame)
function p.tiers(frame)
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
local hi = frame.args.high or ""
local style = (frame.args.style == "card") and "card" or "icon"
local avg = frame.args.average or ""
local size = frame.args.size
local lo = frame.args.low or ""
local theme = frame.args.theme or ""
local gate = frame.args.gate
local hi = frame.args.high or "High chance"
if gate == "" then gate = nil end
local mid = frame.args.middle or "Average chance"
local lo = frame.args.low or "Low chance"


local labels = { "Tier 1", "Tier 2", "Tier 3", "Tier 4", "Legendary" }
local out = {}
local out = {}
for t = 1, 5 do
for t = 1, 5 do
local head = heading_div(frame.args["tier" .. t] or "")
out[#out + 1] = "=== " .. labels[t] .. " ===\n" .. tier_columns(frame, hkey, t, style, size, theme, hi, mid, lo)
local cols = tier_columns(frame, hkey, t, hi, avg, lo)
if t == 1 and gate then
out[#out + 1] = '<div id="' .. gate .. '" class="sb-gate">\n'
.. head .. "\n"
.. '<div class="sb-gate-body">\n'
.. cols
else
out[#out + 1] = head .. "\n" .. cols
end
end
end
return table.concat(out, "\n\n")
return table.concat(out, "\n\n")
Line 164: Line 231:


-- {{#invoke:StreetBrawlItems|hero_counter|HERO|heading=..|note=..}}
-- {{#invoke:StreetBrawlItems|hero_counter|HERO|heading=..|note=..}}
-- The whole counter block (heading + note + cards), or "" when the hero has none.
function p.hero_counter(frame)
function p.hero_counter(frame)
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
local hkey = hero_key(frame.args[1]); if not hkey then return "" end
local _, _, counter = hero_sets(hkey)
local _, _, _, counter = hero_sets(hkey)


local codes = {}
local codes = {}
Line 175: Line 241:


local parts = {}
local parts = {}
for _, c in ipairs(codes) do local r = render_item(frame, c); if r then parts[#parts + 1] = r end end
for _, c in ipairs(codes) do local r = render_item(frame, c, "card"); if r then parts[#parts + 1] = r end end


local out = {}
local out = {}
local heading = frame.args.heading
local heading = frame.args.heading
if heading and heading ~= "" then out[#out + 1] = heading_div(heading) end
if heading and heading ~= "" then out[#out + 1] = "=== " .. heading .. " ===" end
local note = frame.args.note
local note = frame.args.note
if note and note ~= "" then out[#out + 1] = "''" .. note .. "''" end
if note and note ~= "" then out[#out + 1] = "''" .. note .. "''" end
Line 186: Line 252:
end
end


-- {{#invoke:StreetBrawlItems|counters_table}}
-- {{#invoke:StreetBrawlItems|item|ITEM|GROUP|label=..|note=..}}
-- Every hero that has counter items, one row each, sorted by hero name. Items
function p.item(frame)
-- within a row are listed alphabetically. Built as HTML rather than pipe-table
local code = item_code(frame.args[1]); if not code then return "" end
-- markup so the invoke does not have to sit at the start of a line.
local group = mw.text.trim(frame.args[2] or "")
function p.counters_table(frame)
 
local by_hero, rows = {}, {}
local fav, unf, ctr = {}, {}, {}
for _, o in ipairs(sb.Outliers) do
for _, o in ipairs(sb.Outliers) do
if o.Counter ~= nil and iok(o.Item) then
if o.Item == code and RELEASED[o.Hero] then
local hero = heroes[o.Hero]
if o.Bucket == "Good" then fav[#fav + 1] = o.Hero
if hero and hero.Name then
elseif type(o.Weight) == "number" and o.Weight < 1 then unf[#unf + 1] = o.Hero end
local row = by_hero[o.Hero]
if o.Counter ~= nil then ctr[#ctr + 1] = o.Hero end
if not row then
row = { name = hero.Name, items = {}, seen = {} }
by_hero[o.Hero] = row
rows[#rows + 1] = row
end
-- Guard against a hero/item pair being listed twice.
if not row.seen[o.Item] then
row.seen[o.Item] = true
row.items[#row.items + 1] = iname(o.Item)
end
end
end
end
end
end
if #rows == 0 then return "" end
local list = (group == "favored" and fav) or (group == "unfavored" and unf) or (group == "counter" and ctr)
table.sort(rows, function(a, b) return a.name < b.name end)
if not list then return "" end
table.sort(list, function(a, b) return (KEY_TO_NAME[a] or a) < (KEY_TO_NAME[b] or b) end)
 
local parts = {}
for _, k in ipairs(list) do local r = render_hero(frame, k); if r then parts[#parts + 1] = r end end
if #parts == 0 then return "" end


local tbl = mw.html.create("table"):addClass("wikitable")
local pre = ""
local head = tbl:tag("tr")
local label = frame.args.label
head:tag("th"):wikitext("Hero")
if label and label ~= "" then pre = pre .. "'''" .. label .. "'''<br>" end
head:tag("th"):wikitext("Items")
local note = frame.args.note
if note and note ~= "" then pre = pre .. "''" .. note .. "''<br>" end
return pre .. classdiv(parts, "sb-icons")
end


for _, row in ipairs(rows) do
-- {{#invoke:StreetBrawlItems|item_in_pool|ITEM}} -> "1" if in the Street Brawl pool, else ""
table.sort(row.items)
function p.item_in_pool(frame)
local icons = {}
local code = item_code(frame.args[1]); if not code then return "" end
for _, n in ipairs(row.items) do
for _, c in ipairs(sb.AvailableItems) do if c == code then return "1" end end
icons[#icons + 1] = frame:expandTemplate{title = "ItemIcon", args = {n}}
return ""
end
local tr = tbl:tag("tr")
tr:tag("td"):wikitext(frame:expandTemplate{title = "HeroIcon", args = {row.name}})
tr:tag("td"):wikitext(table.concat(icons, ", "))
end
return tostring(tbl)
end
end


return p
return p
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template

Page included on this page: