Module:Area: Difference between revisions
Jump to navigation
Jump to search
>OmegaK2 (added a note in regards to area level) |
m (84 revisions imported) |
||
(17 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
-- | ------------------------------------------------------------------------------- | ||
-- | |||
-- Module:Area | |||
-- | |||
-- This module implements Template:Area and Template:Query area infoboxes | |||
------------------------------------------------------------------------------- | |||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
Line 8: | Line 13: | ||
-- spawnchacne 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 | 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 | |||
local i18n = | |||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
-- | -- Utility & helper functions | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local | 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 = {} | 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 95: | 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]['areas.main_page'] then | ||
Line 157: | Line 124: | ||
'is_map_area', | 'is_map_area', | ||
'is_unique_map_area', | 'is_unique_map_area', | ||
'is_legacy_map_area', | |||
'is_town_area', | 'is_town_area', | ||
'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 178: | Line 145: | ||
field = 'main_page', | field = 'main_page', | ||
type = 'Page', | type = 'Page', | ||
func = function(tpl_args | func = function(tpl_args, value) | ||
if value ~= nil then | if value ~= nil then | ||
local page = mw.title.new(value) | local page = mw.title.new(value) | ||
Line 223: | Line 190: | ||
field = 'area_type_tags', | field = 'area_type_tags', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = m_util. | 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 = { | tags = { | ||
field = 'tags', | field = 'tags', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = m_util. | 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 = { | loading_screen = { | ||
field = 'loading_screen', | field = 'loading_screen', | ||
type = 'Page', | type = 'Page', | ||
func = function (tpl_args, | func = function (tpl_args, value) | ||
if | if value ~= nil then | ||
tpl_args.loading_screen_infobox = string.format(i18n.images.loading_screen_infobox, | -- value contains loading id | ||
tpl_args.loading_screen_infobox = string.format(i18n.images.loading_screen_infobox, value) | |||
return string.format(i18n.images.loading_screen, | return string.format(i18n.images.loading_screen, value) | ||
end | end | ||
end, | end, | ||
Line 261: | Line 235: | ||
field = 'modifier_ids', | field = 'modifier_ids', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = function(tpl_args | func = function(tpl_args, value) | ||
if value == nil then | if value == nil then | ||
return | return | ||
end | end | ||
tpl_args.mods = | tpl_args.mods = m_cargo.array_query{ | ||
tables={'mods'}, | tables={'mods'}, | ||
fields={'mods.stat_text'}, | fields={'mods.stat_text'}, | ||
Line 279: | Line 253: | ||
field = 'stat_text', | field = 'stat_text', | ||
type = 'Text', | type = 'Text', | ||
func = function (tpl_args, | func = function (tpl_args, value) | ||
if tpl_args.mods == nil then | if tpl_args.mods == nil then | ||
return | return | ||
Line 300: | Line 274: | ||
field = 'boss_monster_ids', | field = 'boss_monster_ids', | ||
type = 'List (,) of String', | 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 = {}, | default = {}, | ||
}, | }, | ||
Line 322: | Line 327: | ||
field = 'screenshot', | field = 'screenshot', | ||
type = 'Page', | type = 'Page', | ||
func = function(tpl_args, | func = function(tpl_args, value) | ||
if tpl_args.name ~= nil then | if tpl_args.name ~= nil then | ||
local name = | -- 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 = 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) | tpl_args.screenshot_infobox = string.format(i18n.images.screenshot_infobox, name, tpl_args.screenshot_ext) | ||
Line 355: | Line 361: | ||
-- fields are handled for this below | -- fields are handled for this below | ||
strongbox_rarity_weight = { | strongbox_rarity_weight = { | ||
func = function (tpl_args, | func = function (tpl_args, value) | ||
local weights = m_util.string.split(tpl_args['strongbox_rarity_weight'] or '', ', ') | local weights = m_util.string.split(tpl_args['strongbox_rarity_weight'] or '', ', ') | ||
for index, rarity in ipairs(m_game.constants.rarity_order) do | |||
for index, | |||
local value = tonumber(weights[index]) or 0 | local value = tonumber(weights[index]) or 0 | ||
-- will be read later | -- will be read later | ||
tpl_args | tpl_args[string.format('strongbox_weight_%s', rarity)] = value | ||
end | end | ||
end, | end, | ||
Line 394: | Line 398: | ||
field = 'is_unique_map_area', | field = 'is_unique_map_area', | ||
type = 'Boolean', | 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, | default = false, | ||
}, | }, | ||
Line 408: | Line 427: | ||
is_vaal_area = { | is_vaal_area = { | ||
field = 'is_vaal_area', | field = 'is_vaal_area', | ||
type = 'Boolean', | type = 'Boolean', | ||
default = false, | default = false, | ||
Line 439: | Line 453: | ||
field = 'mainpage_categories', | field = 'mainpage_categories', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = function (tpl_args | func = function (tpl_args, value) | ||
-- Category handling for main page only by adding the categories to a cargo field: | -- Category handling for main page only by adding the categories to a cargo field: | ||
-- Do notice the plural form. | -- Do notice the plural form. | ||
Line 480: | Line 494: | ||
-- | -- | ||
areas = { | areas = { | ||
func = function(tpl_args | func = function(tpl_args, value) | ||
local query_ids = {} | local query_ids = {} | ||
for _, arg in ipairs({'parent_area_id', 'connection_ids', 'vaal_area_ids'}) do | for _, arg in ipairs({'parent_area_id', 'connection_ids', 'vaal_area_ids'}) do | ||
Line 497: | Line 511: | ||
end | end | ||
local results= | local results=m_cargo.array_query{ | ||
tables={'areas'}, | tables={'areas'}, | ||
fields={'areas._pageName', 'areas.name', 'areas.main_page'}, | fields={'areas._pageName', 'areas.name', 'areas.main_page'}, | ||
Line 511: | Line 525: | ||
if tpl_args.is_vaal_area then | if tpl_args.is_vaal_area then | ||
local spawn_areas = {} | local spawn_areas = {} | ||
results = | results = m_cargo.query( | ||
{'areas'}, | {'areas'}, | ||
{'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, | {'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, | ||
Line 546: | 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 559: | Line 572: | ||
}, | }, | ||
header = i18n.headers.id, | header = i18n.headers.id, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return string.format('[[%s|%s]]', mw.title.getCurrentTitle().fullText, tpl_args.id) | return string.format('[[%s|%s]]', mw.title.getCurrentTitle().fullText, tpl_args.id) | ||
end, | end, | ||
Line 587: | 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 594: | 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 604: | 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 614: | Line 643: | ||
}, | }, | ||
header = i18n.headers.entry_messsage, | header = i18n.headers.entry_messsage, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return m_util.html.poe_color('quest', -- Any other alternatives for spoken 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) | string.format(i18n.tooltips.entry_message, tpl_args.entry_npc, tpl_args.entry_text) | ||
Line 625: | 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 634: | 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 643: | 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, | end, | ||
}, | }, | ||
Line 654: | Line 683: | ||
}, | }, | ||
header = i18n.headers.vaal_spawn_areas, | header = i18n.headers.vaal_spawn_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_spawn_areas) | ||
end, | end, | ||
}, | }, | ||
Line 665: | Line 694: | ||
flavour_text = {}, | flavour_text = {}, | ||
}, | }, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return m_util.html.poe_color('flavour', tpl_args.flavour_text) | return m_util.html.poe_color('flavour', tpl_args.flavour_text) | ||
end, | end, | ||
Line 685: | Line 714: | ||
stat_text = {}, | stat_text = {}, | ||
}, | }, | ||
func = function(tpl_args | func = function(tpl_args) | ||
return m_util.html.poe_color('mod', tpl_args.stat_text) | return m_util.html.poe_color('mod', tpl_args.stat_text) | ||
end, | end, | ||
Line 697: | Line 726: | ||
local d = {} | local d = {} | ||
function d.intro_text(tpl_args | function d.intro_text(tpl_args) | ||
--[[ | --[[ | ||
Display an introductory text about the area. | Display an introductory text about the area. | ||
Line 703: | Line 732: | ||
local out = {} | local out = {} | ||
if mw.ustring.find(tpl_args['id'], '_') then | if mw.ustring.find(tpl_args['id'], '_') then | ||
out[#out+1] = | out[#out+1] = mw.getCurrentFrame():expandTemplate{ | ||
title='Incorrect title', | title='Incorrect title', | ||
args = {title=tpl_args['id']} | args = {title=tpl_args['id']} | ||
Line 748: | Line 777: | ||
end | end | ||
function d._check_args(tpl_args | function d._check_args(tpl_args, data) | ||
local continue = true | local continue = true | ||
if data.args ~= nil then | if data.args ~= nil then | ||
Line 776: | Line 805: | ||
end | end | ||
function d.area_box(tpl_args | function d.area_box(tpl_args) | ||
--[[ | --[[ | ||
Display the area info box. | Display the area info box. | ||
Line 811: | 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 | if d._check_args(tpl_args, data) then | ||
tbl | tbl | ||
:tag('tr') | :tag('tr') | ||
Line 818: | Line 847: | ||
:done() | :done() | ||
:tag('td') | :tag('td') | ||
:wikitext(data.func(tpl_args | :wikitext(data.func(tpl_args) or '') | ||
:done() | :done() | ||
:done() | :done() | ||
Line 828: | Line 857: | ||
local i = 2 | local i = 2 | ||
for _, data in ipairs(display.list_map) do | for _, data in ipairs(display.list_map) do | ||
if d._check_args(tpl_args | if d._check_args(tpl_args, data) then | ||
infocard_args[i] = data.func(tpl_args | infocard_args[i] = data.func(tpl_args) | ||
i = i + 1 | i = i + 1 | ||
end | end | ||
Line 837: | Line 866: | ||
end | end | ||
function d.subobject_box(tpl_args | function d.subobject_box(tpl_args) | ||
--[[ | --[[ | ||
Display the subobject box. | Display the subobject box. | ||
Line 846: | Line 875: | ||
-- spawn weight table | -- spawn weight table | ||
tbl = container:tag('table') | local tbl = container:tag('table') | ||
tbl | tbl | ||
:attr('class', 'wikitable sortable') | :attr('class', 'wikitable sortable') | ||
Line 899: | Line 928: | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
-- | -- Main functions | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local | local function _area(tpl_args) | ||
function | |||
--[[ | --[[ | ||
This function adds cargo tables and displays information about the | This function adds cargo tables and displays information about the | ||
Line 953: | Line 978: | ||
strongbox_spawn_chance = '30', | strongbox_spawn_chance = '30', | ||
strongbox_max = '2', strongbox_rarity_weight = '50, 50, 50, 1', | strongbox_max = '2', strongbox_rarity_weight = '50, 50, 50, 1', | ||
flavour_text = 'Bones of betrayal, ashes of purity.', main_page = 'The Dried Lake'} | flavour_text = 'Bones of betrayal, ashes of purity.', main_page = 'The Dried Lake' | ||
} | |||
]] | ]] | ||
-- | -- | ||
Line 966: | Line 986: | ||
-- | -- | ||
-- Handle release_version and removal_version | -- Handle release_version and removal_version | ||
m_util.args.version(tpl_args | m_util.args.version(tpl_args) | ||
local cargo_values = m_util.args.from_cargo_map{ | local cargo_values = m_util.args.from_cargo_map{ | ||
tpl_args=tpl_args, | tpl_args=tpl_args, | ||
table_map=argument_map, | table_map=argument_map, | ||
rtr=true, | rtr=true, | ||
Line 976: | Line 995: | ||
-- Parse spawn weights | -- Parse spawn weights | ||
m_util.args.spawn_weight_list(tpl_args | m_util.args.spawn_weight_list(tpl_args) | ||
-- Display only on main pages: | -- Display only on main pages: | ||
local out = {} | local out = {} | ||
out[#out+1] = d.area_box(tpl_args | out[#out+1] = d.area_box(tpl_args) | ||
-- Property to store what's output to main pages: | -- Property to store what's output to main pages: | ||
Line 993: | Line 1,005: | ||
-- Set all semantic properties: | -- Set all semantic properties: | ||
mw.logObject('Cargo:' .. | mw.logObject('Cargo:' .. m_cargo.store(cargo_values)) | ||
-- mw.logObject(tpl_args) | |||
-- Display only on data page: | -- Display only on data page: | ||
out[#out+1] = d.subobject_box(tpl_args | out[#out+1] = d.subobject_box(tpl_args) | ||
out[#out+1] = d.intro_text(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 | -- Output of function | ||
return table.concat(out | return table.concat(out) | ||
end | end | ||
function | local function _query_area_info(tpl_args) | ||
--[[ | --[[ | ||
Queries and displays the area infobox. | Queries and displays the area infobox. | ||
Line 1,009: | Line 1,028: | ||
]] | ]] | ||
-- = p.query_area_info{conditions = '[[Is area id::test]]', cats='yes'} | -- = p.query_area_info{conditions = '[[Is area id::test]]', cats='yes'} | ||
if tpl_args.where == nil then | if tpl_args.where == nil then | ||
Line 1,020: | Line 1,035: | ||
tpl_args.cats = m_util.cast.boolean(tpl_args.cats) | tpl_args.cats = m_util.cast.boolean(tpl_args.cats) | ||
local results = | local results = m_cargo.query( | ||
{'areas'}, | {'areas'}, | ||
{'areas.infobox_html', 'areas.mainpage_categories'}, | {'areas.infobox_html', 'areas.mainpage_categories'}, | ||
Line 1,046: | Line 1,061: | ||
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