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

From Kancolle Wiki
Jump to navigation Jump to search
com>Ckwng
(Add missing var)
com>Ckwng
(Complex column value handling, auto emphasis functionality, notes handling, refactor)
Line 2: Line 2:
 
local StatIcons = require('Module:StatIcons')
 
local StatIcons = require('Module:StatIcons')
 
local MiscIcons = require('Module:MiscIcons')
 
local MiscIcons = require('Module:MiscIcons')
 +
local Ship = require('Module:Ship')
 
local format = require('Module:StringInterpolation').format
 
local format = require('Module:StringInterpolation').format
  
Line 25: Line 26:
 
! ${ammo_icon}
 
! ${ammo_icon}
 
! style="text-align:left;" | Notes]],
 
! style="text-align:left;" | Notes]],
_image_template = "[[File:%s]]",
+
_column_cell_templates = {
 +
name = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.link} ${value.japanese_name}]],
 +
luck = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.initial} (${value.max})]],
 +
aircraft = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.total}<br />(${value.slots})]],
 +
},
 
_columns = {
 
_columns = {
 +
"id",
 +
"name",
 
"class",
 
"class",
 
"remodel",
 
"remodel",
Line 59: Line 66:
 
_good_stat_color = "yellow",
 
_good_stat_color = "yellow",
 
_outstanding_stat_color = "lime",
 
_outstanding_stat_color = "lime",
_cell = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value}]],
+
_cell = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.value}]],
 
_table_end = [[|}]],
 
_table_end = [[|}]],
 
_rowspan_suffix = "_rowspan",
 
_rowspan_suffix = "_rowspan",
Line 66: Line 73:
 
_good_suffix = "_good",
 
_good_suffix = "_good",
 
_operator_suffix = "_operator",
 
_operator_suffix = "_operator",
 +
_notes_suffix = "_notes",
 
_transparent = "transparent",
 
_transparent = "transparent",
 +
_emphasis_template = "''${value}''",
 
_operators = {
 
_operators = {
 
["<"] = function(x,y) return x < y end,
 
["<"] = function(x,y) return x < y end,
Line 72: Line 81:
 
}
 
}
 
}
 
}
 +
 +
function EliteShipsKai:get_bg_color(value, operator, outstanding, good)
 +
if not value then
 +
return self._transparent
 +
end
 +
local comparison = self._operators[operator or ">"]
 +
if outstanding and comparison(value, outstanding) then
 +
return self._outstanding_stat_color
 +
elseif good and comparison(value, good) then
 +
return self._good_stat_color
 +
else
 +
return self._transparent
 +
end
 +
end
 +
 +
function EliteShipsKai:get_emphasis(value, formatted, operator, good)
 +
local comparison = self._operators[operator or ">"]
 +
if value and good and comparison(value, good) then
 +
return format{self._emphasis_template, value = formatted}
 +
end
 +
return formatted
 +
end
  
 
function EliteShipsKai:name(ship)
 
function EliteShipsKai:name(ship)
return format{"${link} ${japanese_name}", link = ship:link(), japanese_name = ship:japanese_name()}
+
return {values = {link = ship:link(), japanese_name = ship:japanese_name()}, bg_color = self._transparent}
 
end
 
end
  
 
function EliteShipsKai:id(ship)
 
function EliteShipsKai:id(ship)
return ship:id()
+
return {values = {value = ship:id()}, bg_color = self._transparent}
 
end
 
end
  
 
function EliteShipsKai:class(ship)
 
function EliteShipsKai:class(ship)
return ship:class()
+
return {values = {value = ship:class()}, bg_color = self._transparent}
 
end
 
end
  
function EliteShipsKai:remodel_level(ship)
+
function EliteShipsKai:remodel_level(ship, args)
return ship:remodel_level()
+
local remodel_level = ship:remodel_level()
 +
return {values = {value = Formatting:format_stat(remodel_level)}, bg_color = self:get_bg_color(remodel_level, args.remodel_level_operator, args.remodel_level_outstanding, args.remodel_level_good)}
 
end
 
end
  
function EliteShipsKai:firepower_max(ship)
+
function EliteShipsKai:firepower(ship, args)
return ship:firepower_max()
+
local firepower_max = ship:firepower_max()
 +
return {values = {value = Formatting:format_stat(firepower_max)}, bg_color = self:get_bg_color(firepower_max, args.firepower_operator, args.firepower_outstanding, args.firepower_good)}
 
end
 
end
  
function EliteShipsKai:torpedo_max(ship)
+
function EliteShipsKai:torpedo(ship, args)
return ship:torpedo_max()
+
local torpedo_max = ship:torpedo_max()
 +
return {values = {value = Formatting:format_stat(torpedo_max)}, bg_color = self:get_bg_color(torpedo_max, args.torpedo_operator, args.torpedo_outstanding, args.torpedo_good)}
 
end
 
end
  
function EliteShipsKai:aa_max(ship)
+
function EliteShipsKai:aa(ship, args)
return ship:aa_max()
+
local aa_max = ship:aa_max()
 +
return {values = {value = Formatting:format_stat(aa_max)}, bg_color = self:get_bg_color(aa_max, args.aa_operator, args.aa_outstanding, args.aa_good)}
 
end
 
end
  
function EliteShipsKai:asw_max(ship)
+
function EliteShipsKai:asw(ship, args)
return ship:asw_max()
+
local asw_max = ship:asw_max()
 +
return {values = {value = Formatting:format_stat(asw_max)}, bg_color = self:get_bg_color(asw_max, args.asw_operator, args.asw_outstanding, args.asw_good)}
 
end
 
end
  
function EliteShipsKai:los_max(ship)
+
function EliteShipsKai:los(ship, args)
return ship:los_max()
+
local los_max = ship:los_max()
 +
return {values = {value = Formatting:format_stat(los_max)}, bg_color = self:get_bg_color(los_max, args.los_operator, args.los_outstanding, args.los_good)}
 
end
 
end
  
function EliteShipsKai:luck_max(ship)
+
function EliteShipsKai:luck(ship, args)
return ship:luck_max()
+
local luck = ship:luck()
 +
local luck_max = ship:luck_max()
 +
return {values = {luck = Formatting:format_stat(luck), luck_max = self:get_emphasis(luck_max, Formatting:format_stat(luck_max), args.luck_max_operator, args.luck_max_good)}, bg_color = self:get_bg_color(luck, args.luck_operator, args.luck_outstanding, args.luck_good)}
 
end
 
end
  
function EliteShipsKai:hp(ship)
+
function EliteShipsKai:hp(ship, args)
return ship:hp()
+
local hp_max = ship:hp_max()
 +
return {values = {value = Formatting:format_stat(hp_max)}, bg_color = self:get_bg_color(hp_max, args.hp_operator, args.hp_outstanding, args.hp_good)}
 
end
 
end
  
function EliteShipsKai:armor_max(ship)
+
function EliteShipsKai:armor(ship, args)
return ship:armor_max()
+
local armor_max = ship:armor_max()
 +
return {values = {value = Formatting:format_stat(armor_max)}, bg_color = self:get_bg_color(armor_max, args.armor_operator, args.armor_outstanding, args.armor_good)}
 
end
 
end
  
function EliteShipsKai:evasion_max(ship)
+
function EliteShipsKai:evasion(ship, args)
return ship:evasion_max()
+
local evasion_max = ship:evasion_max()
 +
return {values = {value = Formatting:format_stat(evasion_max)}, bg_color = self:get_bg_color(evasion_max, args.evasion_operator, args.evasion_outstanding, args.evasion_good)}
 
end
 
end
  
function EliteShipsKai:speed(ship)
+
function EliteShipsKai:speed(ship, args)
return ship:speed()
+
local speed_max = ship:speed_max()
 +
return {values = {value = Formatting:format_speed(speed_max)}, bg_color = self:get_bg_color(speed_max, args.speed_operator, args.speed_outstanding, args.speed_good)}
 
end
 
end
  
function EliteShipsKai:aircraft(ship)
+
function EliteShipsKai:aircraft(ship, args)
return ship:total_space()
+
local aircraft_max = ship:aircraft_max()
 +
local slots = {}
 +
if aircraft_max > 0 then
 +
for i = 1, ship:slots() do
 +
_, size = ship:slot(i)
 +
table.insert(slots, self:get_emphasis(size, Formatting:format_stat(size), args.aircraft_slot_operator, args.aircraft_slot_good))
 +
end
 +
end
 +
return {values = {value = Formatting:format_detailed_aircraft(aircraft_max, slots)}, bg_color = self:get_bg_color(aircraft_max, args.aircraft_operator, args.aircraft_outstanding, args.aircraft_good)}
 
end
 
end
  
function EliteShipsKai:fuel(ship)
+
function EliteShipsKai:fuel(ship, args)
return ship:fuel()
+
local fuel_max = ship:fuel_max()
 +
return {values = {value = Formatting:format_stat(fuel_max)}, bg_color = self:get_bg_color(fuel_max, args.fuel_operator, args.fuel_outstanding, args.fuel_good)}
 
end
 
end
  
function EliteShipsKai:ammo(ship)
+
function EliteShipsKai:ammo(ship, args)
return ship:ammo()
+
local ammo_max = ship:ammo_max()
 +
return {values = {value = Formatting:format_stat(ammo_max)}, bg_color = self:get_bg_color(ammo_max, args.ammo_operator, args.ammo_outstanding, args.ammo_good)}
 
end
 
end
  
function EliteShipsKai:notes(ship)
+
function EliteShipsKai:notes(ship, args)
--stubbed out for now
+
return {values = {value = args.notes[ship]}, bg_color = self._transparent}
return ""
 
 
end
 
end
  
function EliteShipsKai:Table(ships, ranges)
+
function EliteShipsKai:compare_values(val1, val2)
if not ranges then
+
if #val1 == #val2 then
ranges = {}
+
for value_type, value in pairs(val1) do
 +
if value ~= val2[value_type] then
 +
return false
 +
end
 +
end
 +
else
 +
return false
 
end
 
end
 +
return true
 +
end
 +
 +
function EliteShipsKai:Table(args)
 +
--Process requested ships
 +
local ships = {}
 +
args.notes = {}
 +
for index, ship_name in ipairs(args) do
 +
local split = mw.ustring.find(ship_name, '/')
 +
local ship_base_name, ship_suffix
 +
if split ~= nil then
 +
ship_base_name = ship_name
 +
else
 +
ship_base_name = mw.ustring.sub(ship_name, 1, split - 1)
 +
ship_suffix = mw.ustring.sub(ship_name, split + 1, -1)
 +
end
 +
local ship = Ship:create(ship_base_name, ship_suffix)
 +
ships[index] = ship
 +
args.notes[ship] = args[ship_name .. self._notes_suffix]
 +
end
 +
 
local header_icons = {
 
local header_icons = {
 
remodel_icon = MiscIcons.remodel,  
 
remodel_icon = MiscIcons.remodel,  
Line 167: Line 246:
 
}
 
}
 
for key, value in pairs(header_icons) do
 
for key, value in pairs(header_icons) do
header_icons[key] = mw.ustring.format(self._image_template, value)
+
header_icons[key] = Formatting:format_image(value)
 
end
 
end
 
local header = format(self._header_template, header_icons)
 
local header = format(self._header_template, header_icons)
Line 175: Line 254:
 
local data_rows = {}
 
local data_rows = {}
 
for index, ship in ipairs(ships) do
 
for index, ship in ipairs(ships) do
local row_values = {
+
local row_values = {}
id = self:id(ship),
+
for _, column in ipairs(self._columns) do
name = self:name(ship),
+
row_values[column] = self[column](self, ship, args)
class = self:class(ship),
+
end
remodel = self:remodel_level(ship),
 
firepower = self:firepower_max(ship),
 
torpedo = self:torpedo_max(ship),
 
aa = self:aa_max(ship),
 
asw = self:asw_max(ship),
 
los = self:los_max(ship),
 
luck = self:luck_max(ship),
 
hp = self:hp(ship),
 
armor = self:armor_max(ship),
 
evasion = self:evasion_max(ship),
 
speed = self:speed(ship),
 
aircraft = self:aircraft(ship),
 
fuel = self:fuel(ship),
 
ammo = self:ammo(ship),
 
notes = self:notes(ship),
 
}
 
 
if index > 1 then
 
if index > 1 then
 
for _, column in ipairs(self._columns) do
 
for _, column in ipairs(self._columns) do
 
for i=index-1,1,-1 do
 
for i=index-1,1,-1 do
 
if data_rows[i][column] then
 
if data_rows[i][column] then
if row_values[column] == data_rows[i][column] then
+
if self.compare_values(row_values[column].values, data_rows[i][column].values) then
data_rows[i][column .. self._rowspan_suffix] = data_rows[i][column .. self._rowspan_suffix] + 1
+
data_rows[i][column].rowspan = data_rows[i][column].rowspan + 1
 
row_values[column] = nil
 
row_values[column] = nil
 
else
 
else
break
+
row_values[column].rowspan = 1
 
end
 
end
end
 
end
 
end
 
end
 
for _, column in ipairs(self._columns) do
 
if row_values[column] then
 
row_values[column .. self._rowspan_suffix] = 1
 
row_values[column .. self._bg_color_suffix] = self._cell_color[column] or self._transparent
 
if ranges[column] then
 
local operator = self._operators[ranges[column].operator]
 
if operator(row_values[column], ranges[column].outstanding) then
 
row_values[column .. self._bg_color_suffix] = self._outstanding_stat_color
 
elseif operator(row_values[column], ranges[column].good) then
 
row_values[column .. self._bg_color_suffix] = self._good_stat_color
 
 
end
 
end
 
end
 
end
Line 232: Line 281:
 
for _, column in ipairs(self._columns) do
 
for _, column in ipairs(self._columns) do
 
if row_values[column] then
 
if row_values[column] then
table.insert(rows, format{self._cell, value = row_values[column], rowspan = row_values[column .. self._rowspan_suffix], bg_color = row_values[column .. self._bg_color_suffix]})
+
table.insert(rows, format{self._cell, value = row_values[column].values, rowspan = row_values[column].rowspan, bg_color = row_values[column].bg_color})
 
end
 
end
 
end
 
end

Revision as of 22:53, 12 February 2015

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

local ResourceIcons = require('Module:ResourceIcons')
local StatIcons = require('Module:StatIcons')
local MiscIcons = require('Module:MiscIcons')
local Ship = require('Module:Ship')
local format = require('Module:StringInterpolation').format

local EliteShipsKai = {
	_table_start = [[{| class="wikitable"]],
	_row_starter = "|-",
	_header_template = [[!No.
!Name
!Class
! style="white-space:nowrap;" | ${remodel_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: LightCoral;" | ${firepower_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: LightSkyBlue;" | ${torpedo_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: SandyBrown;" | ${aa_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: #9C8FEE;" | ${asw_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: Aquamarine;" | ${los_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: PaleGreen;" | ${luck_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: Pink;" | ${hp_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: #F2E279;" | ${armor_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: Violet;" | ${evasion_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: #72E6E6;" | ${speed_icon}
! style="width: 30px; text-align: center; vertical-align: middle; background-color: Silver;" | ${aircraft_icon}
! ${fuel_icon}
! ${ammo_icon}
! style="text-align:left;" | Notes]],
	_column_cell_templates = {
		name = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.link} ${value.japanese_name}]],
		luck = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.initial} (${value.max})]],
		aircraft = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.total}<br />(${value.slots})]],
	},
	_columns = {
		"id",
		"name",
		"class",
		"remodel",
		"firepower",
		"torpedo",
		"aa",
		"asw",
		"los",
		"luck",
		"hp",
		"armor",
		"evasion",
		"speed",
		"aircraft",
		"fuel",
		"ammo",
		"notes",
	},
	_cell_color = {
		firepower = "#F0C0C0",
		torpedo = "#C0E4FA",
		aa = "#F4CAA6",
		asw = "#C5BEEE",
		los = "#CCFFEE",
		luck = "#C9FBC9",
		hp = "#FFD9DF",
		armor = "#F2ECC2",
		evasion = "#EEBEEE",
		speed = "#B8E6E6",
		aircraft = "#D9D9D9",
	},
	_good_stat_color = "yellow",
	_outstanding_stat_color = "lime",
	_cell = [[| colspan="1" rowspan="${rowspan}" style="text-align:center; background-color: ${bg_color}" | ${value.value}]],
	_table_end = [[|}]],
	_rowspan_suffix = "_rowspan",
	_bg_color_suffix = "_bg_color",
	_outstanding_suffix = "_outstanding",
	_good_suffix = "_good",
	_operator_suffix = "_operator",
	_notes_suffix = "_notes",
	_transparent = "transparent",
	_emphasis_template = "''${value}''",
	_operators = {
		["<"] = function(x,y) return x < y end,
		[">"] = function(x,y) return x > y end,
	}
}

function EliteShipsKai:get_bg_color(value, operator, outstanding, good)
	if not value then
		return self._transparent
	end
	local comparison = self._operators[operator or ">"]
	if outstanding and comparison(value, outstanding) then
		return self._outstanding_stat_color
	elseif good and comparison(value, good) then
		return self._good_stat_color
	else
		return self._transparent
	end
end

function EliteShipsKai:get_emphasis(value, formatted, operator, good)
	local comparison = self._operators[operator or ">"]
	if value and good and comparison(value, good) then
		return format{self._emphasis_template, value = formatted}
	end
	return formatted
end

function EliteShipsKai:name(ship)
	return {values = {link = ship:link(), japanese_name = ship:japanese_name()}, bg_color = self._transparent}
end

function EliteShipsKai:id(ship)
	return {values = {value = ship:id()}, bg_color = self._transparent}
end

function EliteShipsKai:class(ship)
	return {values = {value = ship:class()}, bg_color = self._transparent}
end

function EliteShipsKai:remodel_level(ship, args)
	local remodel_level = ship:remodel_level()
	return {values = {value = Formatting:format_stat(remodel_level)}, bg_color = self:get_bg_color(remodel_level, args.remodel_level_operator, args.remodel_level_outstanding, args.remodel_level_good)}
end

function EliteShipsKai:firepower(ship, args)
	local firepower_max = ship:firepower_max()
	return {values = {value = Formatting:format_stat(firepower_max)}, bg_color = self:get_bg_color(firepower_max, args.firepower_operator, args.firepower_outstanding, args.firepower_good)}
end

function EliteShipsKai:torpedo(ship, args)
	local torpedo_max = ship:torpedo_max()
	return {values = {value = Formatting:format_stat(torpedo_max)}, bg_color = self:get_bg_color(torpedo_max, args.torpedo_operator, args.torpedo_outstanding, args.torpedo_good)}
end

function EliteShipsKai:aa(ship, args)
	local aa_max = ship:aa_max()
	return {values = {value = Formatting:format_stat(aa_max)}, bg_color = self:get_bg_color(aa_max, args.aa_operator, args.aa_outstanding, args.aa_good)}
end

function EliteShipsKai:asw(ship, args)
	local asw_max = ship:asw_max()
	return {values = {value = Formatting:format_stat(asw_max)}, bg_color = self:get_bg_color(asw_max, args.asw_operator, args.asw_outstanding, args.asw_good)}
end

function EliteShipsKai:los(ship, args)
	local los_max = ship:los_max()
	return {values = {value = Formatting:format_stat(los_max)}, bg_color = self:get_bg_color(los_max, args.los_operator, args.los_outstanding, args.los_good)}
end

function EliteShipsKai:luck(ship, args)
	local luck = ship:luck()
	local luck_max = ship:luck_max()
	return {values = {luck = Formatting:format_stat(luck), luck_max = self:get_emphasis(luck_max, Formatting:format_stat(luck_max), args.luck_max_operator, args.luck_max_good)}, bg_color = self:get_bg_color(luck, args.luck_operator, args.luck_outstanding, args.luck_good)}
end

function EliteShipsKai:hp(ship, args)
	local hp_max = ship:hp_max()
	return {values = {value = Formatting:format_stat(hp_max)}, bg_color = self:get_bg_color(hp_max, args.hp_operator, args.hp_outstanding, args.hp_good)}
end

function EliteShipsKai:armor(ship, args)
	local armor_max = ship:armor_max()
	return {values = {value = Formatting:format_stat(armor_max)}, bg_color = self:get_bg_color(armor_max, args.armor_operator, args.armor_outstanding, args.armor_good)}
end

function EliteShipsKai:evasion(ship, args)
	local evasion_max = ship:evasion_max()
	return {values = {value = Formatting:format_stat(evasion_max)}, bg_color = self:get_bg_color(evasion_max, args.evasion_operator, args.evasion_outstanding, args.evasion_good)}
end

function EliteShipsKai:speed(ship, args)
	local speed_max = ship:speed_max()
	return {values = {value = Formatting:format_speed(speed_max)}, bg_color = self:get_bg_color(speed_max, args.speed_operator, args.speed_outstanding, args.speed_good)}
end

function EliteShipsKai:aircraft(ship, args)
	local aircraft_max = ship:aircraft_max()
	local slots = {}
	if aircraft_max > 0 then
		for i = 1, ship:slots() do
			_, size = ship:slot(i)
			table.insert(slots, self:get_emphasis(size, Formatting:format_stat(size), args.aircraft_slot_operator, args.aircraft_slot_good))
		end
	end
	return {values = {value = Formatting:format_detailed_aircraft(aircraft_max, slots)}, bg_color = self:get_bg_color(aircraft_max, args.aircraft_operator, args.aircraft_outstanding, args.aircraft_good)}
end

function EliteShipsKai:fuel(ship, args)
	local fuel_max = ship:fuel_max()
	return {values = {value = Formatting:format_stat(fuel_max)}, bg_color = self:get_bg_color(fuel_max, args.fuel_operator, args.fuel_outstanding, args.fuel_good)}
end

function EliteShipsKai:ammo(ship, args)
	local ammo_max = ship:ammo_max()
	return {values = {value = Formatting:format_stat(ammo_max)}, bg_color = self:get_bg_color(ammo_max, args.ammo_operator, args.ammo_outstanding, args.ammo_good)}
end

function EliteShipsKai:notes(ship, args)
	return {values = {value = args.notes[ship]}, bg_color = self._transparent}
end

function EliteShipsKai:compare_values(val1, val2)
	if #val1 == #val2 then
		for value_type, value in pairs(val1) do
			if value ~= val2[value_type] then
				return false
			end
		end
	else
		return false
	end
	return true
end

function EliteShipsKai:Table(args)
	--Process requested ships
	local ships = {}
	args.notes = {}
	for index, ship_name in ipairs(args) do
		local split = mw.ustring.find(ship_name, '/')
		local ship_base_name, ship_suffix
		if split ~= nil then
			ship_base_name = ship_name
		else
			ship_base_name = mw.ustring.sub(ship_name, 1, split - 1)
			ship_suffix = mw.ustring.sub(ship_name, split + 1, -1)
		end
		local ship = Ship:create(ship_base_name, ship_suffix)
		ships[index] = ship
		args.notes[ship] = args[ship_name .. self._notes_suffix]
	end

	local header_icons = {
		remodel_icon = MiscIcons.remodel, 
		firepower_icon = StatIcons.firepower, 
		torpedo_icon = StatIcons.torpedo, 
		aa_icon = StatIcons.aa, 
		asw_icon = StatIcons.asw, 
		los_icon = StatIcons.los, 
		luck_icon = StatIcons.luck, 
		hp_icon = StatIcons.hp, 
		armor_icon = StatIcons.armor,
		evasion_icon = StatIcons.evasion,
		speed_icon = StatIcons.speed,
		aircraft_icon = StatIcons.aircraft,
		fuel_icon = ResourceIcons.fuel,
		ammo_icon = ResourceIcons.ammo,
	}
	for key, value in pairs(header_icons) do
		header_icons[key] = Formatting:format_image(value)
	end
	local header = format(self._header_template, header_icons)

	local rows = {self._table_start, header}

	local data_rows = {}
	for index, ship in ipairs(ships) do
		local row_values = {}
		for _, column in ipairs(self._columns) do
			row_values[column] = self[column](self, ship, args)
		end
		if index > 1 then
			for _, column in ipairs(self._columns) do
				for i=index-1,1,-1 do
					if data_rows[i][column] then
						if self.compare_values(row_values[column].values, data_rows[i][column].values) then
							data_rows[i][column].rowspan = data_rows[i][column].rowspan + 1
							row_values[column] = nil
						else
							row_values[column].rowspan = 1
						end
					end
				end
			end
		end
		table.insert(data_rows, row_values)
	end

	for index, row_values in ipairs(data_rows) do
		table.insert(rows, self._row_starter)
		table.insert(rows, format{self._cell, value = row_values.id, rowspan = 1, bg_color = self._transparent})
		table.insert(rows, format{self._cell, value = row_values.name, rowspan = 1, bg_color = self._transparent})
		for _, column in ipairs(self._columns) do
			if row_values[column] then
				table.insert(rows, format{self._cell, value = row_values[column].values, rowspan = row_values[column].rowspan, bg_color = row_values[column].bg_color})
			end
		end
	end

	table.insert(rows, self._row_starter)
	table.insert(rows, header)
	table.insert(rows, self._table_end)
	return table.concat(rows, "\n")
end

return EliteShipsKai