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

From Kancolle Wiki
Jump to navigation Jump to search
com>Ckwng
(Undo, just comment out cap operation)
(Return basic attack power (w/ ASW & NB pre-cap modifiers) from main functions (no flooring), change ASW, carrier shelling and aerial formulas)
Line 245: Line 245:
 
end
 
end
  
function ShipCapabilities:_attack_power_cap(attack_power, cap)
+
-- Basic attack power for shelling and carrier shelling.
--if attack_power > cap then
 
-- return math.floor(cap + math.sqrt(attack_power - cap))
 
--end
 
return math.floor(attack_power)
 
end
 
 
 
 
function ShipCapabilities:day_battle()
 
function ShipCapabilities:day_battle()
 
if not self:_is_submarine() then
 
if not self:_is_submarine() then
Line 270: Line 264:
 
end
 
end
 
end
 
end
return 1, self:_attack_power_cap(firepower + 5, 150)
+
return 1, 5 + firepower
 
end
 
end
 
else
 
else
Line 301: Line 295:
 
end
 
end
 
if has_planes then
 
if has_planes then
return is_installation and 3 or 2, self:_attack_power_cap(1.5 * (firepower + torpedo) + bombing * 2 + 55, 150)
+
return is_installation and 3 or 2, 55 + math.floor(1.5 * (firepower + torpedo + math.floor(1.3 * bombing)))
 
end
 
end
 
end
 
end
Line 311: Line 305:
 
function ShipCapabilities:format_day_battle(mode, attack_power)
 
function ShipCapabilities:format_day_battle(mode, attack_power)
 
if mode then
 
if mode then
return format{self._attack_template, mode = self._day_battle_modes[mode], attack_power = attack_power}
+
return format{self._attack_template, mode = self._day_battle_modes[mode], attack_power = math.floor(attack_power)}
 
elseif mode == false then
 
elseif mode == false then
 
return "No Action"
 
return "No Action"
Line 318: Line 312:
 
end
 
end
  
 +
-- Basic attack power for closing torpedo.
 
function ShipCapabilities:closing_torpedo()
 
function ShipCapabilities:closing_torpedo()
 
local torpedo = self._ship:torpedo_leveled()
 
local torpedo = self._ship:torpedo_leveled()
Line 330: Line 325:
 
end
 
end
 
end
 
end
return self:_attack_power_cap(torpedo + 5, 150)
+
return 5 + torpedo
 
end
 
end
 
return false
 
return false
Line 337: Line 332:
 
function ShipCapabilities:format_torpedo(attack_power)
 
function ShipCapabilities:format_torpedo(attack_power)
 
if attack_power then
 
if attack_power then
return tostring(attack_power)
+
return tostring(math.floor(attack_power))
 
end
 
end
 
return "No"
 
return "No"
Line 344: Line 339:
 
ShipCapabilities.format_closing_torpedo = ShipCapabilities.format_torpedo
 
ShipCapabilities.format_closing_torpedo = ShipCapabilities.format_torpedo
  
 +
-- Detect possible day time special attack modifiers (post-cap).
 
function ShipCapabilities:artillery_spotting()
 
function ShipCapabilities:artillery_spotting()
 
local total_space = self._ship:total_space()
 
local total_space = self._ship:total_space()
Line 393: Line 389:
 
end
 
end
  
 +
-- Basic attack power for night battle carrier shelling.
 +
-- Or basic attack power for night battle attack * detected night special attack modifier (pre-cap).
 
function ShipCapabilities:night_battle()
 
function ShipCapabilities:night_battle()
 
local main_guns, secondary_guns, torpedoes, has_planes, firepower, torpedo = 0, 0, 0, false, self._ship:firepower_leveled(), self._ship:torpedo_leveled()
 
local main_guns, secondary_guns, torpedoes, has_planes, firepower, torpedo = 0, 0, 0, false, self._ship:firepower_leveled(), self._ship:torpedo_leveled()
Line 426: Line 424:
 
if self:_is_carrier() then
 
if self:_is_carrier() then
 
if has_planes and self._ship:night_bombing() then
 
if has_planes and self._ship:night_bombing() then
return 8, self:_attack_power_cap(firepower + torpedo, 300)
+
return 8, firepower + torpedo
 
end
 
end
 
return false
 
return false
 
else
 
else
 
if torpedoes >= 2 and torpedo > 0 then
 
if torpedoes >= 2 and torpedo > 0 then
return 7, self:_attack_power_cap((firepower + torpedo) * 1.5, 300)
+
return 7, (firepower + torpedo) * 1.5
 
elseif main_guns >= 3 and firepower > 0 then
 
elseif main_guns >= 3 and firepower > 0 then
return 4, self:_attack_power_cap((firepower + torpedo) * 2, 300)
+
return 4, (firepower + torpedo) * 2
 
elseif main_guns >= 2 and secondary_guns >= 1 and firepower > 0 then
 
elseif main_guns >= 2 and secondary_guns >= 1 and firepower > 0 then
return 5, self:_attack_power_cap((firepower + torpedo) * 1.75, 300)
+
return 5, (firepower + torpedo) * 1.75
 
elseif main_guns >= 1 and torpedoes == 1 and firepower > 0 and torpedo > 0 then
 
elseif main_guns >= 1 and torpedoes == 1 and firepower > 0 and torpedo > 0 then
return 6, self:_attack_power_cap((firepower + torpedo) * 1.3, 300)
+
return 6, (firepower + torpedo) * 1.3
 
elseif main_guns + secondary_guns >= 2 and firepower > 0 then
 
elseif main_guns + secondary_guns >= 2 and firepower > 0 then
return 3, self:_attack_power_cap((firepower + torpedo) * 1.2, 300)
+
return 3, (firepower + torpedo) * 1.2
 
elseif torpedoes > 0 and torpedo > 0 then
 
elseif torpedoes > 0 and torpedo > 0 then
return 2, self:_attack_power_cap(firepower + torpedo, 300)
+
return 2, firepower + torpedo
 
elseif firepower > 0 then
 
elseif firepower > 0 then
return 1, self:_attack_power_cap(firepower + torpedo, 300)
+
return 1, firepower + torpedo
 
else
 
else
 
return false
 
return false
Line 454: Line 452:
 
local multiplier = self._night_battle_attack_counts[mode]
 
local multiplier = self._night_battle_attack_counts[mode]
 
if multiplier then
 
if multiplier then
attack_power = tostring(attack_power) .. " " .. multiplier
+
attack_power = tostring(math.floor(attack_power)) .. " " .. multiplier
 
end
 
end
 
return format{self._attack_template, mode = self._night_battle_modes[mode], attack_power = attack_power}
 
return format{self._attack_template, mode = self._night_battle_modes[mode], attack_power = attack_power}
Line 463: Line 461:
 
end
 
end
  
 +
-- Basic attack power for opening torpedo.
 
function ShipCapabilities:opening_torpedo()
 
function ShipCapabilities:opening_torpedo()
 
local torpedo = self._ship:torpedo_leveled()
 
local torpedo = self._ship:torpedo_leveled()
Line 488: Line 487:
 
end
 
end
 
if opening_torpedo then
 
if opening_torpedo then
return self:_attack_power_cap(torpedo + 5, 150)
+
return 5 + torpedo
 
end
 
end
 
return false
 
return false
Line 495: Line 494:
 
ShipCapabilities.format_opening_torpedo = ShipCapabilities.format_torpedo
 
ShipCapabilities.format_opening_torpedo = ShipCapabilities.format_torpedo
  
 +
-- Basic attack power for ASW attack * sonar w/ depth charge modifier (pre-cap).
 
function ShipCapabilities:asw_attack()
 
function ShipCapabilities:asw_attack()
 
local base_asw
 
local base_asw
Line 501: Line 501:
 
return false
 
return false
 
elseif self:_is_asw_surface_ship() then
 
elseif self:_is_asw_surface_ship() then
base_asw = 25
+
base_asw = 13
 
elseif self:_is_asw_aviation_ship() then
 
elseif self:_is_asw_aviation_ship() then
base_asw = 10
+
base_asw = 8
 
if not self._ship:night_bombing() then
 
if not self._ship:night_bombing() then
 
night = false
 
night = false
Line 511: Line 511:
 
end
 
end
 
local asw_leveled = self._ship:asw_leveled()
 
local asw_leveled = self._ship:asw_leveled()
local ship_asw, equipment_asw, depth_charge, sonar, bomber = (asw_leveled or 0) / 5, 0, false, false, false
+
local ship_asw, equipment_asw, depth_charge, sonar, bomber = (asw_leveled or 0), 0, false, false, false
 
for i = 1, self._ship:slots() or 0 do
 
for i = 1, self._ship:slots() or 0 do
 
local equipment, size = self._ship:slot(i)
 
local equipment, size = self._ship:slot(i)
Line 534: Line 534:
 
depth_charge_sonar_boost = 1.15
 
depth_charge_sonar_boost = 1.15
 
end
 
end
return self:_attack_power_cap(depth_charge_sonar_boost * (base_asw + 2 * equipment_asw + ship_asw / 5), 100), day, night, not asw_leveled
+
return depth_charge_sonar_boost * (base_asw + 1.5 * equipment_asw + 2 * math.sqrt(ship_asw)), day, night, not asw_leveled
 
end
 
end
  
 
function ShipCapabilities:format_asw_attack(attack_power, day, night, uncertain)
 
function ShipCapabilities:format_asw_attack(attack_power, day, night, uncertain)
 
if attack_power then
 
if attack_power then
 +
attack_power = math.floor(attack_power)
 
local phases = {}
 
local phases = {}
 
if day then
 
if day then
Line 557: Line 558:
 
end
 
end
  
 +
-- Basic attack power for opening airstrike (returns an array with attack values per each bomber).
 
function ShipCapabilities:opening_airstrike()
 
function ShipCapabilities:opening_airstrike()
 
if not self:_is_aviation_ship() then
 
if not self:_is_aviation_ship() then
Line 566: Line 568:
 
if size and size > 0 and equipment and self:_is_bomber(equipment) then
 
if size and size > 0 and equipment and self:_is_bomber(equipment) then
 
local equipment_torpedo, equipment_bombing = equipment:torpedo() or 0, equipment:bombing() or 0
 
local equipment_torpedo, equipment_bombing = equipment:torpedo() or 0, equipment:bombing() or 0
local attack_power = (equipment_torpedo + equipment_bombing) * math.sqrt(size) + 25
 
 
if self:_is_torpedo_bomber(equipment) then
 
if self:_is_torpedo_bomber(equipment) then
table.insert(airstrikes, self:_attack_power_cap(attack_power * 1.5, 150))
+
table.insert(airstrikes, 1.5 * (25 + equipment_torpedo * math.sqrt(size))) -- 0.8 is also possible
 
else
 
else
table.insert(airstrikes, self:_attack_power_cap(attack_power, 150))
+
table.insert(airstrikes, 25 + equipment_bombing * math.sqrt(size))
 
end
 
end
 
end
 
end
Line 584: Line 585:
 
local result = {}
 
local result = {}
 
for _, attack in ipairs(attacks) do
 
for _, attack in ipairs(attacks) do
table.insert(result, tostring(attack))
+
table.insert(result, tostring(math.floor(attack)))
 
end
 
end
 
return table.concat(result, ",")
 
return table.concat(result, ",")

Revision as of 12:37, 26 October 2015

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

local BaseData = require("Module:BaseData")

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

local ShipCapabilities = BaseData{
	-- _anti_air_cut_in_types = {
	-- 	{
	-- 		name = "Akizuki (HA HA R)", 
	-- 		ship = {"Akizuki"},
	-- 		equipment = {"High-angle Gun", "High-angle Gun", "Radar"},
	-- 	},
	-- 	{
	-- 		name = "Akizuki (HA AAR)",
	-- 		ship = {"Akizuki"},
	-- 		equipment = {"High-angle Gun", "Radar"},
	-- 	},
	-- 	{
	-- 		name = "Akizuki (HA HA)",
	-- 		ship = {"Akizuki"},
	-- 		equipment = {"High-angle Gun", "High-angle Gun"}
	-- 	},
	-- 	{
	-- 		name = "Type 3 AAR",
	-- 		equipment = {"Large Caliber Main Gun", "Type 3 Shell", "Anti-Aircraft Fire Director", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "HAFD HAFD AAR",
	-- 		equipment = {"High-angle Gun + Fire Director", "High-angle Gun + Fire Director", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "Type 3",
	-- 		equipment = {"Large Caliber Main Gun", "Type 3 Shell", "Anti-Aircraft Fire Director"},
	-- 	},
	-- 	{
	-- 		name = "HA AAFD AAR",
	-- 		equipment = {"High-angle Gun", "Anti-Aircraft Fire Director", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "HAFD AAR",
	-- 		equipment = {"High-angle Gun + Fire Director", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "HA AAFD",
	-- 		equipment = {"High-angle Gun + Fire Director", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "Maya Kai Ni (HA CD AAR)",
	-- 		ship = {"Maya/Kai Ni"},
	-- 		equipment = {"High-angle Gun", "25mm Triple Autocannon Mount Concentrated Deployment", "Anti-Air Radar"},
	-- 	},
	-- 	{
	-- 		name = "Maya Kai Ni (HA CD)",
	-- 		ship = {"Maya/Kai Ni"},
	-- 		equipment = {"High-angle Gun", "25mm Triple Autocannon Mount Concentrated Deployment"},
	-- 	},
	-- 	{
	-- 		name = "CD AAMG AAR",
	-- 		equipment = {"25mm Triple Autocannon Mount Concentrated Deployment", "Anti-Air Machine Gun", "Anti-Air Radar"}
	-- 	},
	-- },
	_attack_template = "${mode} (${attack_power})",
	_day_battle_modes = {
		[1] = "Shelling",
		[2] = "Bombing",
		[3] = "Bombing, displayed as Shelling",
	},
	_artillery_spotting_modes = {
		[1] = "Double Attack (120% x2)",
		[2] = "Double Attack (120% x2) / Cut-in: Secondary Gun (110%)",
		[3] = "Double Attack (120% x2) / Cut-in: AP (150%)",
		[4] = "Cut-in: Secondary Gun (110%)",
		[5] = "Cut-in: Secondary Gun (110%) / Cut-in: Radar (120%)",
		[6] = "Cut-in: Secondary Gun (110%) / Cut-in: AP (130%)",
	},
	_night_battle_modes = {
		[1] = "Single Attack",
		[2] = "Single Torpedo",
		[3] = "Double Attack",
		[4] = "Cut-in: Main Gun",
		[5] = "Cut-in: Secondary Gun",
		[6] = "Cut-in: Mixed",
		[7] = "Cut-in: Torpedo",
		[8] = "Bombing",
	},
	_night_battle_attack_counts = {
		[3] = "x2",
		[6] = "x2",
		[7] = "x2",
	},
	_asw_attack_modes = {
		day = "Day",
		night = "Night",
	},
}

function ShipCapabilities:create(data)
	if data.ship then
		data._ship = data.ship
		data.ship = nil
	end
	setmetatable(data, data)
	data.__index = self
	return data
end

--function ShipCapabilities:anti_air_cut_in()
	--local result = false
	--base_name = self._ship:base_name()
	--if base_name == "Akizuki" then
	--	result = self:akizuki_anti_air_cut_in()
	--elseif base_name == "Maya" and self._ship:suffix() == "Kai Ni" then
	--	result = self:maya_kai_ni_anti_air_cut_in()

function ShipCapabilities:_is_asw_surface_ship(ship)
	if not ship then
		ship = self._ship
	end
	local ship_type = ship:type()
	return ship_type == 2
		or ship_type == 3
		or ship_type == 4
		or ship_type == 21
end

function ShipCapabilities:_is_asw_aviation_ship(ship)
	if not ship then
		ship = self._ship
	end
	local ship_type = ship:type()
	return ship_type == 6
		or ship_type == 7
		or ship_type == 10
		or ship_type == 16
end

function ShipCapabilities:_is_aviation_ship(ship)
	if not ship then
		ship = self._ship
	end
	local ship_type = ship:type()
	return ship_type == 6
		or ship_type == 7
		or ship_type == 10
		or ship_type == 11
		or ship_type == 14
		or ship_type == 16
		or ship_type == 17
		or ship_type == 18
end

function ShipCapabilities:_is_light_carrier(ship)
	if not ship then
		ship = self._ship
	end
	return ship:type() == 7
end

function ShipCapabilities:_is_carrier(ship)
	if not ship then
		ship = self._ship
	end
	local ship_type = ship:type()
	return ship_type == 7
		or ship_type == 11
		or ship_type == 18
end

function ShipCapabilities:_is_submarine(ship)
	if not ship then
		ship = self._ship
	end
	local ship_type = ship:type()
	return ship_type == 13
		or ship_type == 14
end

function ShipCapabilities:_is_installation(ship)
	if not ship then
		ship = self._ship
	end
	return ship:is_installation()
end

function ShipCapabilities:_is_main_gun(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 1
		or equipment_type == 2
		or equipment_type == 3
		or equipment_type == 38
end

function ShipCapabilities:_is_secondary_gun(equipment)
	return equipment:type() == 4
end

function ShipCapabilities:_is_torpedo(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 5
		or equipment_type == 32
end

function ShipCapabilities:_is_bomber(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 7
		or equipment_type == 8
		or equipment_type == 11
end

function ShipCapabilities:_is_torpedo_bomber(equipment)
	return equipment:type() == 8
end

function ShipCapabilities:_is_reconnaissance_seaplane(equipment)
	return equipment:type() == 10
end

function ShipCapabilities:_is_seaplane(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 10
		or equipment_type == 11
end

function ShipCapabilities:_is_radar(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 12
		or equipment_type == 13
end

function ShipCapabilities:_is_sonar(equipment)
	local equipment_type = equipment:type()
	return equipment_type == 14
		or equipment_type == 40
end

function ShipCapabilities:_is_depth_charge(equipment)
	return equipment:type() == 15
end

function ShipCapabilities:_is_ap_shell(equipment)
	return equipment:type() == 19
end

function ShipCapabilities:_is_midget_submarine(equipment)
	return equipment:type() == 22
end

-- Basic attack power for shelling and carrier shelling.
function ShipCapabilities:day_battle()
	if not self:_is_submarine() then
		local firepower = self._ship:firepower_leveled()
		if not firepower then
			return nil
		end
		local is_installation = self:_is_installation()
		if not self:_is_carrier() and not is_installation then
			if firepower > 0 then
				for i = 1, self._ship:slots() do
					local equipment, size = self._ship:slot(i)
					if equipment then
						local equipment_firepower = equipment:firepower()
						if equipment_firepower then
							firepower = firepower + equipment_firepower
						end
					end
				end
				return 1, 5 + firepower
			end
		else
			local total_space = self._ship:total_space()
			if total_space and total_space > 0 then
				local has_planes, torpedo, bombing = false, self._ship:torpedo_leveled() or 0, 0
				for i = 1, self._ship:slots() do
					local equipment, size = self._ship:slot(i)
					if equipment then
						local is_bomber, equipment_firepower, equipment_torpedo, equipment_bombing = self:_is_bomber(equipment), equipment:firepower(), equipment:torpedo(), equipment:bombing()
						if is_bomber then
							if size and size > 0 then
								has_planes = true
							else
								equipment_firepower = 0
								equipment_torpedo = 0
								equipment_bombing = 0
							end
						end
						if equipment_firepower then
							firepower = firepower + equipment_firepower
						end
						if equipment_torpedo then
							torpedo = torpedo + equipment_torpedo
						end
						if equipment_bombing then
							bombing = bombing + equipment_bombing
						end
					end
				end
				if has_planes then
					return is_installation and 3 or 2, 55 + math.floor(1.5 * (firepower + torpedo + math.floor(1.3 * bombing)))
				end
			end
		end
	end
	return false
end

function ShipCapabilities:format_day_battle(mode, attack_power)
	if mode then
		return format{self._attack_template, mode = self._day_battle_modes[mode], attack_power = math.floor(attack_power)}
	elseif mode == false then
		return "No Action"
	end
	return "??"
end

-- Basic attack power for closing torpedo.
function ShipCapabilities:closing_torpedo()
	local torpedo = self._ship:torpedo_leveled()
	if torpedo and torpedo > 0 then
		for i = 1, self._ship:slots() do
			local equipment, size = self._ship:slot(i)
			if equipment then
				local equipment_torpedo = equipment:torpedo()
				if equipment_torpedo then
					torpedo = torpedo + equipment_torpedo
				end
			end
		end
		return 5 + torpedo
	end
	return false
end

function ShipCapabilities:format_torpedo(attack_power)
	if attack_power then
		return tostring(math.floor(attack_power))
	end
	return "No"
end

ShipCapabilities.format_closing_torpedo = ShipCapabilities.format_torpedo

-- Detect possible day time special attack modifiers (post-cap).
function ShipCapabilities:artillery_spotting()
	local total_space = self._ship:total_space()
	if not total_space or total_space <= 0 then
		return false
	end
	local main_guns, secondary_guns, seaplanes, radars, ap_shells = 0, 0, 0, 0, 0
	for i = 1, self._ship:slots() or 0 do
		local equipment, size = self._ship:slot(i)
		if equipment then
			if self:_is_main_gun(equipment) then
				main_guns = main_guns + 1
			elseif self:_is_secondary_gun(equipment) then
				secondary_guns = secondary_guns + 1
			elseif self:_is_seaplane(equipment) and size and size > 0 then
				seaplanes = seaplanes + 1
			elseif self:_is_radar(equipment) then
				radars = radars + 1
			elseif self:_is_ap_shell(equipment) then
				ap_shells = ap_shells + 1
			end
		end
	end
	if seaplanes >= 1 then
		if main_guns >= 2 then
			if ap_shells >= 1 then
				return 3
			elseif secondary_guns >= 1 then
				return 2
			end
			return 1
		elseif main_guns == 1 and secondary_guns >= 1 then
			if radars >= 1 then
				return 5
			elseif ap_shells >= 1 then
				return 6
			end
			return 4
		end
	end
	return false
end

function ShipCapabilities:format_artillery_spotting(mode)
	if mode then
		return self._artillery_spotting_modes[mode]
	end
	return "No"
end

-- Basic attack power for night battle carrier shelling.
-- Or basic attack power for night battle attack * detected night special attack modifier (pre-cap).
function ShipCapabilities:night_battle()
	local main_guns, secondary_guns, torpedoes, has_planes, firepower, torpedo = 0, 0, 0, false, self._ship:firepower_leveled(), self._ship:torpedo_leveled()
	if not firepower or not torpedo then
		return nil
	end
	for i = 1, self._ship:slots() or 0 do
		local equipment, size = self._ship:slot(i)
		if equipment then
			local equipment_firepower, equipment_torpedo = equipment:firepower(), equipment:torpedo()
			if self:_is_main_gun(equipment) then
				main_guns = main_guns + 1
			elseif self:_is_secondary_gun(equipment) then
				secondary_guns = secondary_guns + 1
			elseif self:_is_torpedo(equipment) then
				torpedoes = torpedoes + 1
			elseif self:_is_bomber(equipment) then
				if size and size > 0 then
					has_planes = true
				else
					equipment_firepower = 0
					equipment_torpedo = 0
				end
			end
			if equipment_firepower then
				firepower = firepower + equipment_firepower
			end
			if equipment_torpedo then
				torpedo = torpedo + equipment_torpedo
			end
		end
	end
	if self:_is_carrier() then
		if has_planes and self._ship:night_bombing() then
			return 8, firepower + torpedo
		end
		return false
	else
		if torpedoes >= 2 and torpedo > 0 then
			return 7, (firepower + torpedo) * 1.5
		elseif main_guns >= 3 and firepower > 0 then
			return 4, (firepower + torpedo) * 2
		elseif main_guns >= 2 and secondary_guns >= 1 and firepower > 0 then
			return 5, (firepower + torpedo) * 1.75
		elseif main_guns >= 1 and torpedoes == 1 and firepower > 0 and torpedo > 0 then
			return 6, (firepower + torpedo) * 1.3
		elseif main_guns + secondary_guns >= 2 and firepower > 0 then
			return 3, (firepower + torpedo) * 1.2
		elseif torpedoes > 0 and torpedo > 0 then
			return 2, firepower + torpedo
		elseif firepower > 0 then
			return 1, firepower + torpedo
		else
			return false
		end
	end
end

function ShipCapabilities:format_night_battle(mode, attack_power)
	if mode then
		local multiplier = self._night_battle_attack_counts[mode]
		if multiplier then
			attack_power = tostring(math.floor(attack_power)) .. " " .. multiplier
		end
		return format{self._attack_template, mode = self._night_battle_modes[mode], attack_power = attack_power}
	elseif mode == false then
		return "No Action"
	end
	return "Unknown"
end

-- Basic attack power for opening torpedo.
function ShipCapabilities:opening_torpedo()
	local torpedo = self._ship:torpedo_leveled()
	local opening_torpedo = self._ship:opening_torpedo()
	if (opening_torpedo ~= true) and (opening_torpedo == false or not torpedo or torpedo <= 0) then
		return false
	end
	if self:_is_submarine() then
		local level = self._ship:level()
		if level and level >= 10 then
			opening_torpedo = true
		end
	end
	for i = 1, self._ship:slots() or 0 do
		local equipment, size = self._ship:slot(i)
		if equipment then
			if self:_is_midget_submarine(equipment) then
				opening_torpedo = true
			end
			local equipment_torpedo = equipment:torpedo()
			if equipment_torpedo then
				torpedo = torpedo + equipment_torpedo
			end
		end
	end
	if opening_torpedo then
		return 5 + torpedo
	end
	return false
end

ShipCapabilities.format_opening_torpedo = ShipCapabilities.format_torpedo

-- Basic attack power for ASW attack * sonar w/ depth charge modifier (pre-cap).
function ShipCapabilities:asw_attack()
	local base_asw
	local asw_override, day, night = self._ship:asw_attack(), true, true
	if asw_override == false then
		return false
	elseif self:_is_asw_surface_ship() then
		base_asw = 13
	elseif self:_is_asw_aviation_ship() then
		base_asw = 8
		if not self._ship:night_bombing() then
			night = false
		end
	else
		return false
	end
	local asw_leveled = self._ship:asw_leveled()
	local ship_asw, equipment_asw, depth_charge, sonar, bomber = (asw_leveled or 0), 0, false, false, false
	for i = 1, self._ship:slots() or 0 do
		local equipment, size = self._ship:slot(i)
		if equipment then
			if not self:_is_reconnaissance_seaplane(equipment) then
				if self:_is_sonar(equipment) then
					sonar = true
				elseif self:_is_depth_charge(equipment) then
					depth_charge = true
				elseif self:_is_bomber(equipment) then
					bomber = true
				end
				equipment_asw = equipment_asw + (equipment:asw() or 0)
			end
		end
	end
	if self:_is_light_carrier() and not bomber then
		return false
	end
	local depth_charge_sonar_boost = 1
	if depth_charge and sonar then
		depth_charge_sonar_boost = 1.15
	end
	return depth_charge_sonar_boost * (base_asw + 1.5 * equipment_asw + 2 * math.sqrt(ship_asw)), day, night, not asw_leveled
end

function ShipCapabilities:format_asw_attack(attack_power, day, night, uncertain)
	if attack_power then
		attack_power = math.floor(attack_power)
		local phases = {}
		if day then
			table.insert(phases, self._asw_attack_modes.day)
		end
		if night then
			table.insert(phases, self._asw_attack_modes.night)
		end
		if #phases == 1 then
			phases[1] = phases[1] .. " Only"
		end
		if uncertain then
			attack_power = attack_power .. "+"
		end
		return format{self._attack_template, mode = table.concat(phases, "/"), attack_power = attack_power}
	end
	return "No"
end

-- Basic attack power for opening airstrike (returns an array with attack values per each bomber).
function ShipCapabilities:opening_airstrike()
	if not self:_is_aviation_ship() then
		return false
	end
	local airstrikes = {}
	for i = 1, self._ship:slots() or 0 do
		local equipment, size = self._ship:slot(i)
		if size and size > 0 and equipment and self:_is_bomber(equipment) then
			local equipment_torpedo, equipment_bombing = equipment:torpedo() or 0, equipment:bombing() or 0
			if self:_is_torpedo_bomber(equipment) then
				table.insert(airstrikes, 1.5 * (25 + equipment_torpedo * math.sqrt(size))) -- 0.8 is also possible
			else
				table.insert(airstrikes, 25 + equipment_bombing * math.sqrt(size))
			end
		end
	end
	if #airstrikes > 0 then
		return airstrikes
	end
	return false
end

function ShipCapabilities:format_opening_airstrike(attacks)
	if attacks then
		local result = {}
		for _, attack in ipairs(attacks) do
			table.insert(result, tostring(math.floor(attack)))
		end
		return table.concat(result, ",")
	end
	return "No"
end

return ShipCapabilities