Line 1: |
Line 1: |
| + | local find = require('Module:Core').includes |
| + | local format = require('Module:Core').format |
| + | local getArgs = require('Module:GetArgs') |
| + | local Ship = require('Module:Ship') |
| + | local Formatting = require('Module:Formatting') |
| + | local SortId = require('Module:DropList/Sort') |
| + | |
| + | -- * Rarity definitions. |
| | | |
− | local getArgs = require('Module:GetArgs') | + | local rare_ships = { |
| + | 'Agano', 'Akashi', 'Akitsu Maru', 'Akitsushima', 'Akizuki', 'Amagi', 'Amagiri', 'Amatsukaze', 'Arashi', |
| + | 'Ark Royal', 'Asagumo', 'Asakaze', 'Asashimo', 'Aquila', 'Bismarck', 'Colorado', 'Commandant Teste', 'Daitou', |
| + | 'Etorofu', 'Fletcher', 'Fujinami', 'Fukae', 'Gambier Bay', 'Gangut','Giuseppe Garibaldi', 'Gotland', |
| + | 'Graf Zeppelin', 'Hachijou', 'Hagikaze', 'Hamanami', 'Harukaze', 'Harusame', 'Hatakaze', 'Hatsukaze', |
| + | 'Hatsuzuki', 'Hayanami', 'Hayashimo', 'Hayasui', 'Hiburi', 'I-13', 'I-14', 'I-26', 'I-400', 'I-401', 'Intrepid', |
| + | 'Ishigaki', 'Iowa', 'Isokaze', 'Jervis', 'Johnston', 'Kamikaze', 'Kamoi', 'Kashima', 'Kasuga Maru', 'Katsuragi', |
| + | 'Kawakaze', 'Kazagumo', 'Kishinami', 'Kiyoshimo', 'Kunashiri', 'Libeccio', 'Littorio', 'Luigi Torelli', 'Maikaze', |
| + | 'Maestrale', 'Matsuwa', 'Maruyu', 'Matsukaze', 'Mikuma', 'Minazuki', 'Minegumo', 'Mizuho', 'Musashi', 'Nelson', |
| + | 'Nisshin', 'Noshiro', 'Nowaki', 'Okinami', 'Ooyodo', 'Oyashio', 'Pola', 'Prinz Eugen', 'Richelieu', 'Roma', 'Sado', |
| + | 'Sagiri', 'Sakawa', 'Samuel B. Roberts', 'Saratoga', 'Shimushu', 'Shinyou', 'Suzutsuki', 'Taigei', 'Taihou', |
| + | 'Takanami', 'Tanikaze', 'Tashkent', 'Teruzuki', 'Tokitsukaze', 'Tsushima', 'U-511', 'Umikaze', 'Unryuu', |
| + | 'Uranami', 'Uzuki', 'Warspite', 'Yahagi', 'Yamakaze', 'Yamato', 'Z1', 'Z3', 'Zara', |
| | | |
− | local DropList = {}
| + | 'Mikura', 'Grecale', 'Duca degli Abruzzi', 'Janus', |
| + | |
| + | 'Houston', 'De Ruyter', 'Perth', 'Shinshuu Maru', |
| + | |
| + | 'Akishimo', 'Hirato', 'Atlanta', |
| + | |
| + | 'Usugumo', 'I-47', 'Matsu', 'Jingei', 'Kaiboukan No.4', |
| + | |
| + | 'Ariake', 'Helena', 'Yashiro', 'South Dakota', 'Hornet', |
| + | |
| + | 'Scirocco', 'Sheffield', 'Washington', 'Take', |
| + | |
| + | 'Momo', 'I-203', 'Northampton', 'Makinami', |
| + | |
| + | 'Honolulu', 'Suzunami', 'Souya', |
| + | |
| + | 'Chougei', 'Conte di Cavour', 'Victorious', 'Kaiboukan No.30', |
| + | |
| + | 'Shounan', 'Scamp', |
| + | |
| + | 'Yawata Maru', |
| + | |
| + | 'Ume', 'Yamashio Maru', 'Fuyutsuki', 'Tamanami', |
| + | |
| + | 'Hayashio', 'I-201', 'Maryland', 'Kurahashi', |
| + | |
| + | 'Ukuru', 'Natsugumo', 'Langley', 'Brooklyn', 'Massachusetts', 'Ranger', 'Jean Bart', |
| + | |
| + | 'Yuugure', 'Heywood L. Edwards', 'Kumano Maru', 'Noumi', 'Tuscaloosa', 'No.101 Transport Ship', |
| + | |
| + | 'Kaiboukan No.22', 'Inagi', 'Shirakumo', 'Salmon', 'Asahi', 'C.Cappellini', 'Javelin', 'Nevada', 'Rodney', |
| + | |
| + | 'Drum', 'I-41', 'I-36', 'Heian Maru', |
| + | } |
| | | |
− | local args_grammar = { | + | local ignored_ships = { |
− | to_trim = '^%s*(.-)%s*$', | + | 'Akatsuki', 'Akebono', 'Aoba', 'Arare', 'Arashio', 'Asashio', 'Ashigara', 'Ayanami', 'Chitose', 'Chiyoda', |
− | comma_list = '[^,]+', | + | 'Choukai', 'Fubuki', 'Fumizuki', 'Furutaka', 'Haguro', 'Hatsuharu', 'Hatsushimo', 'Hatsuyuki', 'Hibiki', 'Houshou', |
− | ship_and_nodes = '^%s*(.-)%s*:%s*(.-)%s*$', | + | 'I-168', 'Ikazuchi', 'Inazuma', 'Isonami', 'Isuzu', 'Jintsuu', 'Kagerou', 'Kako', 'Kasumi', 'Kikuzuki', |
− | just_node = '^%s*(%a)%s*$', | + | 'Kisaragi', 'Kiso', 'Kuma', 'Kuroshio', 'Maya', 'Michishio', 'Mikazuki', 'Miyuki', 'Mochizuki', 'Murakumo', |
− | node_and_diff = '^%s*(%a)%s*/%s*(%S-)%s*$' | + | '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 = { | | local diff_colors = { |
− | ['Easy'] = '5a5', | + | ['Casual'] = 'E8F5E9', |
− | ['Medium'] = 'da6', | + | ['Easy'] = 'C8E6C9', |
− | ['Hard'] = 'd33', | + | ['Medium'] = 'FFE0B2', |
− | ['?'] = '0ff' | + | ['Hard'] = 'FFCDD2', |
| + | ['?'] = 'BBDEFB', |
| + | ['Regular'] = 'C8E6C9', -- (default color) |
| } | | } |
| | | |
| local diff_names = { | | local diff_names = { |
− | ['Easy'] = 'Easy+', | + | ['Casual'] = 'Casual+', |
− | ['Medium'] = 'Medium+', | + | ['Easy'] = 'Easy+', |
− | ['Hard'] = 'Hard+', | + | ['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 center ${classes}" width="100%" style="text-align:center; line-height:15px;"\n!Type\n!<span style="border-bottom:1px dotted;">Ship<sup>[[Template:DropList/doc|?]]</sup></span>\n', |
| + | header = '{|class="wikitable mw-collapsible mw-collapsed" width="50%" style="text-align:center"\n!colspan="100"|Ship drops\n|-\n!Type\n!Ship<sup>[[Module:DropList|?]]</sup>\n', |
| + | header_node = '!${node}\n', |
| + | header_boss_node = '!style="background-color:#FFCDD2;color:red"|\'\'\'${node}\'\'\'\n', |
| + | row = '|-\n', -- class="toggle-target-droplist-non-rare-ship" style="display:none;" |
| + | rare_row = '|-\n', |
| + | type_cell = '|${type}\n', |
| + | -- TODO: japanese tooltips |
| + | ship_cell = '|[[${ship}|<span style="color:${color}">${ship}</span>]]\n', |
| + | none_cell = '|None\n', |
| + | node_cell = '|style="background-color:#${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" |
| + | !Notes |
| + | |- |
| + | |<pre>${debug}</pre> |
| + | |}]] |
| + | } |
| + | |
| + | -- * Definitions for parser. |
| + | |
| + | local args_grammar = { |
| + | node = '^%s*(%w-)%s*$', |
| + | comma_list = '[^,]+', |
| + | ship_and_nodes = '^%s*(.-)%s*:%s*(.-)%s*$', |
| + | just_node = '^%s*(%w-)%s*$', |
| + | node_and_diff = '^%s*(%w-)%s*/%s*(%S-)%s*$', |
| + | node_diff_tooltip = '^%s*(%w-)%s*/%s*(%S-)%s*{(.-)}%s*$', |
| + | node_diff_tooltip_s = '^%s*(%w-)%s*/%s*(%S-)%s*{(.-)}%s*S%s*$', |
| + | just_node_diff = '^%s*(%w-)%s*/%s*(%S-)%s*$', |
| + | just_node_diff_s = '^%s*(%w-)%s*/%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) | | function parseArgs(args) |
| | | |
− | local tbl = { nodes = {}, rows = {} } | + | 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 |
| | | |
− | -- header args
| + | for node_ in string.gmatch(args.nodes, args_grammar.comma_list) do |
− | for node in string.gmatch(args.nodes, args_grammar.comma_list) do | + | local node = node_:match(args_grammar.node) |
− | local node = node:match(args_grammar.to_trim) | + | if node then |
− | table.insert(tbl.nodes, { name = node, boss = node == args.boss }) | + | 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 | | end |
| | | |
| -- ship args | | -- ship args |
− | for arg_name, arg in pairs(args) do | + | for arg_name, ship_and_nodes in pairs(args) do |
| if tonumber(arg_name) then | | if tonumber(arg_name) then |
− | local ship, nodes = arg:match(args_grammar.ship_and_nodes) | + | local ship, nodes = ship_and_nodes:match(args_grammar.ship_and_nodes) |
− | -- TODO: check ship existence? | + | if ship and nodes then |
− | table.insert(tbl.rows, {})
| + | local ship_table = ship == 'None' and { _type = '' } or Ship:get_table(ship, '') |
− | local row = tbl.rows[#tbl.rows]
| + | if ship_table and ship_table._type then |
− | row.id = arg_name
| + | local ignored, rare = find(ignored_ships, ship), find(rare_ships, ship) |
− | row.ship = ship
| + | if find(tbl.rows, ship, 'ship') then |
− | row.type = ''
| + | log('ship duplicate', ship) |
− | row.nodes = {}
| + | elseif not regular and ignored then |
− | for _, node in pairs(tbl.nodes) do
| + | log('ship ignored', ship) |
− | row.nodes[node.name] = nil
| + | else |
− | end
| + | table.insert(tbl.rows, { |
− | for node_and_diff in string.gmatch(nodes, args_grammar.comma_list) do
| + | ship = ship, |
− | local node, diff = node_and_diff:match(args_grammar.node_and_diff)
| + | rare = rare, |
− | if not node or not diff then
| + | ignored = ignored, |
− | node = node_and_diff:match(args_grammar.just_node)
| + | regular = regular, |
− | diff = nil
| + | ship_color = rarity_colors[ignored][rare], |
− | end
| + | type = Formatting:format_ship_code(ship_table._type) or '?', |
− | -- TODO: check node existence?
| + | type_id = ship_table._type or 0, |
− | if node then
| + | sort_id = SortId[ship_table._api_id] or 0, |
− | row.nodes[node] = { color = diff and diff_colors[diff] or diff_colors['?'], diff = diff and diff_names[diff] 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 s_only = false |
| + | local node, diff, tooltip = node_arg:match(args_grammar.node_diff_tooltip_s) |
| + | if not node then |
| + | node, diff, tooltip = node_arg:match(args_grammar.node_diff_tooltip) |
| + | else |
| + | s_only = true |
| + | end |
| + | if not node then |
| + | node, diff = node_arg:match(args_grammar.just_node_diff_s) |
| + | if not node then |
| + | node, diff = node_arg:match(args_grammar.just_node_diff) |
| + | else |
| + | s_only = true |
| + | end |
| + | end |
| + | 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, |
| + | s_only = s_only, |
| + | } |
| + | end |
| + | else |
| + | log('ship node syntax error', string.format('%s for %s', node_arg, ship)) |
| + | end |
| + | end |
| + | end |
| + | else |
| + | log('ship ignored', ship) |
| end | | end |
| + | else |
| + | log('ship syntax error', ship_and_nodes) |
| end | | end |
| end | | end |
Line 68: |
Line 278: |
| end | | end |
| | | |
− | local table_format = {
| + | -- * Formatter. |
− | header = '{| class="wikitable sortable" align="center" width="100%" style="text-align:center"\n!Type\n!Ship\n',
| |
− | header_node = '!width="10%%"|%s\n',
| |
− | header_boss_node = '!width="10%%" style="background-color:pink;color:red;"|\'\'\'%s\'\'\'\n',
| |
− | row = '|-\n',
| |
− | cell = '|%s\n',
| |
− | ship_cell = '|[[%s]]\n',
| |
− | node_cell = '|style="background-color:#%s;"|%s\n',
| |
− | empty_cell = '|\n',
| |
− | footer = '|}\n'
| |
− | }
| |
| | | |
| function showTable(tbl) | | function showTable(tbl) |
| | | |
− | local res = table_format.header | + | 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(row.ship == 'None' and table_format.none_cell or 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, |
| + | background_color = node.color, |
| + | color = node.s_only and ';color:red' or '', |
| + | diff = node.tooltip and Formatting:tooltip2(node.diff, node.tooltip:gsub("@", " / @@"), " / ", "@") or node.diff |
| + | } or table_format.empty_cell) |
| + | end |
| + | end |
| | | |
| -- header | | -- header |
| for _, node in pairs(tbl.nodes) do | | for _, node in pairs(tbl.nodes) do |
− | res = res .. string.format(node.boss and table_format.header_boss_node or table_format.header_node, node.name) | + | add(format{ |
| + | node.boss and table_format.header_boss_node or table_format.header_node, |
| + | node = node.name |
| + | }) |
| end | | end |
| + | |
| + | -- true when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead. |
| + | |
| + | table.sort(tbl.rows, function(a, b) |
| + | if a.type_id < b.type_id then |
| + | return true |
| + | elseif a.type_id == b.type_id then |
| + | return a.sort_id < b.sort_id |
| + | else |
| + | return false |
| + | end |
| + | end) |
| | | |
− | -- rows | + | for _, row in pairs(tbl.rows) do |
| + | if row.rare then |
| + | add_row(row) |
| + | end |
| + | end |
| + | for key, row in pairs(tbl.rows) do |
| + | if not row.rare and not row.ignored then |
| + | add_row(row) |
| + | end |
| + | end |
| for key, row in pairs(tbl.rows) do | | for key, row in pairs(tbl.rows) do |
− | res = res .. table_format.row | + | if row.ignored then |
− | -- res = res .. string.format(table_format.cell, row.id)
| + | add_row(row) |
− | res = res .. string.format(table_format.cell, row.type)
| |
− | res = res .. string.format(table_format.ship_cell, row.ship)
| |
− | for _, node in pairs(tbl.nodes) do
| |
− | local node = row.nodes[node.name]
| |
− | res = res .. (node and string.format(table_format.node_cell, node.color, node.diff) or table_format.empty_cell)
| |
| end | | end |
| end | | end |
| | | |
− | res = res .. table_format.footer | + | add(table_format.footer) |
| + | |
| + | if tbl.debug ~= '' and tbl.log then |
| + | add(format{table_format.debugger, debug = tbl.debug}) |
| + | end |
| | | |
| return res | | return res |
Line 107: |
Line 349: |
| end | | end |
| | | |
− | function DropList.show(frame) | + | local DropList = {} |
− | local args = getArgs{frame = frame:getParent()}
| + | |
| + | function DropList.show(frame, args_) |
| + | local args = args_ or getArgs{frame = frame:getParent()} |
| return showTable(parseArgs(args)) | | return showTable(parseArgs(args)) |
| end | | end |
| | | |
| return DropList | | return DropList |