Module:Damage: Difference between revisions
From Space Station 14 Wiki
No edit summary |
support distribution param |
||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
local round_to_digit_formatted = require('Module:Utils/number').round_to_digit_formatted | |||
local damage_types_json = mw.loadJsonData("Module:Damage/damage types.json") | local damage_types_json = mw.loadJsonData("Module:Damage/damage types.json") | ||
local damage_groups_json = mw.loadJsonData("Module:Damage/damage groups.json") | |||
-- how many digits to round damage to with numbers after comma. | |||
local round_damage_to_digit = 1 | |||
-- ========================= | |||
local function assert_not_nil(value, error_message) | local function assert_not_nil(value, error_message) | ||
Line 12: | Line 19: | ||
end | end | ||
end | end | ||
end | |||
local function numeric_table_length(t) | |||
local count = 0 | |||
for _ in ipairs(t) do count = count + 1 end | |||
return count | |||
end | end | ||
-- ========================= | -- ========================= | ||
-- | -- Lookup a field in a json table by key. | ||
local function | -- Json tables are assumed to be tables with lowercase keys. The `key` is automatically lowercased for the lookup. | ||
local result = | -- If a value is a string, it's treated as an alias (another key), triggering a new lookup. | ||
-- | |||
-- Returns the value by the specified key, or by aliased key if the value was an alias. | |||
-- If value doesn't exist, returns `nil`. | |||
local function lookup_json_table(t, key) | |||
local result = t[string.lower(key)] | |||
if type(result) == "string" then | if type(result) == "string" then | ||
-- alias. lookup actual definition. | -- alias. lookup actual definition. | ||
return | return t[result] | ||
else | else | ||
return result | return result | ||
Line 27: | Line 45: | ||
end | end | ||
-- Generates a | -- ====================== | ||
function | |||
local | -- Generates a damage type/group element. | ||
local | -- @param class Class. | ||
-- @param label Label. | |||
-- @param amount [Optional] Amount. | |||
-- @param color [Optional] Color. | |||
-- @param sign [Optional] Deal/heal damage sign. | |||
local function generate_damage_element(class, label, amount, color, sign) | |||
local label_wrapper_el = mw.html.create('span') | |||
:addClass(class) | |||
if amount then | |||
local amount_el = label_wrapper_el:tag('span') | |||
:addClass("damage-amount") | |||
:wikitext(amount .. " ") | |||
if sign then | |||
if sign == "+" then | |||
amount_el:addClass("heal") | |||
elseif sign == "-" then | |||
amount_el:addClass("deal") | |||
else | |||
error("failed to generate a damage label component: unsupported sign '" .. sign .. "'") | |||
end | |||
end | |||
end | |||
- | local label_el = label_wrapper_el:tag('span') | ||
:addClass("damage-label") | |||
:wikitext(label) | |||
if color then | |||
if | label_el:css("color", color); | ||
end | end | ||
local | return label_wrapper_el | ||
end | |||
-- Generate a damage type element. | |||
-- @param damage_type Damage type. | |||
-- @param damage_type_lookup Lookup result for the damage type. | |||
-- @param amount [Optional] Amount. | |||
-- @param sign [Optional] Deal/heal sign. | |||
local function generate_damage_type(damage_type, damage_type_lookup, amount, sign) | |||
local label = damage_type_lookup.display | |||
local color = damage_type_lookup.color | local color = damage_type_lookup.color | ||
if not | if not label then | ||
error("failed to generate a damage type: damage type is defined, but it does not have a 'display' property") | error("failed to generate a damage type: damage type '" .. damage_type .. "' is defined, but it does not have a 'display' property") | ||
end | |||
return generate_damage_element("damage-type", label, amount, color, sign) | |||
end | |||
-- Generate a damage group element (containing damage type elements). | |||
-- @param damage_group Damage group. | |||
-- @param damage_group_lookup Lookup result for the damage group. | |||
-- @param amount [Optional] Amount. | |||
-- @param sign [Optional] Deal/heal sign. | |||
-- @param distribution [Optional] Damage distribution for damage types. | |||
local function generate_damage_group(damage_group, damage_group_lookup, amount, sign, distribution) | |||
local label = damage_group_lookup.display | |||
local damage_types = damage_group_lookup["damage types"] | |||
local color = damage_group_lookup.color | |||
if not label then | |||
error("failed to generate a damage group: damage group '" .. damage_group .. "' is defined, but it does not have a 'display' property") | |||
elseif not damage_types then | |||
error("failed to generate a damage group: damage group '" .. damage_group .. "' is defined, but it does not have a 'damage types' property") | |||
end | |||
local wrapper_el = mw.html.create('span') | |||
:addClass("damage-group-wrapper") | |||
local damage_group_el = generate_damage_element("damage-group", label, amount, color, sign) | |||
wrapper_el:node(damage_group_el) | |||
wrapper_el:wikitext(" (") | |||
local damage_types_count = numeric_table_length(damage_types) | |||
local amount_per_damage_type_str | |||
if amount then | |||
if distribution == "each" then | |||
local exact_amount_per_damage_type = amount / damage_types_count | |||
amount_per_damage_type_str = round_to_digit_formatted(exact_amount_per_damage_type, round_damage_to_digit) | |||
elseif distribution == "shared" then | |||
amount_per_damage_type_str = amount | |||
else | |||
error("unknown distribution: " .. distribution) | |||
end | |||
end | end | ||
for i, damage_type in ipairs(damage_types) do | |||
if distribution == "shared" and amount and damage_types_count > 1 and i == 1 then | |||
wrapper_el:wikitext(amount .. " damage between ") | |||
end | |||
local damage_type_el = generate_damage_type( | |||
: | damage_type, | ||
lookup_json_table(damage_types_json, damage_type), | |||
-- do not provide amount for the shared because the amount gets specified only once at the start | |||
distribution == "each" and amount_per_damage_type_str or nil, -- or shared | |||
sign | |||
) | |||
wrapper_el:node(damage_type_el) | |||
-- if 2 damages and not on last damage | |||
if damage_types_count >= 2 and i < damage_types_count then | |||
-- add 'and' instead of a comma in between last and second to last items | |||
if i == damage_types_count - 1 then | |||
wrapper_el:wikitext(" and ") | |||
else | |||
wrapper_el:wikitext(", ") | |||
end | |||
end | |||
end | |||
wrapper_el:wikitext(")") | |||
return wrapper_el | |||
end | |||
-- Generates a damage label element. | |||
function p.main(frame) | |||
local args = getArgs(frame) | |||
local label = args[1] | |||
assert_not_nil(label, "failed to generate a damage label: damage type/group not provided") | |||
local amount = args[2] | |||
local | local sign = args[3] | ||
local | local distribution = string.lower(args.split or args.distribution or args.distrib or "each") | ||
-- ================== | |||
if | -- if damage group, format based as follows: <group> (<type 1>, <type 2>, <type 3>) | ||
-- -- if distribution is set to "shared" and an amount is provided, format as follows: <group> (N damage between <type 1>, <type 2>, <type 3>) | |||
-- if damage type, format as follows: <amount> <type> | |||
local damage_group_lookup = lookup_json_table(damage_groups_json, label); | |||
if damage_group_lookup then | |||
return generate_damage_group(label, damage_group_lookup, amount, sign, distribution) | |||
end | end | ||
local damage_type_lookup = lookup_json_table(damage_types_json, label); | |||
if damage_type_lookup then | |||
return generate_damage_type(label, damage_type_lookup, amount, sign) | |||
end | end | ||
error("failed to generate a damage label: unknown damage type/group '" .. label .. "'") | |||
end | end | ||
return p | return p |
Latest revision as of 14:05, 26 May 2025
Module documentation
|
---|
View or edit this documentation • (about module documentation) |
Uses JSON data
This module uses JSON data pages:
Implements {{Damage}}.
local p = {}
local getArgs = require('Module:Arguments').getArgs
local round_to_digit_formatted = require('Module:Utils/number').round_to_digit_formatted
local damage_types_json = mw.loadJsonData("Module:Damage/damage types.json")
local damage_groups_json = mw.loadJsonData("Module:Damage/damage groups.json")
-- how many digits to round damage to with numbers after comma.
local round_damage_to_digit = 1
-- =========================
local function assert_not_nil(value, error_message)
if value == nil then
if error_message == nil then
error("value is nil")
else
error(error_message)
end
end
end
local function numeric_table_length(t)
local count = 0
for _ in ipairs(t) do count = count + 1 end
return count
end
-- =========================
-- Lookup a field in a json table by key.
-- Json tables are assumed to be tables with lowercase keys. The `key` is automatically lowercased for the lookup.
-- If a value is a string, it's treated as an alias (another key), triggering a new lookup.
--
-- Returns the value by the specified key, or by aliased key if the value was an alias.
-- If value doesn't exist, returns `nil`.
local function lookup_json_table(t, key)
local result = t[string.lower(key)]
if type(result) == "string" then
-- alias. lookup actual definition.
return t[result]
else
return result
end
end
-- ======================
-- Generates a damage type/group element.
-- @param class Class.
-- @param label Label.
-- @param amount [Optional] Amount.
-- @param color [Optional] Color.
-- @param sign [Optional] Deal/heal damage sign.
local function generate_damage_element(class, label, amount, color, sign)
local label_wrapper_el = mw.html.create('span')
:addClass(class)
if amount then
local amount_el = label_wrapper_el:tag('span')
:addClass("damage-amount")
:wikitext(amount .. " ")
if sign then
if sign == "+" then
amount_el:addClass("heal")
elseif sign == "-" then
amount_el:addClass("deal")
else
error("failed to generate a damage label component: unsupported sign '" .. sign .. "'")
end
end
end
local label_el = label_wrapper_el:tag('span')
:addClass("damage-label")
:wikitext(label)
if color then
label_el:css("color", color);
end
return label_wrapper_el
end
-- Generate a damage type element.
-- @param damage_type Damage type.
-- @param damage_type_lookup Lookup result for the damage type.
-- @param amount [Optional] Amount.
-- @param sign [Optional] Deal/heal sign.
local function generate_damage_type(damage_type, damage_type_lookup, amount, sign)
local label = damage_type_lookup.display
local color = damage_type_lookup.color
if not label then
error("failed to generate a damage type: damage type '" .. damage_type .. "' is defined, but it does not have a 'display' property")
end
return generate_damage_element("damage-type", label, amount, color, sign)
end
-- Generate a damage group element (containing damage type elements).
-- @param damage_group Damage group.
-- @param damage_group_lookup Lookup result for the damage group.
-- @param amount [Optional] Amount.
-- @param sign [Optional] Deal/heal sign.
-- @param distribution [Optional] Damage distribution for damage types.
local function generate_damage_group(damage_group, damage_group_lookup, amount, sign, distribution)
local label = damage_group_lookup.display
local damage_types = damage_group_lookup["damage types"]
local color = damage_group_lookup.color
if not label then
error("failed to generate a damage group: damage group '" .. damage_group .. "' is defined, but it does not have a 'display' property")
elseif not damage_types then
error("failed to generate a damage group: damage group '" .. damage_group .. "' is defined, but it does not have a 'damage types' property")
end
local wrapper_el = mw.html.create('span')
:addClass("damage-group-wrapper")
local damage_group_el = generate_damage_element("damage-group", label, amount, color, sign)
wrapper_el:node(damage_group_el)
wrapper_el:wikitext(" (")
local damage_types_count = numeric_table_length(damage_types)
local amount_per_damage_type_str
if amount then
if distribution == "each" then
local exact_amount_per_damage_type = amount / damage_types_count
amount_per_damage_type_str = round_to_digit_formatted(exact_amount_per_damage_type, round_damage_to_digit)
elseif distribution == "shared" then
amount_per_damage_type_str = amount
else
error("unknown distribution: " .. distribution)
end
end
for i, damage_type in ipairs(damage_types) do
if distribution == "shared" and amount and damage_types_count > 1 and i == 1 then
wrapper_el:wikitext(amount .. " damage between ")
end
local damage_type_el = generate_damage_type(
damage_type,
lookup_json_table(damage_types_json, damage_type),
-- do not provide amount for the shared because the amount gets specified only once at the start
distribution == "each" and amount_per_damage_type_str or nil, -- or shared
sign
)
wrapper_el:node(damage_type_el)
-- if 2 damages and not on last damage
if damage_types_count >= 2 and i < damage_types_count then
-- add 'and' instead of a comma in between last and second to last items
if i == damage_types_count - 1 then
wrapper_el:wikitext(" and ")
else
wrapper_el:wikitext(", ")
end
end
end
wrapper_el:wikitext(")")
return wrapper_el
end
-- Generates a damage label element.
function p.main(frame)
local args = getArgs(frame)
local label = args[1]
assert_not_nil(label, "failed to generate a damage label: damage type/group not provided")
local amount = args[2]
local sign = args[3]
local distribution = string.lower(args.split or args.distribution or args.distrib or "each")
-- ==================
-- if damage group, format based as follows: <group> (<type 1>, <type 2>, <type 3>)
-- -- if distribution is set to "shared" and an amount is provided, format as follows: <group> (N damage between <type 1>, <type 2>, <type 3>)
-- if damage type, format as follows: <amount> <type>
local damage_group_lookup = lookup_json_table(damage_groups_json, label);
if damage_group_lookup then
return generate_damage_group(label, damage_group_lookup, amount, sign, distribution)
end
local damage_type_lookup = lookup_json_table(damage_types_json, label);
if damage_type_lookup then
return generate_damage_type(label, damage_type_lookup, amount, sign)
end
error("failed to generate a damage label: unknown damage type/group '" .. label .. "'")
end
return p