| 🌟 | 現在、 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:Apex/TTKCalculator」の版間の差分
ナビゲーションに移動
検索に移動
(ストックがつかない条件が付く条件と判定していた問題の修正) |
(セグメントリロードの参照変数を変更) |
||
| 363行目: | 363行目: | ||
-- セグメントリロード | -- セグメントリロード | ||
if stat.time.reload.segment then | if stat.time.reload.segment then | ||
reload = stat.time. | reload = stat.time.reload_segment_loop or 0 | ||
opts.isSegmented = true | opts.isSegmented = true | ||
opts.reloadEnd = stat.time. | opts.reloadEnd = stat.time.reload_segment_end or 0 | ||
-- 拡張マガジンがつかない | -- 拡張マガジンがつかない | ||
2021年8月9日 (月) 23:23時点における版
このモジュールについての説明文ページを モジュール:Apex/TTKCalculator/doc に作成できます
local TTKCalculator = {}
local attachment = mw.loadData('Module:Stat/Attachment')
local aw = require('Module:Utility/Library')
-- モード
TTKCalculator.BURST = 0
TTKCalculator.AUTO = 100
TTKCalculator.SINGLE = 200
TTKCalculator.SINGLE_ANVIL_RECEIVER = 201
-- [prop] 発射レート
function TTKCalculator:_loadFirerates()
local firerates = self.firerates
local type = type(firerates)
if type == 'table' then
self.firerate = firerates[1 + self.level]
elseif type == 'string' then
self.firerate = tonumber(firerates)
else
self.firerate = firerates
end
end
function TTKCalculator:setFirerates(firerates)
self.firerates = firerates or 1
self:_loadFirerates()
end
-- [prop] 装填数
function TTKCalculator:_loadMagazines()
local magazines = self.magazines
local type = type(magazines)
if type == 'table' then
self.magazine = magazines[1 + self.level]
elseif type == 'string' then
self.magazine = tonumber(magazines)
else
self.magazine = magazines
end
end
function TTKCalculator:setMagazines(magazines)
self.magazines = magazines or 20
self:_loadMagazines()
if self.isSegmented then
self:_loadReloads()
end
end
-- [prop] リロード時間
function TTKCalculator:_loadReloads()
local reloads = self.reloads
local type = type(reloads)
if type == 'table' then
self.reload = reloads[1 + self.level]
elseif type == 'string' then
self.reload = tonumber(reloads)
elseif self.isSegmented then
self.reload = (self.magazine - 1) * self.reloads + self.reloadEnd
else
self.reload = reloads
end
end
function TTKCalculator:setReloads(reloads)
self.reloads = reloads or 0
self:_loadReloads()
end
-- [prop] リチャンバー時間
function TTKCalculator:_loadRechambers()
local rechambers = self.rechambers
local type = type(rechambers)
if type == 'table' then
self.rechamber = rechambers[1 + self.level]
elseif type == 'string' then
self.rechamber = tonumber(rechambers)
else
self.rechamber = rechambers
end
end
function TTKCalculator:setRechambers(rechambers)
self.rechambers = rechambers or 0
self:_loadRechambers()
end
-- [prop] レベル
function TTKCalculator:_load()
self:_loadFirerates()
self:_loadMagazines()
self:_loadReloads()
self:_loadRechambers()
end
function TTKCalculator:setLevel(level)
self.level = level
self:_load()
end
-- [func] TTK算出関数
function TTKCalculator:_getTtk(left)
return (left - 1) / self.firerate + (left - 1) * (self.rechamber + self.charged)
end
function TTKCalculator:_getBurstTtkInOneMagazine(left, skipLastDelay)
local ttk = 0
while left > 0 do
local current = math.min(self.burst, left)
left = left - current
if current > 1 then
ttk = ttk + (current - 1) / self.firerate
end
if left == 0 and skipLastDelay then
break
end
if current == self.burst then
ttk = ttk + self.burstDelay
end
end
return ttk
end
function TTKCalculator:_getVariableFirerateTtkInOneMagazine(left)
local ttk = 0
-- The first
left = left - 1
-- To the last
while left > 0 do
left = left - 1
local current = self.start + (self.firerate - self.start) * math.min(1, ttk / self.duration)
local time = 1 / current
ttk = ttk + time + self.rechamber + self.charged
end
return ttk
end
function TTKCalculator:get(shot)
local ttk = 0
local magazine = math.floor(self.magazine / self.roundsPerShot)
-- バースト
if self.burst > 1 and self.burst <= magazine then
local function getTtkInOneMag(left, burst, burstDelay, firerate)
end
while shot > magazine do
local shotTTK = self:_getBurstTtkInOneMagazine(magazine)
ttk = ttk + self.raise + shotTTK + self.reload
shot = shot - magazine
end
local shotTTK = self:_getBurstTtkInOneMagazine(shot, true)
ttk = ttk + self.raise + shotTTK
-- 可変オート
elseif self.start > 0 and self.duration > 0 then
local first = true
local virtualMagazine = magazine - self.maximum
if magazine > 0 then
if self.startMaximum and shot > virtualMagazine then
local shotTTK = self:_getTtk(virtualMagazine)
ttk = ttk + self.raise + shotTTK + self.reload
shot = shot - virtualMagazine
first = false
end
while shot > magazine do
local shotTTK = self:_getVariableFirerateTtkInOneMagazine(magazine)
ttk = ttk + self.raise + shotTTK + self.reload
shot = shot - magazine
end
end
local shotTTK
if self.startMaximum and first then
shotTTK = self:_getTtk(shot)
else
shotTTK = self:_getVariableFirerateTtkInOneMagazine(shot)
end
ttk = ttk + self.raise + shotTTK
-- 非バースト (オート・単発)
else
if magazine > 0 then
while shot > magazine do
local shotTTK = self:_getTtk(magazine)
ttk = ttk + self.raise + shotTTK + self.reload
shot = shot - magazine
end
end
local shotTTK = self:_getTtk(shot)
ttk = ttk + self.raise + shotTTK
end
return ttk
end
function TTKCalculator:getAsLevel(shot, level)
self:setLevel(level)
return self:get(shot)
end
-- コンストラクター
function TTKCalculator.new(firerates, magazines, reloads, opts)
local obj = setmetatable({
firerates = firerates or 1,
magazines = magazines or math.huge,
reloads = reloads or 0,
raise = opts.raise or 0,
start = opts.start or 0,
duration = opts.duration or 0,
maximum = opts.maximum or 0,
startMaximum = opts.startMaximum or false,
burst = opts.burst or 1,
burstDelay = opts.burstDelay or 0,
charged = opts.charged or 0,
rechambers = opts.rechambers or 0,
reloadEnd = opts.reloadEnd or 0,
roundsPerShot = opts.roundsPerShot or 1,
isSegmented = opts.isSegmented,
level = opts.level or 0,
}, { __index = TTKCalculator })
obj:_load()
return obj
end
function TTKCalculator.newFromStat(stat, mode, opts2)
mode = mode or TTKCalculator.AUTO
opts2 = opts2 or {}
local firerate, magazine, reload
local opts = { startMaximum = opts2.startMaximum or false }
local isModdedLoader = (stat.category == 'light_machine_gun' or stat.ammo == 'minigun') and opts2.useModdedLoader
-- バースト
if stat.mode.burst > 1 and mode == TTKCalculator.BURST then
firerate = stat.firerate.burst
opts.burst = stat.mode.burst
opts.burstDelay = stat.firerate.burst_delay
opts.rechambers = 0
opts.roundsPerShot = stat.rounds_per_shot and stat.rounds_per_shot.burst or 1
-- オート
elseif stat.mode.auto and (mode == TTKCalculator.AUTO or not stat.mode.single) then
firerate = stat.firerate.auto
if opts2.useTurbocharger then
opts.raise = stat.firerate.auto_raise_turbocharger or 0
opts.start = stat.firerate.auto_start_turbocharger or 0
opts.duration = stat.firerate.auto_duration_turbocharger or 0
opts.maximum = stat.firerate.auto_maximum_turbocharger or 0
else
opts.raise = stat.firerate.auto_raise or 0
opts.start = stat.firerate.auto_start or 0
opts.duration = stat.firerate.auto_duration or 0
opts.maximum = stat.firerate.auto_maximum or 0
end
opts.rechambers = 0
opts.roundsPerShot = stat.rounds_per_shot and stat.rounds_per_shot.auto or 1
-- 単発
elseif stat.mode.single then
-- アンビルレシーバー
if stat.anvil_receiver and mode == TTKCalculator.SINGLE_ANVIL_RECEIVER then
firerate = stat.anvil_receiver.firerate.single or stat.firerate.single
opts.charged = 0
opts.rechambers = stat.anvil_receiver.firerate.single_rechamber or stat.firerate.single_rechamber or 0
opts.roundsPerShot = stat.rounds_per_shot and stat.rounds_per_shot.anvil_receiver or 1
-- 通常の単発
else
firerate = stat.firerate.single
if opts2.useCharged then
opts.charged = stat.firerate.single_charged or 0
else
opts.charged = stat.firerate.single_charged_minimum or 0
end
opts.rechambers = stat.firerate.single_rechamber or 0
opts.roundsPerShot = stat.rounds_per_shot and stat.rounds_per_shot.single or 1
end
-- プレースホルダー
else
firerate = 1
opts.charged = 0
opts.rechambers = 0
opts.roundsPerShot = 1
end
-- 装填数
if isModdedLoader then
if type(stat.magazine) == 'table' then
if aw.stringstarts(stat.ammo, 'special_') then
magazine = aw.round(1.15 * stat.magazine[4])
else
magazine = {
aw.round(1.15 * stat.magazine[1]),
aw.round(1.15 * stat.magazine[2]),
aw.round(1.15 * stat.magazine[3]),
aw.round(1.15 * stat.magazine[4]),
}
end
elseif stat.magazine == math.huge then
if type(stat.overheat) == 'table' then
magazine = {
math.ceil(1.15 * stat.overheat[1] * firerate),
math.ceil(1.15 * stat.overheat[2] * firerate),
math.ceil(1.15 * stat.overheat[3] * firerate),
math.ceil(1.15 * stat.overheat[4] * firerate),
}
elseif aw.isNumberAndGreaterThanZero(stat.overheat) then
magazine = math.ceil(1.15 * stat.overheat * firerate)
else
magazine = math.huge -- dummy
end
else
magazine = aw.round(1.15 * stat.magazine)
end
-- L-スターEMG
elseif stat.magazine == math.huge then
if type(stat.overheat) == 'table' then
magazine = {
math.ceil(stat.overheat[1] * firerate),
math.ceil(stat.overheat[2] * firerate),
math.ceil(stat.overheat[3] * firerate),
math.ceil(stat.overheat[4] * firerate),
}
elseif aw.isNumberAndGreaterThanZero(stat.overheat) then
magazine = math.ceil(stat.overheat * firerate)
else
magazine = math.huge -- dummy
end
-- ブーステッドローダー
elseif opts2.useBoostedLoader then
magazine = stat.boosted_loader and stat.boosted_loader.magazine or stat.magazine
-- 拡張マガジンがつく場合
elseif type(stat.magazine) == 'table' then
-- 物資投下武器
if aw.stringstarts(stat.ammo, 'special_') then
magazine = stat.magazine[4]
else
magazine = stat.magazine
end
-- 拡張マガジンがつかない場合
else
magazine = stat.magazine
end
-- セグメントリロード
if stat.time.reload.segment then
reload = stat.time.reload_segment_loop or 0
opts.isSegmented = true
opts.reloadEnd = stat.time.reload_segment_end or 0
-- 拡張マガジンがつかない
elseif not stat.attachments.extended_mag_or_shotgun_bolt then
reload = stat.time.reload.full
-- 物資投下武器
elseif aw.stringstarts(stat.ammo, 'special_') then
-- ストックがつく
if stat.attachments.stock then
-- スナイパーストック
if stat.category == 'sniper' or stat.category == 'marksman_weapon' then
reload = stat.time.reload.full * attachment.sniper_stock.reload[3]
-- 標準ストック
else
reload = stat.time.reload.full * attachment.standard_stock.reload[3]
end
-- ストックがつかない
else
reload = stat.time.reload.full
end
-- ストックがつかない
elseif not stat.attachments.stock then
reload = stat.time.reload.full
-- その他
else
local muls
if stat.category == 'sniper' or stat.category == 'marksman_weapon' then
muls = attachment.sniper_stock.reload
else
muls = attachment.standard_stock.reload
end
local base = stat.time.reload.full
if isModdedLoader then
base = 0.75 * base
end
reload = {
base,
muls[1] * base,
muls[2] * base,
muls[3] * base,
}
end
return TTKCalculator.new(firerate, magazine, reload, opts)
end
function TTKCalculator._test(name, count, opts)
local stat = mw.loadData('Module:Stat/Weapon')[name]
local mode = stat.mode.auto and TTKCalculator.AUTO or TTKCalculator.SINGLE
local ttkc = TTKCalculator.newFromStat(stat, mode, opts)
return ttkc:get(count)
end
return TTKCalculator