• 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:ShipMetaKai"

From Kancolle Wiki
Jump to navigation Jump to search
com>Ckwng
m (46 revisions imported)
 
(37 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
local BaseData = require('Module:BaseData')
 
local BaseData = require('Module:BaseData')
 +
local Artist = require('Module:Artist')
 
local Ship = require('Module:Ship')
 
local Ship = require('Module:Ship')
 +
local VoiceActor = require('Module:VoiceActor')
 
local Formatting = require('Module:Formatting')
 
local Formatting = require('Module:Formatting')
  
local format = require('Module:StringOperations').format
+
local U = require('Module:Core')
 +
local format = U.format
  
 
local ShipMetaKai = BaseData{
 
local ShipMetaKai = BaseData{
_template = [[{|class="${table_class}" style="float: right;"  
+
_template = [[{|class="${table_class}"  
 
|-
 
|-
!colspan=2|${name} ${japanese_name}
+
!class="infobox-kai-header-major" colspan=2|${name}<div style="float:right;margin-right:5px">${edit_link}</div>
 
|-
 
|-
 
!Class
 
!Class
Line 22: Line 25:
 
|${availability}
 
|${availability}
 
|-
 
|-
!Implemented on
+
!Implementation
 
|${implementation_date}
 
|${implementation_date}
 
|}]],
 
|}]],
 +
    _flat_template = [[{|class="${table_class}"
 +
|-
 +
!class="infobox-kai-header-major" colspan=4|${name}<div style="float:right;margin-right:5px">${edit_link}</div>
 +
|-
 +
!${voice_actor_header}
 +
|${voice_actor}
 +
!Availability
 +
|${availability}
 +
|-
 +
!${artist_header}
 +
|${artist}
 +
!Implementation
 +
|${implementation_date}
 +
|}]],
 +
    _ship_data_documentation = "Template:ShipDataDocumentation/EditIntro",
 +
    _edit_link_text = "Edit",
 
_voice_actor_header = "[[Glossary#List of Vessels by Japanese Voice Actresses|Seiyuu]]",
 
_voice_actor_header = "[[Glossary#List of Vessels by Japanese Voice Actresses|Seiyuu]]",
 
_artist_header = "[[Glossary#List of Vessels by Artist|Artist]]",
 
_artist_header = "[[Glossary#List of Vessels by Artist|Artist]]",
 
_class_template = "[[:Category:${ship_class}|${ship_class}]]",
 
_class_template = "[[:Category:${ship_class}|${ship_class}]]",
_normal_construction_label = "Normal",
+
_name_template = "${name} ${japanese_name}",
_large_ship_construction_label = "LSC",
+
_person_template = "${name} (${japanese_name})",
 +
_normal_construction_label = "[[Construction#Building_recipes|Normal]]",
 +
_large_ship_construction_label = "[[Construction#Large_Ship_Construction_Recipe|LSC]]",
 
_buildable_label = "Construction",
 
_buildable_label = "Construction",
 
_drop_label = "Drop",
 
_drop_label = "Drop",
 
_details_template = " (${details})",
 
_details_template = " (${details})",
_event_reward_label = "Event Reward",
+
_event_reward_label = "[[Template:Event_Drop|Event Reward]]",
_event_drop_label = "Event Drop",
+
_event_drop_label = "[[Template:Event_Drop|Event Drop]]",
_node_name_template = "${world}-${map}-${node}",
+
_node_name_template = "${world}-${map} ${node}",
 
_node_formation_template = "-${formation}",
 
_node_formation_template = "-${formation}",
_event_node_name_template = "${year} ${quarter} E-${map}-${node}",
+
_event_node_name_template = "${year} ${quarter} E-${map} ${node}",
_date_template = "${year}-${month}-${day}",
+
_event_map_name_template = "${year} ${quarter} E-${map}",
 +
_date_template = "${year}/${month:2}/${day:2}",
 
_all_nodes_symbol = "*",
 
_all_nodes_symbol = "*",
 +
_max_drops_before_collapsible = 6,
 
_quarters = {
 
_quarters = {
 
[1] = "Winter",
 
[1] = "Winter",
Line 45: Line 68:
 
[7] = "Summer",
 
[7] = "Summer",
 
[10] = "Fall",
 
[10] = "Fall",
 +
[12] = "Christmas",
 
},
 
},
 
_difficulties = {
 
_difficulties = {
Line 53: Line 77:
 
},
 
},
 
_fields = {
 
_fields = {
 +
    "edit_link",
 
"name",
 
"name",
 
"class",
 
"class",
Line 66: Line 91:
 
_args = args,
 
_args = args,
 
}:create_infobox()
 
}:create_infobox()
 +
end
 +
 +
function ShipMetaKai:edit_link()
 +
self._vars.edit_link = Formatting:format_edit_link(self._ship_data_module, self._edit_link_text, self._ship_data_documentation)
 
end
 
end
  
 
function ShipMetaKai:name()
 
function ShipMetaKai:name()
 
self._vars.name = Formatting:format_stat(self._ship:name())
 
self._vars.name = Formatting:format_stat(self._ship:name())
self._vars.japanese_name = tostring(Formatting:japanese_text(Formatting:format_stat(self._ship:japanese_name())))
+
local japanese_name = Formatting:format_stat(self._ship:japanese_name())
 +
if japanese_name ~= self._vars.name then
 +
    self._vars.name = format{self._name_template, name = self._vars.name, japanese_name = tostring(Formatting:japanese_text(japanese_name))}
 +
end
 
end
 
end
  
Line 81: Line 113:
  
 
function ShipMetaKai:voice_actor()
 
function ShipMetaKai:voice_actor()
self._vars.voice_actor = Formatting:format_stat(self._ship:voice_actor())
+
self._vars.voice_actor = self:person(VoiceActor(self._ship:voice_actor()))
 
end
 
end
  
 
function ShipMetaKai:artist()
 
function ShipMetaKai:artist()
self._vars.artist = Formatting:format_stat(self._ship:artist())
+
self._vars.artist = self:person(Artist(self._ship:artist()))
 +
end
 +
 
 +
function ShipMetaKai:person(person)
 +
local link, japanese_name, reading = Formatting:format_external_link(person:link()), person:japanese_name(), person:reading()
 +
if japanese_name == false then
 +
return link
 +
elseif reading == false then
 +
    japanese_name = tostring(Formatting:japanese_text(Formatting:format_stat(person:japanese_name())))
 +
else
 +
    japanese_name = tostring(Formatting:japanese_text(Formatting:format_stat(person:japanese_name()), Formatting:format_stat(person:reading())))
 +
end
 +
return format{self._person_template, name = Formatting:format_external_link(person:link()), japanese_name = japanese_name}
 
end
 
end
 +
 +
local custom_quest_links = {
 +
    ["5A05"] = "Partials/Updates/2018_April_23rd#5A05"
 +
}
  
 
function ShipMetaKai:availability()
 
function ShipMetaKai:availability()
Line 102: Line 150:
 
table.insert(result, self._buildable_label .. format{self._details_template, details = table.concat(buildable, ", ")})
 
table.insert(result, self._buildable_label .. format{self._details_template, details = table.concat(buildable, ", ")})
 
end
 
end
for _, method in ipairs(availability) do
+
if availability and availability.quest then
 +
        table.insert(result, "Quest: " .. U.ijoin(U.imap(availability.quest, function(label)
 +
            return string.format("[[%s|%s]]", custom_quest_links[label] or string.format("Quests#%s", label), label)
 +
        end), ", "))
 +
end
 +
for _, method in ipairs(availability or {}) do
 
if method == "drop" then
 
if method == "drop" then
 
local details = {}
 
local details = {}
Line 124: Line 177:
 
end
 
end
 
end
 
end
if #details > 0 then
+
    local details_len = #details
 +
if details_len > 0 then
 
details = format{self._details_template, details = table.concat(details, ", ")}
 
details = format{self._details_template, details = table.concat(details, ", ")}
if #details > self._max_drops_before_collapsible then
+
if details_len > self._max_drops_before_collapsible then
table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details)))
+
table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details):allDone()))
 
else
 
else
 
table.insert(result, self._drop_label .. details)
 
table.insert(result, self._drop_label .. details)
Line 135: Line 189:
 
end
 
end
 
elseif method == "event_reward" then
 
elseif method == "event_reward" then
local details = {}
+
local details, current_event_details = {}, {}
 
if availability.event_reward then
 
if availability.event_reward then
 
for _, map in ipairs(availability.event_reward) do
 
for _, map in ipairs(availability.event_reward) do
local map_name = format{self._map_name_template, year = map[1], quarter = self._quarters[node[2]], map = map[3]}
+
local map_name = format{self._event_map_name_template, year = map[1], quarter = self._quarters[map[2]], map = map[3]}
 
if #map == 4 then
 
if #map == 4 then
 
map_name = map_name .. format{self._details_template, details = self._difficulties[map[4]]}
 
map_name = map_name .. format{self._details_template, details = self._difficulties[map[4]]}
 
end
 
end
 
table.insert(details, map_name)
 
table.insert(details, map_name)
 +
if map[1] == 2016 and map[2] == 7 then
 +
    table.insert(current_event_details, map_name)
 +
end
 
end
 
end
 
end
 
end
if #details > 0 then
+
if #details > 0 and self._detailed_availability then
 
details = format{self._details_template, details = table.concat(details, ", ")}
 
details = format{self._details_template, details = table.concat(details, ", ")}
 +
elseif #current_event_details > 0 then
 +
details = format{self._details_template, details = table.concat(current_event_details, ", ")}
 
else
 
else
 
details = ""
 
details = ""
Line 152: Line 211:
 
table.insert(result, self._event_reward_label .. details)
 
table.insert(result, self._event_reward_label .. details)
 
elseif method == "event_drop" then
 
elseif method == "event_drop" then
local details = {}
+
local details, current_event_details = {}, {}
 
if availability.event_drop then
 
if availability.event_drop then
for _, node in ipairs(availability.event_drop) do
+
for _, drop in ipairs(availability.event_drop) do
 
local nodes, complex
 
local nodes, complex
 
if type(drop[4]) == "table" then
 
if type(drop[4]) == "table" then
Line 164: Line 223:
 
end
 
end
 
for _, node in ipairs(nodes) do
 
for _, node in ipairs(nodes) do
local node_name = format{self._event_node_name_template, year = node[1], quarter = self._quarters[node[2]], map = node[3], node = node}
+
local node_name = format{self._event_node_name_template, year = drop[1], quarter = self._quarters[drop[2]], map = drop[3], node = node}
 
if #drop == 5 then
 
if #drop == 5 then
 
node_name = node_name .. format{self._node_formation_template, formation = complex and drop[5][node] or drop[5]}
 
node_name = node_name .. format{self._node_formation_template, formation = complex and drop[5][node] or drop[5]}
 
end
 
end
table.insert(details, node_name)
+
    table.insert(details, node_name)
 +
    if drop[1] == 2016 and drop[2] == 7 then
 +
        table.insert(current_event_details, map_name)
 +
    end
 
end
 
end
 
end
 
end
end
+
    end
if #details > 0 then
+
    local details_len = #details
 +
if details_len > 0 and self._detailed_availability then
 
details = format{self._details_template, details = table.concat(details, ", ")}
 
details = format{self._details_template, details = table.concat(details, ", ")}
if #details > self._max_drops_before_collapsible then
+
if details_len > self._max_drops_before_collapsible then
table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._event_drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details)))
+
table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._event_drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details):allDone()))
 
else
 
else
 
table.insert(result, self._event_drop_label .. details)
 
table.insert(result, self._event_drop_label .. details)
 
end
 
end
 +
elseif #current_event_details > 0 then
 +
current_event_details = format{self._details_template, details = table.concat(current_event_details, ", ")}
 +
table.insert(result, self._event_drop_label .. current_event_details)
 
else
 
else
 
table.insert(result, self._event_drop_label)
 
table.insert(result, self._event_drop_label)
Line 188: Line 254:
  
 
function ShipMetaKai:implementation_date()
 
function ShipMetaKai:implementation_date()
local implementation_date = self._ship:implementation_date()
+
local form = self._ship
if implementation_date then
+
local next_form = form._remodel_to
self._vars.implementation_date = format{self._date_template, year = implementation_date[1], month = implementation_date[2], day = implementation_date[3]}
+
local i = 1
else
+
local data = {}
self._vars.implementation_date = "??"
+
local forms = {}
 +
if form._implementation_date then
 +
    data[format{
 +
    self._date_template,
 +
    year = form._implementation_date[1],
 +
    month = form._implementation_date[2],
 +
    day = form._implementation_date[3]
 +
}] = { "Base" }
 +
end
 +
while next_form and not forms[next_form] and i < 10 do
 +
    forms[next_form] = true
 +
    form = Ship(next_form)
 +
    if form._implementation_date then
 +
        local d = format{
 +
        self._date_template,
 +
        year = form._implementation_date[1],
 +
        month = form._implementation_date[2],
 +
        day = form._implementation_date[3]
 +
    }
 +
    local name = form:suffix() and form:suffix() ~= "" and form:suffix() or form:name()
 +
    data[d] = data[d] or {}
 +
        table.insert(data[d], name)
 +
    end
 +
    next_form = form._remodel_to
 +
        i = i + 1
 
end
 
end
 +
    local dates = U.isort(U.keys(data))
 +
self._vars.implementation_date = #dates == 0 and "??" or #dates == 1 and dates[1] or U.ijoin(U.imap(dates, function (d)
 +
return string.format("%s (%s)", d, U.ijoin(data[d], ", "))
 +
end), "<br>")
 
end
 
end
  
Line 210: Line 304:
 
function ShipMetaKai:create_infobox_prep()
 
function ShipMetaKai:create_infobox_prep()
 
self._vars = {}
 
self._vars = {}
local table_classes = {"wikitable"}
+
local table_classes = {"infobox", "infobox-kai"}
 
if self._args.classes then
 
if self._args.classes then
 
table.insert(table_classes, self._args.classes)
 
table.insert(table_classes, self._args.classes)
Line 230: Line 324:
 
self[field](self)
 
self[field](self)
 
end
 
end
return format(self._template, self._vars)
+
return format(self._args.thin and self._template or self._flat_template, self._vars)
 
end
 
end
  
Line 244: Line 338:
 
return self:format_template()
 
return self:format_template()
 
end
 
end
 +
 +
function ShipMetaKai.test()
 +
    mw.log(ShipMetaKai:Infobox({ "Ayanami" }))
 +
    mw.log(ShipMetaKai:Infobox({ "U-511" }))
 +
    mw.log(ShipMetaKai:Infobox({ "Zuikaku" }))
 +
end
 +
-- p.test()
  
 
return ShipMetaKai
 
return ShipMetaKai

Latest revision as of 12:43, 12 May 2021

Documentation for this module may be created at Module:ShipMetaKai/doc

local BaseData = require('Module:BaseData')
local Artist = require('Module:Artist')
local Ship = require('Module:Ship')
local VoiceActor = require('Module:VoiceActor')
local Formatting = require('Module:Formatting')

local U = require('Module:Core')
local format = U.format

local ShipMetaKai = BaseData{
	_template = [[{|class="${table_class}" 
|-
!class="infobox-kai-header-major" colspan=2|${name}<div style="float:right;margin-right:5px">${edit_link}</div>
|-
!Class
|${class}
|-
!${voice_actor_header}
|${voice_actor}
|-
!${artist_header}
|${artist}
|-
!Availability
|${availability}
|-
!Implementation
|${implementation_date}
|}]],
    _flat_template = [[{|class="${table_class}" 
|-
!class="infobox-kai-header-major" colspan=4|${name}<div style="float:right;margin-right:5px">${edit_link}</div>
|-
!${voice_actor_header}
|${voice_actor}
!Availability
|${availability}
|-
!${artist_header}
|${artist}
!Implementation
|${implementation_date}
|}]],
    _ship_data_documentation = "Template:ShipDataDocumentation/EditIntro",
    _edit_link_text = "Edit",
	_voice_actor_header = "[[Glossary#List of Vessels by Japanese Voice Actresses|Seiyuu]]",
	_artist_header = "[[Glossary#List of Vessels by Artist|Artist]]",
	_class_template = "[[:Category:${ship_class}|${ship_class}]]",
	_name_template = "${name} ${japanese_name}",
	_person_template = "${name} (${japanese_name})",
	_normal_construction_label = "[[Construction#Building_recipes|Normal]]",
	_large_ship_construction_label = "[[Construction#Large_Ship_Construction_Recipe|LSC]]",
	_buildable_label = "Construction",
	_drop_label = "Drop",
	_details_template = " (${details})",
	_event_reward_label = "[[Template:Event_Drop|Event Reward]]",
	_event_drop_label = "[[Template:Event_Drop|Event Drop]]",
	_node_name_template = "${world}-${map} ${node}",
	_node_formation_template = "-${formation}",
	_event_node_name_template = "${year} ${quarter} E-${map} ${node}",
	_event_map_name_template = "${year} ${quarter} E-${map}",
	_date_template = "${year}/${month:2}/${day:2}",
	_all_nodes_symbol = "*",
	_max_drops_before_collapsible = 6,
	_quarters = {
		[1] = "Winter",
		[4] = "Spring",
		[7] = "Summer",
		[10] = "Fall",
		[12] = "Christmas",
	},
	_difficulties = {
		[0] = "All",
		[1] = "Easy",
		[2] = "Medium",
		[3] = "Hard",
	},
	_fields = {
	    "edit_link",
		"name",
		"class",
		"voice_actor",
		"artist",
		"availability",
		"implementation_date",
	},
}

function ShipMetaKai:Infobox(args)
	return self{
		_args = args,
	}:create_infobox()
end

function ShipMetaKai:edit_link()
	self._vars.edit_link = Formatting:format_edit_link(self._ship_data_module, self._edit_link_text, self._ship_data_documentation)
end

function ShipMetaKai:name()
	self._vars.name = Formatting:format_stat(self._ship:name())
	local japanese_name = Formatting:format_stat(self._ship:japanese_name())
	if japanese_name ~= self._vars.name then
	    self._vars.name = format{self._name_template, name = self._vars.name, japanese_name = tostring(Formatting:japanese_text(japanese_name))}
	end
end

function ShipMetaKai:class()
	local ship_class = self._ship:class()
	if ship_class then
		self._vars.class = format{self._class_template, ship_class = ship_class:name()}
	end
end

function ShipMetaKai:voice_actor()
	self._vars.voice_actor = self:person(VoiceActor(self._ship:voice_actor()))
end

function ShipMetaKai:artist()
	self._vars.artist = self:person(Artist(self._ship:artist()))
end

function ShipMetaKai:person(person)
	local link, japanese_name, reading = Formatting:format_external_link(person:link()), person:japanese_name(), person:reading()
	if japanese_name == false then
		return link
	elseif reading == false then
	    japanese_name = tostring(Formatting:japanese_text(Formatting:format_stat(person:japanese_name())))
	else
	    japanese_name = tostring(Formatting:japanese_text(Formatting:format_stat(person:japanese_name()), Formatting:format_stat(person:reading())))
	end
	return format{self._person_template, name = Formatting:format_external_link(person:link()), japanese_name = japanese_name}
end

local custom_quest_links = {
    ["5A05"] = "Partials/Updates/2018_April_23rd#5A05"
}

function ShipMetaKai:availability()
	local availability = self._ship:availability()
	local result = {}
	local buildable = false
	if self._ship:buildable() then
		buildable = {self._normal_construction_label}
	end
	if self._ship:buildable_lsc() then
		buildable = buildable or {}
		table.insert(buildable, self._large_ship_construction_label)
	end
	if buildable then
		table.insert(result, self._buildable_label .. format{self._details_template, details = table.concat(buildable, ", ")})
	end
	if availability and availability.quest then
        table.insert(result, "Quest: " .. U.ijoin(U.imap(availability.quest, function(label)
            return string.format("[[%s|%s]]", custom_quest_links[label] or string.format("Quests#%s", label), label)
        end), ", "))
	end
	for _, method in ipairs(availability or {}) do
		if method == "drop" then
			local details = {}
			if availability.drop then
				for _, drop in ipairs(availability.drop) do
					local nodes, complex
					if type(drop[3]) == "table" then
						nodes = drop[3]
					elseif drop[3] == true then
						nodes = {self._all_nodes_symbol}
					else
						nodes = {drop[3]}
					end
					for _, node in ipairs(nodes) do
						local node_name = format{self._node_name_template, world = drop[1], map = drop[2], node = node}
						if #drop == 4 then
							node_name = node_name .. format{self._node_formation_template, formation = complex and drop[4][node] or drop[4]}
						end
						table.insert(details, node_name)
					end
				end
			end
		    local details_len = #details
			if details_len > 0 then
				details = format{self._details_template, details = table.concat(details, ", ")}
				if details_len > self._max_drops_before_collapsible then
					table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details):allDone()))
				else
					table.insert(result, self._drop_label .. details)
				end
			else
				table.insert(result, self._drop_label)
			end
		elseif method == "event_reward" then
			local details, current_event_details = {}, {}
			if availability.event_reward then
				for _, map in ipairs(availability.event_reward) do
					local map_name = format{self._event_map_name_template, year = map[1], quarter = self._quarters[map[2]], map = map[3]}
					if #map == 4 then
						map_name = map_name .. format{self._details_template, details = self._difficulties[map[4]]}
					end
					table.insert(details, map_name)
					if map[1] == 2016 and map[2] == 7 then
					    table.insert(current_event_details, map_name)
					end
				end
			end
			if #details > 0 and self._detailed_availability then
				details = format{self._details_template, details = table.concat(details, ", ")}
			elseif #current_event_details > 0 then
				details = format{self._details_template, details = table.concat(current_event_details, ", ")}
			else
				details = ""
			end
			table.insert(result, self._event_reward_label .. details)
		elseif method == "event_drop" then
			local details, current_event_details = {}, {}
			if availability.event_drop then
				for _, drop in ipairs(availability.event_drop) do
					local nodes, complex
					if type(drop[4]) == "table" then
						nodes = drop[4]
					elseif drop[4] == true then
						nodes = {self._all_nodes_symbol}
					else
						nodes = {drop[4]}
					end
					for _, node in ipairs(nodes) do
						local node_name = format{self._event_node_name_template, year = drop[1], quarter = self._quarters[drop[2]], map = drop[3], node = node}
						if #drop == 5 then
							node_name = node_name .. format{self._node_formation_template, formation = complex and drop[5][node] or drop[5]}
						end
    					table.insert(details, node_name)
    					if drop[1] == 2016 and drop[2] == 7 then
    					    table.insert(current_event_details, map_name)
    					end
					end
				end
		    end
		    local details_len = #details
			if details_len > 0 and self._detailed_availability then
				details = format{self._details_template, details = table.concat(details, ", ")}
				if details_len > self._max_drops_before_collapsible then
					table.insert(result, tostring(mw.html.create("div"):addClass("mw-collapsible"):addClass("mw-collapsed"):wikitext(self._event_drop_label):tag("div"):addClass("mw-collapsible-content"):wikitext(details):allDone()))
				else
					table.insert(result, self._event_drop_label .. details)
				end
			elseif #current_event_details > 0 then
				current_event_details = format{self._details_template, details = table.concat(current_event_details, ", ")}
				table.insert(result, self._event_drop_label .. current_event_details)
			else
				table.insert(result, self._event_drop_label)
			end
		end
	end
	self._vars.availability = table.concat(result, "<br/>")
end

function ShipMetaKai:implementation_date()
	local form = self._ship
	local next_form = form._remodel_to
	local i = 1
	local data = {}
	local forms = {}
	if form._implementation_date then
	    data[format{
		    self._date_template,
		    year = form._implementation_date[1],
		    month = form._implementation_date[2],
		    day = form._implementation_date[3]
		}] = { "Base" }
	end
	while next_form and not forms[next_form] and i < 10 do
	    forms[next_form] = true
	    form = Ship(next_form)
	    if form._implementation_date then
	        local d = format{
		        self._date_template,
		        year = form._implementation_date[1],
		        month = form._implementation_date[2],
		        day = form._implementation_date[3]
		    }
		    local name = form:suffix() and form:suffix() ~= "" and form:suffix() or form:name()
		    data[d] = data[d] or {}
	        table.insert(data[d], name)
	    end
	    next_form = form._remodel_to
        i = i + 1
	end
    local dates = U.isort(U.keys(data))
	self._vars.implementation_date = #dates == 0 and "??" or #dates == 1 and dates[1] or U.ijoin(U.imap(dates, function (d)
		return string.format("%s (%s)", d, U.ijoin(data[d], ", "))
	end), "<br>")
end

function ShipMetaKai:create_item()
	if self._args.name then
		self._ship = Ship(self._args.name, self._args.model)
	else
		self._ship = Ship(self._args[1])
	end
end

function ShipMetaKai:get_module()
	self._ship_data_module = Ship:get_module(self._args.name or self._args[1])
end

function ShipMetaKai:create_infobox_prep()
	self._vars = {}
	local table_classes = {"infobox", "infobox-kai"}
	if self._args.classes then
		table.insert(table_classes, self._args.classes)
	end
	local collapsible = self._args.collapsible
	if collapsible then
		table.insert(table_classes, "mw-collapsible")
		table.insert(table_classes, "mw-collapsed")
	end
	self._vars.table_class = table.concat(table_classes, " ")
	--self._vars.table_id = collapsible and collapsible ~= "true" and ("mw-customcollapsible-" .. collapsible) or ""
	--self._vars.float = self._args.float and format{self._float_style_template, float = self._args.float} or ""
	self._vars.voice_actor_header = self._voice_actor_header
	self._vars.artist_header = self._artist_header
end

function ShipMetaKai:format_template()
	for _, field in ipairs(self._fields) do
		self[field](self)
	end
	return format(self._args.thin and self._template or self._flat_template, self._vars)
end

function ShipMetaKai:add_fields()
	return
end

function ShipMetaKai:create_infobox()
	self:add_fields()
	self:create_item()
	self:get_module()
	self:create_infobox_prep()
	return self:format_template()
end

function ShipMetaKai.test()
    mw.log(ShipMetaKai:Infobox({ "Ayanami" }))
    mw.log(ShipMetaKai:Infobox({ "U-511" }))
    mw.log(ShipMetaKai:Infobox({ "Zuikaku" }))
end
-- p.test()

return ShipMetaKai