Module:Area: Difference between revisions
Jump to navigation
Jump to search
>OmegaK2 (Categories) |
m (84 revisions imported) |
||
(69 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
-- | ------------------------------------------------------------------------------- | ||
-- | |||
-- Module:Area | |||
-- | |||
-- This module implements Template:Area and Template:Query area infoboxes | |||
------------------------------------------------------------------------------- | |||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
Line 7: | Line 12: | ||
-- spawn_weight* values | -- spawn_weight* values | ||
-- spawnchacne values | -- spawnchacne values | ||
require('Module:No globals') | |||
local m_util = require('Module:Util') | local m_util = require('Module:Util') | ||
local | local m_cargo = require('Module:Cargo') | ||
local m_game = mw.loadData('Module:Game') | |||
-- | -- Should we use the sandbox version of our submodules? | ||
local | local use_sandbox = m_util.misc.maybe_sandbox('Area') | ||
local f_infocard = require('Module:Infocard')._main | |||
-- | -- The cfg table contains all localisable strings and configuration, to make it | ||
-- | -- easier to port this module to another wiki. | ||
local cfg = use_sandbox and mw.loadData('Module:Area/config/sandbox') or mw.loadData('Module:Area/config') | |||
local | local i18n = cfg.i18n | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
Line 113: | Line 34: | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local factory = {} | local h = {} | ||
function factory. | |||
return function (tpl_args, | -- | ||
-- Functions for processing tpl_args | |||
-- | |||
h.proc = {} | |||
h.proc.factory = {} | |||
function h.proc.factory.list(args) | |||
args = args or {} | |||
return function (tpl_args, value) | |||
return m_util.cast.table(value, { | |||
pattern = args.pattern, | |||
callback = args.callback, | |||
}) | |||
end | end | ||
end | end | ||
local factory = {} | |||
function factory.display_value(k, args) | function factory.display_value(k, args) | ||
return function(tpl_args | return function(tpl_args) | ||
return tpl_args[k] | return tpl_args[k] | ||
end | end | ||
Line 131: | Line 62: | ||
local util = {} | local util = {} | ||
util.display = {} | util.display = {} | ||
function util.display.multiple_areas(tpl_args | function util.display.multiple_areas(tpl_args, area_ids) | ||
local out = {} | local out = {} | ||
for _, area_id in ipairs(area_ids) do | for _, area_id in ipairs(area_ids) do | ||
out[#out+1] = util.display.single_area(tpl_args | out[#out+1] = util.display.single_area(tpl_args, area_id) | ||
end | end | ||
return table.concat(out, '<br>') | return table.concat(out, '<br>') | ||
end | end | ||
function util.display.single_area(tpl_args | function util.display.single_area(tpl_args, area_id) | ||
if tpl_args.areas[area_id] then | if tpl_args.areas[area_id] then | ||
if tpl_args.areas[area_id]['areas.main_page'] then | |||
if tpl_args.areas[area_id][' | return string.format('[[%s|%s]]', tpl_args.areas[area_id]['areas.main_page'], tpl_args.areas[area_id]['areas.name']) | ||
else | else | ||
name | return string.format('%s ([[%s|%s]])', tpl_args.areas[area_id]['areas.name'], tpl_args.areas[area_id]['areas._pageName'], area_id) | ||
end | end | ||
else | else | ||
return area_id | return area_id | ||
Line 156: | Line 85: | ||
-- Argument & display mapping | -- Argument & display mapping | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local display = {} | |||
local argument_map = { | local argument_map = { | ||
table = 'areas', | |||
order = { | |||
'main_page', | |||
'id', | |||
'name', | |||
'act', | |||
'area_level', | |||
'level_restriction_max', | |||
'area_type_tags', | |||
'tags', | |||
'loading_screen', | |||
'connection_ids', | |||
'parent_area_id', | |||
'modifier_ids', | |||
-- populated via modifier ids | |||
'stat_text', | |||
'boss_monster_ids', | |||
'monster_ids', | |||
'entry_text', | |||
'entry_npc', | |||
'flavour_text', | |||
'screenshot_ext', | |||
'screenshot', | |||
'vaal_area_spawn_chance', | |||
'vaal_area_ids', | |||
'strongbox_spawn_chance', | |||
'strongbox_max_count', | |||
'strongbox_rarity_weight', | |||
-- those four are parsed via the argument above | |||
'strongbox_weight_normal', | |||
'strongbox_weight_magic', | |||
'strongbox_weight_rare', | |||
'strongbox_weight_unique', | |||
'is_map_area', | |||
'is_unique_map_area', | |||
'is_legacy_map_area', | |||
'is_town_area', | |||
'is_hideout_area', | |||
'is_vaal_area', | |||
'is_labyrinth_area', | |||
'is_labyrinth_airlock_area', | |||
'is_labyrinth_boss_area', | |||
'has_waypoint', | |||
'mainpage_categories', | |||
-- Non argument, but passed to the script | |||
'areas', | |||
}, | |||
-- | -- | ||
-- User supplied arguments | -- User supplied arguments | ||
-- | -- | ||
main_page = { | fields = { | ||
main_page = { | |||
field = 'main_page', | |||
type = 'Page', | |||
func = function(tpl_args, value) | |||
if value ~= nil then | |||
local page = mw.title.new(value) | |||
if page == nil then | |||
error(string.format(i18n.errors.main_page_is_invalid, value)) | |||
elseif not page.exists then | |||
error(string.format(i18n.errors.main_page_does_not_exist, value)) | |||
else | |||
-- dont need the title object anymore | |||
--tpl_args.main_page = page | |||
end | |||
end | end | ||
return value | |||
end | end | ||
}, | |||
-- | |||
-- Can be populated by PyPoE | |||
-- | |||
id = { | |||
field = 'id', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
name = { | |||
field = 'name', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
act = { | |||
field = 'act', | |||
type = 'Integer', | |||
}, | |||
area_level = { | |||
field = 'area_level', | |||
type = 'Integer', | |||
}, | |||
level_restriction_max = { | |||
field = 'level_restriction_max', | |||
type = 'Integer', | |||
default = 100, | |||
}, | |||
area_type_tags = { | |||
field = 'area_type_tags', | |||
type = 'List (,) of String', | |||
func = h.proc.factory.list{ | |||
callback = m_util.validate.factory.in_table_keys{ | |||
tbl = m_game.constants.tags, | |||
errmsg = i18n.errors.invalid_tag, | |||
errlvl = 4, | |||
}, | |||
}, | |||
default = {}, | |||
}, | |||
tags = { | |||
field = 'tags', | |||
type = 'List (,) of String', | |||
func = h.proc.factory.list{ | |||
callback = m_util.validate.factory.in_table_keys{ | |||
tbl = m_game.constants.tags, | |||
errmsg = i18n.errors.invalid_tag, | |||
errlvl = 4, | |||
}, | |||
}, | |||
default = {}, | |||
}, | |||
loading_screen = { | |||
field = 'loading_screen', | |||
type = 'Page', | |||
func = function (tpl_args, value) | |||
if value ~= nil then | |||
-- value contains loading id | |||
tpl_args.loading_screen_infobox = string.format(i18n.images.loading_screen_infobox, value) | |||
return string.format(i18n.images.loading_screen, value) | |||
end | |||
end, | |||
}, | |||
connection_ids = { | |||
field = 'connection_ids', | |||
type = 'List (,) of String', | |||
default = {}, | |||
}, | |||
parent_area_id = { | |||
field = 'parent_area_id', | |||
type = 'String', | |||
}, | |||
modifier_ids = { | |||
field = 'modifier_ids', | |||
type = 'List (,) of String', | |||
func = function(tpl_args, value) | |||
if value == nil then | |||
return | |||
end | |||
tpl_args.mods = m_cargo.array_query{ | |||
tables={'mods'}, | |||
fields={'mods.stat_text'}, | |||
id_field='mods.id', | |||
id_array=value | |||
} | |||
return value | |||
end, | |||
default = {}, | |||
}, | |||
stat_text = { | |||
field = 'stat_text', | |||
type = 'Text', | |||
func = function (tpl_args, value) | |||
if tpl_args.mods == nil then | |||
return | |||
end | |||
local text = {} | |||
for page, row in pairs(tpl_args.mods) do | |||
if row['mods.stat_text'] ~= '' then | |||
text[#text+1] = row['mods.stat_text'] | |||
end | |||
tpl_args. | |||
end | end | ||
end | return table.concat(text, '<br>') | ||
end, | |||
}, | |||
monster_ids = { | |||
if | field = 'monster_ids', | ||
type = 'List (,) of String', | |||
default = {}, | |||
}, | |||
boss_monster_ids = { | |||
field = 'boss_monster_ids', | |||
type = 'List (,) of String', | |||
func = function(tpl_args, value) | |||
if value == nil then | |||
return | |||
end | end | ||
-- Format the id so it follows cargo standards: | |||
local id = {} | |||
for i, v in ipairs(value) do | |||
id[#id+1] = string.format('"%s"', v) | |||
tpl_args. | end | ||
-- Query monster data: | |||
tpl_args._boss_monster_ids = m_cargo.query( | |||
{'monsters', 'main_pages'}, | |||
' | { | ||
' | 'monsters._pageName', | ||
' | 'monsters.name', | ||
'monsters.metadata_id', | |||
'main_pages._pageName', | |||
}, | }, | ||
{ | |||
join='monsters.metadata_id=main_pages.id', | |||
where=string.format( | |||
'monsters.metadata_id IN (%s)', | |||
table.concat(id, ', ') | |||
), | |||
} | |||
) | |||
return value | |||
end, | |||
default = {}, | |||
}, | |||
entry_text = { | |||
field = 'entry_text', | |||
type = 'Text', | |||
}, | |||
entry_npc = { | |||
field = 'entry_npc', | |||
type = 'String', | |||
}, | |||
flavour_text = { | |||
field = 'flavour_text', | |||
type = 'Text', | |||
}, | |||
screenshot_ext = { | |||
func = nil, | |||
type = 'String', | |||
default = 'jpg', | |||
}, | |||
screenshot = { | |||
field = 'screenshot', | |||
type = 'Page', | |||
func = function(tpl_args, value) | |||
if tpl_args.name ~= nil then | |||
-- value contains screenshot id | |||
local name = value or tpl_args.main_page or tpl_args.name | |||
tpl_args.screenshot = string.format(i18n.images.screenshot, name, tpl_args.screenshot_ext) | |||
tpl_args.screenshot_infobox = string.format(i18n.images.screenshot_infobox, name, tpl_args.screenshot_ext) | |||
end | |||
end, | |||
}, | |||
-- | |||
-- Spawn chances | |||
-- | |||
vaal_area_ids = { | |||
field = 'vaal_area_ids', | |||
type = 'List (,) of String', | |||
default = {}, | |||
}, | |||
vaal_area_spawn_chance = { | |||
field = 'vaal_area_spawn_chance', | |||
type = 'Integer', | |||
default = 0, | |||
}, | |||
strongbox_spawn_chance = { | |||
field = 'strongbox_spawn_chance', | |||
type = 'Integer', | |||
default = 0, | |||
}, | |||
strongbox_max_count = { | |||
field = 'strongbox_max_count', | |||
type = 'Integer', | |||
default = 0, | |||
}, | |||
-- fields are handled for this below | |||
strongbox_rarity_weight = { | |||
func = function (tpl_args, value) | |||
local weights = m_util.string.split(tpl_args['strongbox_rarity_weight'] or '', ', ') | |||
for index, rarity in ipairs(m_game.constants.rarity_order) do | |||
local value = tonumber(weights[index]) or 0 | |||
-- will be read later | |||
tpl_args[string.format('strongbox_weight_%s', rarity)] = value | |||
end | |||
end, | |||
}, | |||
strongbox_weight_normal = { | |||
field = 'strongbox_weight_normal', | |||
type = 'Integer', | |||
}, | |||
strongbox_weight_magic = { | |||
field = 'strongbox_weight_magic', | |||
type = 'Integer', | |||
}, | |||
strongbox_weight_rare = { | |||
field = 'strongbox_weight_rare', | |||
type = 'Integer', | |||
}, | |||
strongbox_weight_unique = { | |||
field = 'strongbox_weight_unique', | |||
type = 'Integer', | |||
}, | |||
-- | |||
-- Area flags | |||
-- | |||
is_map_area = { | |||
field = 'is_map_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_unique_map_area = { | |||
field = 'is_unique_map_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_legacy_map_area = { | |||
field = 'is_legacy_map_area', | |||
type = 'Boolean', | |||
func = function(tpl_args, value) | |||
if tpl_args.is_map_area or tpl_args.is_unique_map_area then | |||
for _, pattern in ipairs(cfg.legacy_map_area_id_patterns) do | |||
if string.find(tpl_args.id, pattern) then | |||
return true | |||
end | |||
end | |||
end | |||
return false | |||
end, | |||
default = false, | |||
}, | |||
is_town_area = { | |||
field = 'is_town_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_hideout_area = { | |||
field = 'is_hideout_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_vaal_area = { | |||
field = 'is_vaal_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_labyrinth_area = { | |||
field = 'is_labyrinth_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_labyrinth_airlock_area = { | |||
field = 'is_labyrinth_airlock_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
is_labyrinth_boss_area = { | |||
field = 'is_labyrinth_boss_area', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
has_waypoint = { | |||
field = 'has_waypoint', | |||
type = 'Boolean', | |||
default = false, | |||
}, | |||
mainpage_categories = { | |||
field = 'mainpage_categories', | |||
type = 'List (,) of String', | |||
func = function (tpl_args, value) | |||
-- Category handling for main page only by adding the categories to a cargo field: | |||
-- Do notice the plural form. | |||
-- -- Areas, Act X areas/Map areas, Unique map areas | |||
local cats = { | |||
'Category:Areas', | |||
} | } | ||
local cats_ini_len = #cats | |||
for _, key in ipairs(display.area_type) do | |||
if tpl_args[key] == true then | |||
cats[#cats+1] = string.format('Category:%ss', i18n.tooltips[key]) | |||
end | |||
end | |||
if #cats == cats_ini_len then | |||
cats[#cats+1] = string.format('Category:Act %s areas', tpl_args.act) | |||
end | |||
return cats | |||
end | end | ||
-- TODO | }, | ||
-- | |||
-- Handled elsewhere | |||
-- | |||
release_version = { | |||
field = 'release_version', | |||
type = 'String', | |||
skip = true, | |||
}, | |||
removal_version = { | |||
field = 'removal_version', | |||
type = 'String', | |||
skip = true, | |||
}, | |||
infobox_html = { | |||
field = 'infobox_html', | |||
type = 'Text', | |||
skip = true, | |||
}, | |||
-- | |||
-- Not argument to the template, but still parsing arguments | |||
-- | |||
areas = { | |||
func = function(tpl_args, value) | |||
local query_ids = {} | |||
for _, arg in ipairs({'parent_area_id', 'connection_ids', 'vaal_area_ids'}) do | |||
if type(tpl_args[arg]) == 'table' then | |||
for _, tbl_id in ipairs(tpl_args[arg]) do | |||
query_ids[tbl_id] = true | |||
end | |||
elseif tpl_args[arg] then | |||
query_ids[tpl_args[arg]] = true | |||
end | |||
end | |||
local query_ids_trimmed = {} | |||
for k, _ in pairs(query_ids) do | |||
query_ids_trimmed[#query_ids_trimmed+1] = k | |||
end | |||
local results=m_cargo.array_query{ | |||
tables={'areas'}, | |||
fields={'areas._pageName', 'areas.name', 'areas.main_page'}, | |||
id_field='areas.id', | |||
id_array=query_ids_trimmed, | |||
warning_on_missing=true, | |||
} | |||
local areas = {} | |||
for _, data in ipairs(results) do | |||
areas[data['areas.id']] = data | |||
end | |||
if tpl_args.is_vaal_area then | |||
local spawn_areas = {} | |||
results = m_cargo.query( | |||
{'areas'}, | |||
{'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, | |||
{ | |||
-- TODO using a workaround since HOLDS is bricked | |||
-- Don't show connected areas without a main_page to avoid showing disabled or areas which are not relevant | |||
where=string.format([[ | |||
areas.vaal_area_ids__full LIKE "%%%s%%" | |||
AND areas.main_page IS NOT NULL | |||
AND areas.vaal_area_spawn_chance > 0 | |||
]], tpl_args.id), | |||
-- area id for story areas basically orders them by appearance, should be good enough | |||
orderBy='areas.id ASC', | |||
} | |||
) | |||
for _, data in ipairs(results) do | |||
table.insert(spawn_areas, data['areas.id']) | |||
areas[data['areas.id']] = data | |||
end | |||
tpl_args.vaal_spawn_areas = spawn_areas | |||
end | |||
return areas | |||
end, | |||
}, | |||
}, | }, | ||
} | } | ||
display.area_type = { | display.area_type = { | ||
'is_map_area', | 'is_map_area', | ||
Line 434: | Line 560: | ||
'is_hideout_area', | 'is_hideout_area', | ||
'is_vaal_area', | 'is_vaal_area', | ||
'is_labyrinth_area', | 'is_labyrinth_area', | ||
'is_labyrinth_airlock_area', | 'is_labyrinth_airlock_area', | ||
Line 441: | Line 566: | ||
display.table_map = { | display.table_map = { | ||
{ | |||
args = { | |||
id = { | |||
}, | |||
}, | |||
header = i18n.headers.id, | |||
func = function(tpl_args) | |||
return string.format('[[%s|%s]]', mw.title.getCurrentTitle().fullText, tpl_args.id) | |||
end, | |||
}, | |||
{ | { | ||
args = { | args = { | ||
Line 465: | Line 600: | ||
header = i18n.headers.level_restriction_max, | header = i18n.headers.level_restriction_max, | ||
func = factory.display_value('level_restriction_max'), | func = factory.display_value('level_restriction_max'), | ||
}, | |||
{ | |||
args = { | |||
boss_monster_ids = { | |||
}, | |||
}, | |||
header = i18n.headers.boss_monster_ids, | |||
func = function(tpl_args) | |||
local out = {} | |||
for _,v in ipairs(tpl_args._boss_monster_ids) do | |||
local page = v['main_pages._pageName'] or v['monsters._pageName'] | |||
local name = v['monsters.name'] or v['monsters.metadata_id'] | |||
out[#out+1] = string.format('[[%s|%s]]', page, name) | |||
end | |||
return table.concat(out, '<br>') | |||
end, | |||
}, | }, | ||
{ | { | ||
Line 472: | Line 623: | ||
}, | }, | ||
header = i18n.headers.area_type_tags, | header = i18n.headers.area_type_tags, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return table.concat(tpl_args.area_type_tags, ', ') | return table.concat(tpl_args.area_type_tags, ', ') | ||
end, | end, | ||
Line 482: | Line 633: | ||
}, | }, | ||
header = i18n.headers.tags, | header = i18n.headers.tags, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return table.concat(tpl_args.tags, ', ') | return table.concat(tpl_args.tags, ', ') | ||
end, | end, | ||
Line 492: | Line 643: | ||
}, | }, | ||
header = i18n.headers.entry_messsage, | header = i18n.headers.entry_messsage, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return string.format(i18n.tooltips.entry_message, tpl_args.entry_npc, tpl_args.entry_text) | return m_util.html.poe_color('quest', -- Any other alternatives for spoken text? | ||
string.format(i18n.tooltips.entry_message, tpl_args.entry_npc, tpl_args.entry_text) | |||
) | |||
end, | end, | ||
}, | }, | ||
Line 501: | Line 654: | ||
}, | }, | ||
header = i18n.headers.parent_area, | header = i18n.headers.parent_area, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return util.display.single_area(tpl_args | return util.display.single_area(tpl_args, tpl_args.parent_area) | ||
end, | end, | ||
}, | }, | ||
Line 510: | Line 663: | ||
}, | }, | ||
header = i18n.headers.connections, | header = i18n.headers.connections, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return util.display.multiple_areas(tpl_args | return util.display.multiple_areas(tpl_args, tpl_args.connection_ids) | ||
end, | end, | ||
}, | }, | ||
Line 519: | Line 672: | ||
}, | }, | ||
header = i18n.headers.vaal_areas, | header = i18n.headers.vaal_areas, | ||
func = function(tpl_args, | func = function(tpl_args) | ||
return util.display.multiple_areas(tpl_args, | return util.display.multiple_areas(tpl_args, tpl_args.vaal_area_ids) | ||
end, | |||
}, | |||
-- virtual field created by querying other area data to find where a vaal area is used | |||
{ | |||
args = { | |||
is_vaal_area = {}, | |||
vaal_spawn_areas = {}, | |||
}, | |||
header = i18n.headers.vaal_spawn_areas, | |||
func = function(tpl_args) | |||
return util.display.multiple_areas(tpl_args, tpl_args.vaal_spawn_areas) | |||
end, | |||
}, | |||
} | |||
display.list_map = { | |||
{ | |||
args = { | |||
flavour_text = {}, | |||
}, | |||
func = function(tpl_args) | |||
return m_util.html.poe_color('flavour', tpl_args.flavour_text) | |||
end, | |||
}, | |||
{ | |||
args = { | |||
loading_screen_infobox = {}, | |||
}, | |||
func = factory.display_value('loading_screen_infobox'), | |||
}, | |||
{ | |||
args = { | |||
screenshot_infobox = {}, | |||
}, | |||
func = factory.display_value('screenshot_infobox'), | |||
}, | |||
{ | |||
args = { | |||
stat_text = {}, | |||
}, | |||
func = function(tpl_args) | |||
return m_util.html.poe_color('mod', tpl_args.stat_text) | |||
end, | end, | ||
}, | }, | ||
Line 530: | Line 725: | ||
local d = {} | local d = {} | ||
function d.area_box(tpl_args | |||
function d.intro_text(tpl_args) | |||
--[[ | |||
Display an introductory text about the area. | |||
]] | |||
local out = {} | |||
if mw.ustring.find(tpl_args['id'], '_') then | |||
out[#out+1] = mw.getCurrentFrame():expandTemplate{ | |||
title='Incorrect title', | |||
args = {title=tpl_args['id']} | |||
} | |||
end | |||
if tpl_args['name'] then | |||
out[#out+1] = string.format( | |||
i18n.intro.text_with_name, | |||
tpl_args['id'], | |||
tpl_args['main_page'] or tostring(mw.title.getCurrentTitle()), | |||
tpl_args['name'] | |||
) | |||
else | |||
out[#out+1] = string.format( | |||
i18n.intro.text_without_name, | |||
tpl_args['id'] | |||
) | |||
end | |||
local connected_areas = {} | |||
for _, arg in ipairs({'connection_ids', 'vaal_area_ids'}) do | |||
if tpl_args[arg] then | |||
for _, id in ipairs(tpl_args[arg]) do | |||
if tpl_args.areas[id] then | |||
connected_areas[#connected_areas+1] = string.format( | |||
'<li>[[%s|%s]] (%s)</li>', | |||
tostring(tpl_args.areas[id]['areas._pageName']), | |||
id, | |||
tostring(tpl_args.areas[id]['areas.name']) | |||
) | |||
end | |||
end | |||
end | |||
end | |||
if #connected_areas > 0 then | |||
out[#out+1] = string.format( | |||
i18n.intro.connections .. '<ul>%s</ul>', | |||
table.concat(connected_areas) | |||
) | |||
end | |||
return table.concat(out) | |||
end | |||
function d._check_args(tpl_args, data) | |||
local continue = true | |||
if data.args ~= nil then | |||
for key, key_data in pairs(data.args) do | |||
if tpl_args[key] == nil or (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 key_data.hide ~= nil and tpl_args[key] == key_data.hide then | |||
continue = false | |||
break | |||
end | |||
end | |||
end | |||
return continue | |||
end | |||
function d.area_box(tpl_args) | |||
--[[ | |||
Display the area info box. | |||
]] | |||
local infocard_args = {} | local infocard_args = {} | ||
infocard_args.header = tpl_args.name | |||
-- Subheader | -- Subheader | ||
Line 549: | Line 823: | ||
if #out > 0 then | if #out > 0 then | ||
infocard_args.subheader = table.concat(out, '') | infocard_args.subheader = table.concat(out, ', ') | ||
else | else | ||
infocard_args.subheader = i18n.tooltips.area | infocard_args.subheader = i18n.tooltips.area | ||
Line 566: | Line 840: | ||
local tbl = mw.html.create('table') | local tbl = mw.html.create('table') | ||
for _, data in ipairs(display.table_map) do | for _, data in ipairs(display.table_map) do | ||
if d._check_args(tpl_args, data) then | |||
if | |||
tbl | tbl | ||
:tag('tr') | :tag('tr') | ||
Line 598: | Line 847: | ||
:done() | :done() | ||
:tag('td') | :tag('td') | ||
:wikitext(data.func(tpl_args | :wikitext(data.func(tpl_args) or '') | ||
:done() | :done() | ||
:done() | :done() | ||
Line 606: | Line 855: | ||
infocard_args[1] = tostring(tbl) | infocard_args[1] = tostring(tbl) | ||
if tpl_args | local i = 2 | ||
for _, data in ipairs(display.list_map) do | |||
if d._check_args(tpl_args, data) then | |||
infocard_args[i] = data.func(tpl_args) | |||
i = i + 1 | |||
end | |||
end | end | ||
return f_infocard(infocard_args) | return f_infocard(infocard_args) | ||
end | |||
function d.subobject_box(tpl_args) | |||
--[[ | |||
Display the subobject box. | |||
]] | |||
local container = mw.html.create('div') | |||
container | |||
:attr('class', 'modbox floatright') | |||
-- spawn weight table | |||
local tbl = container:tag('table') | |||
tbl | |||
:attr('class', 'wikitable sortable') | |||
-- :attr('style', 'style="width: 100%;"') | |||
:tag('tr') | |||
:tag('th') | |||
:attr('colspan', 3) | |||
:wikitext('Spawn Weights') | |||
:done() | |||
:done() | |||
:tag('tr') | |||
:tag('th') | |||
:wikitext('#') | |||
:done() | |||
:tag('th') | |||
:wikitext('Tag') | |||
:done() | |||
:tag('th') | |||
:wikitext('Has spawn weight') | |||
:done() | |||
:done() | |||
:done() | |||
local i = 0 | |||
local value = nil | |||
repeat | |||
i = i + 1 | |||
value = { | |||
tag = tpl_args[string.format('spawn_weight%s_tag', i)], | |||
value = tpl_args[string.format('spawn_weight%s_value', i)], | |||
} | |||
if value.tag then | |||
tbl | |||
:tag('tr') | |||
:tag('td') | |||
:wikitext(i) | |||
:done() | |||
:tag('td') | |||
:wikitext(value.tag) | |||
:done() | |||
:tag('td') | |||
:wikitext(value.value) | |||
:done() | |||
:done() | |||
:done() | |||
end | |||
until value.tag == nil | |||
return tostring(container) | |||
end | end | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
-- | -- Main functions | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local | local function _area(tpl_args) | ||
--[[ | |||
function p.area( | This function adds cargo tables and displays information about the | ||
area. | |||
} | Examples | ||
-------- | |||
= p.area{ | |||
id = '1_1_1', | |||
name = 'The Twilight Strand', | |||
act = 1, | |||
level = 1, | |||
tags = 'no_tempests, area_with_water', | |||
loading_screen = 'Act1', | |||
connection_ids = '1_1_town', | |||
parent_area_id = '1_1_town', | |||
boss_monster_ids = 'Metadata/Monsters/ZombieBoss/ZombieBossHillockNormal', | |||
flavour_text = 'Hope was drowned here.', | |||
main_page = 'The Twilight Strand (Act 1)' | |||
} | |||
= p.area{ | |||
id = '1_1_1', | |||
name = 'The Twilight Strand', | |||
act = 1, | |||
level = 1, | |||
tags = 'no_tempests, area_with_water', | |||
loading_screen = 'Act1', | |||
connection_ids = '1_1_town', | |||
parent_area_id = '1_1_town', | |||
boss_monster_ids = 'Metadata/Monsters/ZombieBoss/ZombieBossHillockNormal', | |||
flavour_text = 'Hope was drowned here.', main_page = 'The Twilight Strand (Act 1)' | |||
} | |||
= p.area{ | |||
id = '1_4_2', | |||
name = 'The Dried Lake', | |||
act = '4', | |||
level = '34', | |||
area_type_tags = 'shore', | |||
tags = 'act_boss_area', | |||
loading_screen = 'Act4', | |||
connection_ids = '1_4_town', | |||
parent_area_id = '1_4_town', | |||
boss_monster_ids = 'Metadata/Monsters/Voll/VollBoss, Metadata/Monsters/SkeletonSoldier/SkeletonSoldierRangedBoss', | |||
vaal_area_spawn_chance = '18', | |||
vaal_area_ids = '1_SideArea4_2, 1_SideArea4_4', | |||
strongbox_spawn_chance = '30', | |||
strongbox_max = '2', strongbox_rarity_weight = '50, 50, 50, 1', | |||
flavour_text = 'Bones of betrayal, ashes of purity.', main_page = 'The Dried Lake' | |||
} | |||
]] | |||
-- | -- | ||
-- Shared args | -- Shared args | ||
-- | -- | ||
-- Handle release_version and removal_version | |||
m_util.args.version(tpl_args) | |||
local cargo_values = m_util.args.from_cargo_map{ | |||
tpl_args=tpl_args, | |||
table_map=argument_map, | |||
rtr=true, | |||
} | |||
-- Parse spawn weights | |||
m_util.args.spawn_weight_list(tpl_args) | |||
-- Display only on main pages: | |||
local out = {} | |||
out[#out+1] = d.area_box(tpl_args) | |||
-- Property to store what's output to main pages: | |||
cargo_values['infobox_html'] = out[1] | |||
-- Set all semantic properties: | |||
mw.logObject('Cargo:' .. m_cargo.store(cargo_values)) | |||
-- mw.logObject(tpl_args) | |||
-- Display only on data page: | |||
out[#out+1] = d.subobject_box(tpl_args) | |||
out[#out+1] = d.intro_text(tpl_args) | |||
-- Attach to table | |||
mw.getCurrentFrame():expandTemplate{title = i18n.templates.attach_template} | |||
-- Category handling for the local data page: | |||
out[#out+1] = m_util.misc.add_category({i18n.categories.area_data}) | |||
-- | -- Output of function | ||
return table.concat(out) | |||
end | |||
local function _query_area_info(tpl_args) | |||
--[[ | |||
Queries and displays the area infobox. | |||
]] | |||
-- = p.query_area_info{conditions = '[[Is area id::test]]', cats='yes'} | |||
if tpl_args.where == nil then | |||
return | |||
end | end | ||
tpl_args.cats = m_util.cast.boolean(tpl_args.cats) | |||
local results = m_cargo.query( | |||
{'areas'}, | |||
{'areas.infobox_html', 'areas.mainpage_categories'}, | |||
{ | |||
where=tpl_args.where, | |||
orderBy=tpl_args.order_by, | |||
} | |||
) | |||
local out = {} | |||
local cats = {} | local cats = {} | ||
for _, | for _, row in ipairs(results) do | ||
if | out[#out+1] = row['areas.infobox_html'] | ||
if row['areas.mainpage_categories'] ~= '' then | |||
for _, cat in ipairs(m_util.string.split(row['areas.mainpage_categories'], ',')) do | |||
cats[#cats+1] = string.gsub(cat, '[Cc]ategory:', '') | |||
end | |||
end | end | ||
end | end | ||
if | if tpl_args.cats then | ||
return table.concat(out) .. m_util.misc.add_category(cats) | |||
else | |||
return table.concat(out) | |||
end | end | ||
end | end | ||
-- ---------------------------------------------------------------------------- | |||
-- Exported functions | |||
-- ---------------------------------------------------------------------------- | |||
local p = {} | |||
p.table_areas = m_cargo.declare_factory{data=argument_map} | |||
-- | |||
-- Template:Area | |||
-- | |||
p.area = m_util.misc.invoker_factory(_area, { | |||
wrappers = cfg.wrappers.area, | |||
}) | |||
-- | |||
-- Template:Query area infoboxes | |||
-- | |||
p.query_area_info = m_util.misc.invoker_factory(_query_area_info, { | |||
wrappers = cfg.wrappers.query_area_info, | |||
}) | |||
return p | return p |
Latest revision as of 06:43, 9 October 2024
You might want to create a documentation page for this module.
Editors can experiment in this module's sandbox and testcases pages.
Please add categories to the /doc subpage. Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Please add categories to the /doc subpage. Subpages of this module.
-------------------------------------------------------------------------------
--
-- Module:Area
--
-- This module implements Template:Area and Template:Query area infoboxes
-------------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
-- TODO
-- ----------------------------------------------------------------------------
-- invalid tags -> utl?
-- spawn_weight* values
-- spawnchacne values
require('Module:No globals')
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local m_game = mw.loadData('Module:Game')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Area')
local f_infocard = require('Module:Infocard')._main
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Area/config/sandbox') or mw.loadData('Module:Area/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Utility & helper functions
-- ----------------------------------------------------------------------------
local h = {}
--
-- Functions for processing tpl_args
--
h.proc = {}
h.proc.factory = {}
function h.proc.factory.list(args)
args = args or {}
return function (tpl_args, value)
return m_util.cast.table(value, {
pattern = args.pattern,
callback = args.callback,
})
end
end
local factory = {}
function factory.display_value(k, args)
return function(tpl_args)
return tpl_args[k]
end
end
local util = {}
util.display = {}
function util.display.multiple_areas(tpl_args, area_ids)
local out = {}
for _, area_id in ipairs(area_ids) do
out[#out+1] = util.display.single_area(tpl_args, area_id)
end
return table.concat(out, '<br>')
end
function util.display.single_area(tpl_args, area_id)
if tpl_args.areas[area_id] then
if tpl_args.areas[area_id]['areas.main_page'] then
return string.format('[[%s|%s]]', tpl_args.areas[area_id]['areas.main_page'], tpl_args.areas[area_id]['areas.name'])
else
return string.format('%s ([[%s|%s]])', tpl_args.areas[area_id]['areas.name'], tpl_args.areas[area_id]['areas._pageName'], area_id)
end
else
return area_id
end
end
-- ----------------------------------------------------------------------------
-- Argument & display mapping
-- ----------------------------------------------------------------------------
local display = {}
local argument_map = {
table = 'areas',
order = {
'main_page',
'id',
'name',
'act',
'area_level',
'level_restriction_max',
'area_type_tags',
'tags',
'loading_screen',
'connection_ids',
'parent_area_id',
'modifier_ids',
-- populated via modifier ids
'stat_text',
'boss_monster_ids',
'monster_ids',
'entry_text',
'entry_npc',
'flavour_text',
'screenshot_ext',
'screenshot',
'vaal_area_spawn_chance',
'vaal_area_ids',
'strongbox_spawn_chance',
'strongbox_max_count',
'strongbox_rarity_weight',
-- those four are parsed via the argument above
'strongbox_weight_normal',
'strongbox_weight_magic',
'strongbox_weight_rare',
'strongbox_weight_unique',
'is_map_area',
'is_unique_map_area',
'is_legacy_map_area',
'is_town_area',
'is_hideout_area',
'is_vaal_area',
'is_labyrinth_area',
'is_labyrinth_airlock_area',
'is_labyrinth_boss_area',
'has_waypoint',
'mainpage_categories',
-- Non argument, but passed to the script
'areas',
},
--
-- User supplied arguments
--
fields = {
main_page = {
field = 'main_page',
type = 'Page',
func = function(tpl_args, value)
if value ~= nil then
local page = mw.title.new(value)
if page == nil then
error(string.format(i18n.errors.main_page_is_invalid, value))
elseif not page.exists then
error(string.format(i18n.errors.main_page_does_not_exist, value))
else
-- dont need the title object anymore
--tpl_args.main_page = page
end
end
return value
end
},
--
-- Can be populated by PyPoE
--
id = {
field = 'id',
type = 'String',
func = nil,
},
name = {
field = 'name',
type = 'String',
func = nil,
},
act = {
field = 'act',
type = 'Integer',
},
area_level = {
field = 'area_level',
type = 'Integer',
},
level_restriction_max = {
field = 'level_restriction_max',
type = 'Integer',
default = 100,
},
area_type_tags = {
field = 'area_type_tags',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.tags,
errmsg = i18n.errors.invalid_tag,
errlvl = 4,
},
},
default = {},
},
tags = {
field = 'tags',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.tags,
errmsg = i18n.errors.invalid_tag,
errlvl = 4,
},
},
default = {},
},
loading_screen = {
field = 'loading_screen',
type = 'Page',
func = function (tpl_args, value)
if value ~= nil then
-- value contains loading id
tpl_args.loading_screen_infobox = string.format(i18n.images.loading_screen_infobox, value)
return string.format(i18n.images.loading_screen, value)
end
end,
},
connection_ids = {
field = 'connection_ids',
type = 'List (,) of String',
default = {},
},
parent_area_id = {
field = 'parent_area_id',
type = 'String',
},
modifier_ids = {
field = 'modifier_ids',
type = 'List (,) of String',
func = function(tpl_args, value)
if value == nil then
return
end
tpl_args.mods = m_cargo.array_query{
tables={'mods'},
fields={'mods.stat_text'},
id_field='mods.id',
id_array=value
}
return value
end,
default = {},
},
stat_text = {
field = 'stat_text',
type = 'Text',
func = function (tpl_args, value)
if tpl_args.mods == nil then
return
end
local text = {}
for page, row in pairs(tpl_args.mods) do
if row['mods.stat_text'] ~= '' then
text[#text+1] = row['mods.stat_text']
end
end
return table.concat(text, '<br>')
end,
},
monster_ids = {
field = 'monster_ids',
type = 'List (,) of String',
default = {},
},
boss_monster_ids = {
field = 'boss_monster_ids',
type = 'List (,) of String',
func = function(tpl_args, value)
if value == nil then
return
end
-- Format the id so it follows cargo standards:
local id = {}
for i, v in ipairs(value) do
id[#id+1] = string.format('"%s"', v)
end
-- Query monster data:
tpl_args._boss_monster_ids = m_cargo.query(
{'monsters', 'main_pages'},
{
'monsters._pageName',
'monsters.name',
'monsters.metadata_id',
'main_pages._pageName',
},
{
join='monsters.metadata_id=main_pages.id',
where=string.format(
'monsters.metadata_id IN (%s)',
table.concat(id, ', ')
),
}
)
return value
end,
default = {},
},
entry_text = {
field = 'entry_text',
type = 'Text',
},
entry_npc = {
field = 'entry_npc',
type = 'String',
},
flavour_text = {
field = 'flavour_text',
type = 'Text',
},
screenshot_ext = {
func = nil,
type = 'String',
default = 'jpg',
},
screenshot = {
field = 'screenshot',
type = 'Page',
func = function(tpl_args, value)
if tpl_args.name ~= nil then
-- value contains screenshot id
local name = value or tpl_args.main_page or tpl_args.name
tpl_args.screenshot = string.format(i18n.images.screenshot, name, tpl_args.screenshot_ext)
tpl_args.screenshot_infobox = string.format(i18n.images.screenshot_infobox, name, tpl_args.screenshot_ext)
end
end,
},
--
-- Spawn chances
--
vaal_area_ids = {
field = 'vaal_area_ids',
type = 'List (,) of String',
default = {},
},
vaal_area_spawn_chance = {
field = 'vaal_area_spawn_chance',
type = 'Integer',
default = 0,
},
strongbox_spawn_chance = {
field = 'strongbox_spawn_chance',
type = 'Integer',
default = 0,
},
strongbox_max_count = {
field = 'strongbox_max_count',
type = 'Integer',
default = 0,
},
-- fields are handled for this below
strongbox_rarity_weight = {
func = function (tpl_args, value)
local weights = m_util.string.split(tpl_args['strongbox_rarity_weight'] or '', ', ')
for index, rarity in ipairs(m_game.constants.rarity_order) do
local value = tonumber(weights[index]) or 0
-- will be read later
tpl_args[string.format('strongbox_weight_%s', rarity)] = value
end
end,
},
strongbox_weight_normal = {
field = 'strongbox_weight_normal',
type = 'Integer',
},
strongbox_weight_magic = {
field = 'strongbox_weight_magic',
type = 'Integer',
},
strongbox_weight_rare = {
field = 'strongbox_weight_rare',
type = 'Integer',
},
strongbox_weight_unique = {
field = 'strongbox_weight_unique',
type = 'Integer',
},
--
-- Area flags
--
is_map_area = {
field = 'is_map_area',
type = 'Boolean',
default = false,
},
is_unique_map_area = {
field = 'is_unique_map_area',
type = 'Boolean',
default = false,
},
is_legacy_map_area = {
field = 'is_legacy_map_area',
type = 'Boolean',
func = function(tpl_args, value)
if tpl_args.is_map_area or tpl_args.is_unique_map_area then
for _, pattern in ipairs(cfg.legacy_map_area_id_patterns) do
if string.find(tpl_args.id, pattern) then
return true
end
end
end
return false
end,
default = false,
},
is_town_area = {
field = 'is_town_area',
type = 'Boolean',
default = false,
},
is_hideout_area = {
field = 'is_hideout_area',
type = 'Boolean',
default = false,
},
is_vaal_area = {
field = 'is_vaal_area',
type = 'Boolean',
default = false,
},
is_labyrinth_area = {
field = 'is_labyrinth_area',
type = 'Boolean',
default = false,
},
is_labyrinth_airlock_area = {
field = 'is_labyrinth_airlock_area',
type = 'Boolean',
default = false,
},
is_labyrinth_boss_area = {
field = 'is_labyrinth_boss_area',
type = 'Boolean',
default = false,
},
has_waypoint = {
field = 'has_waypoint',
type = 'Boolean',
default = false,
},
mainpage_categories = {
field = 'mainpage_categories',
type = 'List (,) of String',
func = function (tpl_args, value)
-- Category handling for main page only by adding the categories to a cargo field:
-- Do notice the plural form.
-- -- Areas, Act X areas/Map areas, Unique map areas
local cats = {
'Category:Areas',
}
local cats_ini_len = #cats
for _, key in ipairs(display.area_type) do
if tpl_args[key] == true then
cats[#cats+1] = string.format('Category:%ss', i18n.tooltips[key])
end
end
if #cats == cats_ini_len then
cats[#cats+1] = string.format('Category:Act %s areas', tpl_args.act)
end
return cats
end
},
--
-- Handled elsewhere
--
release_version = {
field = 'release_version',
type = 'String',
skip = true,
},
removal_version = {
field = 'removal_version',
type = 'String',
skip = true,
},
infobox_html = {
field = 'infobox_html',
type = 'Text',
skip = true,
},
--
-- Not argument to the template, but still parsing arguments
--
areas = {
func = function(tpl_args, value)
local query_ids = {}
for _, arg in ipairs({'parent_area_id', 'connection_ids', 'vaal_area_ids'}) do
if type(tpl_args[arg]) == 'table' then
for _, tbl_id in ipairs(tpl_args[arg]) do
query_ids[tbl_id] = true
end
elseif tpl_args[arg] then
query_ids[tpl_args[arg]] = true
end
end
local query_ids_trimmed = {}
for k, _ in pairs(query_ids) do
query_ids_trimmed[#query_ids_trimmed+1] = k
end
local results=m_cargo.array_query{
tables={'areas'},
fields={'areas._pageName', 'areas.name', 'areas.main_page'},
id_field='areas.id',
id_array=query_ids_trimmed,
warning_on_missing=true,
}
local areas = {}
for _, data in ipairs(results) do
areas[data['areas.id']] = data
end
if tpl_args.is_vaal_area then
local spawn_areas = {}
results = m_cargo.query(
{'areas'},
{'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'},
{
-- TODO using a workaround since HOLDS is bricked
-- Don't show connected areas without a main_page to avoid showing disabled or areas which are not relevant
where=string.format([[
areas.vaal_area_ids__full LIKE "%%%s%%"
AND areas.main_page IS NOT NULL
AND areas.vaal_area_spawn_chance > 0
]], tpl_args.id),
-- area id for story areas basically orders them by appearance, should be good enough
orderBy='areas.id ASC',
}
)
for _, data in ipairs(results) do
table.insert(spawn_areas, data['areas.id'])
areas[data['areas.id']] = data
end
tpl_args.vaal_spawn_areas = spawn_areas
end
return areas
end,
},
},
}
display.area_type = {
'is_map_area',
'is_unique_map_area',
'is_town_area',
'is_hideout_area',
'is_vaal_area',
'is_labyrinth_area',
'is_labyrinth_airlock_area',
'is_labyrinth_boss_area',
}
display.table_map = {
{
args = {
id = {
},
},
header = i18n.headers.id,
func = function(tpl_args)
return string.format('[[%s|%s]]', mw.title.getCurrentTitle().fullText, tpl_args.id)
end,
},
{
args = {
act = {
},
},
header = i18n.headers.act,
func = factory.display_value('act'),
},
{
args = {
area_level = {
},
},
header = i18n.headers.area_level,
func = factory.display_value('area_level'),
},
{
args = {
level_restriction_max = {
hide = 100,
},
},
header = i18n.headers.level_restriction_max,
func = factory.display_value('level_restriction_max'),
},
{
args = {
boss_monster_ids = {
},
},
header = i18n.headers.boss_monster_ids,
func = function(tpl_args)
local out = {}
for _,v in ipairs(tpl_args._boss_monster_ids) do
local page = v['main_pages._pageName'] or v['monsters._pageName']
local name = v['monsters.name'] or v['monsters.metadata_id']
out[#out+1] = string.format('[[%s|%s]]', page, name)
end
return table.concat(out, '<br>')
end,
},
{
args = {
area_type_tags = {
},
},
header = i18n.headers.area_type_tags,
func = function(tpl_args)
return table.concat(tpl_args.area_type_tags, ', ')
end,
},
{
args = {
tags = {
},
},
header = i18n.headers.tags,
func = function(tpl_args)
return table.concat(tpl_args.tags, ', ')
end,
},
{
args = {
entry_text = {},
entry_npc = {},
},
header = i18n.headers.entry_messsage,
func = function(tpl_args)
return m_util.html.poe_color('quest', -- Any other alternatives for spoken text?
string.format(i18n.tooltips.entry_message, tpl_args.entry_npc, tpl_args.entry_text)
)
end,
},
{
args = {
parent_area_ids = {},
},
header = i18n.headers.parent_area,
func = function(tpl_args)
return util.display.single_area(tpl_args, tpl_args.parent_area)
end,
},
{
args = {
connection_ids = {},
},
header = i18n.headers.connections,
func = function(tpl_args)
return util.display.multiple_areas(tpl_args, tpl_args.connection_ids)
end,
},
{
args = {
vaal_area_ids = {},
},
header = i18n.headers.vaal_areas,
func = function(tpl_args)
return util.display.multiple_areas(tpl_args, tpl_args.vaal_area_ids)
end,
},
-- virtual field created by querying other area data to find where a vaal area is used
{
args = {
is_vaal_area = {},
vaal_spawn_areas = {},
},
header = i18n.headers.vaal_spawn_areas,
func = function(tpl_args)
return util.display.multiple_areas(tpl_args, tpl_args.vaal_spawn_areas)
end,
},
}
display.list_map = {
{
args = {
flavour_text = {},
},
func = function(tpl_args)
return m_util.html.poe_color('flavour', tpl_args.flavour_text)
end,
},
{
args = {
loading_screen_infobox = {},
},
func = factory.display_value('loading_screen_infobox'),
},
{
args = {
screenshot_infobox = {},
},
func = factory.display_value('screenshot_infobox'),
},
{
args = {
stat_text = {},
},
func = function(tpl_args)
return m_util.html.poe_color('mod', tpl_args.stat_text)
end,
},
}
-- ----------------------------------------------------------------------------
-- display functions
-- ----------------------------------------------------------------------------
local d = {}
function d.intro_text(tpl_args)
--[[
Display an introductory text about the area.
]]
local out = {}
if mw.ustring.find(tpl_args['id'], '_') then
out[#out+1] = mw.getCurrentFrame():expandTemplate{
title='Incorrect title',
args = {title=tpl_args['id']}
}
end
if tpl_args['name'] then
out[#out+1] = string.format(
i18n.intro.text_with_name,
tpl_args['id'],
tpl_args['main_page'] or tostring(mw.title.getCurrentTitle()),
tpl_args['name']
)
else
out[#out+1] = string.format(
i18n.intro.text_without_name,
tpl_args['id']
)
end
local connected_areas = {}
for _, arg in ipairs({'connection_ids', 'vaal_area_ids'}) do
if tpl_args[arg] then
for _, id in ipairs(tpl_args[arg]) do
if tpl_args.areas[id] then
connected_areas[#connected_areas+1] = string.format(
'<li>[[%s|%s]] (%s)</li>',
tostring(tpl_args.areas[id]['areas._pageName']),
id,
tostring(tpl_args.areas[id]['areas.name'])
)
end
end
end
end
if #connected_areas > 0 then
out[#out+1] = string.format(
i18n.intro.connections .. '<ul>%s</ul>',
table.concat(connected_areas)
)
end
return table.concat(out)
end
function d._check_args(tpl_args, data)
local continue = true
if data.args ~= nil then
for key, key_data in pairs(data.args) do
if tpl_args[key] == nil or (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 key_data.hide ~= nil and tpl_args[key] == key_data.hide then
continue = false
break
end
end
end
return continue
end
function d.area_box(tpl_args)
--[[
Display the area info box.
]]
local infocard_args = {}
infocard_args.header = tpl_args.name
-- Subheader
local out = {}
for _, key in ipairs(display.area_type) do
if tpl_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.is_town_area then
infocard_args.headerright = i18n.images.waypoint_town
elseif tpl_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 tbl = mw.html.create('table')
for _, data in ipairs(display.table_map) do
if d._check_args(tpl_args, data) then
tbl
:tag('tr')
:tag('th')
:wikitext(data.header or '')
:done()
:tag('td')
:wikitext(data.func(tpl_args) or '')
:done()
:done()
end
end
infocard_args[1] = tostring(tbl)
local i = 2
for _, data in ipairs(display.list_map) do
if d._check_args(tpl_args, data) then
infocard_args[i] = data.func(tpl_args)
i = i + 1
end
end
return f_infocard(infocard_args)
end
function d.subobject_box(tpl_args)
--[[
Display the subobject box.
]]
local container = mw.html.create('div')
container
:attr('class', 'modbox floatright')
-- spawn weight table
local tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
-- :attr('style', 'style="width: 100%;"')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext('Spawn Weights')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Tag')
:done()
:tag('th')
:wikitext('Has spawn weight')
:done()
:done()
:done()
local i = 0
local value = nil
repeat
i = i + 1
value = {
tag = tpl_args[string.format('spawn_weight%s_tag', i)],
value = tpl_args[string.format('spawn_weight%s_value', i)],
}
if value.tag then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.tag)
:done()
:tag('td')
:wikitext(value.value)
:done()
:done()
:done()
end
until value.tag == nil
return tostring(container)
end
-- ----------------------------------------------------------------------------
-- Main functions
-- ----------------------------------------------------------------------------
local function _area(tpl_args)
--[[
This function adds cargo tables and displays information about the
area.
Examples
--------
= p.area{
id = '1_1_1',
name = 'The Twilight Strand',
act = 1,
level = 1,
tags = 'no_tempests, area_with_water',
loading_screen = 'Act1',
connection_ids = '1_1_town',
parent_area_id = '1_1_town',
boss_monster_ids = 'Metadata/Monsters/ZombieBoss/ZombieBossHillockNormal',
flavour_text = 'Hope was drowned here.',
main_page = 'The Twilight Strand (Act 1)'
}
= p.area{
id = '1_1_1',
name = 'The Twilight Strand',
act = 1,
level = 1,
tags = 'no_tempests, area_with_water',
loading_screen = 'Act1',
connection_ids = '1_1_town',
parent_area_id = '1_1_town',
boss_monster_ids = 'Metadata/Monsters/ZombieBoss/ZombieBossHillockNormal',
flavour_text = 'Hope was drowned here.', main_page = 'The Twilight Strand (Act 1)'
}
= p.area{
id = '1_4_2',
name = 'The Dried Lake',
act = '4',
level = '34',
area_type_tags = 'shore',
tags = 'act_boss_area',
loading_screen = 'Act4',
connection_ids = '1_4_town',
parent_area_id = '1_4_town',
boss_monster_ids = 'Metadata/Monsters/Voll/VollBoss, Metadata/Monsters/SkeletonSoldier/SkeletonSoldierRangedBoss',
vaal_area_spawn_chance = '18',
vaal_area_ids = '1_SideArea4_2, 1_SideArea4_4',
strongbox_spawn_chance = '30',
strongbox_max = '2', strongbox_rarity_weight = '50, 50, 50, 1',
flavour_text = 'Bones of betrayal, ashes of purity.', main_page = 'The Dried Lake'
}
]]
--
-- Shared args
--
-- Handle release_version and removal_version
m_util.args.version(tpl_args)
local cargo_values = m_util.args.from_cargo_map{
tpl_args=tpl_args,
table_map=argument_map,
rtr=true,
}
-- Parse spawn weights
m_util.args.spawn_weight_list(tpl_args)
-- Display only on main pages:
local out = {}
out[#out+1] = d.area_box(tpl_args)
-- Property to store what's output to main pages:
cargo_values['infobox_html'] = out[1]
-- Set all semantic properties:
mw.logObject('Cargo:' .. m_cargo.store(cargo_values))
-- mw.logObject(tpl_args)
-- Display only on data page:
out[#out+1] = d.subobject_box(tpl_args)
out[#out+1] = d.intro_text(tpl_args)
-- Attach to table
mw.getCurrentFrame():expandTemplate{title = i18n.templates.attach_template}
-- Category handling for the local data page:
out[#out+1] = m_util.misc.add_category({i18n.categories.area_data})
-- Output of function
return table.concat(out)
end
local function _query_area_info(tpl_args)
--[[
Queries and displays the area infobox.
]]
-- = p.query_area_info{conditions = '[[Is area id::test]]', cats='yes'}
if tpl_args.where == nil then
return
end
tpl_args.cats = m_util.cast.boolean(tpl_args.cats)
local results = m_cargo.query(
{'areas'},
{'areas.infobox_html', 'areas.mainpage_categories'},
{
where=tpl_args.where,
orderBy=tpl_args.order_by,
}
)
local out = {}
local cats = {}
for _, row in ipairs(results) do
out[#out+1] = row['areas.infobox_html']
if row['areas.mainpage_categories'] ~= '' then
for _, cat in ipairs(m_util.string.split(row['areas.mainpage_categories'], ',')) do
cats[#cats+1] = string.gsub(cat, '[Cc]ategory:', '')
end
end
end
if tpl_args.cats then
return table.concat(out) .. m_util.misc.add_category(cats)
else
return table.concat(out)
end
end
-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------
local p = {}
p.table_areas = m_cargo.declare_factory{data=argument_map}
--
-- Template:Area
--
p.area = m_util.misc.invoker_factory(_area, {
wrappers = cfg.wrappers.area,
})
--
-- Template:Query area infoboxes
--
p.query_area_info = m_util.misc.invoker_factory(_query_area_info, {
wrappers = cfg.wrappers.query_area_info,
})
return p