Module:Magic

Revision as of 23:30, 4 January 2022 by Falterfire (talk | contribs) (Fixed incorrect duration)
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Data pulled from Module:GameData/data


local p = {}

local MagicData = mw.loadData('Module:Magic/data')

local Areas = require('Module:CombatAreas')
local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Constants = require('Module:Constants')

function processSpell(section, index)
	local result = Shared.clone(MagicData[section][index])
	result.id = index - 1
	result.type = section
	return result
end

function p.getSpell(name, type)
	local section = type
	if type == 'Spell' or type == 'Standard' then
		section = 'Spells'
	elseif type == 'Curse' then
		section = 'Curses'
	elseif type == 'Aurora' then
		section = 'Auroras'
	elseif type == 'Alt Magic' or type == 'Alternative Magic' then
		section='AltMagic'
	end
	
	name = Shared.fixPagename(name)
	if section == nil then
		for i, section in Shared.skpairs(MagicData) do
			for j, spell in Shared.skpairs(section) do
				if spell.name == name then
					return processSpell(i, j)
				end
			end
		end
	elseif section ~= nil and MagicData[section] ~= nil then
		for i, spell in Shared.skpairs(MagicData[section]) do
			if spell.name == name then
				return processSpell(section, i)
			end
		end
	else
		return nil
	end
end

function p.getSpellByID(type, id)
	local section = type
	if type == nil or type == 'Spell' or type == 'Standard' then
		section = 'Spells'
	elseif type == 'Curse' then
		section = 'Curses'
	elseif type == 'Aurora' then
		section = 'Auroras'
	elseif type == 'Alt Magic' or type == 'Alternative Magic' then
		section='AltMagic'
	end
	
	if MagicData[section] ~= nil then
		return processSpell(section, id + 1)
	else
		return nil
	end
end

function p.getTypeString(type)
	if type == 'Auroras' then
		return 'Aurora'
	elseif type == 'Curses' then
		return 'Curse'
	elseif type == 'AltMagic' then
		return 'Alt. Magic'
	elseif type == 'Spells' then
		return "Combat Spell"
	elseif type == 'Ancient' then
		 return 'Ancient Magick'
	end
end

function p._getSpellIcon(spell, size)
	if size == nil then size = 50 end
	if spell.type == 'Auroras' then
		return Icons.Icon({spell.name, type='aurora', notext=true, size=size})
	elseif spell.type == 'Curses' then
		return Icons.Icon({spell.name, type='curse', notext=true, size=size})
	else
		return Icons.Icon({spell.name, type='spell', notext=true, size=size})
	end
end

function p._getSpellRequirements(spell)
	local result = ''
	result = result..Icons._SkillReq('Magic', spell.level)
	if spell.requiredItem ~= nil and spell.requiredItem >= 0 then
		local reqItem = Items.getItemByID(spell.requiredItem)
		result = result..'<br/>'..Icons.Icon({reqItem.name, type='item', notext=true})..' equipped'
	end
	if spell.requiredDungeonCompletion ~= nil then
		local dung = Areas.getAreaByID('dungeon', spell.requiredDungeonCompletion[1])
		result = result..'<br/>'..Icons.Icon({dung.name, type='dungeon', notext=true, qty=spell.requiredDungeonCompletion[2]})..' Clears'
	end
	return result
end

function p._getSpellRunes(spell)
	local result = ''
	for i, req in Shared.skpairs(spell.runesRequired) do
		local rune = Items.getItemByID(req.id)
		if i > 1 then result = result..', ' end
		result = result..Icons.Icon({rune.name, type='item', notext=true, qty=req.qty})
	end
	if spell.runesRequiredAlt ~= nil and not Shared.tablesEqual(spell.runesRequired, spell.runesRequiredAlt) then
		result = result.."<br/>'''OR'''<br/>"
		for i, req in pairs(spell.runesRequiredAlt) do
			local rune = Items.getItemByID(req.id)
			if i > 1 then result = result..', ' end
			result = result..Icons.Icon({rune.name, type='item', notext=true, qty=req.qty})
		end
	end
	return result
end

function p.getSpellRunes(frame)
	local spellName = frame.args ~= nil and frame.args[1] or frame
	local spell = p.getSpell(spellName)
	if spell == nil then
		return "ERROR: No spell named "..spellName.." exists in the data module"
	end
	return p._getSpellRunes(spell)
end

function p._getSpellDescription(spell)
	local result = ''
	if spell.description ~= nil then
		if p.getSpellTypeIndex(spell.type) == 4 and string.find(spell.description, "<br>") ~= nil then
			result = string.sub(spell.description, 0, string.find(spell.description, "<br>")-1)
		else
			result = spell.description
		end
	elseif (spell.modifiers ~= nil or spell.enemyModifiers ~= nil) then
		if spell.modifiers ~= nil then
			local playerModText = Constants.getModifiersText(spell.modifiers, false)
			result = playerModText
		end
		if spell.enemyModifiers ~= nil then
			local enemyModText = Constants.getModifiersText(spell.enemyModifiers, false)
			result = result .. (string.len(result) > 0 and '<br/>' or '') .. 'Enemies are inflicted with:<br/>' .. enemyModText
		end
	elseif spell.type == 'Spells' then
		result = 'Combat spell with a max hit of '..(spell.maxHit * 10)
	end

	return result
end

function p._getSpellStat(spell, stat)
	if stat == 'bigIcon' then
		return p._getSpellIcon(spell, 250)
	elseif stat == 'description' then
		return p._getSpellDescription(spell)
	elseif stat == 'icon' then
		return p._getSpellIcon(spell)
	elseif stat == 'requirements' then
		return p._getSpellRequirements(spell)
	elseif stat == 'runes' then
		return p._getSpellRunes(spell)
	elseif stat == 'type' then
		return p.getTypeString(spell.type)
	end
	return spell[stat]
end

function p.getSpellStat(frame)
	local spellName = frame.args ~= nil and frame.args[1] or frame[1]
	local statName = frame.args ~= nil and frame.args[2] or frame[2]
	local spell = p.getSpell(spellName)
	if spell == nil then
		return "ERROR: No spell named "..spellName.." found"
	end
	return p._getSpellStat(spell, statName)
end

function p.getOtherSpellBoxText(frame)
	local spellName = frame.args ~= nil and frame.args[1] or frame
	local spell = p.getSpell(spellName)
	if spell == nil then
		return "ERROR: No spell named "..spellName.." found"
	end

	local result = ''

	--8/20/21: Changed to using the new getSpellDescription function
	result = result.."\r\n|-\r\n|'''Description:'''<br/>"..p._getSpellStat(spell, 'description')

	return result
end

function p._getSpellCategories(spell)
	local result = '[[Category:Spells]]'
	result = result..'[[Category:'..p.getTypeString(spell.type)..']]'
	return result
end

function p.getSpellCategories(frame)
	local spellName = frame.args ~= nil and frame.args[1] or frame
	local spell = p.getSpell(spellName)
	if spell == nil then
		return "ERROR: No spell named "..spellName.." found"
	end
	return p._getSpellCategories(spell)
end

function p.getSpellsForRune(runeID)
	local spellList = {}
	for secName, secArray in Shared.skpairs(MagicData) do
		for i, spell in pairs(secArray) do
			local foundSpell = false
			for j, req in pairs(spell.runesRequired) do
				if req.id == runeID then
					table.insert(spellList, processSpell(secName, i))
					foundSpell = true
					break
				end
			end
			if spell.runesRequiredAlt ~= nil and not foundSpell then
				for j, req in pairs(spell.runesRequiredAlt) do
					if req.id == runeID then
						table.insert(spellList, processSpell(secName, i))
						break
					end
				end
			end
		end
	end
	table.sort(spellList, function(a, b) 
							 if a.type ~= b.type then
								 return p.getSpellTypeIndex(a.type) < p.getSpellTypeIndex(b.type)
							 else
								 return a.level < b.level
							 end
						 end)
	return spellList
end

function p.getSpellTypeIndex(type)
	if type == 'Spells' then
		return 0
	elseif type == 'Curses' then
		return 1
	elseif type == 'Auroras' then
		return 2
	elseif type == 'Ancient' then
		return 3
	elseif type == 'AltMagic' then
		return 4
	end
	return -1
end

function p.getSpellTypeLink(type)
	if type == 'Spells' then
		return Icons.Icon({'Magic', 'Standard', img='Standard', type='spellType'})
	elseif type == 'Curses' then
		return Icons.Icon({'Curses', 'Curse', img='Curse', type='spellType'})
	elseif type == 'Auroras' then
		return Icons.Icon({'Auroras', 'Aurora', img='Aurora', type='spellType'})
	elseif type == 'Ancient' then
		return Icons.Icon({'Ancient Magicks', 'Ancient', img='Ancient', type='spellType'})
	elseif type == 'AltMagic' then
		return Icons.Icon({'Alt. Magic', type='skill'})
	end
	return ''
end

function p._getSpellRow(spell, includeTypeColumn)
	local rowTxt = '\r\n|-\r\n|data-sort-value="'..spell.name..'"|'
	if spell.type == 'Auroras' then
		rowTxt = rowTxt..Icons.Icon({spell.name, type='aurora', notext=true, size=50})
	elseif spell.type == 'Curses' then
		rowTxt = rowTxt..Icons.Icon({spell.name, type='curse', notext=true, size=50})
	else
		rowTxt = rowTxt..Icons.Icon({spell.name, type='spell', notext=true, size=50})
	end
	rowTxt = rowTxt..'||'..Icons.Icon({spell.name, type='spell', noicon=true})
	rowTxt = rowTxt..'||data-sort-value="'..spell.level..'"|'..Icons._SkillReq('Magic', spell.level)
	--Handle required items/dungeon clears
	if spell.requiredItem ~= nil and spell.requiredItem >= 0 then
		local reqItem = Items.getItemByID(spell.requiredItem)
		rowTxt = rowTxt..'<br/>'..Icons.Icon({reqItem.name, type='item', notext=true})..' equipped'
	end
	if spell.requiredDungeonCompletion ~= nil then
		local dung = Areas.getAreaByID('dungeon', spell.requiredDungeonCompletion[1])
		rowTxt = rowTxt..'<br/>'..Icons.Icon({dung.name, type='dungeon', notext=true, qty=spell.requiredDungeonCompletion[2]})..' Clears'
	end

	if includeTypeColumn then
		rowTxt = rowTxt..'||data-sort-value="'..p.getSpellTypeIndex(spell.type)..'"|'
		rowTxt = rowTxt..p.getSpellTypeLink(spell.type)
	end
	--8/20/21: Changed to just getting the spell's description outright
	rowTxt = rowTxt..'||'..p._getSpellStat(spell, 'description')
	--1/4/22: haha just kidding. Now we're also getting delay between attacks for spells with special attacks
	if spell.specialAttack ~= nil then
		local spAtt = spell.specialAttack
		local interval = spAtt.attackInterval ~= nil and spAtt.attackInterval or -1
		if interval ~= -1 then
			local hits = spAtt.attackCount ~= nil and spAtt.attackCount or 1
			rowTxt = rowTxt..'<br/>('
			rowTxt = rowTxt..Shared.round(interval / 1000, 2, 2)..'s delay between attacks.'
			if hits > 2 then
				rowTxt = rowTxt..' '..Shared.round(interval * (hits - 1) / 1000, 2, 2)..'s total duration.'
			end
			rowTxt = rowTxt..')'
		end
	end
	if p.getSpellTypeIndex(spell.type) == 4 then
		rowTxt = rowTxt..'||'..spell.magicXP
	end
	rowTxt = rowTxt..'||style="text-align:center"|'
	rowTxt = rowTxt..p._getSpellRunes(spell)
	return rowTxt
end

function p.getStandardSpellsTable(frame)
	local result = '{|class="wikitable sortable"\r\n!colspan="2"|Spell'
	result = result..'!!Requirements'
	result = result..'!!style="width:275px"|Description'
	result = result..'!!Runes'
	local spellList = {}
	for i, spell in Shared.skpairs(MagicData.Spells) do
		local rowTxt = p._getSpellRow(processSpell('Spells', i), false)
		result = result..rowTxt
	end
	result = result..'\r\n|}'
	return result
end

function p.getCurseTable(frame)
	local result = '{|class="wikitable sortable"\r\n!colspan="2"|Spell'
	result = result..'!!Requirements'
	result = result..'!!style="width:275px"|Description'
	result = result..'!!Runes'
	local spellList = {}
	for i, spell in Shared.skpairs(MagicData.Curses) do
		local rowTxt = p._getSpellRow(processSpell('Curses', i), false)
		result = result..rowTxt
	end
	result = result..'\r\n|}'
	return result
end

function p.getAuroraTable(frame)
	local result = '{|class="wikitable sortable"\r\n!colspan="2"|Spell'
	result = result..'!!Requirements'
	result = result..'!!style="width:275px"|Description'
	result = result..'!!Runes'
	for i, spell in Shared.skpairs(MagicData.Auroras) do
		local rowTxt = p._getSpellRow(processSpell('Auroras', i), false)
		result = result..rowTxt
	end
	result = result..'\r\n|}'
	return result
end

function p.getAncientTable(frame)
	local result = '{|class="wikitable sortable"\r\n!colspan="2"|Spell'
	result = result..'!!Requirements'
	result = result..'!!style="width:275px"|Description'
	result = result..'!!Runes'
	for i, spell in Shared.skpairs(MagicData.Ancient) do
		local rowTxt = p._getSpellRow(processSpell('Ancient', i), false)
		result = result..rowTxt
	end
	result = result..'\r\n|}'
	return result
end

function p.getAltSpellsTable(frame)
	local result = '{|class="wikitable sortable"\r\n!colspan="2"|Spell'
	result = result..'!!Requirements'
	result = result..'!!style="width:275px"|Description'
	result = result..'!!Experience'
	result = result..'!!Runes'
	local spellList = {}
	for i, spell in Shared.skpairs(MagicData.AltMagic) do
		local rowTxt = p._getSpellRow(processSpell('AltMagic', i), false)
		result = result..rowTxt
	end
	result = result..'\r\n|}'
	return result
end

return p