Module:Sandbox/User:Sfoxrs/sgb

From WIDEVERSE Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/User:Sfoxrs/sgb/doc

-- <pre>
local p = {}

local htnmlext = require('Module:Mw.html extension')
local yesno = require ("Module:Yesno")
local lang = mw.getContentLanguage()

function p.main(frame)
	local invokeArgs = frame.args
    local args = frame:getParent().args
    
    return p._main( invokeArgs, args )
end

function p._main(invokeArgs,args)
	
	local ad = tonumber(args.AD) or 0
    local rangedlvl = tonumber(args.ranged) or 0
    local preciseRank = tonumber(args.precise) or 0
    local equilibriumRank = tonumber(args.eq) or 0
    local weaponSwitch = args.weaponSwitch
    local eqSwitchRank = tonumber(args.eqswitch) or -1
    local ruthlessRank = tonumber(args.ruthless) or 0
    local ruthlessStacks = tonumber(args.rstacks) or 0
    local bitingRank = tonumber(args.biting) or 0
    local bitingLevel20 = args.bitinglvl20
    local eof = args.eof
    local revengeStacks = tonumber(args.revengeStacks) or 0
    local shieldType = args.shieldType
    local hexhunter = args.hexhunter
    local bolts = args.bolts
    local seers = args.seers
    local rangedCape = args.rangedCape
    local maxhp = tonumber(args.maxhp) or 0
    local currenthp = tonumber(args.currenthp) or 0
    local pocket = args.pocket
    local ring = args.ring
    local potion = args.potion
    local berserkBloodEssence = args.essence or ""
    local prayer = args.prayer
    local aura = args.aura
    local vuln = args.vuln
    local slayerPerk = args.slayerPerk
    local slayerAbility = args.slayerAbility
    local spider = args.spider
    local swiftness = args.swiftness
    local splitSoul = args.splitSoul or ""
    local aos = args.aos or ""
    local nArrowsSplitSoul = args.nArrowsSplitSoul or ""
    local needle = args.needle
    local bFury = tonumber(args.dhrelic) or 0
    local ripper = args.ripper
    local telosBeam = args.telosBeam
    local npc = args.npc
    
	return calculateDamage(ad,rangedlvl,preciseRank,equilibriumRank,weaponSwitch,eqSwitchRank,ruthlessRank,ruthlessStacks,bitingRank,bitingLevel20,eof,revengeStacks,shieldType,hexhunter,bolts,seers,rangedCape,maxhp,currenthp,pocket,ring,potion,berserkBloodEssence,prayer,aura,vuln,slayerPerk,slayerAbility,spider,swiftness,splitSoul,aos,nArrowsSplitSoul,needle,bFury,ripper,telosBeam,npc)
	
end

function calculateDamage(ad,rangedlvl,preciseRank,equilibriumRank,weaponSwitch,eqSwitchRank,ruthlessRank,ruthlessStacks,bitingRank,bitingLevel20,eof,revengeStacks,shieldType,hexhunter,bolts,seers,rangedCape,maxhp,currenthp,pocket,ring,potion,berserkBloodEssence,prayer,aura,vuln,slayerPerk,slayerAbility,spider,swiftness,splitSoul,aos,nArrowsSplitSoul,needle,bFury,ripper,telosBeam,npc)
	
	-- calculate effective level and Ability damage (AD)
	local lvlMult = 1
	local lvlAdd = 0
	if(potion=="Elder overload potion") then lvlMult = 1.17; lvlAdd = 5
	elseif(potion=="Supreme overload potion" or potion=="Supreme ranging potion") then lvlMult = 1.16; lvlAdd = 4
	elseif(potion=="Overload") then lvlMult = 1.15; lvlAdd = 3
	end
	local lvlAura = 0
	if(aura=="Reckless") then lvlAura = 0.1 end
	
	local rangedlvlEff = rangedlvl
	if(potion=="Supreme ranging potion") then
		rangedlvlEff = math.floor(rangedlvl*lvlMult+lvlAdd)
		if(berserkBloodEssence=="Yes") then -- 133 stats at level 99 (with or without reckless)
			rangedlvlEff = rangedlvlEff + math.floor(rangedlvl*1.14+2) - rangedlvl
		end
	elseif(potion=="None") then
		rangedlvlEff = math.floor(rangedlvl*(lvlAura + lvlMult))
		if(berserkBloodEssence=="Yes") then -- 123 stats at level 99 with reckless (114 without)
			rangedlvlEff = rangedlvlEff + math.floor(rangedlvl*1.14+2) - rangedlvl
		end
	else --overloads
		rangedlvlEff = math.floor(rangedlvl*(lvlAura + lvlMult)+lvlAdd)
	end
	
	local prayerMod = 1
	if(prayer=="Desolation") then prayerMod = 1.12
	elseif(prayer=="Anguish") then prayerMod = 1.10
	elseif(prayer=="Leech Range Strength + Amulet of zealots") then prayerMod = 1.18
	elseif(prayer=="Overpowering Force + Amulet of zealots") then prayerMod = 1.16
	elseif(prayer=="Rigour") then prayerMod = 1.08
	end
	
	--local adEff = math.floor(ad*prayerMod)
	local adEff = ad
	if(hexhunter=="Yes") then adEff = math.floor(ad*1.125) end
	
	-- base sgb arrow range %s
	local arrowFixedPercent = {80,80,80,80,80}
	local arrowVarPercent = {120,160,133,106,80}
	
	-- sgb as damage from AD
	local arrowFixedBase = {0,0,0,0,0}
	local arrowVarBase = {0,0,0,0,0}
	
	-- sgb arrows as damage from ADeff
	local arrowFixed = {0,0,0,0,0}
	local arrowVar = {0,0,0,0,0}
	
	-- split soul based damages
	local arrowFixedECB = {0,0,0,0,0}
	local arrowVarECB = {0,0,0,0,0}
	
	--base
	for arrow = 1,5 do 
		arrowFixedBase[arrow] = math.floor(adEff*arrowFixedPercent[arrow]/100)
		arrowVarBase[arrow] = math.floor(adEff*arrowVarPercent[arrow]/100)
		arrowFixed[arrow] = math.floor(arrowFixedBase[arrow]*prayerMod) -- prayerMod applied here
		arrowVar[arrow] = math.floor(arrowVarBase[arrow]*prayerMod) -- prayerMod applied here
	end
	
	--boosted
	for arrow = 1,5 do 
		arrowFixed[arrow] = arrowFixed[arrow] + 4*(rangedlvlEff - rangedlvl)
		arrowVar[arrow] = arrowVar[arrow] + 4*(rangedlvlEff - rangedlvl)
	end
	
	--revenge EOF
	if(eof=="Yes") then
		local revengeMod = 0
		if(shieldType=="Shield") then revengeMod = 0.10
		elseif(shieldType=="Repriser") then revengeMod = 0.05
		else revengeMod = 0
		end
		for arrow = 1,5 do
			arrowVar[arrow] = math.floor(arrowVar[arrow]*(1+revengeStacks*revengeMod))
		end
	end
	
	--precise
	local Aprecise = math.floor(.015*preciseRank*(arrowFixed[1]+arrowVar[1]))
	arrowFixed[1] = arrowFixed[1] + Aprecise
	for arrow = 2,5 do arrowFixed[arrow] = arrowFixed[1] end
	arrowVar[1] = arrowVar[1] - Aprecise
	arrowVar[2] = 2*arrowFixed[1]
	arrowVar[3] = math.floor(5/3*arrowFixed[1])
	arrowVar[4] = math.floor(4/3*arrowFixed[1])
	arrowVar[5] = 1*arrowFixed[1]
	
	-- calculate p forced crit
	local bitingMod = 0
	if(bitingLevel20=="Yes") then bitingMod = 1 end
	local pForcedCrit = .02*bitingRank*(1+.1*bitingMod)
	if(pocket=="Grimoire" or pocket=="Grimshaw" or pocket=="Grimshaw (superior)") then pForcedCrit = pForcedCrit + 0.12 end
	if(ring=="Reaver's ring") then pForcedCrit = pForcedCrit + 0.05
	elseif(ring=="Stalker's ring") then pForcedCrit = pForcedCrit + 0.03
	end
	
	--calculate pNatCrit
	local pNatCrit = {0,0,0,0,0}
	for arrow = 1,5 do 
		pNatCrit[arrow] = math.floor(.05*(arrowFixed[arrow]+arrowVar[arrow]))/arrowVar[arrow]
	end
	
	--equilibrium (aura overrides perk)
	for arrow = 1,5 do 
		if(aura=="Equilibrium") then 
			arrowFixed[arrow] = arrowFixed[arrow] + math.floor(.25*arrowVar[arrow])
			arrowVar[arrow] = math.floor((1-.50)*arrowVar[arrow])
		else
			local eqRankEffective = equilibriumRank
			if(weaponSwitch=="Yes" and arrow>1) then eqRankEffective = eqSwitchRank end
			arrowFixed[arrow] = arrowFixed[arrow] + math.floor(.03*eqRankEffective*arrowVar[arrow])
			arrowVar[arrow] = math.floor((1-.04*eqRankEffective)*arrowVar[arrow])
		end
	end
	
	--calculate hits after vuln/swiftness/aura/ruthless/scrim
	local ruthlessMod = 0.005*ruthlessRank*ruthlessStacks
	local vulnMod = 0
	if(vuln=="Yes") then vulnMod = 0.1 end
	local slayerPerkMod = 0
	if(slayerPerk=="Yes") then slayerPerkMod = 0.07 end
	local slayerAbilityMod = 0
	if(slayerAbility=="Yes") then slayerAbilityMod = 0.15 end
	local spiderMod = 0
	if(spider=="2%") then spiderMod = 0.02
	elseif(spider=="3%") then spiderMod = 0.03
	end
	local swiftnessMod = 0
	if(swiftness=="Yes" or swiftness=="Yes \(cast on last few ticks\)") then swiftnessMod = 0.5 end
	local auraMod = 0
	if(aura=="Mahjarrat") then auraMod = 0.05
	elseif(aura=="Reckless" and (swiftness=="Yes \(cast on last few ticks\)" or swiftness=="No")) then auraMod = 0.1
	elseif(aura=="Reckless" and swiftness=="Yes") then auraMod = 0
	end
	local pocketMod = 0
	if(pocket=="Scrimshaw of cruelty" or pocket=="Grimshaw") then pocketMod = 0.05
	elseif(pocket=="Superior scrimshaw of cruelty" or pocket=="Grimshaw (superior)") then pocketMod = 0.0666
	end
	local needleMod = 0
	if(needle=="Yes") then needleMod = 0.07 end
	local berserkersFury = bFury/100
	local ripperDemonPassive = 0
	if(ripper=="Yes") then ripperDemonPassive = math.max(0,.05*(1-currenthp/maxhp)) end
	local telosRedBeamMod = 0
	local telosBlackBeamMod = 0
	if(telosBeam=="Player is in black beam \(Phases 2 or 5\)") then telosBlackBeamMod=-0.30
	elseif(telosBeam=="Telos is in black beam \(Phase 2\)") then telosBlackBeamMod=-0.20
	elseif(telosBeam=="Player is in red beam \(Phase 3\)") then telosRedBeamMod=0.30
	elseif(telosBeam=="Player is in red beam; Telos is in black beam \(Phase 5\)") then telosRedBeamMod=0.30; telosBlackBeamMod=-0.20
	elseif(telosBeam=="Player is not in red beam; Telos is in black beam \(Phase 5\)") then telosBlackBeamMod=-0.20
	end
	local finalMod = (1+ruthlessMod) * (1+vulnMod) * (1+slayerPerkMod) * (1+slayerAbilityMod) * (1+spiderMod) * (1+swiftnessMod) * (1+auraMod) * (1+pocketMod) * (1+needleMod) * (1+berserkersFury) * (1+ripperDemonPassive) * (1+telosRedBeamMod) * (1+telosBlackBeamMod)
	local finalModECB = finalMod/((1+telosRedBeamMod) * (1+telosBlackBeamMod)) --split soul damage is based on pre telos beam damage modifiers
	
	local natCritMin = {0,0,0,0,0}
	local forcedCritMin = {0,0,0,0,0}
	local natCritMinECB = {0,0,0,0,0}
	local forcedCritMinECB = {0,0,0,0,0}
	for arrow = 1,5 do 
		--damage for ecb
		arrowFixedECB[arrow] = math.floor(arrowFixed[arrow] * finalModECB)
		arrowVarECB[arrow] = math.floor(arrowVar[arrow] * finalModECB)
		natCritMinECB[arrow] = math.floor(arrowFixedECB[arrow] + (1-pNatCrit[arrow])*arrowVarECB[arrow])
		forcedCritMinECB[arrow] = math.floor(arrowFixedECB[arrow]+0.95*arrowVarECB[arrow])
		
		--sgb arrow damage
		arrowFixed[arrow] = math.floor(arrowFixed[arrow] * finalMod)
		arrowVar[arrow] = math.floor(arrowVar[arrow] * finalMod)
		natCritMin[arrow] = math.floor(arrowFixed[arrow] + (1-pNatCrit[arrow])*arrowVar[arrow])
		forcedCritMin[arrow] = math.floor(arrowFixed[arrow]+0.95*arrowVar[arrow])
	end
	
	--bolts EOF
	local seersMod = 0
	if(eof=="Yes" and seers=="Yes") then seersMod = 1 end
	local rangedCapeMod = 0
	if(eof=="Yes" and rangedCape=="Yes") then rangedCapeMod = 1 end
	local boltProcChance = 0
	local rubyProcChance = 0 -- for specifically rubys
	local boltDamageMultiplier = 0 -- dragonstone are a seperate hit
	local rubyBoltDamage = 0 --specifically ruby bolt damage
	local uncappedRubyBoltDamage = 0 -- specifically uncapped ruby bolt damage (post softcap)
	local rubyBoltDamageECB = 0 --specifically ruby bolt damage for split soul
	local uncappedRubyBoltDamageECB = 0 -- specifically uncapped ruby bolt damage (post softcap) for split soul
	local softCapMax = 10000
	if(pocket=="Grimoire") then softCapMax = 15000 end
	local softcap = softCapMax
	local ratiohp = currenthp/maxhp
	if(ratiohp<0.5) then softcap = math.floor(softCapMax*2*ratiohp) end
	if(eof=="Yes" and bolts=="Diamond") then 
		boltProcChance = (5+2*seersMod)*(1+0.2*rangedCapeMod)/100
		boltDamageMultiplier = 0.15
	elseif(eof=="Yes" and bolts=="Dragonstone") then
		boltProcChance = (5+2*seersMod)*(1+0.2*rangedCapeMod)/100
		boltDamageMultiplier = 0.25
	elseif(eof=="Yes" and bolts=="Onyx") then
		boltProcChance = (10+2*seersMod)*(1+0.2*rangedCapeMod)/100
		boltDamageMultiplier = 0.25
	elseif(eof=="Yes" and bolts=="Ruby") then
		rubyProcChance = math.max(0.01,(5+2*seersMod-math.floor(currenthp/1000000))*(1+0.2*rangedCapeMod)/100)
		rubyBoltDamage = math.min(math.floor(math.max(1,math.floor(20*ratiohp))/100*currenthp),softcap)*finalMod
		uncappedRubyBoltDamage = rubyBoltDamage
		uncappedRubyBoltDamageECB = rubyBoltDamage/finalMod*finalModECB
		if(potion~="None" or (potion=="None" and berserkBloodEssence=="Yes") or prayer~="None" or aura=="Reckless") then
			if(pocket=="Grimoire") then rubyBoltDamage = math.min(15000,uncappedRubyBoltDamage)
			else rubyBoltDamage = math.min(12000,uncappedRubyBoltDamage)
			end
		else
			rubyBoltDamage=math.min(10000,uncappedRubyBoltDamage)
		end
			
	end
	
	local arrowFixedBeforeBolts = {0,0,0,0,0}
	local arrowVarBeforeBolts = {0,0,0,0,0}
	local arrowFixedBoltProcOnly = {0,0,0,0,0}
	local arrowVarBoltProcOnly = {0,0,0,0,0}
	local natCritMinBoltProcOnly = {0,0,0,0,0}
	local forcedCritMinBoltProcOnly = {0,0,0,0,0}
	--diamond, dragonstone, onyx. ruby done after regular average
	for arrow = 1,5 do
		arrowFixedBeforeBolts[arrow] = arrowFixed[arrow]
		arrowVarBeforeBolts[arrow] = arrowVar[arrow]
		if(eof=="Yes" and (bolts=="Diamond" or bolts=="Dragonstone" or bolts=="Onyx")) then
			--arrowFixed[arrow] = boltProcChance*math.floor(arrowFixed[arrow]*(1+boltDamageMultiplier)) + (1-boltProcChance)*arrowFixed[arrow]
			--arrowVar[arrow] = boltProcChance*math.floor(arrowVar[arrow]*(1+boltDamageMultiplier)) + (1-boltProcChance)*arrowVar[arrow]
			arrowFixedBoltProcOnly[arrow] = math.floor(arrowFixedBeforeBolts[arrow]*(1+boltDamageMultiplier))
			arrowVarBoltProcOnly[arrow] = math.floor(arrowVarBeforeBolts[arrow]*(1+boltDamageMultiplier))
			natCritMinBoltProcOnly[arrow] = math.floor(arrowFixedBoltProcOnly[arrow] + (1-pNatCrit[arrow])*arrowVarBoltProcOnly[arrow])
			forcedCritMinBoltProcOnly[arrow] = math.floor(arrowFixedBoltProcOnly[arrow]+0.95*arrowVarBoltProcOnly[arrow])
		end
	end
	
	--damage caps
	local critCap = 12000
	if(pocket=="Grimoire") then critCap = 15000 end
	local nonCap = 10000
	
	--calculate probability of hits above caps
	local pForcedCritCap = {0,0,0,0,0}
	local pNaturalCritCap = {0,0,0,0,0}
	local pNonCritCap = {0,0,0,0,0}
	
	local pForcedCritCapBoltProcOnly = {0,0,0,0,0}
	local pNaturalCritCapBoltProcOnly = {0,0,0,0,0}
	local pNonCritCapBoltProcOnly = {0,0,0,0,0}
	
	for arrow = 1,5 do 
		--normal sgb arrows
		pForcedCritCap[arrow] = (critCap - forcedCritMin[arrow])/(arrowFixed[arrow]+arrowVar[arrow] - forcedCritMin[arrow])
		pNaturalCritCap[arrow] = (critCap - natCritMin[arrow])/(arrowFixed[arrow]+arrowVar[arrow] - natCritMin[arrow])
		pNonCritCap[arrow] = (nonCap - arrowFixed[arrow])/(natCritMin[arrow] - arrowFixed[arrow])
		
		--diamond, dragonstone, onyx bolt procs
		pForcedCritCapBoltProcOnly[arrow] = (critCap - forcedCritMinBoltProcOnly[arrow])/(arrowFixedBoltProcOnly[arrow]+arrowVarBoltProcOnly[arrow] - forcedCritMinBoltProcOnly[arrow])
		pNaturalCritCapBoltProcOnly[arrow] = (critCap - natCritMinBoltProcOnly[arrow])/(arrowFixedBoltProcOnly[arrow]+arrowVarBoltProcOnly[arrow] - natCritMinBoltProcOnly[arrow])
		pNonCritCapBoltProcOnly[arrow] = (nonCap - arrowFixedBoltProcOnly[arrow])/(natCritMinBoltProcOnly[arrow] - arrowFixedBoltProcOnly[arrow])
	end
	
	--calculate average damages
	local arrowAverage = {0,0,0,0,0}
	for arrow = 1,5 do
		--diamond, dragonstone, onyx bolt proc
		arrowAverage[arrow] = arrowAverage[arrow] + boltProcChance*pForcedCrit*(math.max(0,math.min(1-pForcedCritCapBoltProcOnly[arrow],1))*critCap + math.min(math.max(0,pForcedCritCapBoltProcOnly[arrow]),1)*(math.min(critCap,forcedCritMinBoltProcOnly[arrow]) + math.min(critCap,(arrowFixedBoltProcOnly[arrow]+arrowVarBoltProcOnly[arrow])))/2)
		arrowAverage[arrow] = arrowAverage[arrow] + boltProcChance*(1-pForcedCrit)*(pNatCrit[arrow])*(math.max(0,math.min(1-pNaturalCritCapBoltProcOnly[arrow],1))*critCap + math.min(math.max(0,pNaturalCritCapBoltProcOnly[arrow]),1)*(math.min(natCritMinBoltProcOnly[arrow],critCap) + math.min(critCap,(arrowFixedBoltProcOnly[arrow]+arrowVarBoltProcOnly[arrow])))/2)
		arrowAverage[arrow] = arrowAverage[arrow] + boltProcChance*(1-pForcedCrit)*(1-pNatCrit[arrow])*(math.max(0,math.min(1-pNonCritCapBoltProcOnly[arrow],1))*nonCap + math.min(math.max(0,pNonCritCapBoltProcOnly[arrow]),1)*(math.min(nonCap,arrowFixedBoltProcOnly[arrow]) + math.min(nonCap,natCritMinBoltProcOnly[arrow]))/2)
		--no bolt proc (lines above this should be 0 if no bolts or ruby bolts)
		arrowAverage[arrow] = arrowAverage[arrow] + (1-boltProcChance)*pForcedCrit*(math.max(0,math.min(1-pForcedCritCap[arrow],1))*critCap + math.min(math.max(0,pForcedCritCap[arrow]),1)*(math.min(critCap,forcedCritMin[arrow]) + math.min(critCap,(arrowFixed[arrow]+arrowVar[arrow])))/2)
		arrowAverage[arrow] = arrowAverage[arrow] + (1-boltProcChance)*(1-pForcedCrit)*(pNatCrit[arrow])*(math.max(0,math.min(1-pNaturalCritCap[arrow],1))*critCap + math.min(math.max(0,pNaturalCritCap[arrow]),1)*(math.min(natCritMin[arrow],critCap) + math.min(critCap,(arrowFixed[arrow]+arrowVar[arrow])))/2)
		arrowAverage[arrow] = arrowAverage[arrow] + (1-boltProcChance)*(1-pForcedCrit)*(1-pNatCrit[arrow])*(math.max(0,math.min(1-pNonCritCap[arrow],1))*nonCap + math.min(math.max(0,pNonCritCap[arrow]),1)*(math.min(nonCap,arrowFixed[arrow]) + math.min(nonCap,natCritMin[arrow]))/2)
	end
	--average for ruby bolts
	if(bolts=="Ruby") then
		for arrow = 1,5 do	arrowAverage[arrow] = rubyProcChance*rubyBoltDamage + (1-rubyProcChance)*arrowAverage[arrow] end
	end
	
	--calculate ecb average damages
	-- FUNCTIONS for ecb defined below calculateDamage()
	local ecbAverage = {0,0,0,0,0}
	local minSoulSplitSplat = 2
	if(splitSoul=="Yes") then 
		if(nArrowsSplitSoul=="Arrows 1-5") then minSoulSplitSplat = 1 end
		for arrow = minSoulSplitSplat,5 do
			arrowMin = arrowFixedECB[arrow]
			arrowMax = arrowFixedECB[arrow] + arrowVarECB[arrow]
			fCritMin = forcedCritMinECB[arrow]
				
			ecbAverage[arrow] = avgDmgSplitSoulCalc(arrowMin,arrowMax,fCritMin,arrowMax,pForcedCrit,aos,vulnMod,slayerPerkMod,slayerAbilityMod,spiderMod)
			if(bolts=="Ruby") then --no diff in arrow 1 vs 2-5 here at the moment
				local rubyBoltSplitSoulDamage = dmgSplitSoulSingleValueCalc(uncappedRubyBoltDamageECB,aos,vulnMod,slayerPerkMod,slayerAbilityMod,spiderMod)
				if(arrow==1) then ecbAverage[arrow] = (rubyProcChance*rubyBoltSplitSoulDamage + (1-rubyProcChance)*ecbAverage[arrow])
				else ecbAverage[arrow] = (rubyProcChance*rubyBoltSplitSoulDamage + (1-rubyProcChance)*ecbAverage[arrow])
				end
			end
		end
	end
	
	--display min/max of arrows
	local arrowMinHit = {0,0,0,0,0}
	local arrowMaxHit = {0,0,0,0,0}
	for arrow = 1,5 do
		if(bolts=="No" or eof=="No") then
			arrowMinHit[arrow] = arrowFixed[arrow]
			arrowMaxHit[arrow] = arrowFixed[arrow]+arrowVar[arrow]
		elseif(bolts~="Ruby") then 
			arrowMinHit[arrow] = math.min(arrowFixedBoltProcOnly[arrow],arrowFixedBeforeBolts[arrow])
			arrowMaxHit[arrow] = math.max(arrowFixedBoltProcOnly[arrow]+arrowVarBoltProcOnly[arrow],arrowFixedBeforeBolts[arrow]+arrowVarBeforeBolts[arrow])
		elseif(bolts=="Ruby") then
			arrowMinHit[arrow] = math.min(arrowFixed[arrow],rubyBoltDamage)
			arrowMaxHit[arrow] = math.max(arrowFixed[arrow]+arrowVar[arrow],rubyBoltDamage)
		end
	end
	
	--create arrow damage table
	local resultsDiv = mw.html.create( 'div' )
	local resultsTable = mw.html.create( 'table' )
	resultsTable:addClass( 'wikitable' )
		:addClass( 'align-center-1 align-center-2 align-center-3 align-center-4 align-center-5 align-center-6 align-center-7 align-center-8 align-center-9' )
		:tag( 'caption' )
			:wikitext( 'Average damage for individual arrows as well as the combined average damage for the total number of arrows that land.' )
			:IF(splitSoul=="No")
				:css('text-align', 'left')
			:END()
		:tag( 'tr' )
			:tag( 'th' )
				:wikitext( 'Arrow Damages' )
				:IF(splitSoul=="No")
					:attr( 'colspan', 5 )
				:ELSE()
				:attr( 'colspan', 9 )
				:END()
			:done()
		:done()
		:tag( 'tr' )
			:tag( 'th' )
				:wikitext( 'Arrow' )
				:attr( 'rowspan', 2 )
			:done()
			:tag( 'th' )
				:wikitext( 'Individual Arrow Damages' )
				:IF(splitSoul=="No")
					:attr( 'colspan', 3 )
				:ELSE()
					:attr( 'colspan', 5 )
				:END()
			:done()
			:tag( 'th' )
				:wikitext( 'Total Average Damage over n Arrows' )
				:IF(splitSoul=="No")
					:attr( 'rowspan', 2 )
				:ELSE()
					:attr( 'colspan', 3 )
				:END()
			:done()
		:done()
		:tag( 'tr' )
			:tag( 'th' )
				:wikitext( 'Minimum')
			:done()
			:tag( 'th' )
				:wikitext( 'Maximum')
			:done()
			:tag( 'th' )
				:wikitext( 'Average')
			:done()
			:IF(splitSoul=="Yes")
				:tag( 'th' )
					:wikitext( 'Average from Split Soul')
				:done()
				:tag( 'th' )
					:wikitext( 'Average from Arrow + Split Soul')
				:done()
				:tag( 'th' )
					:wikitext( 'Average from n Arrows')
				:done()
				:tag( 'th' )
					:wikitext( 'Average from Split Soul over n Arrows')
				:done()
				:tag( 'th' )
					:wikitext( 'Average from n Arrows + Split Soul')
				:done()
			:END()
		:done()
	:done()
	local sumAverage = 0
	local ecbSumAverage = 0
	for arrow = 1,5 do
	sumAverage = sumAverage + arrowAverage[arrow]
	ecbSumAverage = ecbSumAverage + ecbAverage[arrow]
	resultsTable:tag( 'tr' )
		:tag( 'td' )
			:wikitext ( string.format("%d",arrow) )
		:done()
		:tag( 'td' )
			:wikitext ( string.format("%s",lang:formatNum(math.floor(arrowMinHit[arrow]+0.5)) ))
		:done()
		:tag( 'td' )
			:wikitext ( string.format("%s",lang:formatNum(math.floor(arrowMaxHit[arrow]+0.5)) ))
		:done()
		:tag( 'td' )
			:wikitext ( string.format("%s",lang:formatNum(math.floor(arrowAverage[arrow]+0.5)) ))
		:done()
		:IF(splitSoul=="Yes")
			:tag( 'td' )
				:wikitext ( string.format("%s",lang:formatNum(math.floor(ecbAverage[arrow]+0.5)) ))
			:done()
			:tag( 'td' )
				:wikitext ( string.format("%s",lang:formatNum(math.floor(arrowAverage[arrow]+ecbAverage[arrow])) ))
			:done()
		:END()
		:tag( 'td' )
			:wikitext ( string.format("%s",lang:formatNum(math.floor(sumAverage+0.5)) ))
		:done()
		:IF(splitSoul=="Yes")
			:tag( 'td' )
				:wikitext ( string.format("%s",lang:formatNum(math.floor(ecbSumAverage+0.5)) ))
			:done()
			:tag( 'td' )
				:wikitext ( string.format("%s",lang:formatNum(math.floor(sumAverage+ecbSumAverage+0.5)) ))
			:done()
		:END()
	:done()
	end
	
	
	--create arrays based on NPC size
	local pArrow1NoBlock = {0.840,0.473,0.144,0.141,0.045,0.083,0.026,0.057,0.017,0.043,0.013}
	local pArrow2NoBlock = {0.160,0.420,0.398,0.327,0.193,0.222,0.124,0.168,0.091,0.135,0.071}
	local pArrow3NoBlock = {0.000,0.100,0.342,0.324,0.324,0.281,0.250,0.240,0.203,0.208,0.171}
	local pArrow4NoBlock = {0.000,0.007,0.106,0.170,0.282,0.231,0.277,0.227,0.247,0.210,0.219}
	local pArrow5NoBlock = {0.000,0.000,0.010,0.038,0.155,0.182,0.323,0.308,0.441,0.404,0.526}
	
	local pArrow1Block = {0.840,0.473,0.144,0.010,0.000}
	local pArrow2Block = {0.160,0.420,0.398,0.106,0.000}
	local pArrow3Block = {0.000,0.100,0.342,0.342,0.000}
	local pArrow4Block = {0.000,0.007,0.106,0.398,0.000}
	local pArrow5Block = {0.000,0.000,0.010,0.144,1.000}

	local npcSizeDiv = mw.html.create( 'div' )
	local npcSizeTable = mw.html.create( 'table' )
	npcSizeTable:addClass( 'wikitable' )
		:addClass( 'align-center-1 align-center-2 align-center-3 align-center-4 align-center-5' )
		:tag( 'caption' )
			:wikitext( 'Average damage based on the NPC size. In general, damage increases with the NPC size.' )
			:IF(splitSoul=="No")
				:css('text-align', 'left')
			:END()
		:tag( 'tr' )
			:tag( 'th' )
				:wikitext( 'Damage based on size of Target' )
				:IF(splitSoul=="Yes")
					:attr( 'colspan', 5 )
				:ELSE()
					:attr( 'colspan', 3 )
				:END()
			:done()
		:done()
		:tag( 'tr' )
			:tag( 'th' )
				:wikitext( 'NPC Size' )
			:done()
			:tag( 'th' )
				:wikitext( 'Expected number of Arrows' )
			:done()
			:tag( 'th' )
				:wikitext( 'Average Damage')
			:done()
			:IF(splitSoul=="Yes")
				:tag( 'th' )
					:wikitext( 'Average from Split Soul')
				:done()
				:tag( 'th' )
					:wikitext( 'Total Average')
				:done()
			:END()
		:done()
	:done()
	if(npc=="No \(Non-blocking\)") then
		for size = 1,11 do
			local sizeArrowAvg = pArrow1NoBlock[size]*arrowAverage[1]+pArrow2NoBlock[size]*(arrowAverage[1]+arrowAverage[2])+pArrow3NoBlock[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3])+pArrow4NoBlock[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4])+pArrow5NoBlock[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4]+arrowAverage[5])
			local ecbSizeArrowAvg = pArrow1NoBlock[size]*ecbAverage[1]+pArrow2NoBlock[size]*(ecbAverage[1]+ecbAverage[2])+pArrow3NoBlock[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3])+pArrow4NoBlock[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4])+pArrow5NoBlock[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4]+ecbAverage[5])
			local nArrows = pArrow1NoBlock[size]*1+pArrow2NoBlock[size]*2+pArrow3NoBlock[size]*3+pArrow4NoBlock[size]*4+pArrow5NoBlock[size]*5
			npcSizeTable:tag( 'tr' )
				:tag( 'td' )
					:wikitext ( string.format("%dx%d",size,size) )
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%.2f",nArrows) )
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+0.5)) ))
				:done()
				:IF(splitSoul=="Yes")
					:tag( 'td' )
						:wikitext ( string.format("%s",lang:formatNum(math.floor(ecbSizeArrowAvg+0.5)) ))
					:done()
					:tag( 'td' )
						:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+ecbSizeArrowAvg+0.5)) ))
					:done()
				:END()
			:done()
		end
	elseif(npc=="Yes \(Blocking\)") then
		for size = 1,4 do
			local sizeArrowAvg = pArrow1Block[size]*arrowAverage[1]+pArrow2Block[size]*(arrowAverage[1]+arrowAverage[2])+pArrow3Block[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3])+pArrow4Block[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4])+pArrow5Block[size]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4]+arrowAverage[5])
			local ecbSizeArrowAvg = pArrow1Block[size]*ecbAverage[1]+pArrow2Block[size]*(ecbAverage[1]+ecbAverage[2])+pArrow3Block[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3])+pArrow4Block[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4])+pArrow5Block[size]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4]+ecbAverage[5])
			local nArrows = pArrow1Block[size]*1+pArrow2Block[size]*2+pArrow3Block[size]*3+pArrow4Block[size]*4+pArrow5Block[size]*5
			npcSizeTable:tag( 'tr' )
				:tag( 'td' )
					:wikitext ( string.format("%dx%d",size,size) )
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%.2f",nArrows) )
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+0.5)) ))
				:done()
			:IF(splitSoul=="Yes")					
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(ecbSizeArrowAvg+0.5)) ))
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+ecbSizeArrowAvg+0.5)) ))
				:done()
			:END()
			:done()
		end
		local sizeArrowAvg = pArrow1Block[5]*arrowAverage[1]+pArrow2Block[5]*(arrowAverage[1]+arrowAverage[2])+pArrow3Block[5]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3])+pArrow4Block[5]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4])+pArrow5Block[5]*(arrowAverage[1]+arrowAverage[2]+arrowAverage[3]+arrowAverage[4]+arrowAverage[5])
		local ecbSizeArrowAvg = pArrow1Block[5]*ecbAverage[1]+pArrow2Block[5]*(ecbAverage[1]+ecbAverage[2])+pArrow3Block[5]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3])+pArrow4Block[5]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4])+pArrow5Block[5]*(ecbAverage[1]+ecbAverage[2]+ecbAverage[3]+ecbAverage[4]+ecbAverage[5])
		local nArrows = pArrow1Block[5]*1+pArrow2Block[5]*2+pArrow3Block[5]*3+pArrow4Block[5]*4+pArrow5Block[5]*5
		npcSizeTable:tag( 'tr' )
			:tag( 'td' )
				:wikitext ( "5x5+" )
			:done()
			:tag( 'td' )
				:wikitext ( string.format("%.2f",nArrows) )
			:done()
			:tag( 'td' )
				:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+0.5)) ))
			:done()
			:IF(splitSoul=="Yes")
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(ecbSizeArrowAvg+0.5)) ))
				:done()
				:tag( 'td' )
					:wikitext ( string.format("%s",lang:formatNum(math.floor(sizeArrowAvg+ecbSizeArrowAvg+0.5)) ))
				:done()
			:END()
		:done()
	end

	--return results (table)
	resultsDiv:node(tostring(resultsTable))
	npcSizeDiv:node(tostring(npcSizeTable))
	return resultsDiv, npcSizeTable
	--return arrowFixedECB[1]," ",arrowVarECB[1]," ",arrowFixedECB[2]," ",arrowVarECB[2]
	--return arrowFixed[1]," ",arrowVar[1]," ",arrowFixedECB[1]," ",arrowVarECB[1]
	--return rubyBoltDamage," ", uncappedRubyBoltDamage," ", uncappedRubyBoltDamageECB
	--return dmgSplitSoulSingleValueCalc(rubyBoltDamage)," ",dmgSplitSoulSingleValueCalc(uncappedRubyBoltDamage)," ",dmgSplitSoulSingleValueCalc(uncappedRubyBoltDamageECB)
	--local check1 = avgDmgSplitSoulCalc(1000,5000,2000,5000,.2,aos,.1,.07,.15)
	--local check2 = dmgSplitSoulOverRangeCalc(1000,5000,aos,.1,.07,.15)
	--local check3 = dmgSplitSoulSingleValueCalc(3000,aos,.1,.07,.15)
	--return check1," ",check2," ",check3
end

-----------------------------------------------------------------------------------------
--calculate ecb spec damages
-----------------------------------------------------------------------------------------
function avgDmgSplitSoulCalc(minHitRange,maxHitRange,fCritMinRange,fCritMaxRange,probFCrit,aosEff,ecbVulnMod,ecbSlayerPerkMod,ecbSlayerAbilityMod,ecbSpiderMod)
	local avgDmgSplitSoul = 0
	--non-forced crit
	local splitSoulDamageRangeNonFCrit = dmgSplitSoulOverRangeCalc(minHitRange,maxHitRange,aosEff,ecbVulnMod,ecbSlayerPerkMod,ecbSlayerAbilityMod,ecbSpiderMod)
	avgDmgSplitSoul = avgDmgSplitSoul + ((1-probFCrit) * splitSoulDamageRangeNonFCrit / (maxHitRange-minHitRange+1))
	--forced crit
	local splitSoulDamageRangeFCrit =  dmgSplitSoulOverRangeCalc(fCritMinRange,fCritMaxRange,aosEff,ecbVulnMod,ecbSlayerPerkMod,ecbSlayerAbilityMod,ecbSpiderMod)
	avgDmgSplitSoul = avgDmgSplitSoul + (probFCrit * splitSoulDamageRangeFCrit / (fCritMaxRange-fCritMinRange+1))
	return avgDmgSplitSoul
end
function dmgSplitSoulOverRangeCalc(minHitRange,maxHitRange,aosEff,ecbVulnMod,ecbSlayerPerkMod,ecbSlayerAbilityMod,ecbSpiderMod)
	local damageFromSpec = 0
	for n = minHitRange,maxHitRange do
		local 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))
		local avgIncreaseHealed = math.floor(amountHealed*.375)
		if(aosEff=="No") then 	damageFromSpec = damageFromSpec + math.floor(math.floor(math.floor(math.floor( math.floor(amountHealed*4) * (1+ecbVulnMod)) * (1+ecbSlayerPerkMod)) * (1+ecbSlayerAbilityMod)) * (1+ecbSpiderMod))
		elseif(aosEff=="Yes") then damageFromSpec = damageFromSpec + math.floor(math.floor(math.floor(math.floor( (.5*math.floor(amountHealed*4) + .5*math.floor((amountHealed+avgIncreaseHealed)*4)) * (1+ecbVulnMod)) * (1+ecbSlayerPerkMod)) * (1+ecbSlayerAbilityMod)) *(1+ecbSpiderMod))
		end
	end
	return damageFromSpec
end
function dmgSplitSoulSingleValueCalc(n,aosEff,ecbVulnMod,ecbSlayerPerkMod,ecbSlayerAbilityMod,ecbSpiderMod)
	local 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))
	local avgIncreaseHealed = math.floor(amountHealed*.375)
	local damageFromSpec = 0
	if(aosEff=="No") then damageFromSpec = math.floor(math.floor(math.floor(math.floor( math.floor(amountHealed*4) * (1+ecbVulnMod)) * (1+ecbSlayerPerkMod)) * (1+ecbSlayerAbilityMod)) * (1+ecbSpiderMod))
	elseif(aosEff=="Yes") then damageFromSpec = math.floor(math.floor(math.floor(math.floor( (.5*math.floor(amountHealed*4) + .5*math.floor((amountHealed+avgIncreaseHealed)*4)) * (1+ecbVulnMod)) * (1+ecbSlayerPerkMod)) * (1+ecbSlayerAbilityMod)) * (1+ecbSpiderMod))
	end
	return damageFromSpec
end
-----------------------------------------------------------------------------------------

return p
-- </nowiki>