- 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:Sandbox/Combat"
Jump to navigation
Jump to search
m |
(redo and add NB damage) |
||
Line 1: | Line 1: | ||
+ | -- ** | ||
+ | -- Damage calculations are based on http://kancollecalc.web.fc2.com/damage_formula.html and WikiWiki combat page. | ||
+ | -- NB CI rate formula is from WikiWiki combat page (also, 検証、仮説スレ18). | ||
+ | -- | ||
local Combat = {} | local Combat = {} | ||
− | -- * | + | -- * Experimental values. |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Combat.modifier = { | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | comined_firepower = { | |
− | + | ctf_first = 0, | |
− | + | ctf_second = 10, | |
− | + | stf_first = 10, | |
− | + | stf_second = -5, | |
− | |||
}, | }, | ||
− | |||
− | |||
− | + | comined_torpedo = -5, | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | night_contact = 5, | |
− | + | formation = { | |
− | + | line_ahead = 1.0, | |
− | + | double_line = 0.8, | |
− | |||
− | |||
− | |||
− | |||
− | |||
diamond = 0.7, | diamond = 0.7, | ||
− | double_line = 1.0, | + | echelon = 0.6, |
− | + | line_abreast = 0.6, | |
− | } | + | combined = { |
− | } | + | line_ahead = 1.1, |
+ | diamond = 0.7, | ||
+ | double_line = 1.0, | ||
+ | line_abreast = 0.8, | ||
+ | }, | ||
+ | }, | ||
+ | |||
+ | engagement = { | ||
+ | green_t = 1.2, | ||
+ | parallel = 1.0, | ||
+ | head_on = 0.8, | ||
+ | red_t = 0.6, | ||
+ | }, | ||
+ | |||
+ | health = { | ||
+ | normal = 1.0, | ||
+ | chuuha = 0.7, | ||
+ | taiha = 0.4, | ||
+ | }, | ||
− | + | anti_ground = 2.5, | |
− | + | wg_bonus = 75, | |
− | |||
− | |||
− | |||
− | + | cap = { | |
− | + | day = 150, | |
− | + | night = 300, | |
+ | }, | ||
− | + | spotting = { | |
− | + | cut_in = { | |
− | + | main_main = 1.5, | |
− | + | main_ap = 1.3, | |
− | + | main_radar = 1.2, | |
− | } | + | main_second = 1.1, |
+ | }, | ||
+ | double = 1.2, | ||
+ | }, | ||
− | + | night_attack = { | |
+ | cut_in = { | ||
+ | main = 2, | ||
+ | main_misc = 1.75, | ||
+ | torpedo = 1.5, | ||
+ | mixed = 1.3, | ||
+ | }, | ||
+ | double = 1.2, | ||
+ | normal = 1, | ||
+ | }, | ||
− | + | critical = 1.5, | |
− | |||
− | + | ap = { | |
− | + | main_ap = 1.08, | |
+ | main_ap_radar = 1.1, | ||
+ | main_second_ap = 1.15, | ||
+ | main_second_ap_radar = 1.15, | ||
+ | }, | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | function | + | function Combat.ammo_modifier(ammo_bars) |
− | return | + | return ammo_bars >= 5 and 1 or ammo_bars / 5 |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | + | -- * Combat object with ship-independent values as fields. | |
− | + | -- Ship and enemy values are passed via arguments. | |
− | |||
− | function | + | function Combat:new(is_night_battle) |
− | return | + | local stage = { |
+ | combined_firepower = 0, | ||
+ | combined_torpedo = 0, | ||
+ | formation = self.modifier.formation.line_ahead, | ||
+ | engagement = self.modifier.engagement.parallel, | ||
+ | night_contact = 0, | ||
+ | is_night_battle = is_night_battle, | ||
+ | cap = is_night_battle and self.modifier.cap.night or self.modifier.cap.day, | ||
+ | contact = 1, -- TODO | ||
+ | expert = 1, -- TODO | ||
+ | } | ||
+ | setmetatable(stage, self) | ||
+ | self.__index = self | ||
+ | return stage | ||
end | end | ||
− | function damage_pre_cap( | + | function Combat:damage_pre_cap(ship) |
− | return | + | return self.engagement * self.formation * ship.health * ship.anti_ground * ship.anti_sub * ship.night_attack * ship.attack_power |
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | function damage_cap(attack_power | + | function Combat:damage_cap(attack_power) |
− | if attack_power > | + | if attack_power > self.cap then |
− | attack_power = | + | attack_power = self.cap + math.sqrt(attack_power - self.cap) |
end | end | ||
return math.floor(attack_power) | return math.floor(attack_power) | ||
end | end | ||
− | function damage_post_cap(attack_power, | + | function Combat:damage_post_cap(attack_power, ship, enemy_armor) |
− | attack_power = | + | attack_power = ship.spotting * self.contact * math.floor(self.expert * ship.critical * math.floor(ship.ap * attack_power)) |
− | + | -- Use a note on a caller side instead | |
− | + | --if ship.night_attack_x2 then | |
− | + | -- attack_power = 2 * attack_power | |
− | if | + | --end |
− | local min_armor = | + | if enemy_armor then |
− | local max_armor = | + | local min_armor = enemy_armor * 0.7 |
− | local min = math.floor((attack_power - max_armor) * | + | local max_armor = enemy_armor * 0.7 + math.max(enemy_armor - 1, 0) * 0.6 |
− | local max = math.floor((attack_power - min_armor) * | + | local min = math.floor((attack_power - max_armor) * ship.ammo) |
+ | local max = math.floor((attack_power - min_armor) * ship.ammo) | ||
return { min, max } | return { min, max } | ||
else | else | ||
− | return math.floor(attack_power * | + | return math.floor(attack_power * ship.ammo) |
end | end | ||
end | end | ||
− | function damage( | + | -- TODO: pass enemy table, do additional detection (e.g. torpedo = 0 vs. ground type enemies |
− | return damage_post_cap(damage_cap(damage_pre_cap( | + | -- or attack_power = 0 when BB vs. enemy submarines, etc.) |
+ | function Combat:damage(ship, enemy_armor) | ||
+ | return self:damage_post_cap(self:damage_cap(self:damage_pre_cap(ship)), ship, enemy_armor) | ||
end | end | ||
− | -- | + | -- TODO: carrier shelling, aerial, ASW, support expedition. |
− | + | Combat.nb_cut_in_types = { | |
− | torpedo = { k = 70, | + | torpedo = { k = 70, luck_cap = 60 }, |
− | mixed = { k = 70, | + | mixed = { k = 70, luck_cap = 70 }, |
− | main = { k = 50, | + | main = { k = 50, luck_cap = 55 }, |
} | } | ||
− | function | + | function Combat.nb_cut_in_rate(ship, modifier) |
− | if | + | if ship._luck <= modifier.luck_cap then |
− | return math.floor(math.sqrt( | + | return math.floor(math.sqrt(modifier.k * ship._luck)) |
else | else | ||
− | return | + | return Combat.nb_cut_in_rate(modifier.luck_cap, modifier) |
end | end | ||
end | end | ||
− | + | function Combat:shelling(ship) | |
+ | ship.attack_power = 5 + ship._firepower_max + ship.equipment_bonus.firepower + self.combined_firepower + ship.anti_ground_bonus | ||
+ | return ship | ||
+ | end | ||
− | + | function Combat:torpedo(ship) | |
− | + | ship.attack_power = 5 + ship._torpedo_max + ship.equipment_bonus.torpedo + self.combined_torpedo | |
− | + | return ship | |
− | + | end | |
− | + | function Combat:night_battle(ship) | |
− | + | if ship.health == self.modifier.health.taiha then | |
− | + | ship.attack_power = 0 | |
− | + | else | |
− | + | ship.attack_power = self.night_contact + ship._firepower_max + ship._torpedo_max + ship.equipment_bonus.firepower + ship.equipment_bonus.torpedo | |
− | + | end | |
− | + | return ship | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | + | -- * Ship object with extra fields related to combat. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | local Ship = {} | |
− | + | function Ship:new(ship, equip, night_attack, spotting) | |
− | |||
− | |||
− | |||
− | + | self._firepower_max = ship._firepower_max or 0 | |
− | + | self._torpedo_max = ship._torpedo_max or 0 | |
+ | self._luck = ship._luck or 0 | ||
− | + | self.equipment = equip or {} | |
− | + | self.equipment_bonus = { firepower = 0, torpedo = 0 } | |
− | + | for _, eq in pairs(self.equipment) do | |
− | + | if eq.firepower then | |
− | + | self.equipment_bonus.firepower = self.equipment_bonus.firepower + eq.firepower + (eq.k and eq.rank and eq.k * math.sqrt(eq.rank) or 0) | |
− | + | end | |
− | + | if eq.torpedo then | |
− | + | self.equipment_bonus.torpedo = self.equipment_bonus.torpedo + eq.torpedo + (eq.k and eq.rank and eq.k * math.sqrt(eq.rank) or 0) | |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
+ | self.equipment_bonus.firepower = math.floor(self.equipment_bonus.firepower) | ||
+ | self.equipment_bonus.torpedo = math.floor(self.equipment_bonus.torpedo) | ||
+ | |||
+ | self.health = ship.health or Combat.modifier.health.normal | ||
+ | self.anti_ground = ship.anti_ground and Combat.modifier.anti_ground or 1 | ||
+ | self.anti_ground_bonus = ship.wg and Combat.modifier.wg_bonus or 0 | ||
+ | self.anti_sub = ship.anti_sub or 1 | ||
+ | self.night_attack = night_attack or 1 | ||
+ | self.night_attack_x2 = night_attack == Combat.modifier.night_attack.cut_in.torpedo or | ||
+ | night_attack == Combat.modifier.night_attack.cut_in.mixed | ||
+ | self.spotting = spotting or 1 | ||
+ | self.critical = ship.critical or 1 | ||
+ | self.ap = ship.ap or 1 | ||
+ | self.ammo = ship.ammo or 1 | ||
+ | return self | ||
end | end | ||
− | |||
− |
Revision as of 20:38, 22 October 2015
Documentation for this module may be created at Module:Sandbox/Combat/doc
-- **
-- Damage calculations are based on http://kancollecalc.web.fc2.com/damage_formula.html and WikiWiki combat page.
-- NB CI rate formula is from WikiWiki combat page (also, 検証、仮説スレ18).
--
local Combat = {}
-- * Experimental values.
Combat.modifier = {
comined_firepower = {
ctf_first = 0,
ctf_second = 10,
stf_first = 10,
stf_second = -5,
},
comined_torpedo = -5,
night_contact = 5,
formation = {
line_ahead = 1.0,
double_line = 0.8,
diamond = 0.7,
echelon = 0.6,
line_abreast = 0.6,
combined = {
line_ahead = 1.1,
diamond = 0.7,
double_line = 1.0,
line_abreast = 0.8,
},
},
engagement = {
green_t = 1.2,
parallel = 1.0,
head_on = 0.8,
red_t = 0.6,
},
health = {
normal = 1.0,
chuuha = 0.7,
taiha = 0.4,
},
anti_ground = 2.5,
wg_bonus = 75,
cap = {
day = 150,
night = 300,
},
spotting = {
cut_in = {
main_main = 1.5,
main_ap = 1.3,
main_radar = 1.2,
main_second = 1.1,
},
double = 1.2,
},
night_attack = {
cut_in = {
main = 2,
main_misc = 1.75,
torpedo = 1.5,
mixed = 1.3,
},
double = 1.2,
normal = 1,
},
critical = 1.5,
ap = {
main_ap = 1.08,
main_ap_radar = 1.1,
main_second_ap = 1.15,
main_second_ap_radar = 1.15,
},
}
function Combat.ammo_modifier(ammo_bars)
return ammo_bars >= 5 and 1 or ammo_bars / 5
end
-- * Combat object with ship-independent values as fields.
-- Ship and enemy values are passed via arguments.
function Combat:new(is_night_battle)
local stage = {
combined_firepower = 0,
combined_torpedo = 0,
formation = self.modifier.formation.line_ahead,
engagement = self.modifier.engagement.parallel,
night_contact = 0,
is_night_battle = is_night_battle,
cap = is_night_battle and self.modifier.cap.night or self.modifier.cap.day,
contact = 1, -- TODO
expert = 1, -- TODO
}
setmetatable(stage, self)
self.__index = self
return stage
end
function Combat:damage_pre_cap(ship)
return self.engagement * self.formation * ship.health * ship.anti_ground * ship.anti_sub * ship.night_attack * ship.attack_power
end
function Combat:damage_cap(attack_power)
if attack_power > self.cap then
attack_power = self.cap + math.sqrt(attack_power - self.cap)
end
return math.floor(attack_power)
end
function Combat:damage_post_cap(attack_power, ship, enemy_armor)
attack_power = ship.spotting * self.contact * math.floor(self.expert * ship.critical * math.floor(ship.ap * attack_power))
-- Use a note on a caller side instead
--if ship.night_attack_x2 then
-- attack_power = 2 * attack_power
--end
if enemy_armor then
local min_armor = enemy_armor * 0.7
local max_armor = enemy_armor * 0.7 + math.max(enemy_armor - 1, 0) * 0.6
local min = math.floor((attack_power - max_armor) * ship.ammo)
local max = math.floor((attack_power - min_armor) * ship.ammo)
return { min, max }
else
return math.floor(attack_power * ship.ammo)
end
end
-- TODO: pass enemy table, do additional detection (e.g. torpedo = 0 vs. ground type enemies
-- or attack_power = 0 when BB vs. enemy submarines, etc.)
function Combat:damage(ship, enemy_armor)
return self:damage_post_cap(self:damage_cap(self:damage_pre_cap(ship)), ship, enemy_armor)
end
-- TODO: carrier shelling, aerial, ASW, support expedition.
Combat.nb_cut_in_types = {
torpedo = { k = 70, luck_cap = 60 },
mixed = { k = 70, luck_cap = 70 },
main = { k = 50, luck_cap = 55 },
}
function Combat.nb_cut_in_rate(ship, modifier)
if ship._luck <= modifier.luck_cap then
return math.floor(math.sqrt(modifier.k * ship._luck))
else
return Combat.nb_cut_in_rate(modifier.luck_cap, modifier)
end
end
function Combat:shelling(ship)
ship.attack_power = 5 + ship._firepower_max + ship.equipment_bonus.firepower + self.combined_firepower + ship.anti_ground_bonus
return ship
end
function Combat:torpedo(ship)
ship.attack_power = 5 + ship._torpedo_max + ship.equipment_bonus.torpedo + self.combined_torpedo
return ship
end
function Combat:night_battle(ship)
if ship.health == self.modifier.health.taiha then
ship.attack_power = 0
else
ship.attack_power = self.night_contact + ship._firepower_max + ship._torpedo_max + ship.equipment_bonus.firepower + ship.equipment_bonus.torpedo
end
return ship
end
-- * Ship object with extra fields related to combat.
local Ship = {}
function Ship:new(ship, equip, night_attack, spotting)
self._firepower_max = ship._firepower_max or 0
self._torpedo_max = ship._torpedo_max or 0
self._luck = ship._luck or 0
self.equipment = equip or {}
self.equipment_bonus = { firepower = 0, torpedo = 0 }
for _, eq in pairs(self.equipment) do
if eq.firepower then
self.equipment_bonus.firepower = self.equipment_bonus.firepower + eq.firepower + (eq.k and eq.rank and eq.k * math.sqrt(eq.rank) or 0)
end
if eq.torpedo then
self.equipment_bonus.torpedo = self.equipment_bonus.torpedo + eq.torpedo + (eq.k and eq.rank and eq.k * math.sqrt(eq.rank) or 0)
end
end
self.equipment_bonus.firepower = math.floor(self.equipment_bonus.firepower)
self.equipment_bonus.torpedo = math.floor(self.equipment_bonus.torpedo)
self.health = ship.health or Combat.modifier.health.normal
self.anti_ground = ship.anti_ground and Combat.modifier.anti_ground or 1
self.anti_ground_bonus = ship.wg and Combat.modifier.wg_bonus or 0
self.anti_sub = ship.anti_sub or 1
self.night_attack = night_attack or 1
self.night_attack_x2 = night_attack == Combat.modifier.night_attack.cut_in.torpedo or
night_attack == Combat.modifier.night_attack.cut_in.mixed
self.spotting = spotting or 1
self.critical = ship.critical or 1
self.ap = ship.ap or 1
self.ammo = ship.ammo or 1
return self
end