Module:Average damage (bleeds) calculator

Documentation for this module may be created at Module:Average damage (bleeds) calculator/doc

-- <pre>
local p = {}

local yesno = require ("Module:Yesno")

function p.main(frame)
    local args = frame:getParent().args
    local debugMode = false
    
    --___________________________________
    -- Set initial values to be used
    --___________________________________
    local bleed = args.bleed
    local min_hit = tonumber(args.minHit) or 0
    local max_hit = tonumber(args.maxHit) or 0
    local mdBleed = tonumber(args.mdBleedHit) or 0
    local strcape = args.strcape
    local lungingPerk = args.lungingPerk
    local splitSoul = args.splitSoul
    local vuln = args.vuln
    local spear = args.spear
	local res = ""
	
	local nonCap = 10000 --damage cap is 10000 for bleeds (nonCrits as bleeds can't crit)
	
	local strcapeMod = 0
	if (strcape=="Yes") then strcapeMod=1 end
	local vulnMod = 0
	if (vuln=="Yes") then vulnMod = 0.1 end
	local spearMod = 0
	if (spear=="Yes") then spearMod=1 end
    --___________________________________
    -- Error messages
    --___________________________________
    if (min_hit > max_hit) then
		return "The minimum hit must not be higher than the maximum hit."
	end
	
	--___________________________________
	-- Calculate average damage from Splt Soul
	--___________________________________
	local amountHealed = 0
	local avgIncreaseHealed = 0
	local damageFromSpec = 0
	function dmgSplitSoulOverRangeCalc(n)
		amountHealed = (math.floor(math.min(2000,n)*.1) + math.floor(math.max(0,math.min(2000,n-2000))*.05) + math.floor(math.max(0,n-4000)*.0125))
		avgIncreaseHealed = math.floor(amountHealed*.375)
		if(splitSoul=="Yes \(without Amulet of Souls\)") then damageFromSpec = damageFromSpec + math.floor( math.floor(amountHealed*4) * (1+vulnMod) )
		elseif(splitSoul=="Yes \(with Amulet of Souls\)") then damageFromSpec = damageFromSpec + math.floor( ((.5*math.floor(amountHealed*4) + .5*math.floor((amountHealed+avgIncreaseHealed)*4))) * (1+vulnMod) )
		end
	end
	function dmgSplitSoulSingleValueCalc(n)
		amountHealed = (math.floor(math.min(2000,n)*.1) + math.floor(math.max(0,math.min(2000,n-2000))*.05) + math.floor(math.max(0,n-4000)*.0125))
		avgIncreaseHealed = math.floor(amountHealed*.375)
		if(splitSoul=="Yes \(without Amulet of Souls\)") then damageFromSpec = damageFromSpec + math.floor( math.floor(amountHealed*4) * (1+vulnMod) )
		elseif(splitSoul=="Yes \(with Amulet of Souls\)") then damageFromSpec = math.floor( ((.5*math.floor(amountHealed*4) + .5*math.floor((amountHealed+avgIncreaseHealed)*4))) * (1+vulnMod) )
		end
	end
	
	--___________________________________
	-- Calculate average damage
	--___________________________________
	local averageHit = 0
	local avgDmgSplitSoul = 0
	function avgDmgCalc_Dismember_Slaughter_FragmentationShot_Combust()
		local minHitChance = math.max(0,math.min(1,min_hit/max_hit))
		local notMinHitChance = math.max(0,math.min(1,1-minHitChance))
		averageHit = (minHitChance*min_hit + (notMinHitChance*(min_hit+max_hit)/2) ) --single bleed while stationary
		if((bleed=="Fragmentation Shot/Combust") and (splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)")) then
			--min hit
			dmgSplitSoulSingleValueCalc(min_hit)
			avgDmgSplitSoul =  minHitChance*damageFromSpec
			--min hit to max hit
			damageFromSpec = 0
			for damage = min_hit,max_hit do dmgSplitSoulOverRangeCalc(damage) end
			avgDmgSplitSoul = avgDmgSplitSoul + (notMinHitChance * damageFromSpec / (max_hit-min_hit+1))
		end
	end
	function avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
		averageHit = (min_hit+max_hit)/2 --initial bleed
		if((bleed=="Corruption Shot/Corruption Blast" or bleed=="Incendiary Shot") and (splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)")) then
			--min hit to max hit
			damageFromSpec = 0
			for damage = min_hit,max_hit do dmgSplitSoulOverRangeCalc(damage) end
			avgDmgSplitSoul = (damageFromSpec / (max_hit-min_hit+1))
		end
	end
	function avgDmgCalc_Massacre_Deadshot()
		averageHit = mdBleed --single bleed
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			dmgSplitSoulSingleValueCalc(mdBleed)
			avgDmgSplitSoul = damageFromSpec
		end
	end
	
	--___________________________________
    -- Average damage
    --___________________________________
	if(bleed == "Dismember") then
		local nHits = 5+3*strcapeMod+2*spearMod
		avgDmgCalc_Dismember_Slaughter_FragmentationShot_Combust()
		averageHit = math.min(nonCap,averageHit)
		res = res .. "Average damage from single bleed: " .. string.format("%.1f",averageHit) .. "<br/>"
		if(strcape=="Yes") then res = res .. "Average damage over an " .. nHits .. " hit Dismember: " .. string.format("%.1f",averageHit*nHits) .. "<br/>" end
		if(strcape=="No") then res = res .. "Average damage over a " .. nHits .. " hit Dismember: " .. string.format("%.1f",averageHit*nHits) .. "<br/>" end
	elseif(bleed == "Slaughter") then
		local nHits = 5+2*spearMod
		avgDmgCalc_Dismember_Slaughter_FragmentationShot_Combust()
		averageHit = math.min(nonCap,averageHit)
		local averageHitStationary = averageHit
		local averageHitWalked = math.min(nonCap,averageHit*3)
		res = res .. "Average damage for single stationary bleed: " .. string.format("%.1f",averageHitStationary) .. "<br/>"
		res = res .. "Average damage for single walked bleed: " .. string.format("%.1f",averageHitWalked) .. "<br/>"
		res = res .. "<br/>"
		for walked = 0,nHits do
			res = res .. "Average damage for " .. (nHits-walked) .. " stationary hits and " .. (walked) .. " walked hits: " .. string.format("%.1f",((nHits-walked)*averageHitStationary + (walked)*averageHitWalked)) .. "<br/>"
		end
	elseif(bleed == "Blood Tendrils") then
		local nHits = 4+2*spearMod
		avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
		averageHit = math.min(nonCap,averageHit)
		local averageHitInitialBleed = averageHit
		local averageHitDoT = math.min(nonCap,averageHit*.5)
		res = res .. "Average damage for the initial bleed: " .. string.format("%.1f",averageHitInitialBleed) .. "<br/>"
		res = res .. "Average damage from individual subsequent bleed hit: " .. string.format("%.1f",averageHitDoT) .. "<br/>"
		res = res .. "<br/>"
		res = res .. "Average damage over initial bleed and " .. nHits .. " subsequent bleed hits: " .. string.format("%.1f",averageHitInitialBleed+averageHitDoT*nHits) .. "<br/>"
	elseif(bleed=="Massacre/Deadshot") then
		local nHits = 5
		avgDmgCalc_Massacre_Deadshot()
		averageHit = math.min(nonCap,averageHit)
		res = res .. "Average damage for a single bleed: " .. string.format("%.1f",averageHit) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul for a single bleed of Deadshot: " .. string.format("%.1f",avgDmgSplitSoul) .. "<br/>"
			res = res .. "<br/>"
		end
		res = res .. "Average damage over " .. nHits .. " hits of Massacre/Deadshot: " .. string.format("%.1f",averageHit*nHits) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul over " .. nHits .. " hits of Deadshot: " .. string.format("%.1f",avgDmgSplitSoul*nHits) .. "<br/>"
		end
	elseif(bleed=="Fragmentation Shot/Combust") then
		local nHits = 5
		local walkModifier = 2
		if(lungingPerk == "Yes \(only affects the walk modifier for Fragmentation Shot/Combust\)") then walkModifier = 1.5 end
		avgDmgCalc_Dismember_Slaughter_FragmentationShot_Combust()
		averageHit = math.min(nonCap,averageHit)
		local averageHitStationary = averageHit
		local averageHitWalked = math.min(nonCap,averageHit*walkModifier)
		local avgDmgSplitSoulStationary = avgDmgSplitSoul
		min_hit = min_hit*walkModifier
		max_hit = max_hit*walkModifier
		avgDmgCalc_Dismember_Slaughter_FragmentationShot_Combust()
		local avgDmgSplitSoulWalked = avgDmgSplitSoul
		res = res .. "Average damage from single stationary bleed: " .. string.format("%.1f",averageHitStationary) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul for a single stationary bleed of Fragmentation Shot: " .. string.format("%.1f",avgDmgSplitSoulStationary) .. "<br/>"
			res = res .. "<br/>"
		end
		res = res .. "Average damage from single walked bleed: " .. string.format("%.1f",averageHitWalked) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul for single walked bleed of Fragmentation Shot: " .. string.format("%.1f",avgDmgSplitSoulWalked) .. "<br/>"
		end
		res = res .. "<br/>"
		for walked = 0,nHits do
			res = res .. "Average damage for " .. (5-walked) .. " stationary hits and " .. (walked) .. " walked hits: " .. string.format("%.1f",((5-walked)*averageHitStationary + (walked)*averageHitWalked)) .. "<br/>"
		end
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "<br/>"
			for walked = 0,5 do
				res = res .. "Average damage from Split Soul for " .. (5-walked) .. " stationary hits and " .. (walked) .. " walked hits of Fragmentation Shot: " .. string.format("%.1f",((5-walked)*avgDmgSplitSoulStationary + (walked)*avgDmgSplitSoulWalked)) .. "<br/>"
			end
		end
	elseif(bleed=="Corruption Shot/Corruption Blast") then
		avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
		averageHit = math.min(nonCap,averageHit)
		local averageHitInitialBleed = averageHit
		local avgDmgSplitSoulInitialBleed = avgDmgSplitSoul
		res = res .. "<div style=\"font-weight:bold\">Average damage for the inital bleed matching min and max hit entered: " .. string.format("%.1f",averageHitInitialBleed) .. "</div>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul for the inital bleed of Corruption Shot matching min and max hit entered: " .. string.format("%.1f",avgDmgSplitSoulInitialBleed) .. "<br/>"
			res = res .. "<br/>"
		end
		res = res .. "Estimation of average damage for all five hits of " .. bleed .. " assuming min and max hit entered correspond to the first hit: (" .. string.format("%.1f",averageHitInitialBleed) .. "+" .. string.format("%.1f",averageHitInitialBleed*0.8) .. "+" .. string.format("%.1f",averageHitInitialBleed*0.6) .. "+" .. string.format("%.1f",averageHitInitialBleed*0.4) .. "+" .. string.format("%.1f",averageHitInitialBleed*0.2) .. ") = " .. string.format("%.1f",averageHitInitialBleed*3) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			min_hit = math.min(nonCap,min_hit)
			max_hit = math.min(nonCap,max_hit)
			min_hit = min_hit*0.8
			max_hit = max_hit*0.8
			avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
			local  avgDmgSplitSoulBleed2 = avgDmgSplitSoul
			min_hit = min_hit/0.8*0.6
			max_hit = max_hit/0.8*0.6
			avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
			local  avgDmgSplitSoulBleed3 = avgDmgSplitSoul
			min_hit = min_hit/0.6*0.4
			max_hit = max_hit/0.6*0.4
			avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
			local  avgDmgSplitSoulBleed4 = avgDmgSplitSoul
			min_hit = min_hit/0.4*0.2
			max_hit = max_hit/0.4*0.2
			avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
			local  avgDmgSplitSoulBleed5 = avgDmgSplitSoul
			local avgDmgSplitSoulEstimationBleeds = avgDmgSplitSoulInitialBleed + avgDmgSplitSoulBleed2 + avgDmgSplitSoulBleed3 + avgDmgSplitSoulBleed4 + avgDmgSplitSoulBleed5
			res = res .. "Estimation of average damage from Split Soul for all five hits of Corruption Shot assuming min and max hit entered correspond to the first hit: (" .. string.format("%.1f",avgDmgSplitSoulInitialBleed) .. "+" .. string.format("%.1f",avgDmgSplitSoulBleed2) .. "+" .. string.format("%.1f",avgDmgSplitSoulBleed3) .. "+" .. string.format("%.1f",avgDmgSplitSoulBleed4) .. "+" .. string.format("%.1f",avgDmgSplitSoulBleed5) .. ") = " .. string.format("%.1f",avgDmgSplitSoulEstimationBleeds) .. "<br/>"
		end
	elseif(bleed=="Incendiary Shot") then
		avgDmgCalc_BloodTendrils_CorruptionShot_CorruptionBlast_IncendiaryShot()
		averageHit = math.min(nonCap,averageHit)
		res = res .. "Average damage: " .. string.format("%.1f",averageHit) .. "<br/>"
		if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
			res = res .. "Average damage from Split Soul: " .. string.format("%.1f",avgDmgSplitSoul) .. "<br/>"
		end
	end
	
	--___________________________________
    -- Return result
    --___________________________________
	return res
end

return p