- Welcome to the Kancolle Wiki!
- If you have any questions regarding site content, account registration, etc., please visit the KanColle Wiki Discord
Difference between revisions of "Module:NodeInfo"
Jump to navigation
Jump to search
com>IloveSuiseiseki |
(merge NodeInfoInvoke) |
||
Line 416: | Line 416: | ||
if self._args["toggle_id"] then | if self._args["toggle_id"] then | ||
table.insert(self._rows, self._collapser_end) | table.insert(self._rows, self._collapser_end) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | local templates = { | ||
+ | title = '<div id="${map} ${node}" style="width:680px;text-align:center">${map} ${node}${nameSuffix} ([https://db.kcwiki.moe/drop/map/${world_number}${map_number}/${node}-SAB.html PoiDB])</div>\n', | ||
+ | title_simple = '<div id="${map} ${node}" style="width:680px;text-align:center">${map} ${node}${nameSuffix}</div>\n', | ||
+ | event_title = '<div id="${map} ${node} ${diff}" style="width:680px;text-align:center">${map} ${node}${nameSuffix} ([https://db.kcwiki.moe/drop/map/${world_number}${map_number}/${diff_number}/${node}-SAB.html PoiDB])</div>\n', | ||
+ | event_title_simple = '<div id="${map} ${node} ${diff}" style="width:680px;text-align:center">${map} ${node}${nameSuffix}</div>\n', | ||
+ | } | ||
+ | |||
+ | local world_numbers = { | ||
+ | ["World 1"] = 1, | ||
+ | ["World 2"] = 2, | ||
+ | ["World 3"] = 3, | ||
+ | ["World 4"] = 4, | ||
+ | ["World 5"] = 5, | ||
+ | ["World 6"] = 6, | ||
+ | ["Winter 2016 Event"] = 33, | ||
+ | ["Spring 2016 Event"] = 34, | ||
+ | ["Summer 2016 Event"] = 35, | ||
+ | ["Fall 2016 Event"] = 36, | ||
+ | ["Winter 2017 Event"] = 37, | ||
+ | ["Spring 2017 Event"] = 38, | ||
+ | ["Summer 2017 Event"] = 39, | ||
+ | ["Fall 2017 Event"] = 40, | ||
+ | ["Winter 2018 Event"] = 41, | ||
+ | } | ||
+ | |||
+ | local diff_numbers_legacy = { | ||
+ | ["Easy"] = 1, | ||
+ | ["Normal"] = 2, | ||
+ | ["Medium"] = 2, | ||
+ | ["Hard"] = 3, | ||
+ | } | ||
+ | |||
+ | local diff_numbers = { | ||
+ | ["Casual"] = 1, | ||
+ | ["Easy"] = 2, | ||
+ | ["Medium"] = 3, | ||
+ | ["Hard"] = 4, | ||
+ | } | ||
+ | |||
+ | local simple_node_types = { "Resource", "Storm", "Empty", "Select" } | ||
+ | |||
+ | function formatTitle(pagename, args) | ||
+ | |||
+ | local world, map = string.match(pagename, "([^/]+)/([^/]+)") | ||
+ | world = world or "?" | ||
+ | map = map or "?" | ||
+ | |||
+ | local world_number = world_numbers[world] or "?" | ||
+ | local map_number = string.match(map:sub(3, 4), "%d") or "?" | ||
+ | |||
+ | local node = args[1] or "?" | ||
+ | local node_type = args[2] or "?" | ||
+ | local is_simple_node_type = node_type == "?" or U.ifind(simple_node_types, node_type) | ||
+ | |||
+ | local diffs = (world_number == "?" or world_number >= 41) and diff_numbers or diff_numbers_legacy | ||
+ | local diff = diffs[args.diff] and args.diff | ||
+ | local diff_number = diffs[diff] or "?" | ||
+ | |||
+ | local nameSuffix = args.name and ": " .. args.name or "" | ||
+ | |||
+ | return U.format{ | ||
+ | is_simple_node_type and | ||
+ | (diff and templates.event_title_simple or templates.title_simple) or | ||
+ | (diff and templates.event_title or templates.title), | ||
+ | map = map, | ||
+ | node = node, | ||
+ | diff = diff, | ||
+ | nameSuffix = nameSuffix, | ||
+ | world_number = world_number, | ||
+ | map_number = map_number, | ||
+ | diff_number = diff_number, | ||
+ | } | ||
+ | end | ||
+ | |||
+ | function NodeInfo.TableFinal(frame) | ||
+ | local args = U.getTemplateArgs(frame) | ||
+ | local table_string = NodeInfo:Table(args.explicit) | ||
+ | if args.explicit.diff or args.implicit.pagename and args.implicit.pagename:sub(1, 5) == "World" then | ||
+ | return formatTitle(args.implicit.pagename, args.explicit) .. table_string | ||
+ | else | ||
+ | return table_string | ||
end | end | ||
end | end |
Revision as of 04:52, 4 May 2018
Documentation for this module may be created at Module:NodeInfo/doc
local U = require("Module:Utils")
local format = require('Module:Utils').format
local BaseTable = require("Module:BaseTable")
local EnemyShip = require("Module:EnemyShip")
local Formatting = require('Module:Formatting')
local ShipBattleCardKai = require("Module:ShipBattleCardKai")
local NodeInfo = BaseTable({
_item_class = EnemyShip,
_table_start = [[{| class="wikitable typography-xl-optout" style="width:680px"]],
_header_template = [[!#
!Formation
!${node_type}
!AD/AP<br>AS/AS+]],
_header_template_simple = [[!#
!colspan="3"|${node_type}]],
_column_cell_templates = {
node = [[| colspan="${colspan}" rowspan="${rowspan}" style="text-align: center; color: ${color}; background-color: ${bg_color};" |${values.node}]],
formation = [[| style="text-align: center; background-color: ${bg_color}; color: ${color};" |${values.formation}]],
fleet = [[| style="width: 490px; background-color: ${bg_color};" |${values.fleet}]],
as = [[| style="text-align: center; background-color: ${bg_color}; color: ${color};" |${values.as}]],
},
_empty_node_template = [[| style="text-align: center;" |${values.node}
| colspan="3" style="text-align: center;" |Must be my imagination (battle avoided)/No enemies sighted<br /><span lang="ja">気のせいだった(戦闘回避)/敵影を見ず。(戦闘なし)</span>]],
_selection_node_template = [[|style="text-align: center;" |${values.node}
| colspan="3" style="text-align: center;" |You may choose which direction your fleet will go. Admiral, which path will you choose?<br /><span lang="ja">艦隊針路選択可能!/艦隊の針路を選択できます。提督、どちらの針路をとられますか?</span>]],
_resource_node_template = [[| style="text-align: center; background-color: ${values.bg_color}; color: ${values.color};" |${values.node}
| colspan="3" style="text-align: center; background-color: ${values.bg_color}; color: ${values.color};" |${values.text}]],
_collapser_template = [[<div class="mw-customtoggle-${toggle_id} wikia-menu-button">${button_display}</div>
<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-${toggle_id}">]],
_collapser_end = [[</div>]],
_columns = {
"node",
"formation",
"fleet",
"as",
},
_day_battle_color = "gold",
_night_battle_color = "blue",
_night_battle_bg_color = "lightblue", -- #BBDEFB
_aerial_battle_bg_color = "lightgreen", -- #C8E6C9
_defense_battle_bg_color = "#81C784",
_raid_battle_bg_color = "#81C784",
_boss_battle_color = "red",
--_resource_node_bg_color = "lightgreen",
_resource_node_bg_color = "initial",
--_maelstrom_node_bg_color = "pink",
_maelstrom_node_bg_color = "initial",
})
function NodeInfo:node(row)
local color, bg_color = "initial", "initial"
if row.tags.boss then
color = self._boss_battle_color
end
if row.tags.aerial then
bg_color = self._aerial_battle_bg_color
end
if row.tags.defense then
bg_color = self._defense_battle_bg_color
end
if row.tags.dogfight then
bg_color = self._defense_battle_bg_color
end
if row.tags.raid then
bg_color = self._raid_battle_bg_color
end
if row.tags.night then
bg_color = self._night_battle_bg_color
end
if row.tags.nighttoday then
bg_color = self._night_battle_bg_color
end
return { values = { node = Formatting:japanese_text(row.node) }, color = color, bg_color = bg_color }
end
function NodeInfo:formation(row)
if row.tags.final then
row.formation = row.formation .. "<br />(Final)"
end
local color = "initial"
if row.tags.boss then
color = self._boss_battle_color
end
return { values = { formation = row.formation }, color = color }
end
function NodeInfo:fleet(row)
return { values = { fleet = row.fleet } }
end
function NodeInfo:as(row)
color = "initial"
if row.tags.boss then
color = self._boss_battle_color
end
return { values = { as = row.as }, color = color }
end
function NodeInfo:upcase(str)
str = str:gsub("(%s)(%l)", function(a, b) return a .. string.upper(b) end)
str = str:gsub("^(%l)", function(a) return string.upper(a) end)
return str
end
function NodeInfo:insert_item(node, formation, fleet, as, tags, as_complete)
--[=[
-- Can give weird results when major contributors to air power are unknown
-- [[Category:Todo]] : use tooltips with explanations instead
local air_parity = (as_complete or as > 0) and string.format("%.1d", math.ceil((2./3.) * as)) or "??"
local air_superiority = (as_complete or as > 0) and string.format("%.1d", math.ceil(as * (3 / 2))) or "??"
local air_supremacy = (as_complete or as > 0) and tostring(as * 3) or "??"
local air_string = not as_complete and as > 0 and (air_parity .. "+/" .. air_superiority .. "+/" .. air_supremacy .. "+")
or (air_parity .. "/" .. air_superiority .. "/" .. air_supremacy)
--]=]
local air_denial_string = "?"
local air_parity_string = "?"
local air_superiority_string = "?"
local air_supremacy_string = "?"
if as_complete then
local air_denial = as > 0 and math.floor(as / 3 + 1) or 0
local air_parity = as > 0 and math.floor(as * 2 / 3 + 1) or 0
local air_superiority = math.ceil(as * 3 / 2)
local air_supremacy = as * 3
air_denial_string = string.format("%.1d", air_denial)
air_parity_string = string.format("%.1d", air_parity)
air_superiority_string = string.format("%.1d", air_superiority)
air_supremacy_string = string.format("%.1d", air_supremacy)
end
local air_string = air_denial_string .. "/" .. air_parity_string .. "<br>" .. air_superiority_string .. "/" .. air_supremacy_string
table.insert(self._items, {
node = node,
formation = formation,
fleet = fleet,
as = air_string,
tags = tags,
})
end
function NodeInfo:create_items()
--Modes are as follows:
--1 = Node
--2 = Tag processing
--3 = Resource type
--4 = Amount of resources
--5 = Formation
--6 = Fleet building
local mode = 1
local node, formation = nil, nil
local fleet = {}
local as_rating, as_complete = 0, true
local tags = {}
local resource
for index, item_key in ipairs(self._args) do
if item_key == "-" then
if mode == 6 then --We're at a break and have built a full row; time to insert it
self:insert_item(node, formation, table.concat(fleet, " "), as_rating, tags, as_complete)
end
table.insert(self._items, "break")
fleet, as_rating, as_complete = {}, 0, true
tags = {}
mode = 1
else
if mode == 1 then
--First item should always be the node
node = item_key
mode = 2
elseif mode == 2 then
self._node_type = string.lower(string.match(item_key, "(.-)/") or item_key)
if mw.ustring.find(string.lower(item_key), "resource") or string.lower(item_key) == "storm" then
local split = mw.ustring.find(item_key, '/')
if split then
tags[string.lower(mw.ustring.sub(item_key, 1, split - 1))] = true
item_key = mw.ustring.sub(item_key, split + 1)
end
tags[string.lower(item_key)] = true
mode = 3
elseif string.lower(item_key) == "empty" then
table.insert(self._items, node .. "/empty")
mode = 1
elseif string.lower(item_key) == "select" then
table.insert(self._items, node .. "/select")
mode = 1
else
while mw.ustring.find(item_key, '/') do
local split = mw.ustring.find(item_key, '/')
tags[string.lower(mw.ustring.sub(item_key, 1, split - 1))] = true
item_key = mw.ustring.sub(item_key, split + 1)
end
tags[string.lower(item_key)] = true
mode = 5
end
elseif mode == 3 then
resource = self:upcase(item_key)
mode = 4
elseif mode == 4 then
local amount = item_key
if tags["storm"] and mw.ustring.sub(amount, 1, 1) ~= "-" then
amount = "-" .. amount
end
local boss = tags["boss"] and "true" or "false"
local string = node .. "/" .. resource .. "/" .. amount .. "/" .. boss
table.insert(self._items, string)
mode = 1
elseif mode == 5 then
formation = self:upcase(item_key)
mode = 6
else
--Fleets are of variable size, so we append onto a string until we hit the next node declaration
local split = mw.ustring.find(item_key, '/')
local ship_name, ship_suffix
if split then
ship_name = mw.ustring.sub(item_key, 1, split - 1)
ship_suffix = mw.ustring.sub(item_key, split + 1)
else
ship_name = item_key
ship_suffix = ""
end
local ship = EnemyShip(ship_name, ship_suffix)
local ship_air_power = ship:air_power(tags.raid)
local ship_caption =
(ship:name() or "?")
.. " (" .. Formatting:format_enemy_stat(ship:api_id()) .. "): "
.. (ship:armor() or "?") .. " Armor, " .. (ship:hp() or "?") .. " HP"
.. (ship_air_power ~= 0 and ", " .. (ship_air_power or "?") .. " AP" or "")
table.insert(fleet, ShipBattleCardKai:get{
ship = ship,
caption = ship_caption,
link = ship:link(),
flagship = #fleet == 0
})
if ship_air_power then
as_rating = as_rating + ship_air_power
else
as_complete = false
end
end
end
end
if mode == 6 then
self:insert_item(node, formation, table.concat(fleet, " "), as_rating, tags, as_complete)
end
end
function NodeInfo:create_data_rows()
for index, item in ipairs(self._items) do
local row_values
if type(item) == "string" then
row_values = item
else
row_values = {}
for _, column in ipairs(self._columns) do
row_values[column] = self[column](self, item)
end
if index > 1 then
for _, column in ipairs(self._columns) do
for i = index - 1, 1, -1 do
if column == "node" then
local previous_cell = self._data_rows[i][column]
if previous_cell then
if row_values[column].values.node == previous_cell.values.node then
previous_cell.rowspan = previous_cell.rowspan and previous_cell.rowspan + 1 or 2
row_values[column] = nil
else
row_values[column].rowspan = 1
row_values[column].colspan = 1
end
break
end
end
end
end
else
for _, column in ipairs(self._columns) do
row_values[column].rowspan = 1
row_values[column].colspan = 1
end
end
end
table.insert(self._data_rows, row_values)
end
end
function NodeInfo:format_node_type()
local node_types = {
normal = 'Normal Battle Node',
boss = 'Boss Battle Node',
resource = 'Resource Node',
storm = 'Maelstrom Node',
empty = 'Empty Node',
select = 'Selection Node',
night = 'Night Battle Node',
aerial = 'Aerial Battle Node',
defense = 'Air Defense Node',
nighttoday = 'Night to Day Battle Node',
raid = 'Air Raids',
}
return self._args["comment"] or node_types[self._node_type] or "Fleet"
end
function NodeInfo:is_simple_node_type()
return self._node_type == 'resource' or self._node_type == 'storm' or self._node_type == 'empty' or self._node_type == 'select'
end
function NodeInfo:create_header()
local header_string = format{
self:is_simple_node_type() and self._header_template_simple or self._header_template,
node_type = self:format_node_type()
}
self._header = header_string
self._header_bottom = header_string
end
function NodeInfo:start_rows()
self._rows = {}
if self._args["toggle_id"] then
table.insert(self._rows, format{self._collapser_template,
toggle_id = self._args["toggle_id"],
button_display = self._args["button_display"] or "Show/Hide Formation Table",
})
end
table.insert(self._rows, self._table_start)
table.insert(self._rows, self._header)
end
function NodeInfo:process_resource_node(resource, amount)
--Amount may or may not be just numbers
local action, units, node_type, bg_color = "Gained", "", "Resource", self._resource_node_bg_color
if mw.ustring.sub(amount, 1, 1) == "-" then
action = "Lost"
amount = mw.ustring.sub(amount, 2)
node_type = "Storm"
bg_color = self._maelstrom_node_bg_color
end
if mw.ustring.find(amount, " ") then
local split = mw.ustring.find(amount, " ")
units = mw.ustring.sub(amount, split + 1)
amount = mw.ustring.sub(amount, 1, split - 1)
end
local text = action .. " " .. amount .. " " .. resource .. " " .. units
return text, node_type, bg_color
end
function NodeInfo:build_rows()
local bg_color
for index, row_values in ipairs(self._data_rows) do
if row_values ~= "break" then
table.insert(self._rows, self._row_starter)
if row_values == "header" then
table.insert(self._rows, self._header)
elseif type(row_values) == "table" then
if row_values["node"] then
bg_color = row_values["node"].bg_color
elseif bg_color == nil then
bg_color = "initial"
end
for _, column in ipairs(self._columns) do
if row_values[column] then
row_values[column].bg_color = bg_color
end
if row_values[column] then
table.insert(self._rows, format(self._column_cell_templates[column] or self._cell, row_values[column]))
end
end
elseif mw.ustring.find(row_values, '/') then
--node/resource/amount/boss
local values = {}
while mw.ustring.find(row_values, '/') do
local split = mw.ustring.find(row_values, '/')
if split then
table.insert(values, mw.ustring.sub(row_values, 1, split - 1))
row_values = mw.ustring.sub(row_values, split + 1)
end
end
table.insert(values, row_values)
if values[2] == "empty" then
table.insert(self._rows, format{self._empty_node_template, values = { node = Formatting:japanese_text(values[1]) } })
elseif values[2] == "select" then
table.insert(self._rows, format{self._selection_node_template, values = { node = Formatting:japanese_text(values[1]) } })
else
local resource = Formatting:format_image{values[2] .. ".png", caption = self:upcase(values[2]), size = "22x22px"}
local text, node_type, bg_color = self:process_resource_node(resource, values[3])
local color = "initial"
if values[4] == "true" then
color = self._boss_battle_color
end
table.insert(self._rows, format{self._resource_node_template, values = {
node = Formatting:japanese_text(values[1]),
text = text,
color = color,
bg_color = bg_color,
}})
end
end
end
end
end
function NodeInfo:finish_rows()
table.insert(self._rows, self._row_starter)
table.insert(self._rows, self._header_bottom or self._header)
table.insert(self._rows, self._table_end)
if self._args["toggle_id"] then
table.insert(self._rows, self._collapser_end)
end
end
local templates = {
title = '<div id="${map} ${node}" style="width:680px;text-align:center">${map} ${node}${nameSuffix} ([https://db.kcwiki.moe/drop/map/${world_number}${map_number}/${node}-SAB.html PoiDB])</div>\n',
title_simple = '<div id="${map} ${node}" style="width:680px;text-align:center">${map} ${node}${nameSuffix}</div>\n',
event_title = '<div id="${map} ${node} ${diff}" style="width:680px;text-align:center">${map} ${node}${nameSuffix} ([https://db.kcwiki.moe/drop/map/${world_number}${map_number}/${diff_number}/${node}-SAB.html PoiDB])</div>\n',
event_title_simple = '<div id="${map} ${node} ${diff}" style="width:680px;text-align:center">${map} ${node}${nameSuffix}</div>\n',
}
local world_numbers = {
["World 1"] = 1,
["World 2"] = 2,
["World 3"] = 3,
["World 4"] = 4,
["World 5"] = 5,
["World 6"] = 6,
["Winter 2016 Event"] = 33,
["Spring 2016 Event"] = 34,
["Summer 2016 Event"] = 35,
["Fall 2016 Event"] = 36,
["Winter 2017 Event"] = 37,
["Spring 2017 Event"] = 38,
["Summer 2017 Event"] = 39,
["Fall 2017 Event"] = 40,
["Winter 2018 Event"] = 41,
}
local diff_numbers_legacy = {
["Easy"] = 1,
["Normal"] = 2,
["Medium"] = 2,
["Hard"] = 3,
}
local diff_numbers = {
["Casual"] = 1,
["Easy"] = 2,
["Medium"] = 3,
["Hard"] = 4,
}
local simple_node_types = { "Resource", "Storm", "Empty", "Select" }
function formatTitle(pagename, args)
local world, map = string.match(pagename, "([^/]+)/([^/]+)")
world = world or "?"
map = map or "?"
local world_number = world_numbers[world] or "?"
local map_number = string.match(map:sub(3, 4), "%d") or "?"
local node = args[1] or "?"
local node_type = args[2] or "?"
local is_simple_node_type = node_type == "?" or U.ifind(simple_node_types, node_type)
local diffs = (world_number == "?" or world_number >= 41) and diff_numbers or diff_numbers_legacy
local diff = diffs[args.diff] and args.diff
local diff_number = diffs[diff] or "?"
local nameSuffix = args.name and ": " .. args.name or ""
return U.format{
is_simple_node_type and
(diff and templates.event_title_simple or templates.title_simple) or
(diff and templates.event_title or templates.title),
map = map,
node = node,
diff = diff,
nameSuffix = nameSuffix,
world_number = world_number,
map_number = map_number,
diff_number = diff_number,
}
end
function NodeInfo.TableFinal(frame)
local args = U.getTemplateArgs(frame)
local table_string = NodeInfo:Table(args.explicit)
if args.explicit.diff or args.implicit.pagename and args.implicit.pagename:sub(1, 5) == "World" then
return formatTitle(args.implicit.pagename, args.explicit) .. table_string
else
return table_string
end
end
U.registerTableTests(NodeInfo, {
{ "A", "Boss", "Line Ahead", "Northern Princess" }
})
-- p.run_table_tests()
return NodeInfo