Line 5: |
Line 5: |
| -- Accuracy rate formula: 検証、仮説スレ17, 314, http://kancolle.wikia.com/wiki/Sandbox/Accuracy_Evasion_Tables | | -- Accuracy rate formula: 検証、仮説スレ17, 314, http://kancolle.wikia.com/wiki/Sandbox/Accuracy_Evasion_Tables |
| -- | | -- |
| + | |
| + | -- * TODO: Switch to Combat2. |
| | | |
| local Combat = {} | | local Combat = {} |
− |
| |
− | -- * Experimental values.
| |
| | | |
| Combat.modifier = { | | Combat.modifier = { |
Line 127: |
Line 127: |
| function Combat:damage_post_cap(attack_power, ship, enemy_armor) | | 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)) | | 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 | | if enemy_armor then |
| local min_armor = enemy_armor * 0.7 | | local min_armor = enemy_armor * 0.7 |
Line 142: |
Line 138: |
| 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) | | function Combat:damage(ship, enemy_armor) |
| return self:damage_post_cap(self:damage_cap(self:damage_pre_cap(ship)), ship, enemy_armor) | | return self:damage_post_cap(self:damage_cap(self:damage_pre_cap(ship)), ship, enemy_armor) |
Line 166: |
Line 160: |
| return ship | | return ship |
| end | | end |
− |
| |
− | -- TODO: carrier shelling, aerial, ASW, support expedition.
| |
| | | |
| Combat.nb_cut_in_types = { | | Combat.nb_cut_in_types = { |
Line 184: |
Line 176: |
| | | |
| function Combat.evasion_rate(ship, high_morale) | | function Combat.evasion_rate(ship, high_morale) |
− | local e = ship:evasion_leveled()
| + | local e = ship:evasion_leveled() |
− | if high_morale then
| + | if high_morale then |
− | return math.floor(100 * 2 * e / (2 * e + 40))
| + | return math.floor(100 * 2 * e / (2 * e + 40)) |
− | else
| + | else |
− | return math.floor(100 * e / (e + 40))
| + | return math.floor(100 * e / (e + 40)) |
− | end
| + | end |
| end | | end |
| | | |
| function Combat.accuracy_rate(ship) | | function Combat.accuracy_rate(ship) |
− | return math.floor(100 * ((math.sqrt(ship._level) - 1) / 45 + ship._luck / 1000))
| + | return math.floor(100 * ((math.sqrt(ship._level) - 1) / 45 + ship._luck / 1000)) |
| end | | end |
| | | |
| function Combat.air_power(ship) | | function Combat.air_power(ship) |
− | local slot1 = math.floor(25 + 10 * math.sqrt(ship._equipment[1].size))
| + | local slot1 = math.floor(25 + 10 * math.sqrt(ship._equipment[1].size)) |
− | local slot2 = math.floor(25 + 10 * math.sqrt(ship._equipment[2].size))
| + | local slot2 = math.floor(25 + 10 * math.sqrt(ship._equipment[2].size)) |
− | local slot3 = math.floor(25 + 10 * math.sqrt(ship._equipment[3].size))
| + | local slot3 = math.floor(25 + 10 * math.sqrt(ship._equipment[3].size)) |
− | local slot4 = ship._equipment[4] and math.floor(25 + 10 * math.sqrt(ship._equipment[4].size)) or 0
| + | local slot4 = ship._equipment[4] and math.floor(25 + 10 * math.sqrt(ship._equipment[4].size)) or 0 |
− | return {
| + | return { |
− | slot_all = slot1 + slot2 + slot3 + slot4,
| + | slot_all = slot1 + slot2 + slot3 + slot4, |
− | slot1 = slot1,
| + | slot1 = slot1, |
− | slot2 = slot2,
| + | slot2 = slot2, |
− | slot3 = slot3,
| + | slot3 = slot3, |
− | slot4 = slot4,
| + | slot4 = slot4, |
− | }
| + | } |
| end | | end |
| | | |
Line 248: |
Line 240: |
| end | | end |
| | | |
− | -- Using Module:ShipCapabilities. | + | -- * Using Module:ShipCapabilities. |
| | | |
| local BaseData = require("Module:BaseData") | | local BaseData = require("Module:BaseData") |
Line 302: |
Line 294: |
| }, | | }, |
| | | |
| + | -- handled by ShipCapabilities |
| --night_attack = { | | --night_attack = { |
| -- cut_in = { | | -- cut_in = { |
Line 313: |
Line 306: |
| --}, | | --}, |
| | | |
| + | -- TODO: also use ShipCapabilities? |
| spotting = { | | spotting = { |
| cut_in = { | | cut_in = { |
Line 335: |
Line 329: |
| [2] = 1.17, | | [2] = 1.17, |
| [3] = 1.20, | | [3] = 1.20, |
− | } | + | }, |
| + | |
| + | cap = { |
| + | day = 150, |
| + | night = 300, |
| + | asw = 100, |
| + | }, |
| + | |
| + | day_battle = 1, |
| + | opening_torpedo = 2, |
| + | closing_torpedo = 3, |
| + | night_battle = 4, |
| + | asw = 5, |
| + | opening_airstrike = 6, |
| + | day_battle = 7, |
| | | |
| } | | } |
Line 354: |
Line 362: |
| end | | end |
| | | |
− | function Combat2:damage(basic_attack_power_fn, ship, enemy, critical) | + | function Combat2:damage(type, ship, enemy, critical) |
| + | |
| + | ship = ShipCapabilities{ ship = ship } |
| | | |
| local vs_installation = enemy and enemy:is_installation() | | local vs_installation = enemy and enemy:is_installation() |
Line 364: |
Line 374: |
| local health = ship._health or Combat2.health.normal | | local health = ship._health or Combat2.health.normal |
| | | |
− | local cap = 150 | + | local cap = Combat2.cap.day |
| local spotting = 1 | | local spotting = 1 |
| local ap = 1 | | local ap = 1 |
Line 371: |
Line 381: |
| local attack_power = 0 | | local attack_power = 0 |
| | | |
− | if basic_attack_power_fn == ShipCapabilities.day_battle then | + | if type == Combat2.day_battle then |
| spotting = ship._spotting or 1 | | spotting = ship._spotting or 1 |
| ap = ship._ap or 1 | | ap = ship._ap or 1 |
| expert = 1 + ((ship._expert_n or 0) + (ship._expert_first and 1 or 0)) / 10 | | expert = 1 + ((ship._expert_n or 0) + (ship._expert_first and 1 or 0)) / 10 |
− | _, attack_power = basic_attack_power_fn(ship, vs_installation, fleet.firepower) | + | _, attack_power = ship:day_battle(vs_installation, fleet.firepower) |
− | elseif basic_attack_power_fn == ShipCapabilities.closing_torpedo or basic_attack_power_fn == ShipCapabilities.opening_torpedo then | + | elseif type == Combat2.closing_torpedo or type == Combat2.opening_torpedo then |
| if not fleet.torpedo then | | if not fleet.torpedo then |
| return false | | return false |
| end | | end |
| formation = fleet.salvo | | formation = fleet.salvo |
− | attack_power = basic_attack_power_fn(ship, fleet.torpedo) | + | attack_power = Combat2.closing_torpedo and ship:closing_torpedo(fleet.torpedo) or Combat2.opening_torpedo and ship:opening_torpedo(fleet.torpedo) |
− | elseif basic_attack_power_fn == ShipCapabilities.format_asw_attack then | + | elseif type == Combat2.asw then |
| formation = fleet.asw | | formation = fleet.asw |
− | cap = 100 | + | cap = Combat2.cap.asw |
− | attack_power = basic_attack_power_fn(ship) | + | attack_power = ship:asw_attack() |
− | elseif basic_attack_power_fn == ShipCapabilities.night_battle then | + | elseif type == Combat2.night_battle then |
| if health == Combat2.health.taiha then | | if health == Combat2.health.taiha then |
| return false | | return false |
Line 392: |
Line 402: |
| formation = 1 | | formation = 1 |
| engagement = 1 | | engagement = 1 |
− | cap = 300 | + | cap = Combat2.cap.night |
− | _, attack_power = basic_attack_power_fn(ship, vs_installation, self.stage.night_contact) | + | _, attack_power = ship:night_battle(vs_installation, self.stage.night_contact) |
− | elseif basic_attack_power_fn == ShipCapabilities.opening_airstrike then | + | elseif type == Combat2.opening_airstrike then |
| expert = 1 + ((ship._expert_n or 0) + (ship._expert_first and 1 or 0)) / 10 | | expert = 1 + ((ship._expert_n or 0) + (ship._expert_first and 1 or 0)) / 10 |
| contact = self.stage.contact and Combat2.contact[self.stage.contact] or 1 | | contact = self.stage.contact and Combat2.contact[self.stage.contact] or 1 |
− | attack_power = basic_attack_power_fn(ship) | + | attack_power = ship:opening_airstrike() |
| end | | end |
| | | |
Line 424: |
Line 434: |
| local min = math.floor((attack_power - max_armor) * ammo_modifier) | | local min = math.floor((attack_power - max_armor) * ammo_modifier) |
| local max = math.floor((attack_power - min_armor) * ammo_modifier) | | local max = math.floor((attack_power - min_armor) * ammo_modifier) |
− | return { min = min, max = max } | + | return { min = math.max(0, min), max = math.max(0, max) } |
| else | | else |
| return math.floor(attack_power * ammo_modifier) | | return math.floor(attack_power * ammo_modifier) |
Line 432: |
Line 442: |
| | | |
| Combat.Combat2 = Combat2 | | Combat.Combat2 = Combat2 |
| + | |
| + | -- * Template interface. |
| + | |
| + | local Formatting = require("Module:Formatting") |
| + | local Ship = require("Module:Ship") |
| + | local ShipCapabilities = require("Module:ShipCapabilities") |
| + | local Equipment = require("Module:Equipment") |
| + | |
| + | local setups = { |
| + | DD = { |
| + | "10cm Twin High-angle Gun Mount + Anti-Aircraft Fire Director", |
| + | "10cm Twin High-angle Gun Mount + Anti-Aircraft Fire Director", |
| + | }, |
| + | DD_CI = { |
| + | "61cm Quintuple (Oxygen) Torpedo Mount", |
| + | "61cm Quintuple (Oxygen) Torpedo Mount", |
| + | "61cm Quintuple (Oxygen) Torpedo Mount", |
| + | }, |
| + | } |
| + | |
| + | function init_setup(ship, ci, improved) |
| + | local setup = setups[Formatting:format_ship_code(ship._type) .. (ci and "_CI" or "")] or setups[ship._name .. (ci and "_CI" or "")] or {} |
| + | ship._equipment = {} |
| + | for i = 1, #setup do |
| + | ship._equipment[i] = { equipment = Equipment(setup[i]){ _level = improved and 10 or 0 } } |
| + | end |
| + | end |
| + | |
| + | function nb(ship) |
| + | init_setup(ship) |
| + | return Combat2():damage(Combat2.night_battle, ship) |
| + | end |
| + | |
| + | function nb_max(ship) |
| + | init_setup(ship, false, true) |
| + | return Combat2():damage(Combat2.night_battle, ship) |
| + | end |
| + | |
| + | function nb_ci(ship) |
| + | init_setup(ship, true) |
| + | return Combat2():damage(Combat2.night_battle, ship) |
| + | end |
| + | |
| + | function nb_ci_max(ship) |
| + | init_setup(ship, true, true) |
| + | return Combat2():damage(Combat2.night_battle, ship) |
| + | end |
| + | |
| + | function format_nb_damage(damage) |
| + | return damage >= Combat2.cap.night and string.format('<span style="color:green;">%s</span>', damage) or tostring(damage) |
| + | end |
| + | |
| + | function format_nb_ci_boost(boost) |
| + | if boost >= 90 then |
| + | return string.format('<span style="color:green;">%s</span>', boost) |
| + | elseif boost >= 70 then |
| + | return string.format('<span style="color:yellow;">%s</span>', boost) |
| + | elseif boost >= 50 then |
| + | return string.format('<span style="color:orange;">%s</span>', boost) |
| + | else |
| + | return string.format('<span style="color:red;">%s</span>', boost) |
| + | end |
| + | end |
| + | |
| + | local nb_ci_types = { |
| + | torpedo = { k = 70, luck_cap = 60 }, |
| + | mixed = { k = 70, luck_cap = 70 }, |
| + | main = { k = 50, luck_cap = 55 }, |
| + | } |
| + | |
| + | function nb_ci_rate(luck, modifier) |
| + | if luck <= modifier.luck_cap then |
| + | return math.floor(math.sqrt(modifier.k * luck)) |
| + | else |
| + | return math.floor(math.sqrt(modifier.k * modifier.luck_cap)) |
| + | end |
| + | end |
| + | |
| + | function format_luck(luck) |
| + | local maruyu_sets = math.floor(60 - luck) / 8 |
| + | local hint = string.format("%s%% base rate, ", nb_ci_rate(luck, nb_ci_types.torpedo)) |
| + | hint = hint .. ( |
| + | (maruyu_sets < 0 or luck == 60) and "capped (luck >= 60)" |
| + | or maruyu_sets == 0 and "few Maruyu to cap (60 luck)" |
| + | or string.format("~%s Maruyu sets (5 Maruyu Kai each) to cap (60 luck)", maruyu_sets)) |
| + | if luck >= 60 then |
| + | return Formatting:tooltip(luck, hint, nil, {color = "green"}) |
| + | elseif luck >= 50 then |
| + | return Formatting:tooltip(luck, hint, nil, {color = "yellow"}) |
| + | elseif luck >= 40 then |
| + | return Formatting:tooltip(luck, hint, nil, {color = "orange"}) |
| + | else |
| + | return Formatting:tooltip(luck, hint, nil, {color = "red"}) |
| + | end |
| + | end |
| + | |
| + | local functions = { |
| + | _full_name = function(ship) return string.format("%s %s", ship._name, ship._suffix) end, |
| + | _link = function(ship) return string.format("[[%s]]", ship._name) end, |
| + | _nb = function(ship) return format_nb_damage(nb(ship)) end, |
| + | _nb_max = function(ship) return format_nb_damage(nb_max(ship)) end, |
| + | _nb_ci = function(ship) return format_nb_damage(nb_ci(ship)) end, |
| + | _nb_ci_max = function(ship) return format_nb_damage(nb_ci_max(ship)) end, |
| + | _nb_ci_boost = function(ship) return format_nb_ci_boost(nb_ci(ship) - nb(ship)) end, |
| + | _nb_ci_boost_max = function(ship) return format_nb_ci_boost(nb_ci_max(ship) - nb_max(ship)) end, |
| + | -- override Lua stat |
| + | _luck = function(ship) return format_luck(ship._luck) end, |
| + | } |
| + | |
| + | function format_value(v, ship) |
| + | if string.sub(v, 1, 1) == "_" then |
| + | local fn = functions[v] |
| + | if fn then |
| + | return fn(ship) |
| + | else |
| + | local lua_stat = ship[v] |
| + | if lua_stat ~= nil then |
| + | return tostring(lua_stat) |
| + | else |
| + | return "N/A" |
| + | end |
| + | end |
| + | else |
| + | return v |
| + | end |
| + | end |
| + | |
| + | function Combat.format_values(frame) |
| + | |
| + | local args = frame.args |
| + | local ship_key = args[1] |
| + | local ship = Ship(ship_key){ _level = 99 } |
| + | |
| + | if ship and ship._type then |
| + | local args_length = #args |
| + | if args_length > 2 then |
| + | local result = "|-\n" |
| + | for i = 2, args_length do |
| + | result = result .. string.format("|%s\n", format_value(args[i], ship)) |
| + | end |
| + | return result |
| + | elseif args_length == 2 then |
| + | return format_value(args[2], ship) |
| + | end |
| + | end |
| + | |
| + | return "N/A" |
| + | |
| + | end |
| | | |
| return Combat | | return Combat |