Module:Revolution AADPT

From WIDEVERSE Wiki
Revision as of 21:23, 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:Revolution AADPT/doc

--<nowiki>
local p = {}
-- dependencies: [[Module:Yesno]]
local yesno = require('Module:Yesno')
-- data: [[Module:Revolution AADPT/data]]
local ability_data = mw.loadData('Module:Revolution AADPT/data')

local settings = {}
	
local abilities = {}
local bar = {}
local cd_groups = {}

--[[
Make an ability from the data, and adds it to the abilities array
params
	a - string - ability name
returns
	the ability object for optional use
--]]
function p.make_ability(a)
	local abil = ability_data[a]
	local ret = {}
	if settings.ice and a == 'wrack' then
		abil = ability_data.wrack_ice
	end
	if a == "tuska's wrath" then
		if settings.slayer then
			abil = ability_data.tuska_slayer
		else
			abil = ability_data.tuska_noslayer
		end
	end
	
	if abilities[abil.name] ~= nil then
		return abilities[abil.name]
	end
	
	ret = {
		name = abil.name,
		cooldown = abil.cooldown,
		duration = abil.duration or 3,
		damage = abil.dmg or abil.damage*0.6,
		stundur = abil.stundur or 0,
		stundmg = abil.stundmg or (abil.stundamage and abil.stundamage*0.6) or abil.dmg or abil.damage*0.6,
		shared = abil.shared,
		next_abil_mult = abil.next_abil_mult or 1,
		damagetype = abil.damagetype or "",
		cd = 0,
		used = false,
		stunbuffed = false,
	}
	setmetatable(ret, {__tostring = function() return abil.name end})
	
	if ret.stundmg > ret.damage then
		ret.stunbuffed = true
	end
	
	if ret.shared then
		if cd_groups[ret.shared] == nil then
			cd_groups[ret.shared] = {}
		end
		table.insert(cd_groups[ret.shared], abil.name)
	end
	
	abilities[abil.name] = ret
	
	return abilities[abil.name]
end

--[[
Resets abilities cooldowns and other statuses; mostly for testing, but good for using the same instance multiple times
params
	a   table   the ability object
returns
	nothing
--]]
local function reset(a)
	a.cd = 0
	a.used = false
end


--[[
Reduce the cooldown of an ability by a number of ticks
params
	a   table   the ability object
	i   int	 the amount to reduce by
returns
	nothing
--]]
local function reduce_cooldown(a, i)
	if a.cd < i then
		a.cd = 0
	else
		a.cd = a.cd - i
	end
end

--[[
Set the cooldown of an ability, and all abilities in its cooldown groups
params
	a   table   the ability object
	i   int	 the amount to reduce by
returns
	nothing
--]]
local function set_cooldown(a)
	local b
	a.cd = a.cooldown
	--cooldown group
	if a.shared then
		for _,b in ipairs(cd_groups[a.shared]) do
			abilities[b].cd = a.cooldown
		end
	end
end

	
--[[
calculates the AADPT of the provided bar
params
	bar	 array of strings	list of ability names in order
returns
	average ability damage per tick
--]]
function p.calcrevo()
	local ret = {
		t = 0,
		d = 0,
		stunbuffed = false,
		broke = false,
	}
	ret.dpt = function() return ret.d/ret.t end
	local incr, stunned, dmg, next_abil, next_mult = 0, 0, 0, nil, 1
	local a
	
	for n,a in pairs(abilities) do
		reset(a)
	end
	
	while ret.t < settings.ticks do
		--cooldowns
		for _,a in pairs(abilities) do
			reduce_cooldown(a, incr)
		end
		
		if stunned < incr then
			stunned = 0
		else
			stunned = stunned - incr
		end
		
		--find next ability
		next_abil = nil
		for _,a in ipairs(bar) do 
			if abilities[a].cd == 0 then
				next_abil = abilities[a]
				break
			end
		end
		
		if next_abil == nil then
			ret.broke = true
			return ret --broken revobar
		end
		
		-- multipliers don't apply to bleeds
		if string.find(next_abil.damagetype, 'bleed') then
			next_mult = 1
		end
		
		--increment counters
		set_cooldown(next_abil)
		incr = next_abil.duration
		ret.t = ret.t + incr
		next_abil.used = true
		
		dmg = next_abil.damage
		if stunned > 0 then
			if next_abil.stunbuffed then --automatically detect if enabling stuns would affect the bar value
				ret.stunbuffed = true
			end
			if settings.stuns then
				dmg = next_abil.stundmg
			end
		end
	
		ret.d = ret.d + dmg * next_mult
		
		if next_abil.stundur > 0 then
			stunned = next_abil.stundur
		end
		
		next_mult = next_abil.next_abil_mult
		
	end
	
	return ret
end

--make a permalink to [[Calculator:Revolution]]
function p.generate_permalink()
	local uri = mw.uri.new(mw.uri.fullUrl('Calculator:Revolution'))
	local query = {}
	
	query.stuns = 0
	if settings.stuns then
		query.stuns = 1
	end
	
	query.ice = 0
	if settings.ice then
		query.ice = 1
	end
	
	query.slayer = 0
	if settings.slayer then
		query.slayer = 1
	end
	
	query.ticks = settings.ticks
	query.hand = settings.hand
	query.cbclass = settings.cbclass
	
	query.bar = table.concat(bar,',')
	
	uri.query = query;
	return uri
end


function p.permalink(frame)
	return p._permalink(frame:getParent().args)
end

function p._permalink(args)
	setup(args)
	local alt = args.alt or 'Open in calculator'
	return '[' .. p.generate_permalink() .. ' ' .. alt .. ']'
end


--all the setup stuff
local function setup(a)
	settings = {
		stuns = false,
		ice = false,
		slayer = false,
		ticks = 1000,
		hand = 1,
		cbclass = 'melee',
	}
	settings.stuns = yesno(a.stuns, false)
	settings.ice = yesno(a.ice, false)
	settings.slayer = yesno(a.slayer, false)
	settings.hand = a.hand or 1
	settings.cbclass = a.cbclass or 'melee'
	settings.ticks = tonumber(a.ticks) or 1000
	abilities = {}
	bar = {}
	local b = mw.text.split(a.bar, ',')
	for _,ab in ipairs(b) do
		table.insert(bar, p.make_ability(string.lower(ab)).name)
	end
end

local function plinkp(s)
	return string.format('[[File:%s.png|30x30px|alt=RS3 ability %s used in a Revolution bar|link=%s]]',s,s,s)
end


--test run
function p.run(frame)
	return p._run(frame:getParent().args)
end

function p._run(args)
	setup(args)
	return p.calcrevo().dpt() .. '\t\t' .. tostring(p.generate_permalink())
end

--generate table row
function p.row(frame)
	return p._row(frame:getParent().args)
end

function p._row(args)
	setup(args)
	local notes = args.notes or '' 
	local stunoriginal = settings.stuns
	local val = p.calcrevo()
	local dpt = val.dpt()
	local barstr = ''
	local stunstr = ''
	if val.stunbuffed and not settings.stuns then
		settings.stuns = true
		stunstr = '<br />(Stuns: ' .. math.floor(p.calcrevo().dpt() * 10000)/100 .. '%)'
	end
	
	--turn into % with some 2 decimal places
	--i.e. change from 0.273737 to 27.37, % appended later
	dpt = math.floor(dpt * 10000)/100
	
	for i,a in ipairs(bar) do
		barstr = barstr .. plinkp(a)
		if next(bar, i) then
			barstr = barstr .. '&nbsp;'
		end
	end
	settings.stuns = stunoriginal
	local tr = mw.html.create('tr')
				:tag('td')
					:wikitext(notes)
				:done()
				:tag('td')
					:wikitext(barstr)
				:done()
				:tag('td')
					:css('text-align', 'right')
					:wikitext(dpt .. '%' .. stunstr)
				:done()
				:tag('td')
					:wikitext('['..tostring(p.generate_permalink())..' Open in calculator]')
				:done()
			:done()
	return tr
end

return p
--</nowiki>