🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
モジュール:Apex/TTKCalculator
ナビゲーションに移動
検索に移動
このモジュールについての説明文ページを モジュール:Apex/TTKCalculator/doc に作成できます
local TTKCalculator = {} 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 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]), } elseif stat.magazine == math.huge then if aw.isNumberAndGreaterThanZero(stat.overheat) then magazine = 1 + math.floor(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 aw.isNumberAndGreaterThanZero(stat.overheat) then magazine = 1 + math.floor(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 -- 拡張マガジンがつかない場合 else magazine = stat.magazine end -- セグメントリロード if stat.time.reload.segment then reload = stat.time.reload.segment.fullloop or stat.time.reload.segment.loop or 0 opts.isSegmented = true opts.reloadEnd = stat.time.reload.segment.fullloopend or stat.time.reload.segment.loopend or 0 -- ショットガンまたは拡張マガジンがつかない elseif stat.ammo == 'shotgun' or stat.ammo == 'special_shotgun' or not stat.attachments.extended_mag_or_shotgun_bolt then reload = stat.time.reload.full -- 投下物資 (ヘビーアモ) --elseif stat.ammo == 'special_heavy' then -- reload = 0.87 * stat.time.reload.full -- 投下物資 (その他) elseif aw.stringstarts(stat.ammo, 'special_') then reload = 0.9 * stat.time.reload.full -- ヘビー --elseif stat.ammo == 'heavy' then -- local base = stat.time.reload.full -- if isModdedLoader then -- base = 0.75 * base -- end -- reload = { -- base, -- base, -- 0.92 * base, -- 0.87 * base, -- } -- その他 else local base = stat.time.reload.full if isModdedLoader then base = 0.75 * base end reload = { base, 0.963 * base, 0.933 * base, 0.9 * 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