Module:Average damage calculator

From WIDEVERSE Wiki
Revision as of 22:22, 4 November 2021 by Admin (talk | contribs) (1 revision imported)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

-- <pre>
local p = {}

local yesno = require ("Module:Yesno")

function p.main(frame)
    local args = frame:getParent().args
    
    --___________________________________
    -- Set initial values to be used
    --___________________________________
    local dType = args.dmgType
    local tuskaW = args.tuska
    local min_hit = tonumber(args.minHit) or 0
    local max_hit = tonumber(args.maxHit) or 0    
    local eqPerkRank = tonumber(args.eqRank) or 9
    local eqActiveAura = args.eqAura
    local bitingPerkRank = tonumber(args.bitingRank) or 0
    local gearLevel20 = args.level20
    local eGrimoire = args.grimoire
    local corbiculatotem = args.corbicula
    local kalgScroll = args.kalg
    local min_MFury = tonumber(args.minMFury) or 0
    local max_MFury = tonumber(args.maxMFury) or 0
    local splitSoul = args.splitSoul
    local vuln = args.vuln
    local debugMode = args.debugToggle
    local atLeastX = tonumber(args.atLeastX) or 0
    
    local dmgCap = 10000
    local critCap = 12000
    
    local res = ""
    
    --___________________________________
    -- Error messages
    --___________________________________
    if (min_hit > max_hit) then
        return "The minimum hit must not be higher than the maximum hit."
    end
    
    if (min_MFury > max_MFury) then
    	return "The minimum hit set for Greater Fury must not be higher than the maximum hit set for Greater Fury."
    end

    --___________________________________
    -- Define modifiers to critical hits
    -- and critical hit chance
    --___________________________________
    local pBiting = .02*bitingPerkRank
	local pGrimoire = 0
	local pFuryAndConc1 = .05
	local pFuryAndConc2 = .10
	local pFuryAndConc3 = .15
	local pMFury = .10
	local pMFuryGuarantee = 1
	local pCorbicula = 0 -- only affects the Meteor Strike ultimate ability
	local pKalgScroll = 0
    
    if (gearLevel20 == "Yes") then pBiting = pBiting*1.1 end
    if (eGrimoire == "Yes") then 
    	critCap = 15000
    	pGrimoire = .12
	end
	
	if (corbiculatotem == "1") then pCorbicula = .20
	elseif (corbiculatotem == "2") then pCorbicula = .40
	end
	
	if (kalgScroll == "Yes") then pKalgScroll = .05 end
	
	if (dType == "Yes") then pMFuryGuarantee = .10 end --The guarantee from MFury will not be used an auto
	if (dType == "No" and tuskaW == "Yes") then  -- Tuska's Wrath always has a damage/crit cap of 15k
		dmgCap = 15000;
		critCap = 15000;
	end

	--___________________________________
	-- Calculate forced crit hit chance,
    -- forced crit min, and forced crit max
	--___________________________________
	local pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll)
	local forcedCritMin = min_hit + math.floor(.95*(max_hit - min_hit))
	local forcedCritMax = min_hit + math.floor(math.floor(.95*(max_hit - min_hit))/.95) 
	
	--___________________________________
	-- Calculate natural crit hit chance
    -- and natural crit min
	--___________________________________
    local preEqMin = 0
    local preEqRand = 0
    local naturalCritMin = 0
	--local naturalCritMin = math.max(.95*max_hit,min_hit)

    if (eqActiveAura=="Yes") then
        preEqMin = min_hit - (max_hit - min_hit)/(1-(.25+.25))*.25
        preEqRand = (max_hit-min_hit)/(1-(.25+.25))
    else
        preEqMin = min_hit - (max_hit - min_hit)/(1-eqPerkRank*(.03+.01))*(eqPerkRank*.03)
        preEqRand = (max_hit-min_hit)/(1-eqPerkRank*(.03+.01))
    end

    local oneMinuspNaturalCrit = 0
    local pNaturalCrit = 0
    if (min_hit==max_hit) then
    	pNaturalCrit = 1
    	naturalCritMin = min_hit+oneMinuspNaturalCrit*(max_hit-min_hit)
    else
    	oneMinuspNaturalCrit = ((preEqMin+preEqRand)*.95-preEqMin)/preEqRand
    	naturalCritMin = math.max(min_hit+oneMinuspNaturalCrit*(max_hit-min_hit),min_hit)
    	pNaturalCrit = math.min(1,1-oneMinuspNaturalCrit)
    end
	
	--___________________________________
	-- Define how much of the damage will 
	-- be set to the damage and crit caps
	--___________________________________
	local z1 = 0
	local z2 = 0
	local y = 0
	
	if (forcedCritMax == forcedCritMin) and (forcedCritMax >= critCap) then z1 = -999
	elseif (forcedCritMax == forcedCritMin) and (forcedCritMax < critCap) then z1 = 999
	else z1 = (critCap - forcedCritMin)/(forcedCritMax - forcedCritMin)
	end
	if (max_hit == naturalCritMin) and (max_hit >= critCap) then z2 = -999
	elseif (max_hit == naturalCritMin) and (max_hit <= critCap) then z2 = 999
	else z2 = (critCap - naturalCritMin)/(max_hit - naturalCritMin)
	end
	if (min_hit == naturalCritMin) and (min_hit >= dmgCap) then y = -999
	elseif (min_hit == naturalCritMin) and (min_hit < dmgCap) then y = 999
	else y = (dmgCap - min_hit)/(naturalCritMin - min_hit)
	end
	
	--___________________________________
	-- Define chance for MFury to crit
	--___________________________________
	local pCritMFury = -999
	if (dType=="No") then
		local preEqMinMFury = 0
		local preEqRandMFury = 0
		local naturalCritMinMFury = 0

		if (eqActiveAura=="Yes") then
			preEqMinMFury = min_MFury - (max_MFury - min_MFury)/(1-(.25+.25))*.25
			preEqRandMFury = (max_MFury-min_MFury)/(1-(.25+.25))
		else
			preEqMinMFury = min_MFury - (max_MFury - min_MFury)/(1-eqPerkRank*(.03+.01))*(eqPerkRank*.03)
			preEqRandMFury = (max_MFury-min_MFury)/(1-eqPerkRank*(.03+.01))
		end

		local oneMinuspNaturalCritMFury = 0
		local pNaturalCritMFury = 0
		if (min_MFury==max_MFury) then
			pNaturalCritMFury = 1
			naturalCritMinMFury = min_MFury+oneMinuspNaturalCritMFury*(max_MFury-min_MFury)
		else
			oneMinuspNaturalCritMFury = ((preEqMinMFury+preEqRandMFury)*.95-preEqMinMFury)/preEqRandMFury
			naturalCritMinMFury = min_MFury+oneMinuspNaturalCritMFury*(max_MFury-min_MFury)
			pNaturalCritMFury = math.min(1,1-oneMinuspNaturalCritMFury)
		end
		pCritMFury = math.min(1,pForcedCrit+(1-pForcedCrit)*pNaturalCritMFury)
	end

	--___________________________________
	-- Calculate average damage
	--___________________________________
	local avgDmg = 0
	local avgDmgCrit = 0
	local avgDmgNonCrit = 0
	
	function avgDmgCalc()
		avgDmg = pForcedCrit*(math.max(0,math.min(1-z1,1))*critCap + math.min(math.max(0,z1),1)*(math.min(critCap,forcedCritMin) + math.min(critCap,forcedCritMax))/2)
		avgDmg = avgDmg + (1-pForcedCrit)*(pNaturalCrit)*(math.max(0,math.min(1-z2,1))*critCap + math.min(math.max(0,z2),1)*(math.min(naturalCritMin,critCap) + math.min(critCap,max_hit))/2)
		avgDmg = avgDmg + (1-pForcedCrit)*(1-pNaturalCrit)*(math.max(0,math.min(1-y,1))*dmgCap + math.min(math.max(0,y),1)*(math.min(dmgCap,min_hit) + math.min(dmgCap,naturalCritMin))/2)
	end
	function avgDmgCritCalc()
		local totalChanceToCrit = math.min(1,pForcedCrit+(1-pForcedCrit)*(pNaturalCrit))
		avgDmgCrit = pForcedCrit/totalChanceToCrit*(math.max(0,math.min(1-z1,1))*critCap + math.min(math.max(0,z1),1)*(math.min(critCap,forcedCritMin) + math.min(critCap,forcedCritMax))/2)
		avgDmgCrit = avgDmgCrit + (1-pForcedCrit)*(pNaturalCrit)/totalChanceToCrit*(math.max(0,math.min(1-z2,1))*critCap + math.min(math.max(0,z2),1)*(math.min(naturalCritMin,critCap) + math.min(critCap,max_hit))/2)
	end
	function avgDmgNonCritCalc()
		avgDmgNonCrit = (math.max(0,math.min(1-y,1))*dmgCap + math.min(math.max(0,y),1)*(math.min(dmgCap,min_hit) + math.min(dmgCap,naturalCritMin))/2)
	end
	--___________________________________
	-- Calculate average damage from Splt Soul
	--___________________________________
	local avgDmgSplitSoul = 0
	local amountHealed = 0
	local avgIncreaseHealed = 0
	local damageFromSpec = 0
	local vulnMod = 0
	if(vuln=="Yes") then vulnMod = 0.1 end
	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 avgDmgSplitSoulCalc()
		--non-forced crit
		damageFromSpec = 0
		for damage = min_hit,max_hit do dmgSplitSoulOverRangeCalc(damage) end
		avgDmgSplitSoul = avgDmgSplitSoul + ((1-pForcedCrit) * damageFromSpec / (max_hit-min_hit+1))
		--forced crit
		damageFromSpec = 0
		for damage = forcedCritMin,forcedCritMax do dmgSplitSoulOverRangeCalc(damage) end
		avgDmgSplitSoul = avgDmgSplitSoul + (pForcedCrit * damageFromSpec / (forcedCritMax-forcedCritMin+1))
	end
	--___________________________________
	-- Calculate probability of hitting at least X
	--___________________________________
	local probX = 0
	function probDamageAtLeastX(rangeMin,rangeMax)
		if(rangeMin==rangeMax) then
			if (rangeMin>atLeastX) then
				probX = 1
			else
				probbX = 0
			end
		else
			probX = math.max(0,math.min(1, (rangeMax-atLeastX)/(rangeMax-rangeMin) ))
		end
		return probX
	end
		
	
	avgDmgCalc()
	avgDmgCritCalc()
	avgDmgNonCritCalc()
	if(splitSoul=="Yes \(with Amulet of Souls\)" or splitSoul=="Yes \(without Amulet of Souls\)") then avgDmgSplitSoulCalc() end
    
    local resDEBUG = ""
    --___________________________________
    -- Debug mode
    --___________________________________
    if debugMode == "Yes" then
    	resDEBUG = resDEBUG .. "___________________________________" .. "<br/>"
    	resDEBUG = resDEBUG .. "DEBUG MODE" .. "<br/>"
    	resDEBUG = resDEBUG .. "___________________________________" .. "<br/>"    
    	
		--res = res .. (math.max(0,math.min(1-z1,1))*critCap + math.min(math.max(0,z1),1)*(math.min(critCap,forcedCritMin) + math.min(critCap,max_hit))/2) .. "<br/>"
	    --res = res .. (math.max(0,math.min(1-z2,1))*critCap + math.min(math.max(0,z2),1)*(math.min(naturalCritMin,critCap) + math.min(critCap,max_hit))/2) .. "<br/>"
	    --res = res .. (math.max(0,math.min(1-y,1))*dmgCap + math.min(math.max(0,y),1)*(math.min(dmgCap,min_hit) + math.min(dmgCap,naturalCritMin))/2) .. "<br/>"
		--res = res .. pForcedCrit*(math.max(0,math.min(1-z1,1))*critCap + math.min(math.max(0,z1),1)*(math.min(critCap,forcedCritMin) + math.min(critCap,max_hit))/2) .. "<br/>"
	    --res = res .. (1-pForcedCrit)*(pNaturalCrit)*(math.max(0,math.min(1-z2,1))*critCap + math.min(math.max(0,z2),1)*(math.min(naturalCritMin,critCap) + math.min(critCap,max_hit))/2) .. "<br/>"
	    --res = res .. (1-pForcedCrit)*(1-pNaturalCrit)*(math.max(0,math.min(1-y,1))*dmgCap + math.min(math.max(0,y),1)*(math.min(dmgCap,min_hit) + math.min(dmgCap,naturalCritMin))/2) .. "<br/>"

    	
	    resDEBUG = resDEBUG .. "preEqFixed = " .. preEqMin .. "<br/>"
	    resDEBUG = resDEBUG .. "preEqVariable = " .. preEqRand .. "<br/>"
	    resDEBUG = resDEBUG .. "preEqMax = (preEqFixed + preEqVariable) = " .. preEqMin+preEqRand .. "<br/>"
	    
	    resDEBUG = resDEBUG .. "pForcedCrit = " .. string.format("%.3f",pForcedCrit) .. "<br/>"
	    resDEBUG = resDEBUG .. "pNaturalCrit = " .. "(1-" .. string.format("%.3f",pForcedCrit) .. ")*" .. string.format("%.4f",pNaturalCrit) .. " = " .. string.format("%.4f",(1-pForcedCrit)*pNaturalCrit) .. "<br/>"
	    resDEBUG = resDEBUG .. "pNonCrit = " .. "(1-" .. string.format("%.3f",pForcedCrit) .. ")*" .. "(1-" .. string.format("%.4f",pNaturalCrit) .. ") = " .. string.format("%.4f",(1-pForcedCrit)*(1-pNaturalCrit)) .. "<br/>"
	    resDEBUG = resDEBUG .. "pGreaterFuryCrit = " .. string.format("%.4f",pCritMFury) .. "<br/>"
	    
	    resDEBUG = resDEBUG .. "Hit range used: [" .. min_hit .. "," .. max_hit .. "]" .. "<br/>"
	    resDEBUG = resDEBUG .. "forcedCritMax = " .. forcedCritMax .. "<br/>"
	    resDEBUG = resDEBUG .. "forcedCritMin = " .. forcedCritMin .. "<br/>"
	    resDEBUG = resDEBUG .. "naturalCritMin = " .. naturalCritMin .. "<br/>"
	    
	    resDEBUG = resDEBUG .. "z1 = " .. z1 .. "<br/>"
	    resDEBUG = resDEBUG .. "z2 = " .. z2 .. "<br/>"
	    resDEBUG = resDEBUG .. "y = " .. y .. "<br/>"
	    
	    resDEBUG = resDEBUG .. "math.max(0,math.min(1-z1,1)) = " .. math.max(0,math.min(1-z1,1)) .. "<br/>"
	    resDEBUG = resDEBUG .. "math.max(0,math.min(1-z2,1)) = " .. math.max(0,math.min(1-z2,1)) .. "<br/>"
	    resDEBUG = resDEBUG .. "math.max(0,math.min(1-y,1)) = " .. math.max(0,math.min(1-y,1)) .. "<br/>"
	    	
		resDEBUG = resDEBUG .. "math.min(math.max(0,z1),1) = " .. math.min(math.max(0,z1),1) .. "<br/>"
	    resDEBUG = resDEBUG .. "math.min(math.max(0,z2),1) = " .. math.min(math.max(0,z2),1) .. "<br/>"
	    resDEBUG = resDEBUG .. "math.min(math.max(0,y),1) = " .. math.min(math.max(0,y),1) .. "<br/>"
	    
	    resDEBUG = resDEBUG .. string.format("%.3f",pForcedCrit) .. "*(" .. string.format("%.3f",math.max(0,math.min(1-z1,1))) .. "*" .. critCap .. "+" ..  string.format("%.3f",math.min(math.max(0,z1),1)) .. "*(" .. math.min(critCap,forcedCritMin) .. "+" .. math.min(critCap,forcedCritMax) .. ")/2)" 
		resDEBUG = resDEBUG .. "+(1-".. string.format("%.3f",pForcedCrit) .. ")*" .. string.format("%.4f",pNaturalCrit) .. "*(" .. string.format("%.4f",math.max(0,math.min(1-z2,1))) .. "*" .. critCap .. "+" .. string.format("%.3f",math.min(math.max(0,z2),1)) .. "*(" .. math.min(naturalCritMin,critCap) .. "+" .. math.min(critCap,max_hit) ..")/2)"
		resDEBUG = resDEBUG .. "+(1-".. string.format("%.3f",pForcedCrit) .. ")*(1-" ..  string.format("%.4f",pNaturalCrit) .. ")*(" .. string.format("%.4f",math.max(0,math.min(1-y,1))) .. "*" .. dmgCap .. "+" .. string.format("%.3f",math.min(math.max(0,y),1)) .. "*(" .. math.min(dmgCap,min_hit) .. "+" .. math.min(dmgCap,naturalCritMin) ..")/2)" .. "<br/>"
		
	    resDEBUG = resDEBUG .. "___________________________________" .. "<br/>"
	end
	
	--___________________________________
	--Probability of hitting at least X
	--___________________________________
	local totalProbX = 0
	totalProbX = pForcedCrit*probDamageAtLeastX(forcedCritMin,forcedCritMax)+(1-pForcedCrit)*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-pForcedCrit)*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
    
    --___________________________________
    -- Average damage
    --___________________________________
    local avgDmgAbility = avgDmg
    res = res .. "<div style=\"font-weight:bold\">Average damage: " .. string.format("%.1f",avgDmgAbility) .. "</div>"
    res = res .. "Average damage (non-critical, chance = " .. string.format("%.2f",math.min(1,(1-pForcedCrit)*(1-pNaturalCrit))*100) .. "%): " .. string.format("%.1f",avgDmgNonCrit) .. "<br/>"
    res = res .. "Average damage (critical, chance = " .. string.format("%.2f",math.min(1,pForcedCrit+(1-pForcedCrit)*(pNaturalCrit))*100) .. "%): " .. string.format("%.1f",avgDmgCrit) .. "<br/>"
    
    --___________________________________
    -- Output for special cases from
    -- abilities that modify crit chance
    --___________________________________
    pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll+pFuryAndConc2)
    avgDmgCalc()
    res = res .. "Average damage after two hits of Fury/Concentrated Blast: " .. string.format("%.1f",avgDmg) .. "<br/>"
    local totalProbXConc2 = 0
	totalProbXConc2 = pForcedCrit*probDamageAtLeastX(forcedCritMin,forcedCritMax)+(1-pForcedCrit)*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-pForcedCrit)*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
    --avgDmgCritCalc()
    --avgDmgNonCritCalc()
    --res = res .. "If used after the second hit of Fury/Concentrated Blast, average damage (non-critical, chance = " .. math.min(1,(1-pForcedCrit)*(1-pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgNonCrit) .. "<br/>"        
    --res = res .. "If used after the second hit of Fury/Concentrated Blast, average damage (critical, chance = " .. math.min(1,pForcedCrit+(1-pForcedCrit)*(pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgCrit) .. "<br/>"
	
	pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll+pMFury)
	local pMFuryNonCritForcedCrit = pForcedCrit
    avgDmgCalc()
	local avgDmgNonCritMFury = avgDmg
	pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll+pMFuryGuarantee)
	avgDmgCalc()
	local avgDmgCritMFury = avgDmg
	if (max_MFury>0 and dType=="No") then
		local avgDmgCombinedMFury = pCritMFury*avgDmgCritMFury + (1-pCritMFury)*avgDmgNonCritMFury
	    res = res .. "Average damage after Greater Fury: " .. string.format("%.1f",avgDmgCombinedMFury) .. "<br/>"
	end
	if (dType=="Yes") then
    	res = res .. "Average damage after Greater Fury: " .. string.format("%.1f",avgDmgNonCritMFury) .. "<br/>"
    end
    
    local totalProbXMFury = 0
    if(max_MFury>0 and dType=="No") then
		totalProbXMFury = (pCritMFury+(1-pCritMFury)*pMFuryNonCritForcedCrit)*probDamageAtLeastX(forcedCritMin,forcedCritMax) + (1-(pCritMFury+(1-pCritMFury)*pMFuryNonCritForcedCrit))*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-(pCritMFury+(1-pCritMFury)*pMFuryNonCritForcedCrit))*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
	end
	if (dType=="Yes") then
		totalProbXMFury = (pMFuryNonCritForcedCrit)*probDamageAtLeastX(forcedCritMin,forcedCritMax) + (1-(pMFuryNonCritForcedCrit))*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-(pMFuryNonCritForcedCrit))*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
	end
    
	
	res = res .. "<br/>"
	
	pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll+pMFury)
    if (dType=="No") then
    	res = res .. "Average damage after (non-critical) Greater Fury: " .. string.format("%.1f",avgDmgNonCritMFury) .. "<br/>"
	    res = res .. "Average damage after (critical) Greater Fury: " .. string.format("%.1f",avgDmgCritMFury) .. "<br/>"
    end
    pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pKalgScroll+pFuryAndConc1)
    avgDmgCalc()
    res = res .. "Average damage after one hit of Fury/Concentrated Blast: " .. string.format("%.1f",avgDmg) .. "<br/>"
    local totalProbXConc1 = 0
	totalProbXConc1 = pForcedCrit*probDamageAtLeastX(forcedCritMin,forcedCritMax)+(1-pForcedCrit)*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-pForcedCrit)*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
    --avgDmgCritCalc()
    --avgDmgNonCritCalc()
	--res = res .. "If used after the first hit of Fury/Concentrated Blast, average damage (non-critical, chance = " .. math.min(1,(1-pForcedCrit)*(1-pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgNonCrit) .. "<br/>"    
    --res = res .. "If used after the first hit of Fury/Concentrated Blast, average damage (critical, chance = " .. math.min(1,pForcedCrit+(1-pForcedCrit)*(pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgCrit) .. "<br/>"
    pForcedCrit = math.min(1,pBiting+pGrimoire+pCorbicula+pFuryAndConc3)
    avgDmgCalc()
    res = res .. "Average damage after three hits of Fury/Concentrated Blast: " .. string.format("%.1f",avgDmg) .. "<br/>"
    local totalProbXConc3 = 0
	totalProbXConc3 = pForcedCrit*probDamageAtLeastX(forcedCritMin,forcedCritMax)+(1-pForcedCrit)*pNaturalCrit*probDamageAtLeastX(naturalCritMin,max_hit)+(1-pForcedCrit)*(1-pNaturalCrit)*probDamageAtLeastX(min_hit,naturalCritMin)
    --avgDmgCritCalc()
    --avgDmgNonCritCalc()
	--res = res .. "If used after the third hit of Fury/Concentrated Blast, average damage (non-critical, chance = " .. math.min(1,(1-pForcedCrit)*(1-pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgNonCrit) .. "<br/>"    
    --res = res .. "If used after the third hit of Fury/Concentrated Blast, average damage (critical, chance = " .. math.min(1,pForcedCrit+(1-pForcedCrit)*(pNaturalCrit))*100 .. "%) is: " .. string.format("%.1f",avgDmgCrit) .. "<br/>"
    
    res = res .. "<br/>"
   
    --___________________________________
    -- Return probability of hitting at least X
    --___________________________________
		local resX = ""
		if(atLeastX > 0) then
			resX = resX .. "Probability of hitting over " .. atLeastX .. " damage: " .. string.format("%.2f",totalProbX*100) .. "%<br/>"
			resX = resX .. "Probability of hitting over " .. atLeastX .. " damage after two hits of Fury/Concentrated Blast: " .. string.format("%.2f",totalProbXConc2*100) .. "%<br/>"
			if(max_MFury>0) then 
				resX = resX .. "Probability of hitting over " .. atLeastX .. " damage after Greater Fury: " .. string.format("%.2f",totalProbXMFury*100)  .. "%<br/>"
			end
			resX = resX .. "<br/>"
			resX = resX .. "Probability of hitting over " .. atLeastX .. " damage after one hit of Fury/Concentrated Blast: " .. string.format("%.2f",totalProbXConc1*100) .. "%<br/>"
			resX = resX .. "Probability of hitting over " .. atLeastX .. " damage after three hits of Fury/Concentrated Blast: " .. string.format("%.2f",totalProbXConc3*100) .. "%<br/>"
			resX = resX .. "<br/>"
		end
    --___________________________________
    -- Average damage if Eldtrich crossbow Special attack is used
    --___________________________________
    local resECB = ""
    if(splitSoul=="Yes (with Amulet of Souls)" or splitSoul=="Yes (without Amulet of Souls)") then
	    resECB = resECB .. "<div style=\"font-weight:bold\">Average damage from ability: " .. string.format("%.1f",avgDmgAbility) .. "</div>"
	    resECB = resECB .. "Average damage from Split Soul: " .. string.format("%.1f",avgDmgSplitSoul) .. "<br/>"
    end
   	resECB = resECB .. "<br/>"
    
    --___________________________________
    -- Output of what was set in the
    -- user interface
    --___________________________________
    local resINPUT = ""
    resINPUT = resINPUT .. "Auto attack: " .. dType .. "<br/>"
    --___________________________________
    -- Calculating the damage range
    --___________________________________
    local minHitDmgRange = 0
    local maxHitDmgRange = math.min(critCap,max_hit)
    if (min_hit>.95*max_hit and min_hit>=critCap) then
    	minHitDmgRange = critCap
    elseif (min_hit>.95*max_hit and min_hit<critCap) then
    	minHitDmgRange = min_hit
	else
		minHitDmgRange = math.min(dmgCap,min_hit)
	end
    resINPUT = resINPUT .. "Damage range: [" .. minHitDmgRange .. "," .. maxHitDmgRange .. "]" .. "<br/>"
    
    resINPUT = resINPUT .. "Biting perk rank: " .. bitingPerkRank .. "<br/>"
    resINPUT = resINPUT .. "Biting perk on level 20 gear: " .. gearLevel20 .. "<br/>"
    resINPUT = resINPUT .. "Erethdor's grimoire active: " .. eGrimoire .. "<br/>"
	resINPUT = resINPUT .. "#Corbicula farm totems: " .. corbiculatotem .. "<br/>"
	resINPUT = resINPUT .. "Crit-i-kal scroll from Kal'gerion demon (familiar) active: " .. kalgScroll .. "<br/>"
    resINPUT = resINPUT .. "Eldritch crossbow special attack active: " .. splitSoul .. "<br/>"
    resINPUT = resINPUT .. "(Optional) Minimum hit of Greater Fury: " .. min_MFury .. "<br/>"
    resINPUT = resINPUT .. "(Optional) Minimum hit of Greater Fury: " .. max_MFury .. "<br/>"
    resINPUT = resINPUT .. "Find the probability of hitting at least X damage (Enter value for X) " .. atLeastX .. "<br/>"
    resINPUT = resINPUT .. "Display additional information? " .. debugMode .. "<br/>"
    
    --___________________________________
    -- Return result
    --___________________________________
    if(splitSoul ~= "No") then 
		return resDEBUG .. resECB .. resINPUT
	else
		return resDEBUG .. res .. resX .. resINPUT
	end
end

return p