Module:DropList

local find = require('Module:Utils').find local format = require('Module:StringInterpolation').format local getArgs = require('Module:GetArgs') local Ship = require('Module:Ship') local Formatting = require('Module:Formatting')

-- * Rarity definitions. -- sync with http://kancolle.wikia.com/wiki/Template:DropList/doc

local rare_ships = { 'Agano', 'Akashi', 'Akitsu Maru', 'Akitsushima', 'Akizuki', 'Amagi', 'Amagiri', 'Amatsukaze', 'Arashi', 'Ark Royal', 'Asagumo', 'Asakaze', 'Asashimo', 'Aquila', 'Bismarck', 'Commandant Teste', 'Etorofu', 'Fujinami', 'Gangut', 'Graf Zeppelin', 'Hagikaze', 'Harukaze', 'Harusame', 'Hatakaze', 'Hatsukaze', 'Hatsuzuki', 'Hayashimo', 'Hayasui', 'I-13', 'I-14', 'I-26', 'I-401', 'Isokaze', 'Kamikaze', 'Kamoi', 'Kashima', 'Kasuga Maru', 'Katsuragi', 'Kazagumo', 'Kiyoshimo', 'Kunashiri', 'Libeccio', 'Littorio', 'Luigi Torelli', 'Matsuwa', 'Maikaze', 'Maruyu', 'Matsukaze', 'Mikuma', 'Minazuki', 'Mizuho', 'Musashi', 'Noshiro', 'Nowaki', 'Okinami', 'Ooyodo', 'Oyashio', 'Pola', 'Prinz Eugen', 'Richelieu', 'Roma', 'Sagiri', 'Sakawa', 'Saratoga', 'Shimushu', 'Taigei', 'Taihou', 'Takanami', 'Tanikaze', 'Teruzuki', 'Tokitsukaze', 'U-511', 'Umikaze', 'Unryuu', 'Uranami', 'Uzuki', 'Yahagi', 'Yamakaze', 'Yamato', 'Z1', 'Z3', 'Zara', }

local ignored_ships = { 'Akatsuki', 'Akebono', 'Aoba', 'Arare', 'Arashio', 'Asashio', 'Ashigara', 'Ayanami', 'Chitose', 'Chiyoda', 'Choukai', 'Fubuki', 'Fumizuki', 'Furutaka', 'Haguro', 'Hatsuharu', 'Hatsushimo', 'Hatsuyuki', 'Hibiki', 'Houshou', 'I-168', 'Ikazuchi', 'Inazuma', 'Isonami', 'Isuzu', 'Jintsuu', 'Kagerou', 'Kako', 'Kasumi', 'Kikuzuki', 'Kisaragi', 'Kiso', 'Kuma', 'Kuroshio', 'Maya', 'Michishio', 'Mikazuki', 'Miyuki', 'Mochizuki', 'Murakumo', 'Murasame', 'Mutsuki', 'Nachi', 'Nagatsuki', 'Naka', 'Natori', 'Nenohi', 'Oboro', 'Ooshio', 'Samidare', 'Satsuki', 'Sazanami', 'Shigure', 'Shikinami', 'Shiranui', 'Shiratsuyu', 'Shirayuki', 'Suzukaze', 'Tama', 'Tatsuta', 'Tenryuu', 'Ushio', 'Wakaba', 'Yura', 'Yuudachi', }

-- * Definitions for formatter.

local diff_colors = { ['Easy']   = 'C8E6C9', ['Medium'] = 'FFE0B2', ['Hard']   = 'FFCDD2', ['?']      = 'BBDEFB', ['Regular'] = '', -- (default color) }

local diff_names = { ['Easy']   = 'Easy+', ['Medium'] = 'Medium+', ['Hard']   = 'Hard+', ['?']      = '?',	['Regular'] = '✓', }

local rarity_colors = { [true] = { [false] = '',     -- ignored, non-rare (default color) [true] = '',      -- ignored, rare (default color) },	[false] = { [false] = 'green', -- non-ignored, non-rare [true] = 'red',   -- non-ignored, rare }, }

local table_format = { header          = '{| class="article-table sortable ${classes}" align="center" width="100%" style="text-align:center; line-height:15px;"\n!Type\n! Ship? \n', header_node     = '!${node}\n', header_boss_node = '!style="background-color:#FFCDD2;color:red;"|\'\'\'${node}\'\'\'\n', row             = '|- class="toggle-target-droplist-non-rare-ship" style="display:none;"\n', rare_row        = '|-\n', type_cell       = '|${type}\n', -- TODO: japanese tooltips ship_cell       = '|${ship} \n', node_cell       = '|style="background-color:#${color};"|${diff}\n', empty_cell      = '|\n', footer          = '|}\n', debugger        = [[{| style="width:100%;" align="center" cellspacing="0" class="article-table mw-collapsible mw-collapsed" !Warnings }
 * ${debug}
 * }]]
 * }]]

-- * Definitions for parser.

local args_grammar = { node             = '^%s*(%a)%s*$', comma_list       = '[^,]+', ship_and_nodes   = '^%s*(.-)%s*:%s*(.-)%s*$', just_node        = '^%s*(%a)%s*$', node_and_diff    = '^%s*(%a)%s*/%s*(%S-)%s*$', node_diff_tooltip = '^%s*(%a)%s*/%s*(%S-)%s*{(.-)}%s*$', -- TODO: -- * just_node_tooltip -- * Add battle ranks: -- node_diff_rank = '^%s*(%a)%s*/%s*(%S-)%s*/%s*(%a)%s*$', -- * Hide difficulty: -- node_rank = '^%s*(%a)%s*//%s*(%a)%s*$', -- * Tooltips with extra info? }

-- * Parser.

function parseArgs(args)

local tbl = { nodes = {}, rows = {}, debug = '', classes = args.classes }

function log(message, value) tbl.debug = tbl.debug .. string.format('%s: %s\n', message, value) end

local regular = args.regular

if not args.nodes then log('info', 'empty table') return tbl end

local boss_nodes = {} for boss_node_ in string.gmatch(args.boss or "", args_grammar.comma_list) do		local boss_node = boss_node_:match(args_grammar.node) if boss_node then local boss_node = string.upper(boss_node) if find(boss_nodes, boss_node) then log('boss node duplicate', boss_node) else table.insert(boss_nodes, boss_node) end else log('boss node syntax error', boss_node_) end end if #boss_nodes == 0 then log('warning', 'no boss node(s) specified') end

for node_ in string.gmatch(args.nodes, args_grammar.comma_list) do		local node = node_:match(args_grammar.node) if node then local node = string.upper(node) if find(tbl.nodes, node, 'name') then log('node duplicate', node) else local is_boss = find(boss_nodes, node) table.insert(tbl.nodes, { name = node, boss = is_boss }) end else log('node syntax error', node_) end end for _, boss_node in pairs(boss_nodes) do		if not find(tbl.nodes, boss_node, 'name') then log('boss node ignored', boss_node) end end

-- ship args for arg_name, ship_and_nodes in pairs(args) do		if tonumber(arg_name) then local ship, nodes = ship_and_nodes:match(args_grammar.ship_and_nodes) if ship and nodes then local ship_table = Ship:get_table(ship, '') if ship_table and ship_table._type then local ignored, rare = find(ignored_ships, ship), find(rare_ships, ship) if find(tbl.rows, ship, 'ship') then log('ship duplicate', ship) elseif not regular and ignored then log('ship ignored', ship) else table.insert(tbl.rows, {							ship = ship,							rare = rare,							regular = regular,							ship_color = rarity_colors[ignored][rare],							type = Formatting:format_ship_code(ship_table._type) or '?',							nodes = {},						}) local row = tbl.rows[#tbl.rows] for _, node in pairs(tbl.nodes) do							row.nodes[node.name] = nil end for node_arg in string.gmatch(nodes, args_grammar.comma_list) do							local node, diff, tooltip = node_arg:match(args_grammar.node_diff_tooltip) if not node then node, diff = node_arg:match(args_grammar.node_and_diff) end if not node then node = node_arg:match(args_grammar.just_node) end diff = regular and 'Regular' or diff_names[diff] and diff or '?' if node and diff then local node = string.upper(node) if row.nodes[node] then log('ship node duplicate', string.format('%s for %s', node, ship)) elseif not find(tbl.nodes, node, 'name') then log('node ignored', string.format('%s for %s', node, ship)) else row.nodes[node] = { color = diff_colors[diff], diff = diff_names[diff], tooltip = tooltip, }								end else log('ship node syntax error', string.format('%s for %s', node_arg, ship)) end end end else log('ship ignored', ship) end else log('ship syntax error', ship_and_nodes) end end end

return tbl

end

-- * Formatter.

function showTable(tbl)

local res = format{table_format.header, classes = tbl.classes or ''}

function add(str) res = res .. str end

function add_row(row) add(row.rare and table_format.rare_row or table_format.row) add(format{table_format.type_cell, type = row.type}) add(format{table_format.ship_cell, color = row.ship_color, ship = row.ship}) for _, node in pairs(tbl.nodes) do			local node = row.nodes[node.name] add(node and format{				table_format.node_cell, color = node.color, diff = node.tooltip and Formatting:tooltip(node.diff, node.tooltip) or node.diff			} or table_format.empty_cell) end end

-- header for _, node in pairs(tbl.nodes) do		add(format{			node.boss and table_format.header_boss_node or table_format.header_node,			node = node.name		}) end

-- rows for _, row in pairs(tbl.rows) do		-- TODO: Sort by type/name if row.rare then add_row(row) end end for key, row in pairs(tbl.rows) do		-- TODO: Sort by type/name if not row.rare then add_row(row) end end

add(table_format.footer)

if tbl.debug ~= '' then add(format{table_format.debugger, debug = tbl.debug}) end

return res

end

local DropList = {}

function DropList.show(frame, args_) local args = args_ or getArgs{frame = frame:getParent} return showTable(parseArgs(args)) end

return DropList