🌟現在、鉄壁 鉄壁ヘッドショットには対応済みです。
鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。

「モジュール:Apex/STKCalculator」の版間の差分

提供:Apex Data
ナビゲーションに移動 検索に移動
(チャージライフルのビーム演算に対応)
(ヘッドショットに対するパッシブ倍率を無効化する機能をフラグで有効・無効にできるように変更)
 
(同じ利用者による、間の23版が非表示)
16行目: 16行目:
function STKCalculator:_getPartMultiplier(forcePart)
function STKCalculator:_getPartMultiplier(forcePart)
local part
local part
if forcePart then
if self.patternIndex <= #self.pattern.first then
part = forcePart
elseif self.patternIndex <= #self.pattern.first then
part = self.pattern.first[self.patternIndex]
part = self.pattern.first[self.patternIndex]
else
else
part = self.pattern.loop[self.patternIndex - #self.pattern.first]
part = self.pattern.loop[self.patternIndex - #self.pattern.first]
end
if forcePart and part ~= apex.SKY then
part = forcePart
end
end
45行目: 47行目:
end
end


function STKCalculator:_checkPellets()
function STKCalculator:_saveState(damage)
self.damageStack    = self.damageStack + damage
self.currentPellets = self.currentPellets - 1
if self.currentPellets <= 0 then
if self.currentPellets <= 0 then
self.currentPellets = self.pellets
self.currentPellets = self.pellets
table.insert(self.damages, self.damageStack)
table.insert(self.damages, self.damageStack)
self.damageStack   = 0
self.damageStack = 0
self:_nextPart()
end
end
 
local function calcDamage(base, passthrough, partmul, passive, opts, finalfunc)
-- 貫通減衰倍率
if passthrough < 1 then
base = apex.calcPassthroughDamage(base, passthrough)
end
-- 部位倍率、小柄・鉄壁
base = apex.calcDamageFromPartAndPassive(base, partmul, passive, opts)
-- 最終関数
if finalfunc then
base = finalfunc(base)
end
end
return base
end
end


function STKCalculator:_calcShotToKill(base, passive, points, cond, isLast, forcePart)
function STKCalculator:_calcShotToKill(base, passive, points, cond, isLast, forcePart, finalfunc)
local partmul = self:_getPartMultiplier(forcePart)
local partmul = self:_getPartMultiplier(forcePart)
local damage = apex.calcDamageFromPartAndPassive(base, partmul, passive, self.opts)
local damage = calcDamage(base, self.passthrough, partmul, passive, self.opts, finalfunc)
local hasBeam = self.beamdamage > 0 and self.beamticks > 0
local hasBeam = self.beamdamage > 0 and self.beamticks > 0
local beamdamage
if hasBeam then
if hasBeam then
damage = damage + self.beamticks * apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
beamdamage = apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
else
beamdamage = 0
end
end
while cond(points, damage) do
repeat
points             = points - damage
if hasBeam then
self.damageStack   = self.damageStack + damage
for t = 1, self.beamticks do
self.currentPellets = self.currentPellets - 1
if not cond(points, damage) then
break
end
points           = points - beamdamage
self.damageStack = self.damageStack + beamdamage
end
end
if not cond(points, damage) then
break
end
self:_checkPellets()
points = points - damage
if not forcePart then
self:_saveState(damage)
self:_nextPart()
partmul = self:_getPartMultiplier(forcePart)
partmul = self:_getPartMultiplier(forcePart)
damage = calcDamage(base, self.passthrough, partmul, passive, self.opts, finalfunc)
damage = apex.calcDamageFromPartAndPassive(base, partmul, passive, self.opts)
if hasBeam then
if hasBeam then
beamdamage = apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
damage = damage + self.beamticks * apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
end
end
end
end
until not cond(points, damage)
if isLast then
if isLast then
82行目: 116行目:
table.insert(self.damages, self.damageStack)
table.insert(self.damages, self.damageStack)
self.damageStack    = 0
self.damageStack    = 0
self:_nextPart()
end
end
end
end
return points
return points
end
-- ポイントが0かどうか確認する関数
local function isEqualToZero(points, _)
return points > 0
end
-- ポイントがダメージ以上かどうか確認する関数
local function isGreaterThanOrEqualToDamage(points, damage)
return points >= damage
end
end


93行目: 138行目:
-- ガンシールド
-- ガンシールド
if gunshield > 0 then
if gunshield > 0 then
local cond = function(points, _)
local cond
return points > 0
if self.gunshieldBleedthrough then
cond = isGreaterThanOrEqualToDamage
else
cond = isEqualToZero
end
self.patternIndex = 1 + #self.pattern.first -- 強制的に loop パターンの呼び出し
gunshield = self:_calcShotToKill(self.damage, 1, gunshield, cond, not self.gunshieldBleedthrough, apex.BODY)
-- ガンシールドとシールド/体力の混合
while gunshield > 0 do
local mul = self:_getPartMultiplier(apex.BODY)
if mul > 0 then
local leftDamage = apex.calcDamageFromPartAndPassive(self.damage - gunshield, mul, passive, self.opts)
if shield >= leftDamage then
shield = shield - leftDamage
elseif shield > 0 then
health = health - (leftDamage - shield)
shield = 0
else
health = health - leftDamage
end
self:_saveState(gunshield + leftDamage)
gunshield = 0
else
self:_saveState(0)
end
end
end
self:_calcShotToKill(self.damage, 1, gunshield, cond, true, apex.BODY)
self.patternIndex = 1 -- 強制的に first パターンに戻す
end
end
-- ハンマーポイント弾
-- ディスラプター弾
if self.hammerpointRounds > 0 then
if self.disruptorRounds > 1 then
-- シールド
-- シールド
local cond1 = function(points, damage)
local finalfunc = function(damage)
return points >= damage
return apex.calcDisruptorDamage(damage, self.disruptorRounds)
end
end
shield = self:_calcShotToKill(self.damage, passive, shield, cond1)
shield = self:_calcShotToKill(self.damage, passive, shield, isGreaterThanOrEqualToDamage, false, nil, finalfunc)
-- シールドと体力の混合
-- シールドと体力の混合
if shield > 0 then
while shield > 0 do
local mergedDamage
local mul = self:_getPartMultiplier(apex.BODY)
if shield < self.damage then
if mul > 0 then
mergedDamage = apex.calcDamageFromPartAndPassive(shield + math.floor(self.hammerpointRounds * (self.damage - shield)), self:_getPartMultiplier(), passive, self.opts)
local partDamage = apex.calcPartDamage(self.damage, mul)
local minDamage = apex.calcPassiveDamage(partDamage, passive, self.opts)
local maxDamage = apex.calcPassiveDamage(apex.calcDisruptorDamage(partDamage, self.disruptorRounds), passive, self.opts)
local mergedDamage = aw.clamp(maxDamage, minDamage, math.max(minDamage, shield))
health = health - (mergedDamage - shield)
shield = 0
self:_saveState(mergedDamage)
else
else
mergedDamage = apex.calcDamageFromPartAndPassive(self.damage, self:_getPartMultiplier(), passive, self.opts)
self:_saveState(0)
end
end
health              = health - (mergedDamage - shield)
self.damageStack    = self.damageStack + mergedDamage
self.currentPellets = self.currentPellets - 1
self:_checkPellets()
self:_nextPart()
end
end
-- 体力
-- 体力
local cond2 = function(points, damage)
health = self:_calcShotToKill(self.damage, passive, health, isEqualToZero, true)
return points > 0
-- ハンマーポイント弾
elseif self.hammerpointRounds > 1 then
-- シールド
shield = self:_calcShotToKill(self.damage, passive, shield, isGreaterThanOrEqualToDamage)
-- シールドと体力の混合
while shield > 0 do
local mul = self:_getPartMultiplier(apex.BODY)
if mul > 0 then
local baseMergedDamage
if shield < self.damage then
baseMergedDamage = shield + apex.calcHammerpointDamage(self.damage - shield, self.hammerpointRounds)
else
baseMergedDamage = self.damage
end
local mergedDamage = apex.calcDamageFromPartAndPassive(baseMergedDamage, mul, passive, self.opts)
health = health - (mergedDamage - shield)
shield = 0
self:_saveState(mergedDamage)
else
self:_saveState(0)
end
end
end
health = self:_calcShotToKill(math.floor(self.hammerpointRounds * self.damage), passive, health, cond2, true)
-- 体力
local hammerpointDamage = apex.calcHammerpointDamage(self.damage, self.hammerpointRounds)
health = self:_calcShotToKill(hammerpointDamage, passive, health, isEqualToZero, true)
-- ボディーシールド
-- ボディーシールド
else
else
local cond = function(points, _)
self:_calcShotToKill(self.damage, passive, health + shield, isEqualToZero, true)
return points > 0
end
self:_calcShotToKill(self.damage, passive, health + shield, cond, true)
end
end
end
end
149行目: 244行目:
if pattern then
if pattern then
pattern.first = pattern.first or {}
pattern.first = pattern.first or {}
pattern.loop  = pattern.loop  or {}
pattern.loop  = pattern.loop  or { apex.BODY }
self.pattern  = pattern
self.pattern  = pattern
else
else
160行目: 255行目:
if opts.pattern then
if opts.pattern then
opts.pattern.first = opts.pattern.first or {}
opts.pattern.first = opts.pattern.first or {}
opts.pattern.loop  = opts.pattern.loop  or {}
opts.pattern.loop  = opts.pattern.loop  or { apex.BODY }
else
else
opts.pattern = { first = {}, loop = { apex.BODY }}
opts.pattern = { first = {}, loop = { apex.BODY }}
168行目: 263行目:
if opts.ampedCover then
if opts.ampedCover then
damage = aw.round(1.2 * damage)
damage = aw.round(1.2 * damage)
end
-- チャージ倍率が有効
if opts.charged then
damage = aw.round(opts.charged * damage)
end
end
local obj = setmetatable({
local obj = setmetatable({
damage     = damage,
damage     = damage,
bodyshot   = opts.bodyshot   or 1,
bodyshot   = opts.bodyshot   or 1,
headshot   = opts.headshot   or 2,
headshot   = opts.headshot   or 2,
legsshot   = opts.legsshot   or 0.75,
legsshot   = opts.legsshot   or 0.75,
skyshot   = opts.skyshot   or 0,
skyshot     = opts.skyshot     or 0,
pattern   = opts.pattern,
passthrough = opts.passthrough or 1,
pellets   = opts.pellets   or 1,
pattern     = opts.pattern,
beamdamage = opts.beamdamage or 0,
pellets     = opts.pellets     or 1,
beamticks = opts.beamticks or 0,
beamdamage = opts.beamdamage or 0,
beamticks   = opts.beamticks   or 0,
disruptorRounds  = opts.disruptorRounds or 0,
hammerpointRounds = opts.hammerpointRounds or 0,
hammerpointRounds = opts.hammerpointRounds or 0,
gunshieldBleedthrough = opts.gunshieldBleedthrough ~= false,
opts      = {
opts      = {
ampedCover = opts.ampedCover or false,
ampedCover = opts.ampedCover or false,
round      = opts.round      or false,
round      = opts.round      or false,
ignorePassiveForHeadshot = opts.ignorePassiveForHeadshot ~= false,
},
},
}, { __index = STKCalculator })
}, { __index = STKCalculator })
191行目: 295行目:


function STKCalculator.newFromStat(stat, opts)
function STKCalculator.newFromStat(stat, opts)
local damagestat
local stat2, damagestat, pellets
if opts.useAnvilReceiver then
if stat.anvil_receiver and opts.useAnvilReceiver then
damagestat = stat.damage.anvil_receiver or stat.damage
stat2      = stat.anvil_receiver
damagestat = stat.anvil_receiver.damage or stat.damage
pellets    = opts.pellets or stat.anvil_receiver.pellet or stat.pellet
elseif stat.shatter_caps and opts.useShatterCaps then
stat2      = stat.shatter_caps
damagestat = stat.shatter_caps.damage  or stat.damage
pellets    = opts.pellets or stat.shatter_caps.pellet  or stat.pellet
else
else
stat2      = stat
damagestat = stat.damage
damagestat = stat.damage
pellets    = opts.pellets or stat.pellet
end
end
local damage
local damage
if opts.useAmpedMode then
if opts.useAmpedMode then
damage = damegestat.amped or damegestat.base
damage = damagestat.amped or damagestat.base
elseif opts.useCharged then
damage = damagestat.charged or damagestat.base
else
else
damage = damegestat.base
damage = damagestat.base
end
end
local beamdamage, beamticks
local beamdamage, beamticks
if stat.beam then
if damagestat.beam then
beamdamage = stat.beam.base
beamdamage = damagestat.beam.base
if opts.ticks then
if opts.ticks then
beamticks = math.min(opts.ticks, stat.beam.ticks)
beamticks = math.min(opts.ticks, damagestat.beam.ticks)
else
else
beamticks = stat.beam.ticks
beamticks = damagestat.beam.ticks
end
end
else
else
220行目: 334行目:
return STKCalculator.new(damage, {
return STKCalculator.new(damage, {
bodyshot   = opts.bodyshot,
bodyshot   = opts.bodyshot,
headshot   = damagestat.headshot,
headshot   = stat2.damage_head_scale or stat.damage_head_scale,
legsshot   = damagestat.legshot,
legsshot   = stat2.damage_legs_scale or stat.damage_legs_scale,
skyshot   = opts.skyshot,
skyshot     = opts.skyshot,
pattern   = opts.pattern,
passthrough = opts.passthrough,
pellets   = opts.pellets,
pattern     = opts.pattern,
beamdamage = beamdamage,
pellets     = pellets,
beamticks = beamticks,
beamdamage = beamdamage,
hammerpoint_rounds = opts.useHammerpointRounds and damegestat.hammerpoint_rounds or 0,
beamticks   = beamticks,
disruptorRounds  = opts.useDisruptorRounds  and stat.disruptor_rounds  and stat.disruptor_rounds.damage_shield_scale      or 0,
hammerpointRounds = opts.useHammerpointRounds and stat.hammerpoint_rounds and stat.hammerpoint_rounds.damage_unshielded_scale or 0,
})
})
end
end
234行目: 350行目:
function apex.calcShotCount(base, part, passive, health, shield, gunshield, opts)
function apex.calcShotCount(base, part, passive, health, shield, gunshield, opts)
opts = opts or {}
opts = opts or {}
opts.ampedCover       = opts.ampedCover or false
opts.ampedCover               = opts.ampedCover or false
opts.bodyshot         = part or opts.bodyshot or 1
opts.bodyshot                 = part or opts.bodyshot or 1
opts.hammerpointRounds = opts.hammerpointRounds or 0
opts.disruptorRounds          = opts.disruptorRounds or 0
opts.pellets           = opts.pellets or 1
opts.hammerpointRounds       = opts.hammerpointRounds or 0
opts.round             = opts.round or false
opts.gunshieldBleedthrough    = opts.gunshieldBleedthrough ~= false
opts.ignorePassiveForHeadshot = opts.ignorePassiveForHeadshot ~= false
opts.passthrough              = opts.passthrough or 1
opts.pellets                 = opts.pellets or 1
opts.round                   = opts.round or false
local stkc = STKCalculator.new(base, opts)
local stkc = STKCalculator.new(base, opts)
244行目: 364行目:
return stkc:getTable()
return stkc:getTable()
end
end
STKCalculator.calcShotCount = apex.calcShotCount


return STKCalculator
return STKCalculator

2022年5月25日 (水) 08:11時点における最新版

このモジュールについての説明文ページを モジュール:Apex/STKCalculator/doc に作成できます

local STKCalculator = {}

local aw   = require('Module:Utility/Library')
local apex = require('Module:Utility/ApexLibrary')

local STKCalculator = {}

function STKCalculator:reset()
	self.damages = {}
	self.damageStack = 0
	self.currentPellets = self.pellets
	
	self.patternIndex = 1
end

function STKCalculator:_getPartMultiplier(forcePart)
	local part
	if self.patternIndex <= #self.pattern.first then
		part = self.pattern.first[self.patternIndex]
	else
		part = self.pattern.loop[self.patternIndex - #self.pattern.first]
	end
	
	if forcePart and part ~= apex.SKY then
		part = forcePart
	end
	
	local mul
	if part == apex.BODY then
		mul = self.bodyshot
	elseif part == apex.LEGS then
		mul = self.legsshot
	elseif part == apex.SKY then
		mul = self.skyshot
	else
		mul = apex.calcHeadshotMultiplier(self.headshot, part)
	end
	return mul
end

function STKCalculator:_nextPart()
	if self.patternIndex == #self.pattern.first + #self.pattern.loop then
		self.patternIndex = 1 + #self.pattern.first
	else
		self.patternIndex = self.patternIndex + 1
	end
end

function STKCalculator:_saveState(damage)
	self.damageStack    = self.damageStack + damage
	self.currentPellets = self.currentPellets - 1
	
	if self.currentPellets <= 0 then
		self.currentPellets = self.pellets
		table.insert(self.damages, self.damageStack)
		self.damageStack = 0
		self:_nextPart()
	end
end

local function calcDamage(base, passthrough, partmul, passive, opts, finalfunc)
	-- 貫通減衰倍率
	if passthrough < 1 then
		base = apex.calcPassthroughDamage(base, passthrough)
	end
	
	-- 部位倍率、小柄・鉄壁
	base = apex.calcDamageFromPartAndPassive(base, partmul, passive, opts)
	
	-- 最終関数
	if finalfunc then
		base = finalfunc(base)
	end
	
	return base
end

function STKCalculator:_calcShotToKill(base, passive, points, cond, isLast, forcePart, finalfunc)
	local partmul = self:_getPartMultiplier(forcePart)
	local damage = calcDamage(base, self.passthrough, partmul, passive, self.opts, finalfunc)
	local hasBeam = self.beamdamage > 0 and self.beamticks > 0
	local beamdamage
	if hasBeam then
		beamdamage = apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
	else
		beamdamage = 0
	end
	repeat
		if hasBeam then
			for t = 1, self.beamticks do
				if not cond(points, damage) then
					break
				end
				
				points           = points - beamdamage
				self.damageStack = self.damageStack + beamdamage
			end
		end
		if not cond(points, damage) then
			break
		end
		
		points = points - damage
		self:_saveState(damage)
		
		partmul = self:_getPartMultiplier(forcePart)
		damage = calcDamage(base, self.passthrough, partmul, passive, self.opts, finalfunc)
		if hasBeam then
			beamdamage = apex.calcDamageFromPartAndPassive(self.beamdamage, partmul, passive, self.opts)
		end
	until not cond(points, damage)
	
	if isLast then
		if self.damageStack > 0 then
			self.currentPellets = self.pellets
			table.insert(self.damages, self.damageStack)
			self.damageStack    = 0
			self:_nextPart()
		end
	end
	
	return points
end

-- ポイントが0かどうか確認する関数
local function isEqualToZero(points, _)
	return points > 0
end

-- ポイントがダメージ以上かどうか確認する関数
local function isGreaterThanOrEqualToDamage(points, damage)
	return points >= damage
end

function STKCalculator:calcShotToKill(health, shield, gunshield, passive)
	legend = legend or 1
	
	-- ガンシールド
	if gunshield > 0 then
		local cond
		if self.gunshieldBleedthrough then
			cond = isGreaterThanOrEqualToDamage
		else
			cond = isEqualToZero
		end
		self.patternIndex = 1 + #self.pattern.first	-- 強制的に loop パターンの呼び出し
		gunshield = self:_calcShotToKill(self.damage, 1, gunshield, cond, not self.gunshieldBleedthrough, apex.BODY)
		
		-- ガンシールドとシールド/体力の混合
		while gunshield > 0 do
			local mul = self:_getPartMultiplier(apex.BODY)
			if mul > 0 then
				local leftDamage = apex.calcDamageFromPartAndPassive(self.damage - gunshield, mul, passive, self.opts)
				
				if shield >= leftDamage then
					shield = shield - leftDamage
				elseif shield > 0 then
					health = health - (leftDamage - shield)
					shield = 0
				else
					health = health - leftDamage
				end
				self:_saveState(gunshield + leftDamage)
				gunshield = 0
			else
				self:_saveState(0)
			end
		end
		
		self.patternIndex = 1 -- 強制的に first パターンに戻す
	end
	
	-- ディスラプター弾
	if self.disruptorRounds > 1 then
		-- シールド
		local finalfunc = function(damage)
			return apex.calcDisruptorDamage(damage, self.disruptorRounds)
		end
		shield = self:_calcShotToKill(self.damage, passive, shield, isGreaterThanOrEqualToDamage, false, nil, finalfunc)
		
		-- シールドと体力の混合
		while shield > 0 do
			local mul = self:_getPartMultiplier(apex.BODY)
			if mul > 0 then
				local partDamage = apex.calcPartDamage(self.damage, mul)
				local minDamage = apex.calcPassiveDamage(partDamage, passive, self.opts)
				local maxDamage = apex.calcPassiveDamage(apex.calcDisruptorDamage(partDamage, self.disruptorRounds), passive, self.opts)
				local mergedDamage = aw.clamp(maxDamage, minDamage, math.max(minDamage, shield))
				health = health - (mergedDamage - shield)
				shield = 0
				self:_saveState(mergedDamage)
			else
				self:_saveState(0)
			end
		end
		
		-- 体力
		health = self:_calcShotToKill(self.damage, passive, health, isEqualToZero, true)
	
	-- ハンマーポイント弾
	elseif self.hammerpointRounds > 1 then
		-- シールド
		shield = self:_calcShotToKill(self.damage, passive, shield, isGreaterThanOrEqualToDamage)
		
		-- シールドと体力の混合
		while shield > 0 do
			local mul = self:_getPartMultiplier(apex.BODY)
			if mul > 0 then
				local baseMergedDamage
				if shield < self.damage then
					baseMergedDamage = shield + apex.calcHammerpointDamage(self.damage - shield, self.hammerpointRounds)
				else
					baseMergedDamage = self.damage
				end
				
				local mergedDamage = apex.calcDamageFromPartAndPassive(baseMergedDamage, mul, passive, self.opts)
				health = health - (mergedDamage - shield)
				shield = 0
				self:_saveState(mergedDamage)
			else
				self:_saveState(0)
			end
		end
		
		-- 体力
		local hammerpointDamage = apex.calcHammerpointDamage(self.damage, self.hammerpointRounds)
		health = self:_calcShotToKill(hammerpointDamage, passive, health, isEqualToZero, true)
		
	-- ボディーシールド
	else
		self:_calcShotToKill(self.damage, passive, health + shield, isEqualToZero, true)
	end
end

function STKCalculator:getTable()
	return self.damages
end

function STKCalculator:get()
	return #self.damages
end

function STKCalculator:setPattern(pattern)
	if pattern then
		pattern.first = pattern.first or {}
		pattern.loop  = pattern.loop  or { apex.BODY }
		self.pattern  = pattern
	else
		self.pattern  = { first = {}, loop = { apex.BODY }}
	end
end

function STKCalculator.new(damage, opts)
	opts = opts or {}
	if opts.pattern then
		opts.pattern.first = opts.pattern.first or {}
		opts.pattern.loop  = opts.pattern.loop  or { apex.BODY }
	else
		opts.pattern = { first = {}, loop = { apex.BODY }}
	end

	-- 増幅バリケードが有効
	if opts.ampedCover then
		damage = aw.round(1.2 * damage)
	end

	-- チャージ倍率が有効
	if opts.charged then
		damage = aw.round(opts.charged * damage)
	end
	
	local obj = setmetatable({
		damage      = damage,
		bodyshot    = opts.bodyshot    or 1,
		headshot    = opts.headshot    or 2,
		legsshot    = opts.legsshot    or 0.75,
		skyshot     = opts.skyshot     or 0,
		passthrough = opts.passthrough or 1,
		pattern     = opts.pattern,
		pellets     = opts.pellets     or 1,
		beamdamage  = opts.beamdamage  or 0,
		beamticks   = opts.beamticks   or 0,
		disruptorRounds   = opts.disruptorRounds or 0,
		hammerpointRounds = opts.hammerpointRounds or 0,
		gunshieldBleedthrough = opts.gunshieldBleedthrough ~= false,
		opts       = {
			ampedCover = opts.ampedCover or false,
			round      = opts.round      or false,
			ignorePassiveForHeadshot = opts.ignorePassiveForHeadshot ~= false,
		},
	}, { __index = STKCalculator })
	obj:reset()
	return obj
end

function STKCalculator.newFromStat(stat, opts)
	local stat2, damagestat, pellets
	if stat.anvil_receiver and opts.useAnvilReceiver then
		stat2      = stat.anvil_receiver
		damagestat = stat.anvil_receiver.damage or stat.damage
		pellets    = opts.pellets or stat.anvil_receiver.pellet or stat.pellet
	elseif stat.shatter_caps and opts.useShatterCaps then
		stat2      = stat.shatter_caps
		damagestat = stat.shatter_caps.damage   or stat.damage
		pellets    = opts.pellets or stat.shatter_caps.pellet   or stat.pellet
	else
		stat2      = stat
		damagestat = stat.damage
		pellets    = opts.pellets or stat.pellet
	end
	
	local damage
	if opts.useAmpedMode then
		damage = damagestat.amped or damagestat.base
	elseif opts.useCharged then
		damage = damagestat.charged or damagestat.base
	else
		damage = damagestat.base
	end
	
	local beamdamage, beamticks
	if damagestat.beam then
		beamdamage = damagestat.beam.base
		
		if opts.ticks then
			beamticks = math.min(opts.ticks, damagestat.beam.ticks)
		else
			beamticks = damagestat.beam.ticks
		end
	else
		beamdamage = 0
		beamticks = 0
	end
	
	return STKCalculator.new(damage, {
		bodyshot    = opts.bodyshot,
		headshot    = stat2.damage_head_scale or stat.damage_head_scale,
		legsshot    = stat2.damage_legs_scale or stat.damage_legs_scale,
		skyshot     = opts.skyshot,
		passthrough = opts.passthrough,
		pattern     = opts.pattern,
		pellets     = pellets,
		beamdamage  = beamdamage,
		beamticks   = beamticks,
		disruptorRounds   = opts.useDisruptorRounds   and stat.disruptor_rounds   and stat.disruptor_rounds.damage_shield_scale       or 0,
		hammerpointRounds = opts.useHammerpointRounds and stat.hammerpoint_rounds and stat.hammerpoint_rounds.damage_unshielded_scale or 0,
	})
end

function apex.calcShotCount(base, part, passive, health, shield, gunshield, opts)
	opts = opts or {}
	opts.ampedCover               = opts.ampedCover or false
	opts.bodyshot                 = part or opts.bodyshot or 1
	opts.disruptorRounds          = opts.disruptorRounds or 0
	opts.hammerpointRounds        = opts.hammerpointRounds or 0
	opts.gunshieldBleedthrough    = opts.gunshieldBleedthrough ~= false
	opts.ignorePassiveForHeadshot = opts.ignorePassiveForHeadshot ~= false
	opts.passthrough              = opts.passthrough or 1
	opts.pellets                  = opts.pellets or 1
	opts.round                    = opts.round or false
	
	local stkc = STKCalculator.new(base, opts)
	stkc:calcShotToKill(health, shield, gunshield, passive)
	return stkc:getTable()
end
STKCalculator.calcShotCount = apex.calcShotCount

return STKCalculator