Module:NpcData: Difference between revisions

LVL (talk | contribs)
Added `get_nested_var` function for accessing nested data
LVL (talk | contribs)
Removed dead code
 
(7 intermediate revisions by the same user not shown)
Line 4: Line 4:
local npcs_data = mw.loadJsonData("Data:NpcData.json")
local npcs_data = mw.loadJsonData("Data:NpcData.json")
local util_module = require('Module:Utilities')
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
-- returns the entire data table for a specific NPC, used by other Lua modules
function p.get_npc_data(name)
function p.get_npc_data(name)
if not name or name == '' then
    if not name or name == '' then
return nil
        return nil
end
    end
return npcs_data[name]
    return npcs_data[name]
end
end


-- Retrieves a specific stat value for a given NPC.
-- Retrieves a specific stat value for a given NPC. Handles both simple and nested calls.
--{{#invoke:NpcData|get_npc_var|NPC_KEY|STAT_KEY|SIG_FIGS}}--
-- {{#invoke:NpcData|get_npc_var|NPC_KEY|STAT_KEY_1|STAT_KEY_2|...|SIG_FIGS}}
p.get_npc_var = function(frame)
p.get_npc_var = function(frame)
-- Get arguments from the #invoke call and trim whitespace
    -- Safer argument handling for both live and debug environments
local args = frame.args
    local args = {}
local npc_name = args[1] and mw.text.trim(args[1]) or nil
    if frame.getParent then
local npc_stat_key = args[2] and mw.text.trim(args[2]) or nil
        local parent_args = frame:getParent().args
local sig_figs = args[3] and mw.text.trim(args[3]) or nil
        for k, v in pairs(parent_args) do args[k] = v end
    end
    -- Direct args from #invoke or the debug table overwrite parent args
    for k, v in pairs(frame.args) do args[k] = v end


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


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


-- Get the specific stat value
    local current_value = npc
local var_value = npc[npc_stat_key]
    local last_key_index = 1
if var_value == nil then
    local path = {npc_name} -- Track the path for better error messages
return '<span class="error">Error: Stat "' .. npc_stat_key .. '" not found for NPC "' .. npc_name .. '".</span>'
end


-- round if a number is provided
    -- Traverse through the arguments to find the nested value
if sig_figs and tonumber(sig_figs) then
    for i = 2, #args do
var_value = util_module.round_to_sig_fig(var_value, sig_figs)
        local key = args[i] and mw.text.trim(args[i]) or nil
if var_value == nil then
        if not key or key == '' then break end
return '<span class="error">Error: Rounding failed for value.</span>'
end
end


return var_value
        -- Check if this might be the sig_figs argument (numeric on a non-table)
end
        if tonumber(key) and type(current_value) ~= "table" then
 
            break
-- Retrieves an element from a list (array) within an NPC's data.
        end
--{{#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
 
-- Retrieves an ability key from an NPC's "BoundAbilities" map.
--{{#invoke:NpcData|get_ability_key|NPC_KEY|SLOT_KEY}}--
p.get_ability_key = function(frame)
local npc_name = frame.args[1] and mw.text.trim(frame.args[1]) or nil
local slot_name = frame.args[2] and mw.text.trim(frame.args[2]) or nil
 
if not npc_name or npc_name == '' then return '<span class="error">Error: NPC name not provided.</span>' end
    if not slot_name or slot_name == '' then return '<span class="error">Error: Slot name not provided.</span>' end
 
local npc_data = npcs_data[npc_name]
if not npc_data then return '<span class="error">Error: NPC "'..npc_name.. '" not found.</span>' end


local bound_abilities_data = npc_data["BoundAbilities"]
        if type(current_value) ~= "table" then
if not bound_abilities_data or type(bound_abilities_data) ~= "table" then
            return '<span class="error">Error: Invalid path at "' .. table.concat(path, '.') .. '". Tried to index a ' .. type(current_value) .. ' value.</span>'
return '<span class="error">Error: NPC "' .. npc_name .. '" has no \'BoundAbilities\' data.</span>'
        end
end
       
        -- Try string key first
        local next_value = current_value[key]
       
        -- If nil, try numeric key
        if next_value == nil then
            local num_key = tonumber(key)
            if num_key then
                next_value = current_value[num_key]
            end
        end
       
        if next_value == nil then
            return '<span class="error">Error: Key "' .. key .. '" not found in path "' .. table.concat(path, '.') .. '".</span>'
        end
       
        current_value = next_value
        table.insert(path, key)
        last_key_index = i
    end


local ability_key = bound_abilities_data[slot_name]
    -- Handle sig_figs if provided
     if not ability_key then
    local sig_figs_arg = args[last_key_index + 1]
return '<span class="error">Error: Slot "' .. slot_name .. '" not found for NPC "' .. npc_name .. '".</span>'
     local sig_figs = sig_figs_arg and tonumber(mw.text.trim(sig_figs_arg)) or nil
end
      
      
return ability_key
    if sig_figs then
end
        if type(current_value) ~= "number" then
 
            return '<span class="error">Error: Cannot apply sig_figs to non-numeric value at "' .. table.concat(path, '.') .. '" (type: ' .. type(current_value) .. ').</span>'
-- Retrieves a nested value using dot notation (e.g., "Shield.BaseAbsorptionPerSecond")
        end
--{{#invoke:NpcData|get_nested_var|NPC_KEY|PATH|SIG_FIGS}}--
        current_value = util_module.round_to_sig_fig(current_value, sig_figs)
p.get_nested_var = function(frame)
        if current_value == nil then
local args = frame.args
            return '<span class="error">Error: Rounding failed for value at "' .. table.concat(path, '.') .. '".</span>'
local npc_name = args[1] and mw.text.trim(args[1]) or nil
        end
local path = args[2] and mw.text.trim(args[2]) or nil
    end
local sig_figs = args[3] and mw.text.trim(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 path or path == '' then
return '<span class="error">Error: Path 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
 
-- Traverse nested structure
local value = npc
for key in string.gmatch(path, '([^.]+)') do
if type(value) ~= "table" then
return '<span class="error">Error: Path "' .. path .. '" is invalid.</span>'
end
value = value[key]
if value == nil then
return '<span class="error">Error: Key "' .. key .. '" not found in path.</span>'
end
end


-- Apply rounding if needed
    -- Convert tables/booleans to strings for display
if sig_figs and tonumber(sig_figs) then
    if type(current_value) == "table" then
value = util_module.round_to_sig_fig(value, sig_figs)
        return '<span class="error">Error: Path "' .. table.concat(path, '.') .. '" points to a table/object. Specify a deeper path to get a value.</span>'
if value == nil then
    elseif type(current_value) == "boolean" then
return '<span class="error">Error: Rounding failed for value.</span>'
        return tostring(current_value)
end
    end
end


return value
    return current_value
end
end


return p
return p