Module:NpcData

Revision as of 15:03, 14 November 2025 by LVL (talk | contribs)

This module allows you to display stats for any NPC (Non-Player Character) from the game's data files which can be found here Data:NpcData.json. For most uses, it is recommended to use the {{NpcData}} template.

How to Use

To get data from the module, you use a command that looks like {{#invoke:NpcData|...}}. You will tell it which function to use, which NPC you want, and what information you need.

The basic format is: {{#invoke:NpcData|function_name|parameter1|parameter2|...}}

Available Functions

Get a Single or Nested Stat (`get_npc_var`)

This is the primary function for retrieving NPC data. It can get a simple top-level stat or traverse deeply into nested objects and arrays (up to 6 levels deep via the template).

Syntax {{#invoke:NpcData|get_npc_var|NPC Name|Key 1|Key 2|...|Rounding}}

Parameters

  • NPC Name: The internal key for the NPC (e.g., `npc_boss_tier2`, `trooper_normal`).
  • Key 1, Key 2, ...: The path to the stat you want.
    • For a simple stat, this is one key (e.g., `MaxHealth`).
    • For nested data, provide each key in order (e.g., `RebirthModifier`, `RespawnDelay`).
    • For arrays (lists), use the position number as a key (e.g., `IntrinsicModifiers`, `1`, `BULLET_ARMOR_DAMAGE_RESIST`).
  • Rounding: (Optional) A number to round the result to that many significant figures. This should always be the last parameter.

Examples

  • To get the max health of a Normal Trooper:
    • Code: {{#invoke:NpcData|get_npc_var|trooper_normal|MaxHealth}}
    • Result: 300
  • To get the name of a Walker's second ability (nested in BoundAbilities):
    • Code: {{#invoke:NpcData|get_npc_var|npc_boss_tier2|BoundAbilities|ESlot_Signature_2|Name}}
    • Result: Laser
  • To get a value from a list of modifiers (nested array):
    • Code: {{#invoke:NpcData|get_npc_var|npc_boss_tier2|IntrinsicModifiers|1|BULLET_ARMOR_DAMAGE_RESIST}}
    • Result: Error: Key "1" not found.
  • If a path is incorrect, an error message will show the full path attempted:
    • Code: {{#invoke:NpcData|get_npc_var|trooper_normal|InvalidKey|Stat}}
    • Result: Error: Key "InvalidKey" not found in path "trooper_normal".

local p = {}

-- Load data and utility modules
local npcs_data = mw.loadJsonData("Data:NpcData.json")
local util_module = require('Module:Utilities')
local lang_module = require('Module:Lang')

-- returns the entire data table for a specific NPC, used by other Lua modules
function p.get_npc_data(name)
	if not name or name == '' then
		return nil
	end
	return npcs_data[name]
end

-- Retrieves a specific stat value for a given NPC. Handles both simple and nested calls.
--{{#invoke:NpcData|get_npc_var|NPC_KEY|STAT_KEY_1|STAT_KEY_2|...|SIG_FIGS}}--
p.get_npc_var = function(frame)
	-- Use pcall to handle both template and module calls gracefully
	local parent_args = frame:getParent() and frame:getParent().args or {}
	local direct_args = frame.args
	local args = {}
	-- Merge args, giving direct #invoke args priority
	for k, v in pairs(parent_args) do args[k] = v end
	for k, v in pairs(direct_args) do args[k] = v end

	local npc_name = args[1] and mw.text.trim(args[1]) or nil
	if not npc_name or npc_name == '' then
		return '<span class="error">Error: NPC name not provided.</span>'
	end

	local npc = npcs_data[npc_name]
	if not npc then
		return '<span class="error">Error: NPC "' .. npc_name .. '" not found.</span>'
	end

	local current_value = npc
	local last_key_index = 1

	-- Traverse through the arguments to find the nested value
	for i = 2, #args do
		local key = args[i] and mw.text.trim(args[i]) or nil
		if not key or key == '' then break end

		-- Check if the current argument is the rounding value
		if tonumber(key) and type(current_value) == "number" then
			break
		end

		if type(current_value) ~= "table" then
			return '<span class="error">Error: Invalid path. Tried to index a non-table value.</span>'
		end
		
		current_value = current_value[key]
		if current_value == nil then
			return '<span class="error">Error: Key "' .. key .. '" not found.</span>'
		end
		last_key_index = i
	end

	-- Determine if a rounding value was provided
	local sig_figs_arg = args[last_key_index + 1]
	local sig_figs = sig_figs_arg and tonumber(mw.text.trim(sig_figs_arg)) or nil
	
	if sig_figs then
		current_value = util_module.round_to_sig_fig(current_value, sig_figs)
		if current_value == nil then
			return '<span class="error">Error: Rounding failed for value.</span>'
		end
	end

	return current_value
end

-- Retrieves an element from a list (array) within an NPC's data.
--{{#invoke:NpcData|get_list_elem|NPC_KEY|LIST_KEY|INDEX}}--
p.get_list_elem = function(frame)
	local npc_name = frame.args[1] and mw.text.trim(frame.args[1]) or nil
	local var = frame.args[2] and mw.text.trim(frame.args[2]) or nil
	local number_str = frame.args[3] and mw.text.trim(frame.args[3]) or nil
	
	if not npc_name or npc_name == '' then return '<span class="error">Error: NPC name not provided.</span>' end
	if not var or var == '' then return '<span class="error">Error: List variable name not provided.</span>' end
	if not number_str or number_str == '' then return '<span class="error">Error: Index not provided.</span>' end
	
	local number_int = tonumber(number_str)
	if not number_int then return '<span class="error">Error: Invalid index provided. Must be a number.</span>' end

	local npc = npcs_data[npc_name]
	if not npc then return '<span class="error">Error: NPC "' .. npc_name .. '" not found.</span>' end
	
	local list = npc[var]
	if list == nil or type(list) ~= "table" then return "" end
	
	local element = list[number_int]
	if element == nil then return "" end
	
	return element
end

return p