Module:Area

From Path of Exile 2 Wiki
Revision as of 18:41, 26 June 2017 by >OmegaK2 (Fixes)
Jump to navigation Jump to search
Module documentation[create] [purge]
-- SMW powered area module

-- ----------------------------------------------------------------------------
-- TODO
-- ----------------------------------------------------------------------------
-- invalid tags -> utl?
-- spawn_weight* values
-- spawnchacne values
-- 
-- i18n for properties

-- ----------------------------------------------------------------------------
-- Imports
-- ----------------------------------------------------------------------------

local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
local m_game = require('Module:Game')
local f_infocard = require('Module:Infocard')._main

-- ----------------------------------------------------------------------------
-- Localization
-- ----------------------------------------------------------------------------

-- Strings
local i18n = {
    images = {
        waypoint_no = '[[File:No waypoint area icon.png|link=|No Waypoint]]',
        waypoint_yes = '[[File:Waypoint area icon.png|link=|No Waypoint]]',
        waypoint_town = '[[File:Town area icon.png|link=|Town Hub]]',
        loading_screen = '[[File:%s loading screen.png|250px]]',
    },

    args = {
        id = 'id',
        name = 'name',
        act = 'act',
        area_level = 'level',
        level_restriction_max = 'level_restriction_max',
        area_type_tags = 'area_type_tags',
        tags = 'tags',
        loading_screen = 'loading_screen',
        connection_ids = 'connection_ids',
        parent_area_id = 'parent_area_id',
        modifier_ids = 'modifier_ids',
        boss_monster_ids = 'boss_monster_ids',
        monster_ids = 'monster_ids',
        entry_text = 'entry_text',
        entry_npc = 'entry_npc',
        vaal_area_spawn_chance = 'vaal_area_spawn_chance',
        vaal_area_ids = 'vaal_area_ids',
        strongbox_spawn_chance = 'strongbox_spawn_chance',
        strongbox_max_count = 'strongbox_max',
        strongbox_rarity_weight = 'strongbox_rarity_weight',
        is_map_area = 'is_map_area',
        is_unique_map_area = 'is_unique_map_area',
        is_town_area = 'is_town_area',
        is_hideout_area = 'is_hideout_area',
        is_vaal_area = 'is_vaal_area',
        is_master_daily_area = 'is_master_daily_area',
        is_labyrinth_area = 'is_labyrinth_area',
        is_labyrinth_airlock_area = 'is_labyrinth_airlock_area',
        is_labyrinth_boss_area = 'is_labyrinth_boss_area',
        has_waypoint = 'has_waypoint',
    },
    errors = {
        invalid_tag = '%s is not a valid tag',
    },
    tooltips = {
        -- boolean tooltips
        is_map_area = 'Map area',
        is_unique_map_area = 'Unique Map area',
        is_town_area = 'Town area',
        is_hideout_area = 'Hideout area',
        is_vaal_area = 'Vaal area',
        is_master_daily_area = 'Master daily spawn area',
        is_labyrinth_area = 'Labyrinth area',
        is_labyrinth_airlock_area = 'Labyrinth airlock area',
        is_labyrinth_boss_area = 'Labyrinth boss area',
        area = 'area',
        
        --
        act = 'Act: %s',
        area_level = 'Area level: %s',
        level_restriction_max = m_util.html.abbr('Max level', 'Characters above this level can not enter this zone.') .. ': %s',
        area_type_tags = 'Area type tags: %s',
        tags = 'Tags: %s',
        parent_area = m_util.html.abbr('Parent Town', 'Portals will lead to the parent town') .. ': %s',
        connections = 'Connections: %s',
        -- monsters
        -- boss monsters
        entry_message = '%s: %s',
    },
}

-- ----------------------------------------------------------------------------
-- Utility & helper functions
-- ----------------------------------------------------------------------------

local factory = {}
function factory.arg_list(k, args)
    return function (tpl_args, frame)
        tpl_args[k] = m_util.string.split(tpl_args[k] or '', ', ')
    end
end


function factory.display_value(k, args)
    return function(tpl_args, frame)
        return tpl_args[k]
    end
end

-- ----------------------------------------------------------------------------
-- Argument & display mapping
-- ----------------------------------------------------------------------------

local argument_map = {
    [i18n.args.id] = {
        property = 'Is area id',
        func = nil,
    },
    [i18n.args.name] = {
        property = 'Has name',
        func = nil,
    },
    [i18n.args.act] = {
        property = 'Has act',
        func = m_util.cast.factory.number(i18n.args.act),
    },
    [i18n.args.area_level] = {
        property = 'Has area level',
        func = m_util.cast.factory.number(i18n.args.area_level),
    },
    [i18n.args.level_restriction_max] = {
        property = 'Has maximum level restriction',
        func = m_util.cast.factory.number(i18n.args.level_restriction_max),
        default = 100,
    },
    [i18n.args.area_type_tags] = {
        property = 'Has area type tags',
        func = m_util.cast.factory.assoc_table(i18n.args.area_type_tags, {
            tbl = m_game.constants.tags,
            errmsg = i18n.errors.invalid_tag,
        }),
    },
    [i18n.args.tags] = {
        property = 'Has tags',
        func = m_util.cast.factory.assoc_table(i18n.args.tags, {
            tbl = m_game.constants.tags,
            errmsg = i18n.errors.invalid_tag,
        }),
    },
    [i18n.args.loading_screen] = {
        property = 'Has loading screen image',
        func = function (tpl_args, frame)
            if tpl_args[i18n.args.loading_screen] ~= nil then
                tpl_args[i18n.args.loading_screen] = string.format(i18n.images.loading_screen, tpl_args[i18n.args.loading_screen]) 
            end
        end,
    },
    [i18n.args.connection_ids] = {
        property = 'Has area connection ids',
        func = factory.arg_list(i18n.args.connection_ids),
    },
    [i18n.args.parent_area_id] = {
        property = 'Has parent area id',
    },
    [i18n.args.modifier_ids] = {
        property = 'Has mod ids',
        func = factory.arg_list(i18n.args.modifier_ids),
    },
    [i18n.args.monster_ids] = {
        property = 'Has monster ids',
        func = factory.arg_list(i18n.args.monster_ids)
    },
    [i18n.args.boss_monster_ids] = {
        property = 'Has boss monster ids',
        func = factory.arg_list(i18n.args.boss_monster_ids)
    },
    [i18n.args.entry_text] = {
        property = 'Has entry text message',
    },
    [i18n.args.entry_npc] = {
        property = 'Has entry npc',
    },
    --
    -- Spawn chances
    --
    [i18n.args.vaal_area_ids] = {
        property = 'Has vaal area ids',
        func = factory.arg_list(i18n.args.vaal_area_ids),
    },
    [i18n.args.vaal_area_spawn_chance] = {
        property = 'Has vaal area spawn chance',
        func = m_util.cast.factory.number(i18n.args.vaal_area_spawn_chance),
        default = 0,
    },
    [i18n.args.strongbox_spawn_chance] = {
        property = 'Has strongbox spawn chance',
        func = m_util.cast.factory.number(i18n.args.strongbox_spawn_chance),
        default = 0,
    },
    [i18n.args.strongbox_max_count] = {
        property = 'Has maximum number of strongboxes',
        func = m_util.cast.factory.number(i18n.args.strongbox_max_count),
        default = 0,
    },
    [i18n.args.strongbox_rarity_weight] = {
        property = nil,
        func = function (tpl_args, frame)
            local weights = m_util.string.split(tpl_args[i18n.args.strongbox_rarity_weight] or '', ', ')
            
            tpl_args[i18n.args.strongbox_rarity_weight] = {}
            
            for index, data in ipairs(m_game.constants.item.rarity) do
                local value = weights[index] or 0
                tpl_args[i18n.args.strongbox_rarity_weight][data.long_lower] = value
                tpl_args._properties[string.format('Has %s rarity strongbox weight', data.long_lower)] = value 
            end
        end,
    },
    --
    -- Area flags
    --
    [i18n.args.is_map_area] = {
        property = 'Is map area',
        func = m_util.cast.factory.boolean(i18n.args.is_map_area),
        default = false,
    },
    [i18n.args.is_unique_map_area] = {
        property = 'Is unique map area',
        func = m_util.cast.factory.boolean(i18n.args.is_unique_map_area),
        default = false,
    },
    [i18n.args.is_town_area] = {
        property = 'Is town area',
        func = m_util.cast.factory.boolean(i18n.args.is_town_area),
        default = false,
    },
    [i18n.args.is_hideout_area] = {
        property = 'Is hideout area',
        func = m_util.cast.factory.boolean(i18n.args.is_hideout_area),
        default = false,
    },
    [i18n.args.is_vaal_area] = {
        property = 'Is vaal area',
        func = m_util.cast.factory.boolean(i18n.args.is_vaal_area),
        default = false,
    },
    [i18n.args.is_master_daily_area] = {
        property = 'Is master daily area',
        func = m_util.cast.factory.boolean(i18n.args.is_master_daily_area),
        default = false,
    },
    [i18n.args.is_labyrinth_area] = {
        property = 'Is labyrinth area',
        func = m_util.cast.factory.boolean(i18n.args.is_labyrinth_area),
        default = false,
    },
    [i18n.args.is_labyrinth_airlock_area] = {
        property = 'Is labyrinth airlock area',
        func = m_util.cast.factory.boolean(i18n.args.is_labyrinth_airlock_area),
        default = false,
    },
    [i18n.args.is_labyrinth_boss_area] = {
        property = 'Is labyrinth boss area',
        func = m_util.cast.factory.boolean(i18n.args.is_labyrinth_boss_area),
        default = false,
    },
    [i18n.args.has_waypoint] = {
        property = 'Has waypoint',
        func = m_util.cast.factory.boolean(i18n.args.has_waypoint),
        default = false,
    },
}

local argument_order = {
    'id',
    'name',
    'act',
    'area_level',
    'level_restriction_max',
    'area_type_tags',
    'tags',
    'loading_screen',
    'connection_ids',
    'parent_area_id',
    'modifier_ids',
    'boss_monster_ids',
    'monster_ids',
    'entry_text',
    'entry_npc',
    'vaal_area_spawn_chance',
    'vaal_area_ids',
    'strongbox_spawn_chance',
    'strongbox_max_count',
    'strongbox_rarity_weight',
    'is_map_area',
    'is_unique_map_area',
    'is_town_area',
    'is_hideout_area',
    'is_vaal_area',
    'is_master_daily_area',
    'is_labyrinth_area',
    'is_labyrinth_airlock_area',
    'is_labyrinth_boss_area',
    'has_waypoint',
}

local display  = {}
display.area_type = {
    'is_map_area',
    'is_unique_map_area',
    'is_town_area',
    'is_hideout_area',
    'is_vaal_area',
    'is_master_daily_area',
    'is_labyrinth_area',
    'is_labyrinth_airlock_area',
    'is_labyrinth_boss_area',
}

display.map = {
    {
        args = {
            [i18n.args.act] = {
            },
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.act, tpl_args[i18n.args.act]) 
        end,
    }, 
    {
        args = {
            [i18n.args.area_level] = {
            },
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.area_level, tpl_args[i18n.args.area_level]) 
        end,
    },
    {
        args = {
            [i18n.args.level_restriction_max] = {
                hide = 100,
            },
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.level_restriction_max, tpl_args[i18n.args.level_restriction_max]) 
        end,
    },
    {
        args = {
            [i18n.args.area_type_tags] = {
            },
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.area_type_tags, table.concat(tpl_args[i18n.args.area_type_tags], ', ')) 
        end,
    },
    {
        args = {
            [i18n.args.tags] = {
            },
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.tags, table.concat(tpl_args[i18n.args.tags], ', ')) 
        end,
    },
    {
        args = {
            [i18n.args.entry_text] = {},
            [i18n.args.entry_npc] = {},
        },
        func = function(tpl_args, frame)
            return string.format(i18n.tooltips.entry_message, tpl_args[i18n.args.entry_npc], tpl_args[i18n.args.entry_text]) 
        end,
    },
    {
        args = {
           [i18n.args.loading_screen] = {},
        },
        func = function(tpl_args, frame)
            return tpl_args.loading_screen
        end,
    },
}

-- ----------------------------------------------------------------------------
-- display functions
-- ----------------------------------------------------------------------------

local d = {}
function d.area_box(tpl_args, frame)
    local infocard_args = {}
    
    -- Top header
    if tpl_args[i18n.args.name] ~= nil then
        infocard_args.header = string.format('%s (%s)', tpl_args[i18n.args.name], tpl_args[i18n.args.id])
    else
        infocard_args.header = tpl_args[i18n.args.name]
    end
    
    -- Subheader
    local out = {}
    for _, key in ipairs(display.area_type) do
        if tpl_args[i18n.args[key]] == true then
            out[#out+1] = i18n.tooltips[key]
        end
    end

    if #out > 0 then
        infocard_args.subheader = table.concat(out, '')
    else
        infocard_args.subheader = i18n.tooltips.area
    end
    
    -- Side header
    if tpl_args[i18n.args.is_town_area] then
        infocard_args.headerright = i18n.images.waypoint_town
    elseif tpl_args[i18n.args.has_waypoint] then
        infocard_args.headerright = i18n.images.waypoint_yes
    else
        infocard_args.headerright = i18n.images.waypoint_no
    end
    
    -- Main sections, loop through
    local i = 1
    for _, data in ipairs(display.map) do
        local continue = true
        if data.args ~= nil then
            for key, key_data in pairs(data.args) do
                if tpl_args[key] == nil then
                    continue = false
                    break
                elseif key_data.hide == nil and type(tpl_args[key]) == 'table' and #tpl_args[key] == 0 then
                    continue = false
                    break
                elseif type(key_data.hide) == 'table' then
                    local br = false
                    for _, value in ipairs(key_data.hide) do
                        if tpl_args[key] == value then
                            br = true
                            break
                        end
                    end
                    if br then
                        continue = false
                        break
                    end
                elseif tpl_args[key] == key_data.hide then
                    continue = false
                    break
                end
            end
        end
        
        if continue then
            infocard_args[i] = data.func(tpl_args, frame)
            
            i = i +1
        end
    end

    return f_infocard(infocard_args)
end

-- ----------------------------------------------------------------------------
-- Page functions
-- ----------------------------------------------------------------------------

local p = {}

function p.area(frame)
    local tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)
    
    --
    -- Shared args
    --

    tpl_args._properties = {}
    
    -- parse args
    for _, k in ipairs(argument_order) do
        local key = i18n.args[k]
        if key == nil then
            error('Missing i18n for argument: ' .. k)
        end
        local data = argument_map[key]
        if data == nil then
            error('Missing data in argument_map: ' .. key)
        end
        if data.func ~= nil then
            data.func(tpl_args, frame)
        end
        if data.default ~= nil and tpl_args[key] == nil then
            tpl_args[key] = data.default
        end
        
        if data.property ~= nil and tpl_args[key] ~= nil then
            tpl_args._properties[data.property] = tpl_args[key]
        end
    end
    
    -- parse spawn weights
    m_util.args.weight_list(tpl_args, {
        frame=frame, 
        output_argument='spawn_weights',
    })
    
    -- display
    local out = d.area_box(tpl_args, frame)
    
    tpl_args._properties['Has infobox HTML'] = out
    
    -- set semantic properties
    m_util.smw.set(frame, tpl_args._properties)
    
    -- display
    return out
end

return p