Spellhandling and Rotation Quickstart Guide
This guide will walk you through the process of using PAL's spellhandling system to create a combat routine. We'll cover populating the spellbook, creating callbacks for spells, and executing them in your rotation. We'll use an Arcane Mage as our example throughout this guide.
Table of Contents
- Setting Up Your Environment
- Populating the Spellbook
- Creating Spell Callbacks
- Defining Action Lists
- Implementing the Rotation
- Advanced Features
Setting Up Your Environment
First, ensure you have the necessary files set up:
Routines/Mage/Arcane/Spellbook_Arcane.lua
: Spellbook for Arcane MageRoutines/Mage/Arcane/Arcane.lua
: Rotation logic for Arcane Mageroutines.lua
: Update the spec to load your files
In routines.lua
, set up the loading of the files - this is a snippet:
[8] = {
className = "Mage",
basePath = "Routines/Mage/Mage",
specializations = {
[1] = "Routines/Mage/Arcane/Arcane",
[2] = "Routines/Mage/Fire/Fire",
[3] = "Routines/Mage/Frost/Frost"
},
specHelperPaths = {
[1] = {
"Routines/Mage/Arcane/Spellbook_Arcane",
},
[2] = {
"Routines/Mage/Fire/Spellbook_Fire",
},
[3] = {
"Routines/Mage/Frost/Spellbook_Frost",
},
}
},
Populating the Spellbook
In Routines/Mage/Arcane/Spellbook_Arcane.lua
, create spell objects for your Arcane Mage:
local Tinkr = ... ---@type Tinkr
local LT = select(2, ...) ---@type LT
local Routine = Tinkr.Routine
local Exports = Tinkr.Routine.Exports
local mage = LT.spellhandling.spellbooks.mage
local NewSpell = LT.spellhandling.NewSpell
LT.spellhandling.PopulateSpellbook({
ArcaneBlast = NewSpell(30451),
ArcaneMissiles = NewSpell(5143),
ArcaneBarrage = NewSpell(44425),
TouchOfTheMagi = NewSpell(321507),
ArcaneSurge = NewSpell(365350, {ignoreCost = true}),
-- Add more spells as needed
}, "MAGE")
This creates spell objects for each Arcane Mage ability. The NewSpell
function takes a spell ID as its first argument and an optional table of properties as its second argument.
Creating Spell Callbacks
After populating the spellbook, define callbacks for each spell. These callbacks determine when and how each spell should be cast:
mage.ArcaneBlast:Callback(function(spell, unit)
return spell:Cast(unit)
end)
mage.ArcaneMissiles:Callback(function(spell, unit, logic)
if logic == "clearcasting" then
if Exports:buff(mage.Clearcasting.id, "player") then
return spell:Cast(unit)
end
elseif logic == "opener_st" then
if mage.Evocation:wasLastCast() then
item.StatPotionR3:execute("player")
return spell:Cast(unit)
end
end
end)
mage.ArcaneBarrage:Callback(function(spell, unit, logic)
if logic == "max_charges" then
if getArcaneCharges() == 4 then
return spell:Cast(unit)
end
elseif logic == "low_mana" then
if getPlayerManaPercent() < 70 and mage.Evocation:GetCooldown() > 45 then
return spell:Cast(unit)
end
end
end)
-- Add more callbacks for other spells
Callbacks can take additional arguments (like logic
) to define different conditions for casting the same spell.
Defining Action Lists
In Routines/Mage/Arcane/Arcane.lua
, define action lists for different scenarios:
local actionList = {}
actionList.Cooldowns = function()
if mage.ArcaneSurge:execute(target, "burn_phase") then return true end
if mage.TouchOfTheMagi:execute(target, "burn_phase_after_arcane_barrage") then return true end
end
actionList.SingleTarget = function()
if mage.ArcaneBarrage:execute(target, "low_mana") then return true end
if mage.ArcaneMissiles:execute(target, "clearcasting") then return true end
if mage.ArcaneBlast:execute(target) then return true end
end
actionList.AOE = function()
if mage.ArcaneExplosion:execute("player") then return true end
if mage.ArcaneOrb:execute(target) then return true end
-- Add more AOE actions
end
These action lists group related actions together, making the main rotation logic cleaner and more modular.
Implementing the Rotation
Now, implement the main rotation logic:
Routine:RegisterRoutine(function()
if LT.ShouldISkip() or casting() or channeling() then
return true
end
local enemyCount = LT.mobCount(10, target)
if combat() then
if LT.button_CD then
if actionList.Cooldowns() then return true end
end
if enemyCount > 1 and LT.config.read('buttons_multitarget', false) then
return actionList.AOE()
else
return actionList.SingleTarget()
end
end
end, Routine.Classes.Mage, Routine.Specs.Mage.Arcane)
This rotation checks for combat, executes cooldowns if enabled, and then chooses between AOE and single-target rotations based on the number of enemies and user settings.
Advanced Features
Custom Buttons
PAL allows you to create custom buttons for your rotation:
local custom_buttons = {
{
key = "autoDefensives",
buttonname = "autoDefensives",
texture = "spell_arcane_arcaneresilience",
tooltip = "Automatically uses defensives",
text = "Automatically uses defensives",
},
-- Add more custom buttons
}
LT.BuildGUI()
LT.button_factory(custom_buttons)
Defensive Abilities
You can create a separate action list for defensive abilities:
actionList.Defensive = function()
if mage.GreaterInvisibility:execute("heavy_mitigation") then return true end
if mage.PrismaticBarrier:execute(player, "medium_mitigation") then return true end
end
Then, call this action list in your main rotation when appropriate.
By following this guide, you should now have a good understanding of how to use PAL's spellhandling system to create a combat routine. Remember to test your rotation thoroughly and adjust as needed for optimal performance.