Module:Area

This module is used on 4000+ pages.
To avoid major disruption and server load, do not make unnecessary edits to this module. Test changes to this module first using its /sandbox and /testcases subpages or your user space. All of the changes can then be applied to this module in a single edit.
Consider discussing changes on the talk page or on Discord before implementing them.
The item module provides functionality for various area-related templates.
Overview
This module is responsible for creating area boxes, other area-related tasks. In the process a lot of the input data is verified and also added as semantic property to pages; as such, any templates deriving from this module should not be used on user pages other then for temporary testing purposes.
This template is also backed by an export script in PyPoE (pypoe_exporter wiki area ...
) which can be used to export item data from the game files which then can be used on the wiki. Use the export when possible.
Implemented templates
Core templates
- {{Area}}
- {{Query area infoboxes}}
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
-- 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]]',
},
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