Module:NodeInfo

local BaseTable = require("Module:BaseTable") local EnemyShip = require("Module:EnemyShip") local Formatting = require('Module:Formatting') local ShipBattleCardKai = require("Module:ShipBattleCardKai")

local format = require('Module:StringInterpolation').format

local NodeInfo = BaseTable({   _item_class = EnemyShip,    _header_template = !,    _column_cell_templates = {        node = ${values.node},        formation = ${values.formation},        fleet = ${values.fleet},        as = ${values.as},    },    _empty_node_template = ${values.node}    | colspan="3" style="text-align: center;" |Must be my imagination (battle avoided)/No enemies sighted 気のせいだった（戦闘回避）/敵影を見ず. (戦闘なし),    _selection_node_template = ${values.node}    | colspan="3" style="text-align: center;" |You may choose which direction your fleet will go. Admiral, which path will you choose? 艦隊針路選択可能！/艦隊の針路を選択できます. 提督、どちらの針路をとられますか？ , _resource_node_template = ${values.node}   | style="text-align: center; background-color: ${values.bg_color}; color: ${values.color};" |${values.node_type}    | colspan="2" style="text-align: center; background-color: ${values.bg_color}; color: ${values.color};" |${values.text}, _collapser_template = ${button_display}    , _collapser_end = , _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 .. " (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 -- : 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_parity = as_complete and string.format("%.1d", math.ceil((2./3.) * as)) or "??" local air_superiority = as_complete and string.format("%.1d", math.ceil(as * (3 / 2))) or "??" local air_supremacy = as_complete and tostring(as * 3) or "??" local air_string = air_parity .. "/" .. air_superiority .. "/" .. air_supremacy 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") 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_caption = (ship:name or "?") .. " (" .. (ship:api_id or "?") .. "): " .. (ship:armor or "?") .. " Armor, " .. (ship:hp or "?") .. " HP" table.insert(fleet, ShipBattleCardKai:get{ship = ship, caption = ship_caption, link = ship:link, flagship = #fleet == 0})

local ship_air_power = ship:air_power(tags.raid) 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', }   return self._args["comment"] or node_types[self._node_type] or "Fleet" end

function NodeInfo:create_header local header_string = format{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,    	                node_type = node_type,    	                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

return NodeInfo