Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
| spell_routines.inc v2.4
| Originally Written by Rusty~
| Upkeep performed by A_Druid_00
| Includes MQ2Exchange integration for item swapping by BrainDeath
| Also includes FD fix that would cause an endless loop if you were hit by FD mid-cast by A_Druid_00
| Features:
| - Casts spells, clicks items, or uses AA abilities for you
| - Allows back to back casting without waiting on spell gems to pop all the way up
| - Will interrupt spell if target dies while casting. If on a mount, it will dismount and duck if the time left
| is greater than 7 seconds, else it will move forward a bit to interrupt, then move you back
| ** IMPORTANT: if you don't want to interrupt a spell while mounted, put this at the top of your macro: **
| ** /declare noInterrupt int outer 1 **
| - Allows you to use items in bags. Equips item, clicks it, then returns it to its previous location
| - Lets you set how long you want to keep trying to cast the spell (defaults to 0)
| If the spell is interrupted before the given time, it will recast, else it will return CAST_INTERRUPTED
| - Lets you call a custom subroutine while waiting for spell to finish casting
| Try to keep custom subroutines very small. A common use would be to interrupt the spell if a certain condition is true
| - This file also includes a sub named Interrupt. You can call this to interrupt any spell you're casting instantly.
| - You can also use the SwapItem sub included in this to swap items to certain slots
| - Added EquipItem sub to easily equip items in your main Inventory slots.
| - Note: if you don't want this to cast spells while you're invis, in your main macro have this at the top:
| /declare noInvis int outer 1
| This will make it return CAST_INVIS if you're invis
| Below is a list of outer scope variables you can access in your macros:
| refreshTime - How much time is left till you're done recovering from casting
| castEndTime - How much time left till you're done casting the current spell... usable in custom spell Subs
| spellNotHold - 1 if your last spell didn't take hold, 0 otherwise
| spellRecastTime1-9 - How much time left till that spell is back up
|======================================================================================================================
| EquipItem: An easier way to equip items you have in bags ( useful for weapons or focus items )
| slot name is optional. If not given, it will equip it in the first possible spot
| Usage:
| /call EquipItem "item name|slotname"
| Returns: "old item name|slotname"
| Examples:
| To Equip Sharp Ended Broken Lever when you have Serpent of Vindication equiped:
| /call EquipItem "Sharp Ended Broken Lever"
| It will return "Staff of Vindication|mainhand"
| To reequip the original item, you can save the return in a variable, and then use it later like this:
| /varset oldPrimary ${Macro.Return}
| | ... do stuff here with your new item equiped
| /call EquipItem ${oldPrimary}
|======================================================================================================================
| SwapItem: a subroutine which is used in the Cast sub itself. You don't need to do this to cast an item in a bag
| but you can call it in your macro to SwapItems (such as weapons or focus items)
| Usage:
| /call SwapItem "item name" slotname
| Examples:
| To swap Darkblade of the Warlord to your main hand:
| /call SwapItem "Darkblade of the Warlord" mainhand
| To swap stat food in one bag with other food in another bag:
| /call SwapItem "Bristlebanes Party Platter" ${FindItem[halas 10lb meat pie].InvSlot}
|======================================================================================================================
| Cast: the main subroutine that casts spells or items for you
| Usage:
| /call Cast "spellname|itemname|AAname|AA#" [item|alt|gem#] [give up time][s|m] [custom subroutine name] [Number of resist recasts]
| Examples:
| To cast Howl of Tashan and mem it in slot 3 if not memmed:
| /call Cast "Howl of Tashan" gem3
| To cast Arcane Rune and keep trying for 7 seconds, in case of interrupts.
| /call Cast "Arcane Rune" gem5 7s
| To click Grim Aura earring that's in a bag:
| /call Cast "Shrunken Goblin Skull Earring" item
| To use AA ability Eldritch Rune:
| /call Cast "Eldritch Rune" alt
| or
| /call Cast "173" alt
| To call a subroutine that interrupts CH if target gets healed before it lands:
| /call Cast "Complete Healing" gem1 0 CheckHP
| Then in your macro have somewhere:
| Sub CheckHP
| /if ( ${Target.PctHPs}>=80 ) /call Interrupt
| /return
| Returns these values:
|----------------------+----------------------------------------------------------------------+
| CAST_CANCELLED | Spell was cancelled by ducking (either manually or because mob died) |
| CAST_CANNOTSEE | You can't see your target |
| CAST_IMMUNE | Target is immune to this spell |
| CAST_INTERRUPTED | Casting was interrupted and exceeded the given time limit |
| CAST_INVIS | You were invis, and noInvis is set to true |
| CAST_NOTARGET | You don't have a target selected for this spell |
| CAST_NOTMEMMED | Spell is not memmed and you gem to mem was not specified |
| CAST_NOTREADY | AA ability or spell is not ready yet |
| CAST_OUTOFMANA | You don't have enough mana for this spell! |
| CAST_OUTOFRANGE | Target is out of range |
| CAST_RESISTED | Your spell was resisted! |
| CAST_SUCCESS | Your spell was cast successfully! (yay) |
| CAST_UNKNOWNSPELL | Spell/Item/Ability was not found |
|----------------------+----------------------------------------------------------------------+
#event BeginCast "You begin casting#*#"
#event Collapse "Your gate is too unstable, and collapses.#*#"
#event FDFail "#1# has fallen to the ground.#*#"
#event Fizzle "Your spell fizzles#*#"
#event Immune "Your target is immune to changes in its attack speed#*#"
#event Immune "Your target is immune to changes in its run speed#*#"
#event Immune "Your target cannot be mesmerized#*#"
#event Interrupt "Your casting has been interrupted#*#"
#event Interrupt "Your spell is interrupted#*#"
#event NoHold "Your spell did not take hold#*#"
#event NoHold "Your spell would not have taken hold#*#"
#event NoHold "You must first target a group member#*#"
#event NoHold "Your spell is too powerful for your intended target#*#"
#event NoLOS "You cannot see your target.#*#"
#event NoTarget "You must first select a target for this spell!#*#"
#event NotReady "Spell recast time not yet met.#*#"
#event OutOfMana "Insufficient Mana to cast this spell!#*#"
#event OutOfRange "Your target is out of range, get closer!#*#"
#event Recover "You haven't recovered yet...#*#"
#event Recover "Spell recovery time not yet met#*#"
#event Resisted "Your target resisted the #1# spell#*#"
#event Resisted2 "You resist the #1# spell#*#"
#event Standing "You must be standing to cast a spell#*#"
#event Stunned "You are stunned#*#"
#event Stunned "You can't cast spells while stunned!#*#"
#event Stunned "You *CANNOT* cast spells, you have been silenced!#*#"
Sub Cast(spellName,spellType,giveUpValue,mySub,int ResistTotal)
/declare castTime float local
/if (!${Defined[castReturn]}) /declare castReturn string outer CAST_CANCELLED
/if (${Me.Invis} && ${noInvis}) /return
/if (${spellType.Equal[item]}) {
/if (!${FindItem[${spellName}].InvSlot}) /return CAST_UNKNOWNSPELL
/varset castTime ${FindItem[${spellName}].CastTime}
} else /if (${spellType.Equal[alt]}) {
/if (!${Me.AltAbilityReady[${spellName}]}) /return CAST_NOTREADY
/varset castTime ${Me.AltAbility[${spellName}].Spell.MyCastTime}
} else {
/if (!${Me.Book[${spellName}]}) /return CAST_UNKNOWNSPELL
/declare spellID int local ${Me.Book[${Me.Book[${spellName}]}].ID}
/varset castTime ${Spell[${spellName}].MyCastTime}
/if (${Me.CurrentMana}<${Spell[${spellID}].Mana}) /return CAST_OUTOFMANA
}
/if (${castTime}>0.1) {
/if (${Stick.Status.Equal[ON]}) /stick pause
/if (${FollowFlag}) /call PauseFunction
/if (${Me.Moving}) /keypress back
}
/if (!${Defined[spellType]}) /declare spellType string local spell
/if (!${Defined[spellRecastTime1]}) {
/if (!${Defined[noInterrupt]}) /declare noInterrupt int outer 0
/declare ResistCounter int outer
/declare moveBack bool outer false
/declare selfResist int outer
/declare selfResistSpell string outer
/declare giveUpTimer timer outer
/declare castEndTime timer outer
/declare refreshTime timer outer
/declare itemRefreshTime float outer
/declare i int local
/declare spellNotHold int outer
/delay 5
/for i 1 to 9
/declare spellRecastTime${i} timer outer
/if (${Me.SpellReady[${i}]}) {
/varset spellRecastTime${i} 0
} else {
/varcalc spellRecastTime${i} 10*${Me.Gem[${i}].RecastTime}
}
/next i
}
/if (${Defined[giveUpValue]}) /varset giveUpTimer ${giveUpValue}
/if (${Defined[ResistTotal]}) /varset ResistCounter ${ResistTotal}
/varset spellNotHold 0
/varset selfResist 0
:wait_for_stop
/if (${Me.Casting.ID} || (${Me.Moving} && ${castTime}>0.1)) {
/if (${Bool[${mySub}]}) /call ${mySub} ${spellID}
/goto :wait_for_stop
}
/if (${Window[SpellBookWnd].Open}) /keypress spellbook
/if (${Me.Ducking}) /keypress duck
/call DoCastingEvents
/varset castReturn X
/if (${spellType.Equal[item]}) /call ItemCast "${spellName}" "${mySub}"
/if (${spellType.Equal[alt]}) /call AltCast "${spellName}" "${mySub}"
/if (${spellType.NotEqual[item]} && ${spellType.NotEqual[alt]}) /call SpellCast "${spellType}" "${spellName}" "${mySub}" "${spellID}" "${giveUpValue}"
/if (${Stick.Status.Equal[PAUSED]}) /squelch /stick unpause
/if (${PauseFlag}) /call PauseFunction
/varset giveUpTimer 0
/varset ResistCounter 0
/return ${castReturn}
Sub SpellCast(spellType,spellName,mySub,int spellID,giveUpValue)
:cast_spell
/if (!${Me.Gem[${spellName}]}) {
/if (${Cursor.ID}) /call ClearCursor
/if (${spellType.Left[3].Equal[gem]}) {
/memspell ${spellType.Right[1]} "${spellName}"
} else {
/return CAST_NOTMEMMED
}
/if (${Bool[${mySub}]}) /call ${mySub} ${spellID}
/delay 6s ${Me.Gem[${spellName}]}
/if (${Me.Gem[${spellName}]}) /varcalc spellRecastTime${Me.Gem[${spellName}]} 10*${Spell[${spellID}].RecastTime}
/if (!${Me.Gem[${spellName}]}) /return CAST_INTERRUPTED
:wait_for_mem
/if (${Bool[${mySub}]}) /call ${mySub} ${spellID}
/delay 15s ${Me.SpellReady[${spellName}]}
/if (!${Me.SpellReady[${spellName}]}) {
/if (${giveUpTimer}) /goto :wait_for_mem
/return CAST_NOTREADY
}
}
/varset spellType spell
/if (${spellName.Find[illusion: ]} && ${Me.AltAbilityReady[project illusion]}) /call Cast "project illusion" alt
/varset giveUpTimer ${giveUpValue}
/declare recoverWaitTime timer local 30
:cast_spell_loop
/if (!${Me.SpellReady[${spellName}]} && (${spellRecastTime${Me.Gem[${spellName}]}}<${giveUpTimer} || ${refreshTime}>0 || ${castReturn.Equal[CAST_RESISTED]})) {
/if (${Bool[${mySub}]}) /call ${mySub} ${spellID}
/goto :cast_spell_loop
} else {
/if (!${Me.SpellReady[${spellName}]} && !${castReturn.Equal[CAST_RESISTED]}) /return CAST_NOTREADY
}
/cast "${spellName}"
/if (${Me.Casting.ID}) {
/varset spellID ${Me.Casting.ID}
/varcalc castEndTime ${Me.Casting.MyCastTime}*10
/if (${castEndTime}<${Math.Calc[${Me.Casting.CastTime}*5]}) /varcalc castEndTime ${Me.Casting.CastTime}*5
}
/varset moveBack false
/call WaitCast ${mySub} ${spellID}
/if (${moveBack}) {
/keypress back hold
/delay 4
/keypress back
/delay 15 !${Me.Moving}
}
/if (${castReturn.Equal[CAST_CANCELLED]}) /return CAST_CANCELLED
/call DoCastingEvents
/if (!${castReturn.Equal[CAST_SUCCESS]}) {
/if (${castReturn.Equal[CAST_RECOVER]}) {
/if (!${recoverWaitTime}) {
/varcalc spellRecastTime${Me.Gem[${spellName}]} 10*${Spell[${spellID}].RecastTime}
/if (!${giveUpTimer}) /return CAST_NOTREADY
}
/goto :cast_spell_loop
}
/if (${castReturn.Equal[CAST_RESTART]} || ${castReturn.Equal[CAST_STUNNED]} || ${castReturn.Equal[CAST_FIZZLE]} || ${castReturn.Equal[CAST_COLLAPSE]} || (${castReturn.Equal[CAST_INTERRUPTED]} && ${giveUpTimer}) || (${castReturn.Equal[CAST_RESISTED]} && ${ResistCounter})) /goto :cast_spell_loop
}
/if (!${castReturn.Equal[CAST_CANNOTSEE]} && !${castReturn.Equal[CAST_OUTOFRANGE]} && !${castReturn.Equal[CAST_OUTOFMANA]} && !${castReturn.Equal[CAST_NOTARGET]} && !${castReturn.Equal[CAST_INTERRUPTED]}) {
/varcalc refreshTime 10*${Spell[${spellID}].RecoveryTime}
/varcalc spellRecastTime${Me.Gem[${spellName}]} 10*${Spell[${spellID}].RecastTime}
}
/return
Sub ItemCast(spellName,mySub)
/declare charges int local
/declare oldItemName string local
/declare slotName string local
/declare swapItemBack bool local false
:cast_item
/if (${FindItem[${spellName}].InvSlot}>21) {
/varset swapItemBack true
/if (${FindItem[${spellName}].WornSlot[1]} && ${FindItem[${spellName}].EffectType.Find[worn]}) {
/varset slotName ${FindItem[${spellName}].WornSlot[1].Name}
} else /if (${FindItem[${spellName}].InvSlot}>29) {
/varset slotName pack8
} else {
/varset slotName ${FindItem[${spellName}].InvSlot.Name}
}
/varset oldItemName ${InvSlot[${slotName}].Item.Name}
/call SwapItem "${spellName}" ${slotName}
}
:wait_item_loop
/if (${itemRefreshTime}>${MacroQuest.Running}) /goto :wait_item_loop
/varset itemRefreshTime ${Math.Calc[${MacroQuest.Running}+000]}
/varset charges ${FindItem[${spellName}].Charges}
/cast item "${spellName}"
/if (${Me.Casting.ID}) /varcalc castEndTime ${FindItem[${spellName}].CastTime}*10
/if (${charges}) /delay 1s ${FindItem[${spellName}].Charges}!=${charges}
/call WaitCast ${mySub}
/if (${swapItemBack} && ${FindItem[${oldItemName}].ID}) /call SwapItem "${oldItemName}" ${slotName}
/if (${castReturn.Equal[CAST_CANCELLED]}) /return CAST_CANCELLED
/call DoCastingEvents
/if (${castReturn.Equal[CAST_RESTART]} || ${castReturn.Equal[CAST_STUNNED]} || (${castReturn.Equal[CAST_INTERRUPTED]} && ${giveUpTimer}) || ${castReturn.Equal[CAST_COLLAPSE]} || (${castReturn.Equal[CAST_RESISTED]} && ${ResistCounter})) /goto :cast_item
/return
Sub AltCast(spellName,mySub)
:cast_alt
/alt activate ${Me.AltAbility[${spellName}].ID}
/if (${Me.AltAbility[${spellName}].Spell.MyCastTime}>=0.5) /delay 1s ${Me.Casting.ID}
/call WaitCast ${mySub}
/if (${castReturn.Equal[CAST_CANCELLED]}) /return CAST_CANCELLED
/call DoCastingEvents
/if (${castReturn.Equal[CAST_RESTART]} || ${castReturn.Equal[CAST_STUNNED]} || (${castReturn.Equal[CAST_INTERRUPTED]} && ${giveUpTimer}) || (${castReturn.Equal[CAST_RESISTED]} && ${ResistCounter})) /goto :cast_alt
/return
Sub ClearCursor
/declare i int local
:auto_inv
/if (${Cursor.ID}) {
/if (${Cursor.Container}) {
/for i 1 to 8
/if (!${InvSlot[pack${i}].Item.Container}) /nomodkey /itemnotify pack${i} leftmouseup
/next i
} else {
/autoinventory
}
/goto :auto_inv
}
/return
Sub DoCastingEvents
/doevents Recover
/doevents BeginCast
/doevents Fizzle
/doevents Interrupt
/doevents Standing
/doevents FDFail
/doevents OutOfRange
/doevents OutOfMana
/doevents NoLOS
/doevents Resisted2
/doevents Resisted
/doevents Immune
/doevents Stunned
/doevents Collapse
/doevents NoTarget
/doevents NotReady
/doevents NoHold
/return
Sub EquipItem(WhatWhere)
/declare DestName string local
/declare ItemName string local ${WhatWhere.Arg[1,|]}
/declare SlotName string local ${WhatWhere.Arg[2,|]}
/if (${SlotName.Equal[NULL]}) /varset SlotName ${InvSlot[${FindItem[=${ItemName}].WornSlot[1]}].Name}
/if (${FindItem[=${ItemName}].InvSlot}<22 || !${FindItem[=${ItemName}].WornSlot[${SlotName}]}) /return
/if (!${InvSlot[${SlotName}].Item.Name.Equal[NULL]}) /varset DestName "${InvSlot[${SlotName}].Item.Name}|${SlotName}"
/call SwapItem "${ItemName}" "${SlotName}"
/return ${DestName}
Sub Interrupt
/if (${Me.Mount.ID}) /dismount
/stopcast
/if (${Defined[castReturn]}) /varset castReturn CAST_CANCELLED
/return ${castReturn}
Sub SwapItem(itemName,slotName)
/declare i int local
/if (${Cursor.ID}) /call ClearCursor
/exchange "${itemName}" ${slotName}
/delay 5s ${InvSlot[${slotName}].Item.Name.Equal[${itemName}]}
/if (${Cursor.ID}) /call ClearCursor
/return
Sub WaitCast(mySub,int spellID)
/declare currentTarget int local ${Target.ID}
/declare currentTargetType string local ${Target.Type}
:wait_cast_loop
/if (${Bool[${mySub}]}) /call ${mySub} ${spellID}
/if (${Me.Casting.ID}) {
/if (${currentTarget} && !${Spawn[${currentTarget}].Type.Equal[${currentTargetType}]}) {
/if (!${Me.Casting.TargetType.Equal[PB AE]} && !${Me.Casting.TargetType.Equal[self]} && !${moveBack} && (!${Me.Mount.ID} || !${noInterrupt})) {
/if (!${Me.Mount.ID} || ${castEndTime}>70) {
/call Interrupt
} else /if (${Me.Casting.RecastTime}>3) {
/varset castReturn CAST_CANCELLED
/keypress forward hold
/delay 6
/keypress forward
/varset moveBack true
}
}
}
/if (${Me.State.Equal[DUCK]}) /varset castReturn CAST_CANCELLED
/goto :wait_cast_loop
}
/return
Sub Event_BeginCast
/if (${Defined[castReturn]}) /varset castReturn CAST_SUCCESS
/return
Sub Event_Collapse
/if (${Defined[castReturn]}) /varset castReturn CAST_COLLAPSE
/varset giveUpTimer 200
/return
Sub Event_FDFail(line,name)
/if (${name.Equal[${Me.Name}]} && ${Defined[castReturn]}) {
/if (!${Me.Standing}) /stand
/varset castReturn CAST_RESTART
}
/return
Sub Event_Fizzle
/if (${Defined[castReturn]}) /varset castReturn CAST_FIZZLE
/return
Sub Event_Immune
/if (${Defined[castReturn]}) /varset castReturn CAST_IMMUNE
/return
Sub Event_Interrupt
/if (${Defined[castReturn]}) /varset castReturn CAST_INTERRUPTED
/return
Sub Event_NoHold
/if (${Defined[spellNotHold]}) /varset spellNotHold 1
/return
Sub Event_NoLOS
/if (${Defined[castReturn]}) /varset castReturn CAST_CANNOTSEE
/return
Sub Event_NoTarget
/if (${Defined[castReturn]}) /varset castReturn CAST_NOTARGET
/return
Sub Event_NotReady
/if (${Defined[castReturn]}) /varset castReturn CAST_NOTREADY
/return
Sub Event_OutOfMana
/if (${Defined[castReturn]}) /varset castReturn CAST_OUTOFMANA
/return
Sub Event_OutOfRange
/if (${Defined[castReturn]}) /varset castReturn CAST_OUTOFRANGE
/return
Sub Event_Recover
/if (${Defined[castReturn]}) /varset castReturn CAST_RECOVER
/return
Sub Event_Resisted(line,name)
/if (${selfResist} && ${name.Equal[${selfResistSpell}]}) /varset selfResist 0
/if (${ResistCounter}) /varcalc ResistCounter ${ResistCounter}-1
/if (${Defined[castReturn]}) /varset castReturn CAST_RESISTED
/return
Sub Event_Resisted2(line,name)
/if (${Defined[selfResist]}) {
/varset selfResist 1
/varset selfResistSpell ${name}
}
/return
Sub Event_Standing
/stand
/if (${Defined[castReturn]}) /varset castReturn CAST_RESTART
/return
Sub Event_Stunned
/if (${Me.Stunned}) {
/delay 3s !${Me.Stunned}
} else {
/delay 7
}
/if (${Defined[castReturn]}) /varset castReturn CAST_STUNNED
/return