Module:GameData: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Vergir (talk | contribs)
m skip AutoRegisterModifierValueFromAbilityPropertyName on property matchin
Vergir (talk | contribs)
Add get_prop: unified property lookup across abilities, heroes, and items (with help from vergir-bot LLM)
Line 71: Line 71:


     return results
     return results
end
--------------------------------------------------------------------------------
-- Unified property lookup: get_prop
-- Searches Abilities → Heroes → Items, returns raw values for use in templates.
--------------------------------------------------------------------------------
-- Lazy-loaded data caches
local _ability_data, _item_data, _hero_data, _resource_lookup
local function load_ability_data()
    if not _ability_data then _ability_data = mw.loadJsonData(p.Dataset.ABILITIES) end
    return _ability_data
end
local function load_item_data()
    if not _item_data then _item_data = mw.loadJsonData(p.Dataset.ITEMS) end
    return _item_data
end
local function load_hero_data()
    if not _hero_data then _hero_data = mw.loadJsonData(p.Dataset.HEROES) end
    return _hero_data
end
-- Find an ability by key or display name (mirrors Module:Abilities logic)
local function find_ability(identifier)
    local data = load_ability_data()
    if data[identifier] then return data[identifier] end
    if not _resource_lookup then
        _resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")
    end
    local resource = _resource_lookup[identifier:lower()]
    if resource then return data[resource.key] end
    return nil
end
-- Find an item by display name (mirrors Module:ItemData logic, prefers active)
local function find_item(name)
    local data = load_item_data()
    for _, v in pairs(data) do
        if v["Name"] == name and is_active(v) then return v end
    end
    for _, v in pairs(data) do
        if v["Name"] == name then return v end
    end
    return nil
end
-- Find a hero by key or display name (mirrors Module:HeroData logic)
local function find_hero(identifier)
    local data = load_hero_data()
    if data[identifier] then return data[identifier] end
    for _, v in pairs(data) do
        if v["Name"] == identifier then return v end
    end
    return nil
end
-- Traverse a table using dot notation, unwrap tables with a .Value field
local function resolve_prop(tbl, prop)
    if not prop or prop == "" then return nil end
    local element = tbl
    for segment in string.gmatch(prop, "[^%.]+") do
        if type(element) ~= "table" then return nil end
        element = element[segment]
        if element == nil then return nil end
    end
    if type(element) == "table" then
        return element.Value or ""
    end
    return element
end
-- {{#invoke:GameData|get_prop|ENTITY_NAME|PROPERTY}}
-- Searches Abilities → Heroes → Items. Returns the raw value (no formatting).
-- Supports dot notation for nested properties (e.g. "Scale.Value").
-- Tables with a .Value field are automatically unwrapped.
function p.get_prop(frame)
    local name = frame.args[1]
    local prop = frame.args[2]
    if not name or not prop then return "" end
    -- 1. Abilities
    local entity = find_ability(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
    end
    -- 2. Heroes (also checks Weapon / Weapon.AltFire)
    entity = find_hero(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
        if entity.Weapon then
            result = resolve_prop(entity.Weapon, prop)
            if result ~= nil then return result end
            if entity.Weapon.AltFire then
                result = resolve_prop(entity.Weapon.AltFire, prop)
                if result ~= nil then return result end
            end
        end
    end
    -- 3. Items
    entity = find_item(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
    end
    return ""
end
end


return p
return p

Revision as of 12:14, 1 June 2026

Documentation for this module may be created at Module:GameData/doc

-- Module:GameData
-- Provides generic access to game data files, with consistent active-entity filtering.
-- Used by ItemTables, and intended for future AbilityTables, HeroTables, etc.

local p = {}

-- Dataset descriptors. Values are the data file paths passed to mw.loadJsonData.
-- Callers should use these constants rather than raw strings.
p.Dataset = {
    ITEMS     = "Data:ItemData.json",
    ABILITIES = "Data:AbilityData.json",
    HEROES    = "Data:HeroData.json",
}

-- Returns true if a record represents an active, usable entity.
-- Applies consistently across all datasets:
--   - IsDisabled must not be true
--   - Name must not be nil
--   - IsSelectable, if present, must not be false
local function is_active(record)
    if record["IsDisabled"] == true then return false end
    if record["Name"] == nil then return false end
    if record["IsSelectable"] ~= nil and record["IsSelectable"] == false then return false end
    return true
end

-- Recursively searches a record for a match against prop, which may be:
--   - a key name: matches if the key exists with a non-zero/non-empty value
--   - a plain value: matches if the string appears as a value anywhere in the record
-- Returns true if a match is found, false otherwise.
local function record_matches_prop(record, prop)
    for k, v in pairs(record) do
        -- Key match: property name exists with a meaningful value
        if k == prop then
            if type(v) == "table" then v = v["Value"] end
            if v ~= nil and v ~= 0 and v ~= "" and v ~= "0" and v ~= "0m" then
                return true
            end
        end
        if type(v) == "table" and k ~= "AutoRegisterModifierValueFromAbilityPropertyName" then
            if record_matches_prop(v, prop) then return true end
        elseif type(v) == "string" then
            -- Value match: prop string appears as a value (e.g. Scale.Type = "melee")
            if v == prop then return true end
        end
    end
    return false
end

-- Returns all active entities from a dataset that match at least one of the
-- given properties. A property may be matched either as a key name (the
-- property exists with a non-zero value) or as a plain string value anywhere
-- in the record (e.g. "melee" matching Scale.Type = "melee").
-- @param   dataset     string  one of the GameData.Dataset constants
-- @param   properties  table   array of property strings
-- @return              table   array of matching entity records
function p.get_entities(dataset, properties)
    local data = mw.loadJsonData(dataset)
    local results = {}

    for _, record in pairs(data) do
        if is_active(record) then
            for _, prop in ipairs(properties) do
                if record_matches_prop(record, prop) then
                    table.insert(results, record)
                    break
                end
            end
        end
    end

    return results
end

--------------------------------------------------------------------------------
-- Unified property lookup: get_prop
-- Searches Abilities → Heroes → Items, returns raw values for use in templates.
--------------------------------------------------------------------------------

-- Lazy-loaded data caches
local _ability_data, _item_data, _hero_data, _resource_lookup

local function load_ability_data()
    if not _ability_data then _ability_data = mw.loadJsonData(p.Dataset.ABILITIES) end
    return _ability_data
end
local function load_item_data()
    if not _item_data then _item_data = mw.loadJsonData(p.Dataset.ITEMS) end
    return _item_data
end
local function load_hero_data()
    if not _hero_data then _hero_data = mw.loadJsonData(p.Dataset.HEROES) end
    return _hero_data
end

-- Find an ability by key or display name (mirrors Module:Abilities logic)
local function find_ability(identifier)
    local data = load_ability_data()
    if data[identifier] then return data[identifier] end
    if not _resource_lookup then
        _resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")
    end
    local resource = _resource_lookup[identifier:lower()]
    if resource then return data[resource.key] end
    return nil
end

-- Find an item by display name (mirrors Module:ItemData logic, prefers active)
local function find_item(name)
    local data = load_item_data()
    for _, v in pairs(data) do
        if v["Name"] == name and is_active(v) then return v end
    end
    for _, v in pairs(data) do
        if v["Name"] == name then return v end
    end
    return nil
end

-- Find a hero by key or display name (mirrors Module:HeroData logic)
local function find_hero(identifier)
    local data = load_hero_data()
    if data[identifier] then return data[identifier] end
    for _, v in pairs(data) do
        if v["Name"] == identifier then return v end
    end
    return nil
end

-- Traverse a table using dot notation, unwrap tables with a .Value field
local function resolve_prop(tbl, prop)
    if not prop or prop == "" then return nil end
    local element = tbl
    for segment in string.gmatch(prop, "[^%.]+") do
        if type(element) ~= "table" then return nil end
        element = element[segment]
        if element == nil then return nil end
    end
    if type(element) == "table" then
        return element.Value or ""
    end
    return element
end

-- {{#invoke:GameData|get_prop|ENTITY_NAME|PROPERTY}}
-- Searches Abilities → Heroes → Items. Returns the raw value (no formatting).
-- Supports dot notation for nested properties (e.g. "Scale.Value").
-- Tables with a .Value field are automatically unwrapped.
function p.get_prop(frame)
    local name = frame.args[1]
    local prop = frame.args[2]
    if not name or not prop then return "" end

    -- 1. Abilities
    local entity = find_ability(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
    end

    -- 2. Heroes (also checks Weapon / Weapon.AltFire)
    entity = find_hero(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
        if entity.Weapon then
            result = resolve_prop(entity.Weapon, prop)
            if result ~= nil then return result end
            if entity.Weapon.AltFire then
                result = resolve_prop(entity.Weapon.AltFire, prop)
                if result ~= nil then return result end
            end
        end
    end

    -- 3. Items
    entity = find_item(name)
    if entity then
        local result = resolve_prop(entity, prop)
        if result ~= nil then return result end
    end

    return ""
end

return p