Editing
Module
:
AbilityTable/ComplexRenderers
Give feedback
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.
Anti-spam check. Do
not
fill this in!
-- Complex cell renderers for AbilityTable. local Lists = require("Module:AbilityTable/Lists") -- ============================================================ -- Shared helpers -- ============================================================ -- Unwraps a value that may be a raw number or a { Value = N } table. local function unwrap_value(v) if type(v) == "number" then return v end if type(v) == "table" then return v["Value"] end return nil end -- Searches Upgrades[] for a field and returns { tier = N, value = V } at its -- first appearance, or nil if the field is absent from all upgrade tiers. local function find_in_upgrades(ability, field) local upgrades = ability["Upgrades"] if type(upgrades) ~= "table" then return nil end for i, tier in ipairs(upgrades) do if type(tier) == "table" and tier[field] ~= nil then return { tier = i, value = unwrap_value(tier[field]) } end end return nil end -- Finds the first non-zero value for any of the given fields, checking base -- then upgrades in order. Returns field, tier (nil = base), absolute value. local function find_first_occurrence(ability, fields) for _, field in ipairs(fields) do local v = unwrap_value(ability[field]) if v and v ~= 0 then return field, nil, math.abs(v) end end local upgrades = ability["Upgrades"] if type(upgrades) == "table" then for i, tier in ipairs(upgrades) do if type(tier) == "table" then for _, field in ipairs(fields) do local v = unwrap_value(tier[field]) if v and v ~= 0 then return field, i, math.abs(v) end end end end end return nil, nil, nil end -- Sums the non-zero values of `fields` within a single record layer (the base -- ability record, or one upgrade tier). Returns nil when none are present. local function sum_fields(layer, fields) local total = nil for _, field in ipairs(fields) do local v = unwrap_value(layer[field]) if v and v ~= 0 then total = (total or 0) + math.abs(v) end end return total end -- Sums the barrier value and Spirit scaling contributed by a single record -- layer (the base ability record, or one upgrade tier). Returns nil when the -- layer grants no barrier at all; a tier that only raises the scaling still -- counts, so "+0 value, +1.0 scaling" upgrades are not lost. local function sum_barrier(layer, fields) local value, scale, found = 0, 0, false for _, field in ipairs(fields) do local entry = layer[field] if entry ~= nil then local v = unwrap_value(entry) or 0 local s = 0 if type(entry) == "table" and type(entry["Scale"]) == "table" then s = entry["Scale"]["Value"] or 0 end if v ~= 0 or s ~= 0 then found = true end value = value + v scale = scale + s end end if not found then return nil end return value, scale end -- Pads a whole-number scaling out to one decimal, so a running total of 2 -- reads "2.0" next to its "1.5" neighbours instead of "2". Values that already -- carry decimals are left alone, which keeps precision on things like 0.75. local function format_scale(scale) local text = tostring(scale) if not text:find(".", 1, true) then text = text .. ".0" end return text end -- Formats one barrier step. Spirit scaling goes through the compact {{Ss}} -- form, expanded via the frame the surrounding #invoke is already running -- under: module return values are not re-expanded, so a literal "{{Ss|0.8}}" -- would reach the page as text. The plain fallback covers a nil frame -- (module console). local function format_barrier(value, scale) local out = tostring(value) if scale and scale ~= 0 then local scale_text = format_scale(scale) local frame = mw.getCurrentFrame() if frame then out = out .. " " .. frame:expandTemplate{ title = "Ss", args = { scale_text, compact = "1", show_value = "1" }, } else out = out .. " Γ" .. scale_text end end return out end -- ============================================================ -- Generic renderer for a single numeric stat that can increase -- additively through upgrades. Shows value in a named column -- and generates upgrade notes with running totals. -- Note: auto-generated notes omit trailing periods; the main -- module's ensure_period handles that. -- ============================================================ local function render_upgradable_stat(ability, col_name, fields, suffix) suffix = suffix or "" local cells = {} local notes = {} local first_field, first_tier, first_val = find_first_occurrence(ability, fields) if not first_field then return cells end local cell_str = tostring(first_val) .. suffix if first_tier then cell_str = cell_str .. " (T" .. first_tier .. ")" end cells[col_name] = cell_str local upgrades = ability["Upgrades"] if type(upgrades) == "table" then local running = first_val local seen_first = (first_tier == nil) for i, tier in ipairs(upgrades) do if type(tier) == "table" then if first_tier == i then seen_first = true elseif seen_first then local delta = nil for _, field in ipairs(fields) do local v = unwrap_value(tier[field]) if v and v ~= 0 then delta = math.abs(v); break end end if delta then local total = running + delta table.insert(notes, "T" .. i .. " upgrade increases " .. col_name:lower() .. " by " .. delta .. suffix .. " (total " .. total .. suffix .. ")") running = total end end end end end if #notes > 0 then cells["Notes"] = table.concat(notes, " ") end return cells end -- ============================================================ -- Exported renderers -- ============================================================ local p = {} -- Renders the barrier an ability grants, with its Spirit Power scaling. -- Both the value and the scaling accumulate across upgrades, so every step -- after the first shows the running total: "100 x0.8 β 180 x1.5 (T2)". -- A tier that only improves the scaling still gets its own segment. function p.RenderBarrier(ability) local fields = Lists.lists["barrier"] local segments = {} local value, scale = sum_barrier(ability, fields) if value then table.insert(segments, format_barrier(value, scale)) else value, scale = 0, 0 end local upgrades = ability["Upgrades"] if type(upgrades) == "table" then for i, tier in ipairs(upgrades) do if type(tier) == "table" then local delta_value, delta_scale = sum_barrier(tier, fields) if delta_value then value, scale = value + delta_value, scale + delta_scale table.insert(segments, format_barrier(value, scale) .. " (T" .. i .. ")") end end end end if #segments == 0 then return {} end return { ["Barrier"] = table.concat(segments, " β ") } end -- Renders charge count and time between charges. -- Special case for abilities that gain charges only through upgrades. function p.RenderCharges(ability) local base_charges = unwrap_value(ability["AbilityCharges"]) local base_cooldown = unwrap_value(ability["AbilityCooldownBetweenCharge"]) local has_base = base_charges ~= nil and base_charges > 0 local upgrade_info = find_in_upgrades(ability, "AbilityCharges") local cooldown, upgrade_cooldown if has_base then if type(base_cooldown) == "number" and base_cooldown > 0 then cooldown = base_cooldown else local cd = find_in_upgrades(ability, "AbilityCooldownBetweenCharge") if cd and cd.value and cd.value > 0 then cooldown = cd.value end end else local cd = find_in_upgrades(ability, "AbilityCooldownBetweenCharge") if cd and cd.value and cd.value > 0 then upgrade_cooldown = cd.value end end local cells = {} if has_base then cells["Charges"] = tostring(base_charges) if cooldown then cells["Time Between Charges"] = tostring(cooldown) .. "s" end end local note_parts = {} if upgrade_info then local n = upgrade_info.value or "?" local charge_str = n .. " charge" .. (n ~= 1 and "s" or "") if has_base then table.insert(note_parts, "+" .. charge_str .. " on T" .. upgrade_info.tier .. " upgrade") else local cd_str = upgrade_cooldown and (upgrade_cooldown .. "s") or "unknown" table.insert(note_parts, "Becomes charged on T" .. upgrade_info.tier .. " upgrade with " .. charge_str .. " and " .. cd_str .. " time between charges") end end if ability["AbilityChargesConditionally"] ~= nil then table.insert(note_parts, "Has a conditional charge") end if #note_parts > 0 then cells["Notes"] = table.concat(note_parts, " ") end return cells end -- Renders base damage and melee scaling. -- Special case for upgrades that switch from Light to Heavy Melee scaling. function p.RenderMelee(ability) local melee_types = {} for _, t in ipairs(Lists.lists["melee"]) do melee_types[t] = true end -- Find the base property with active melee/heavy_melee scaling (Scale.Value > 0) local base_prop, base_damage, base_scale, base_type for k, v in pairs(ability) do if k ~= "Upgrades" and type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and melee_types[scale["Type"]] and type(scale["Value"]) == "number" and scale["Value"] > 0 then base_prop = k base_damage = v["Value"] or 0 base_scale = scale["Value"] base_type = scale["Type"] break end end end local cells = {} cells["Base Damage"] = tostring(base_damage or 0) if base_scale then cells["Light Melee Scaling"] = "Γ" .. base_scale end local upgrades = ability["Upgrades"] if type(upgrades) ~= "table" then return cells end local notes = {} local running_damage = base_damage or 0 local running_scale = base_scale or 0 local running_type = base_type for i, tier in ipairs(upgrades) do if type(tier) == "table" then local damage_delta = 0 local new_scale = nil local new_type = nil for k, v in pairs(tier) do if type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and melee_types[scale["Type"]] then damage_delta = damage_delta + (v["Value"] or 0) if scale["Value"] > 0 then new_scale = scale["Value"] new_type = scale["Type"] end end end end local flat_delta = 0 if base_prop and type(tier[base_prop]) == "number" then flat_delta = tier[base_prop] end local tier_parts = {} if new_type and new_type ~= running_type then running_damage = running_damage + damage_delta running_scale = new_scale running_type = new_type local type_label = new_type == "heavy_melee" and "'''Heavy Melee'''" or "Light Melee" local parts = {} if running_damage > 0 then table.insert(parts, running_damage .. " base damage") end table.insert(parts, "Γ" .. new_scale .. " " .. type_label .. " scaling") table.insert(tier_parts, "on T" .. i .. " becomes " .. table.concat(parts, " with ")) elseif new_scale then running_damage = running_damage + damage_delta running_scale = running_scale + new_scale local parts = {} if damage_delta ~= 0 then table.insert(parts, "+" .. damage_delta .. " base damage") end table.insert(parts, "+Γ" .. new_scale .. " scaling (total Γ" .. running_scale .. ")") table.insert(tier_parts, "on T" .. i .. " gets " .. table.concat(parts, ", ")) end if flat_delta ~= 0 and not new_scale then running_damage = running_damage + flat_delta table.insert(tier_parts, "on T" .. i .. " gets +" .. flat_delta .. " base damage (total " .. running_damage .. ")") end if #tier_parts > 0 then table.insert(notes, table.concat(tier_parts, ", ")) end end end if #notes > 0 then cells["Notes"] = table.concat(notes, ". ") end return cells end -- Renders base damage and heavy melee scaling. -- Notes when heavy melee is only available via upgrade. function p.RenderHeavyMelee(ability) -- Find base heavy_melee property local base_damage, base_scale for k, v in pairs(ability) do if k ~= "Upgrades" and type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and scale["Type"] == "heavy_melee" and type(scale["Value"]) == "number" then base_damage = v["Value"] or 0 base_scale = scale["Value"] break end end end local cells = {} -- Active at base if base_scale and base_scale > 0 then cells["Base Damage"] = tostring(base_damage) cells["Heavy Melee Scaling"] = "Γ" .. base_scale return cells end -- Not at base β find in upgrades local upgrades = ability["Upgrades"] if type(upgrades) ~= "table" then return cells end for i, tier in ipairs(upgrades) do if type(tier) == "table" then for k, v in pairs(tier) do if type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and scale["Type"] == "heavy_melee" and type(scale["Value"]) == "number" and scale["Value"] > 0 then cells["Base Damage"] = tostring(v["Value"] or 0) cells["Heavy Melee Scaling"] = "Γ" .. scale["Value"] cells["Notes"] = "Only becomes Heavy Melee on '''T" .. i .. "''' upgrade" return cells end end end end end return cells end -- Renders Spirit Power scaling. -- Shows the Scale.Value for abilities whose Scale.Type is "spirit". function p.RenderSpiritScaling(ability) local base_scale = nil local base_prop = nil -- Find base Spirit scaling for k, v in pairs(ability) do if k ~= "Upgrades" and type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and scale["Type"] == "spirit" and type(scale["Value"]) == "number" and scale["Value"] ~= 0 then base_scale = scale["Value"] base_prop = k break end end end local cells = {} if base_scale then cells["Spirit Scaling"] = "Γ" .. base_scale end local upgrades = ability["Upgrades"] if type(upgrades) ~= "table" then return cells end local notes = {} for i, tier in ipairs(upgrades) do if type(tier) == "table" then local upgrade_scale = nil for k, v in pairs(tier) do if type(v) == "table" then local scale = v["Scale"] if type(scale) == "table" and scale["Type"] == "spirit" and type(scale["Value"]) == "number" and scale["Value"] ~= 0 then upgrade_scale = scale["Value"] break end end end if upgrade_scale then table.insert(notes, "on T" .. i .. " gets +Γ" .. upgrade_scale .. " Spirit scaling") end end end if #notes > 0 then cells["Notes"] = table.concat(notes, ". ") end return cells end -- Renders heal reduction percentage. -- Special case for DisableHealing, shown as 100%. function p.RenderHealReduce(ability) -- DisableHealing is always 100%, handle it separately local v = unwrap_value(ability["DisableHealing"]) if v and v ~= 0 then return { ["Heal Reduction"] = "100%" } end local upgrade = find_in_upgrades(ability, "DisableHealing") if upgrade then return { ["Heal Reduction"] = "100% (T" .. upgrade.tier .. ")" } end -- Everything else goes through the generic renderer local filtered = {} for _, prop in ipairs(Lists.lists["healreduce"]) do if prop ~= "DisableHealing" then table.insert(filtered, prop) end end return render_upgradable_stat(ability, "Heal Reduction", filtered, "%") end -- Renders move slow percentage. -- Appends a note if the ability also self-slows the caster. function p.RenderMoveSlow(ability) local cells = render_upgradable_stat(ability, "Move Slow", Lists.lists["moveslow"], "%") local channel_slow = unwrap_value(ability["ChannelSlowPercent"]) if channel_slow and channel_slow ~= 0 then local note = "Also slows the caster for " .. math.abs(channel_slow) .. "%" cells["Notes"] = cells["Notes"] and (cells["Notes"] .. "; " .. note) or note end return cells end -- Renders dash slow percentage. -- Special case for GroundDashReductionPercent coexisting with another dashslow -- prop, which means it's a caster self-slow and is noted separately. function p.RenderDashSlow(ability) local stat_props = Lists.lists["dashslow"] local props = {} for _, pr in ipairs(stat_props) do table.insert(props, pr) end local caster_dash_slow = nil local base_ground = unwrap_value(ability["GroundDashReductionPercent"]) if base_ground and base_ground ~= 0 then local has_enemy_prop = false for _, prop in ipairs(stat_props) do if prop ~= "GroundDashReductionPercent" then local v = unwrap_value(ability[prop]) if v and v ~= 0 then has_enemy_prop = true; break end end end if not has_enemy_prop then local upgrades = ability["Upgrades"] if type(upgrades) == "table" then for _, tier in ipairs(upgrades) do if type(tier) == "table" then for _, prop in ipairs(stat_props) do if prop ~= "GroundDashReductionPercent" then local v = unwrap_value(tier[prop]) if v and v ~= 0 then has_enemy_prop = true; break end end end end if has_enemy_prop then break end end end end if has_enemy_prop then caster_dash_slow = math.abs(base_ground) local filtered = {} for _, prop in ipairs(props) do if prop ~= "GroundDashReductionPercent" then table.insert(filtered, prop) end end props = filtered end end local cells = render_upgradable_stat(ability, "Dash Slow", props, "%") if caster_dash_slow then local note = "Gives " .. caster_dash_slow .. "% dash slow for the caster" cells["Notes"] = cells["Notes"] and (cells["Notes"] .. "; " .. note) or note end return cells end -- Renders the amount of Debuff Resist an ability grants. -- Upgrades stack additively onto the base value, so every step after the first -- shows the running total: "20% (T3)" when granted only by an upgrade, -- "10% β 25% (T2)" when a base value is later increased. Chains for any number -- of steps. No ability currently has both a base and an upgrade value. function p.RenderExtraDebuffResist(ability) local fields = Lists.lists["extradebuffresist"] local segments = {} local running = sum_fields(ability, fields) if running then table.insert(segments, running .. "%") end local upgrades = ability["Upgrades"] if type(upgrades) == "table" then for i, tier in ipairs(upgrades) do if type(tier) == "table" then local delta = sum_fields(tier, fields) if delta then running = (running or 0) + delta table.insert(segments, running .. "% (T" .. i .. ")") end end end end if #segments == 0 then return {} end return { ["Debuff Resist"] = table.concat(segments, " β ") } end return p
Summary:
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:
Module:AbilityTable/ComplexRenderers/doc
(
view source
)
Navigation menu
Personal tools
Create account
Log in
associated-pages
Module
Discussion
English
Views
Read
Edit source
History
Tools
Search
Discord
Discord
Navigation
Main page
About us
Random page
Special pages
Recent changes
Viscous/Movement
5h ago
Β·
Justis
Viscous/Movement
5h ago
Β·
Justis
Mirage
11h ago
Β·
Korvokorvo1234
Vyper/Voice lines
23h ago
Β·
~2026-RegenStrikeSpirit1098
Show more...
Interface Admin
Common CSS
Vector CSS
Minerva CSS
Citizen CSS
Brown theme CSS
Gadgets
Gadgets definition
Editing
How to edit
Style guide
All guides
New files
Unresolved feedback
Tools
What links here
Related changes
Page information