Module:Damage: Difference between revisions

From Space Station 14 Wiki
Aliser (talk | contribs)
fix "nil" amount for groups when amount is specified
Aliser (talk | contribs)
support damage/healing param
Line 49: Line 49:
-- @param color [Optional] Text color.
-- @param color [Optional] Text color.
-- @param outline_color [Optional] Text outline color.
-- @param outline_color [Optional] Text outline color.
local function generate_label_element(class, label, amount, color, outline_color)
local function generate_label_element(class, label, amount, color, outline_color, sign)
local label_wrapper_el = mw.html.create('span')
local label_wrapper_el = mw.html.create('span')
:addClass(class)
:addClass(class)
Line 71: Line 71:
label_el:css("--shadow-col", outline_color);
label_el:css("--shadow-col", outline_color);
label_el:css("text-shadow", "-1px -1px 0 var(--shadow-col), 1px -1px 0 var(--shadow-col), -1px 1px 0 var(--shadow-col), 1px 1px 0 var(--shadow-col)");
label_el:css("text-shadow", "-1px -1px 0 var(--shadow-col), 1px -1px 0 var(--shadow-col), -1px 1px 0 var(--shadow-col), 1px 1px 0 var(--shadow-col)");
end
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


Line 81: Line 91:
-- @param damage_type_lookup Lookup result for the damage type.
-- @param damage_type_lookup Lookup result for the damage type.
-- @param amount [Optional] Optional amount.
-- @param amount [Optional] Optional amount.
local function generate_damage_type(damage_type, damage_type_lookup, amount)
local function generate_damage_type(damage_type, damage_type_lookup, amount, sign)
local display = damage_type_lookup.display
local display = damage_type_lookup.display
local color = damage_type_lookup.color
local color = damage_type_lookup.color
Line 90: Line 100:
end
end


return generate_label_element("damage-type", display, amount, color, outline_color)
return generate_label_element("damage-type", display, amount, color, outline_color, sign)
end
end


local function generate_damage_group(damage_group, damage_group_lookup, amount)
local function generate_damage_group(damage_group, damage_group_lookup, amount, sign)
local display = damage_group_lookup.display
local display = damage_group_lookup.display
local damage_types = damage_group_lookup["damage types"]
local damage_types = damage_group_lookup["damage types"]
Line 108: Line 118:
:addClass("damage-group-wrapper")
:addClass("damage-group-wrapper")


local damage_group_el = generate_label_element("damage-group", display, amount, color, outline_color)
local damage_group_el = generate_label_element("damage-group", display, amount, color, outline_color, sign)
wrapper_el:node(damage_group_el)
wrapper_el:node(damage_group_el)
Line 126: Line 136:
for i, damage_type in ipairs(damage_types) do
for i, damage_type in ipairs(damage_types) do
wrapper_el:node(
wrapper_el:node(
generate_damage_type(damage_type, lookup_json_table(damage_types_json, damage_type), amount_per_damage_type_str)
generate_damage_type(damage_type, lookup_json_table(damage_types_json, damage_type), amount_per_damage_type_str, sign)
)
)


Line 151: Line 161:


local amount = args[2]
local amount = args[2]
local sign = args[3]


-- ==================
-- ==================
Line 159: Line 171:
local damage_group_lookup = lookup_json_table(damage_groups_json, damage_type_or_group);
local damage_group_lookup = lookup_json_table(damage_groups_json, damage_type_or_group);
if damage_group_lookup then
if damage_group_lookup then
return generate_damage_group(damage_type_or_group, damage_group_lookup, amount)
return generate_damage_group(damage_type_or_group, damage_group_lookup, amount, sign)
end
end


local damage_type_lookup = lookup_json_table(damage_types_json, damage_type_or_group);
local damage_type_lookup = lookup_json_table(damage_types_json, damage_type_or_group);
if damage_type_lookup then
if damage_type_lookup then
return generate_damage_type(damage_type_or_group, damage_type_lookup, amount)
return generate_damage_type(damage_type_or_group, damage_type_lookup, amount, sign)
end
end



Revision as of 05:51, 24 May 2025

Module documentation
View or edit this documentation (about module documentation)
Uses JSON data

Implements {{Damage}}.


local p = {}
local getArgs = require('Module:Arguments').getArgs

local damage_types_json = mw.loadJsonData("Module:Damage/damage types.json")
local damage_groups_json = mw.loadJsonData("Module:Damage/damage groups.json")

-- =========================

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 label element.
-- @param class Wrapper element class.
-- @param label Label.
-- @param amount [Optional] Amount.
-- @param color [Optional] Text color.
-- @param outline_color [Optional] Text outline color.
local function generate_label_element(class, label, amount, color, outline_color, sign)
	local label_wrapper_el = mw.html.create('span')
		:addClass(class)

	local label_el = mw.html.create('span')
		:addClass("label")
		:wikitext("<b>" .. label .. "</b>")

	local amount_el = mw.html.create('span')
		:addClass("amount")
		:wikitext(amount and amount .. " " or "")

	label_wrapper_el:node(amount_el)
	label_wrapper_el:node(label_el)

	if color then
		label_el:css("color", color);
	end

	if outline_color then
		label_el:css("--shadow-col", outline_color);
		label_el:css("text-shadow", "-1px -1px 0 var(--shadow-col), 1px -1px 0 var(--shadow-col), -1px 1px 0 var(--shadow-col), 1px 1px 0 var(--shadow-col)");
	end

	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

	return label_wrapper_el:allDone()
end


-- Generate a damage type element.
-- @param damage_type Damage type.
-- @param damage_type_lookup Lookup result for the damage type.
-- @param amount [Optional] Optional amount.
local function generate_damage_type(damage_type, damage_type_lookup, amount, sign)
	local display = damage_type_lookup.display
	local color = damage_type_lookup.color
	local outline_color = damage_type_lookup["outline color"]

	if not display 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_label_element("damage-type", display, amount, color, outline_color, sign)
end

local function generate_damage_group(damage_group, damage_group_lookup, amount, sign)
	local display = damage_group_lookup.display
	local damage_types = damage_group_lookup["damage types"]
	local color = damage_group_lookup.color
	local outline_color = damage_group_lookup["outline color"]

	if not display 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_label_element("damage-group", display, amount, color, outline_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
		local exact_amount_per_damage_type = amount / damage_types_count
		local amount_per_damage_type = tonumber(string.format("%.3f", exact_amount_per_damage_type))
		-- add a "≈" if initial amount and rounded amount are different, i.e. when there are too many digits after comma
		amount_per_damage_type_str = exact_amount_per_damage_type ~= amount_per_damage_type 
			and "≈" .. amount_per_damage_type 
			or tostring(amount_per_damage_type)
	end
	
	for i, damage_type in ipairs(damage_types) do
		wrapper_el:node(
			generate_damage_type(damage_type, lookup_json_table(damage_types_json, damage_type), amount_per_damage_type_str, sign)
		)

		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:allDone() 
end

-- Generates a term element with a tooltip and/or a link.
function p.main(frame)
	local args = getArgs(frame)
	local damage_type_or_group = args[1]
	assert_not_nil(damage_type_or_group, "failed to generate a damage label: damage type/group not provided")

	local amount = args[2]

	local sign = args[3]

	-- ==================

	-- if damage group, format as follows: <group> (<type 1>, <type 2>, <type 3>)
	-- if damage type, format as follows: <amount> <type>

	local damage_group_lookup = lookup_json_table(damage_groups_json, damage_type_or_group);
	if damage_group_lookup then
		return generate_damage_group(damage_type_or_group, damage_group_lookup, amount, sign)
	end

	local damage_type_lookup = lookup_json_table(damage_types_json, damage_type_or_group);
	if damage_type_lookup then
		return generate_damage_type(damage_type_or_group, damage_type_lookup, amount, sign)
	end

	error("failed to generate a damage label: unknown damage type/group '" .. damage_type_or_group .. "'")
end

return p