Module:Critical hit chance calculator: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
(No difference)
|
Revision as of 09:23, 7 October 2021
Documentation for this module may be created at Module:Critical hit chance calculator/doc
-- <pre>
local p = {}
local htnmlext = require('Module:Mw.html extension')
local yesno = require ("Module:Yesno")
local lang = mw.getContentLanguage()
local min = math.min
local max = math.min
local floor = math.floor
function p.main(frame)
local invokeArgs = frame.args
local args = frame:getParent().args
return p._main( invokeArgs, args )
end
function onOff(value)
return value and 1 or 0
end
function p._main(invokeArgs,args)
--args
--player values
local level = tonumber(args.level) or 0
local ad = tonumber(args.AD) or 0
--fCrit Modifiers
local bitingRank = tonumber(args.biting) or 0
local level20biting = yesno(args.level20biting) or false
local pocket = args.pocket
local ring = args.ring
local ringChannellers = tonumber(args.ringChannellers) or 0
local forcedAbility = args.forcedAbility
local abilFury = tonumber(args.abilityFury) or 0
local abilGreaterFury = args.abilityGreaterFury
local abilConcBlast = tonumber(args.abilityConcentratedBlast) or 0
local abilGConcBlast = tonumber(args.abilityGreaterConcentratedBlast) or 0
local familiar = yesno(args.familiar) or false
local ammunition = yesno(args.ammunition) or false
local corbicula = tonumber(args.corbicula) or 0
local setEffect = args.setEffect
local warpriestOfTuska = tonumber(args.warpriestOfTuska) or 0
--nCrit Modifiers
local abilMin = tonumber(args.abilityMin) or 0
local abilMax = tonumber(args.abilityMax) or 0
local prayer = args.prayer
local potion = args.potion
local essence = yesno(args.essence) or false
local aura = args.aura
local slayerHelm = args.slayerHelm
local genocidal = tonumber(args.genocidal) or 0
local baneAmmo = yesno(args.baneAmmo) or false
local baneWeaponry = yesno(args.baneWeaponry) or false
local revenge = yesno(args.revenge) or false
local revengeStacks = tonumber(args.revengeStacks) or 0
local shieldType = args.shieldType
local preciseRank = tonumber(args.precise) or 0
local equilibriumRank = tonumber(args.equilibrium) or 0
if(abilMin>abilMax) then
return "<div style=\"font-weight:bold\">The minimum must not be higher than the maximum.</div>"
end
if(ammunition and baneAmmo) then
return "<div style=\"font-weight:bold\">Two different types of ammunition cannot be used at the same time.</div>"
end
local fCritProb = calculateForcedCriticalHitProbability(bitingRank,level20biting,pocket,ring,ringChannellers,forcedAbility,abilFury,abilGreaterFury,abilConcBlast,abilGConcBlast,familiar,ammunition,corbicula,setEffect,warpriestOfTuska)
local nCritProb = calculateNaturalCriticalHitProbability(level,ad,abilMin,abilMax,prayer,potion,essence,aura,slayerHelm,genocidal,baneAmmo,baneWeaponry,revenge,revengeStacks,shieldType,preciseRank,equilibriumRank)
local nCritProb = (1-fCritProb/100)*nCritProb
local totalCritProb = fCritProb + (1-fCritProb/100)*nCritProb
local nonCritProb = 100 - totalCritProb
fCritProb = floor(fCritProb*10^2 + 0.5)/10^2
nCritProb = floor(nCritProb*10^2 + 0.5)/10^2
totalCritProb = floor(totalCritProb*10^2 + 0.5)/10^2
nonCritProb = floor(nonCritProb*10^2 + 0.5)/10^2
--table for output
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' )
:tag( 'tr' )
:tag( 'th' )
:wikitext('Critical hit chance')
:attr( 'colspan', 3)
:done()
:tag( 'th' )
:wikitext('Non-critical hit chance')
:attr( 'rowspan', 2)
:done()
:done()
:tag( 'tr' )
:tag( 'th' )
:wikitext('Total critical hit chance')
:done()
:tag( 'th' )
:wikitext('Forced critical hit chance')
:done()
:tag( 'th' )
:wikitext('Natural critical hit chance')
:done()
:done()
:tag ( 'tr' )
:tag( 'td' )
:wikitext( string.format("<b>%.2f</b>",lang:formatNum(totalCritProb)) .. "<b>%</b>" )
:done()
:tag( 'td' )
:wikitext( string.format("%.2f",lang:formatNum(fCritProb)) .. "%" )
:done()
:tag( 'td' )
:wikitext( string.format("%.2f",lang:formatNum(nCritProb)) .. "%" )
:done()
:tag( 'td' )
:wikitext( string.format("<b>%.2f</b>",lang:formatNum(nonCritProb)) .. "<b>%</b>" )
:done()
:done()
--return results (table)
resultsDiv:node(tostring(resultsTable))
return resultsDiv
end
function calculateNaturalCriticalHitProbability(lvl,abilitydamage,aMin,aMax,pray,pot,ess,auraSlot,slayerHelmet,genocidalPerk,baneAmmunition,baneMeleeWeaponry,aRevenge,aRevengeStacks,shieldSlot,pRank,eRank)
-- calculate effective level and Ability damage (AD)
local lvlMult = 1
local lvlAdd = 0
if(pot=="Elder overload potion") then lvlMult = 1.17; lvlAdd = 5
elseif(pot=="Supreme overload potion" or potion=="Supreme strength/magic/ranging potion") then lvlMult = 1.16; lvlAdd = 4
elseif(pot=="Overload") then lvlMult = 1.15; lvlAdd = 3
end
local lvlAura = 0
if(auraSlot=="Berserker/Maniacal/Reckless aura") then lvlAura = 0.1 end
local lvlEff = lvl
if(pot=="Supreme strength/magic/ranging potion") then
lvlEff = floor(lvl*lvlMult+lvlAdd)
if(ess) then -- 133 stats at level 99 (with or without berserker auras)
lvlEff = lvlEff + floor(lvl*1.14+2) - lvl
end
elseif(pot=="None") then
lvlEff = floor(lvl*(lvlAura + lvlMult))
if(ess) then -- 123 stats at level 99 with berserker auras (114 without)
lvlEff = lvlEff + floor(lvl*1.14+2) - lvl
end
else --overloads
lvlEff = floor(lvl*(lvlAura + lvlMult)+lvlAdd)
end
local prayerMod = 1
if(pray=="Malevolence/Affliction/Desolation") then prayerMod = 1.12
elseif(pray=="Turmoil/Torment/Anguish") then prayerMod = 1.10
elseif(pray=="Leech (Magic/Range) Strength + Amulet of zealots") then prayerMod = 1.18
elseif(pray=="Ultimate Strength/OverCharge/Overpowering Force + Amulet of zealots") then prayerMod = 1.16
elseif(pray=="Piety/Augury/Rigour") then prayerMod = 1.08
end
local adEff = abilitydamage
--base
local abilFixed = floor(adEff*aMin/100)
local abilVar = floor(adEff*(aMax-aMin)/100)
--prayer
abilFixed = floor(abilFixed*prayerMod)
abilVar = floor(abilVar*prayerMod)
--boosted
abilFixed = abilFixed + 4*(lvlEff - lvl)
abilVar = abilVar + 4*(lvlEff - lvl)
--revenge
if(aRevenge) then
local revengeMod = 0
if(shieldSlot=="Shield") then revengeMod = 0.10
elseif(shieldSlot=="Defender/Rebounder/Repriser") then revengeMod = 0.05
else revengeMod = 0
end
abilVar = floor(abilVar*(1+aRevengeStacks*revengeMod))
end
--slayer helmet
if(slayerHelmet == "Full slayer helmet") then
abilVar = floor(abilVar*1.125)
elseif(slayerHelmet == "Reinforced slayer helmet") then
abilVar = floor(abilVar*1.13)
elseif(slayerHelmet == "Strong slayer helmet") then
abilVar = floor(abilVar*1.135)
elseif(slayerHelmet == "Mighty slayer helmet") then
abilVar = floor(abilVar*1.14)
elseif(slayerHelmet == "Corrupted slayer helmet") then
abilVar = floor(abilVar*1.145)
end
--genocidal
abilVar = floor(abilVar*(1 + genocidalPerk/100))
--bane ammo
abilVar = floor(abilVar*(1 + onOff(baneAmmunition)*0.40))
--bane weaponry
abilVar = floor(abilVar*(1 + onOff(baneMeleeWeaponry)*0.25))
--precise
local Aprecise = floor(0.015*pRank*(abilFixed+abilVar))
local abilFixedPrecise = abilFixed + Aprecise
local abilVarPrecise = abilVar - Aprecise
if(abilVarPrecise<=0) then
abilFixed = abilFixed+abilVar
abilVar = 0
else
abilFixed = abilFixedPrecise
abilVar = abilVarPrecise
end
--calculate where natural crit hits begin with precise
local pNatCritPrecise = 0
if(abilVar==0) then
pNatCritPrecise = 1
else
pNatCritPrecise = min(1,floor(0.05*(abilFixed+abilVar))/abilVar)
end
--equilibrium (aura overrides perk)
if(auraSlot=="Equilibrium aura") then
abilFixed = abilFixed + floor(.25*abilVar)
abilVar = floor((1-.50)*abilVar)
else
abilFixed = abilFixed + floor(0.03*eRank*abilVar)
abilVar = floor((1-0.04*eRank)*abilVar)
end
--calculate natural crit chance
local minNCrit = 0
local nCritChance = 0
if(abilVar==0) then
minNCrit = abilFixed+abilVar
nCritChance = 1
else
minNCrit = abilFixed + floor((1-pNatCritPrecise)*abilVar)
nCritChance = (abilFixed+abilVar-minNCrit)/(abilVar)
end
--return natural crit chance
return min(100,nCritChance*100)
--return abilFixed .. " " .. abilVar .. " " .. minNCrit .. " " .. nCritChance .. " " .. pNatCritPrecise .. " "
end
function calculateForcedCriticalHitProbability(bRank,lv20b,pocketSlot,ringSlot,channellers,fAbil,fury,gfury,conc,gconc,fam,ammo,corbi,setEff,tuska)
--forced crit probabilities are addititve. warpriest of tuska appears to override biting
local fCritChance = 0
if(setEff == "Tuska's Might (Sliske's Parody)") then
fCritChance = 6
elseif(setEff == "Tuska's Might (Warpriest of Tuska)") then
fCritChance = tuska
else
fCritChance = bRank*2 * ( 1 + 0.1*onOff(lv20b) )
end
--pocket
if(pocketSlot == "Erethdor's grimoire") then
fCritChance = fCritChance + 12
end
--rings
if(ringSlot == "Reaver's ring") then
fCritChance = fCritChance + 5
elseif(ringSlot == "Channeller's ring") then
fCritChance = fCritChance + 4*channellers
elseif(ringSlot == "Stalker's ring") then
fCritChance = fCritChance + 3
elseif(ringSlot == "Champion's ring") then
fCritChance = fCritChance + 3
end
--abilities
if(fAbil == "Fury") then
fCritChance = fCritChance + 5*fury
elseif(fAbil == "Greater Fury") then
if(gfury == "+10%") then
fCritChance = fCritChance + 10
elseif(gfury == "100%") then
fCritChance = 100
end
elseif(fAbil == "Concentrated Blast") then
fCritChance = fCritChance + 5*conc
elseif(fAbil == "Greater Concentrated Blast") then
fCritChance = fCritChance + 5*gconc
end
--familiar
if(fam) then
fCritChance = fCritChance + 5
end
--ammunition
if(ammo) then
fCritChance = fCritChance + 3
end
--corbicula (only affects meteor strike)
fCritChance = fCritChance + 20*corbi
--return forced crit chance (max of 100%)
return min(100,fCritChance)
end
return p