Spell_Routines.ini --- Update

Joined
Jun 7, 2007
Messages
816
Reaction score
3
Points
18
Noticed an issue with this nifty include file.

Due to the recent addition of extra gem slots, the current Spell_Routines.ini file needs to have a small change to it in order for it to function again.

I'm pretty sure that Spell_Routines is included in this site's compile, so this change should be reflected asap.

If this thread should be in the compiles area, I apologize and ask that a mod move it there, but i thought that it might belong here.

Line 173:

Code:
/for i 1 to 10

Needs to be changed to:

Code:
/for i 1 to 12

This will allow for gem slot calculation up to current max of 12 gem slots.

Complete updated File:

Code:
| 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|slotID 
|    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] 
|     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                                     | 
| CAST_NOTHOLD         | Spell woundn't take hold on target                                   | 
|----------------------+----------------------------------------------------------------------+ 

#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 NoMount "#*#You can not summon a mount here.#*#" 
#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 12 
  /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]}) { 
    /if (${spellType.Length}==4) /memspell ${spellType.Right[1]} "${spellName}" 
    /if (${spellType.Length}==5) /memspell ${spellType.Right[2]} "${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}>22) { 
  /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}>30) { 
    /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}<23 || !${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_NoMount 
/if (${Defined[castReturn]}) /varset castReturn CAST_NOMOUNT 
/return CAST_NOMOUNT 

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
 
Last edited:
Thanks, updated. Next release (later today/tonight) will include the changed version.

htw
 
Has Spell_routines been updated in are Oct 23rd compile? seeing a updated different one out there.
 
El_Nene posted an updated one over on the VIP forums.
This one works for all my macros so far.
 
El_Nene posted an updated one over on the VIP forums.
This one works for all my macros so far.

Could you link the post thread url... or give the specific subject title of the thread he posted it in ...

Linking the post thread URL is fine.. since you require vip access to bring up the page from the link.. so no harm done posting the link.

Having issues searching for posts by "El_Nene" on the mq2 site ...
 
I don't know how accurate / updated that posted copy is ....

It has the old item data structure .... invslot >21 / Invslot >29 checks.... pre charm item slot addition.

Code:
:cast_item
/if (${FindItem[${spellName}].InvSlot}[COLOR="Lime"]>21[/COLOR]) {
  /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}[COLOR="lime"]>29[/COLOR]) {
    /varset slotName pack8
  } else {
    /varset slotName ${FindItem[${spellName}].InvSlot.Name}
  }
  /varset oldItemName ${InvSlot[${slotName}].Item.Name}
  /call SwapItem "${spellName}" ${slotName}
}

Where my most current version has:

Code:
:cast_item 
/if (${FindItem[${spellName}].InvSlot}[COLOR="Red"]>22[/COLOR]) { 
  /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}[COLOR="red"]>30[/COLOR]) { 
    /varset slotName pack8 
  } else { 
    /varset slotName ${FindItem[${spellName}].InvSlot.Name} 
  } 
  /varset oldItemName ${InvSlot[${slotName}].Item.Name} 
  /call SwapItem "${spellName}" ${slotName} 
}

If I am not mistaken ... the item slot checks had to be increased by 1 to accomodate the additional worn charm slot addition in TSS expansion.

So i'm a little weary as to it's accuracy... unless something changed in HoT to make the 21/29 slot check valid again.

I see his solution to the invslot varient solution... basiclaly looping through all pack containers and opening them to obtain the valid slotid .... with a new K variable for loop... so that temp fix works well until a perm solution is made .... just wondering of he has a oversight to the slot id checks .. or i am missing something.

If anyone has insight into this matter... ( Devestator / JimJohnson / WickedMoFo )... would appreciate input .... I mention their names specifically.. because I have always had the best technical answers provided for my macro / function questions by them.

I'm also following up with el_nene on mq2 site as he posted this version.
 
Last edited:
You cannot depend on constant InvSlot numbers anymore.

Depending on UI, inventory bags opened, bank bags open etc etc you can end up with a primary pack 1 inventory slot having an InvSlot of 0. I've done it.

The entire section of this inc needs to be recoded to take into account non constant InvSlot returns.

I see his solution to the invslot varient solution... basiclaly looping through all pack containers and opening them to obtain the valid slotid .... with a new K variable for loop... so that temp fix works well until a perm solution is made .... just wondering of he has a oversight to the slot id checks .. or i am missing something.

I don't see any accounting for variant InvSlots in that code above, I see constant numbers >22, >30.
 
Last edited:
You cannot depend on constant InvSlot numbers anymore.

Depending on UI, inventory bags opened, bank bags open etc etc you can end up with a primary pack 1 inventory slot having an InvSlot of 0. I've done it.

The entire section of this inc needs to be recoded to take into account non constant InvSlot returns.

I see his solution to the invslot varient solution... basiclaly looping through all pack containers and opening them to obtain the valid slotid .... with a new K variable for loop... so that temp fix works well until a perm solution is made .... just wondering of he has a oversight to the slot id checks .. or i am missing something.

I don't see any accounting for variant InvSlots in that code above, I see constant numbers >22, >30.


I simply didn't post his changes.


NEW
Code:
Sub Cast(spellName,spellType,giveUpValue,mySub,int ResistTotal)
/declare castTime float local
[COLOR="lime"]/declare k int local[/COLOR]
/if (!${Defined[castReturn]}) /declare castReturn string outer CAST_CANCELLED
[COLOR="Lime"]/call DoCastingEvents[/COLOR]
[COLOR="lime"]/varset castReturn X[/COLOR]
/if (${Me.Invis} && ${noInvis}) /return
/if (${spellType.Equal[item]}) {
  /if (!${FindItem[${spellName}].InvSlot}) {
[COLOR="lime"]     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	 /next k
  }
  /if (!${FindItem[${spellName}].InvSlot}) {
     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	 /next k  
	 /return CAST_UNKNOWNSPELL
  }[/COLOR] 
  /varset castTime ${FindItem[${spellName}].CastTime}
} else /if (${spellType.Equal[alt]}) {
  /if (!${Me.AltAbilityReady[${spellName}]}) /return CAST_NOTREADY
  /varset castTime ${Me.AltAbility[${spellName}].Spell.CastTime}
} else {
  /if (!${Me.Book[${spellName}]}) /return CAST_UNKNOWNSPELL
  /declare spellID int local ${Me.Book[${Me.Book[${spellName}]}].ID}
  /varset castTime ${Spell[${spellName}].CastTime}
  /if (${Me.CurrentMana}<${Spell[${spellID}].Mana}) /return CAST_OUTOFMANA
}


OLD
Code:
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.Item.ID}) /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 
}

He is opening the item packs to obtain the slotid.. but as to the previous post i made... he seems to be checking ranges on old worn slots... being 1 value less than what i know to be accurate to accomodate the worn charm slot.

If you are saying that even the slots for worn items are not constant anymore... then that is definately an issue.
 
Last edited:
If you are saying that even the slots for worn items are not constant anymore... then that is definately an issue.

That is exactly what I'm saying:

Depending on UI, inventory bags opened, bank bags open etc etc you can end up with a primary pack 1 inventory slot having an InvSlot of 0. I've done it.

In other words I have managed to make FindItem[].InvSlot return 0 where it used to return 23 for pack1 (And not 0 being NULL, 0 as in /itemnotify 0 leftmouseup picked up the item there).

No .InvSlot can be considered a constant number anymore.
 
Last edited:
I haven't tested this but I think this will work for what that is trying to do:

Code:
Sub ItemCast(spellName,mySub)
/declare charges int local
/declare oldItemName string local
/declare slotName string local
/declare swapItemBack bool local false
/declare needSwap						bool local FALSE
/declare itemInBag					bool local FALSE
/declare eqLoop							int local 0
/declare equippedArray[33]	string local

	/varset equippedArray[1] head
	/varset equippedArray[2] face
	/varset equippedArray[3] neck
	/varset equippedArray[4] rightear
	/varset equippedArray[5] leftear
	/varset equippedArray[6] arms
	/varset equippedArray[7] hands
	/varset equippedArray[8] rightwrist
	/varset equippedArray[9] leftwrist
	/varset equippedArray[10] rightfinger
	/varset equippedArray[11] leftfinger
	/varset equippedArray[12] shoulder
	/varset equippedArray[13] back
	/varset equippedArray[14] chest
	/varset equippedArray[15] waist
	/varset equippedArray[16] legs
	/varset equippedArray[17] feet
	/varset equippedArray[18] mainhand
	/varset equippedArray[19] offhand
	/varset equippedArray[20] ranged
	/varset equippedArray[21] ammo
	/varset equippedArray[22] charm
	/varset equippedArray[23] powersource
	/varset equippedArray[24] pack1
	/varset equippedArray[25] pack2
	/varset equippedArray[26] pack3
	/varset equippedArray[27] pack4
	/varset equippedArray[28] pack5
	/varset equippedArray[29] pack6
	/varset equippedArray[30] pack7
	/varset equippedArray[31] pack8
	/varset equippedArray[32] pack9
	/varset equippedArray[33] pack10
	
:cast_item
/varset spellItemSlot 0
/varset itemInBag TRUE
/varset needSwap FALSE
/varset swapItemBack FALSE
/for eqLoop 1 to 33
	/if (${Me.Inventory[${equippedArray[${eqLoop}]}].ID}==${FindItem[${spellName}].ID} && !${Me.Inventory[${equippedArray[${eqLoop}]}].Container}) {
		/varset itemInBag FALSE
		/varset slotName ${equippedArray[${eqLoop}]}
		/if (${eqLoop}>23 && ${FindItem[${spellName}].WornSlot[1]} && ${FindItem[${spellName}].EffectType.Find[worn]}) {
                        /varset slotName ${FindItem[${spellName}].WornSlot[1].Name}
			/varset swapItemBack TRUE
			/varset needSwap TRUE
		}
	}
/next eqLoop
/if (${itemInBag}) {
	/if (${FindItem[${spellName}].WornSlot[1]} && ${FindItem[${spellName}].EffectType.Find[worn]}) {
	 	/varset slotName ${FindItem[${spellName}].WornSlot[1].Name}
	} else {
		/varset slotName pack8
	}
	/varset swapItemBack TRUE
	/varset needSwap TRUE
}
/if (${needSwap}) {
	/varset oldItemName ${Me.Inventory[${slotName}].Name}
	/call SwapItem "${spellName}" ${slotName}
}
|*/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
/delay 1s ${FindItem[${spellName}].Charges}!=${charges}
/call WaitCast ${mySub}
/call Event_BeginCast
/if (${FindItem[${spellName}].CastTime}<0.5) /delay 5
/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

Also you need to make a small change to SwapItem routine (old line is commented):

Code:
| /delay 5s ${InvSlot[${slotName}].Item.Name.Equal[${itemName}]}
/delay 5s ${Me.Inventory[${slotName}].Name.Equal[${itemName}]}
 
Last edited:
All the test I have done with default UI are solid for this solution. If you tell me an UI that doesnt work with this spell_routines.inc I will try to find a fix for it. But that may also require a change on MQ2 code for FindItem TLO.
 
All the test I have done with default UI are solid for this solution. If you tell me an UI that doesnt work with this spell_routines.inc I will try to find a fix for it. But that may also require a change on MQ2 code for FindItem TLO.


It will not work on my personal custom ui. It depends on the order the windows are loaded when EQ starts and your UI. My hotbar window loads before the Inventory window, and my hotbar has my pack slots on it so I can access them without opening my inventory. Therefore they get asigned the first 10 available InvSlots in the eq memory. At least that is how I understand it to be working, I haven't dug through the code to verify since it's easy enough to work around, just requires adapting.

Test out the code I posted previously, I'm pretty sure it will work for ALL cases, which is what you want on something like this that is going to be used my many different people with many varying configurations. I will test it myself later tonight when I get time if no else has yet.

I do not believe they can do anything in MQ2 FindItem TLO to fix it. At least not with creating a map array just to give the illusion of the equipment InvSlots always being constant (basically what I did with the array in my code previously), and I doubt they would do that.

Dev
 
Ok .. tested the replaced sub itemcast by devestator.


It gave an initial error because the /varset spellitemslot was made with no prior local declare.

Fixed that...

But it would not work ..

I realized the bags were not opening up as intended by the new code ....

So i tried opening all bags first... then that worked... but then it failed to swap the original item back into pack8 slot.


Full code Revisions:

Code:
| 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. 
|
|    ** IMPORTANT:  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|slotID 
|    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] 
|     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                                     | 
| CAST_NOTHOLD         | Spell woundn't take hold on target                                   | 
|----------------------+----------------------------------------------------------------------+ 

#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 NoMount "#*#You can not summon a mount here.#*#" 
#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
/declare k int local
/if (!${Defined[castReturn]}) /declare castReturn string outer CAST_CANCELLED
/call DoCastingEvents
/varset castReturn X
/if (${Me.Invis} && ${noInvis}) /return
/if (${spellType.Equal[item]}) {
  /if (!${FindItem[${spellName}].InvSlot}) {
     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	     /delay 1s
	 /next k
  }
  /if (!${FindItem[${spellName}].InvSlot}) {
     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	     /delay 1s
	 /next k  
	 /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.CastTime}
} else {
  /if (!${Me.Book[${spellName}]}) /return CAST_UNKNOWNSPELL
  /declare spellID int local ${Me.Book[${Me.Book[${spellName}]}].ID}
  /varset castTime ${Spell[${spellName}].CastTime}
  /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
  |---- Spell Gem Slots
  /for i 1 to 12
  /declare spellRecastTime${i} timer outer
  /if (${Me.SpellReady[${i}]}) {
    /varset spellRecastTime${i} 0
  } else {
    /varcalc spellRecastTime${i} 10*${Me.Gem[${i}].RecastTime}
  }
  /next i
  |---- Spell Gem Slots
}
/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
/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]}) {
	/if (${spellType.Length}==4) /memspell ${spellType.Right[1]} "${spellName}" 
	/if (${spellType.Length}==5) /memspell ${spellType.Right[2]} "${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
}
/call Event_BeginCast
/cast "${spellName}"
/if (${Me.Casting.ID}) {
  /varset spellID ${Me.Casting.ID}
  /varcalc castEndTime ${Me.Casting.CastTime}*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
/declare needSwap		bool 	local 	FALSE
/declare itemInBag		bool 	local 	FALSE
/declare eqLoop			int 	local 	0
/declare equippedArray[33]	string 	local
/declare spellItemSlot		string 	local

	/varset equippedArray[1] head
	/varset equippedArray[2] face
	/varset equippedArray[3] neck
	/varset equippedArray[4] rightear
	/varset equippedArray[5] leftear
	/varset equippedArray[6] arms
	/varset equippedArray[7] hands
	/varset equippedArray[8] rightwrist
	/varset equippedArray[9] leftwrist
	/varset equippedArray[10] rightfinger
	/varset equippedArray[11] leftfinger
	/varset equippedArray[12] shoulder
	/varset equippedArray[13] back
	/varset equippedArray[14] chest
	/varset equippedArray[15] waist
	/varset equippedArray[16] legs
	/varset equippedArray[17] feet
	/varset equippedArray[18] mainhand
	/varset equippedArray[19] offhand
	/varset equippedArray[20] ranged
	/varset equippedArray[21] ammo
	/varset equippedArray[22] charm
	/varset equippedArray[23] powersource
	/varset equippedArray[24] pack1
	/varset equippedArray[25] pack2
	/varset equippedArray[26] pack3
	/varset equippedArray[27] pack4
	/varset equippedArray[28] pack5
	/varset equippedArray[29] pack6
	/varset equippedArray[30] pack7
	/varset equippedArray[31] pack8
	/varset equippedArray[32] pack9
	/varset equippedArray[33] pack10
	
:cast_item
/varset spellItemSlot 0
/varset itemInBag TRUE
/varset needSwap FALSE
/varset swapItemBack FALSE
/for eqLoop 1 to 33
	/if (${Me.Inventory[${equippedArray[${eqLoop}]}].ID}==${FindItem[${spellName}].ID} && !${Me.Inventory[${equippedArray[${eqLoop}]}].Container}) {
		/varset itemInBag FALSE
		/varset slotName ${equippedArray[${eqLoop}]}
		/if (${eqLoop}>23 && ${FindItem[${spellName}].WornSlot[1]} && ${FindItem[${spellName}].EffectType.Find[worn]}) {
                        /varset slotName ${FindItem[${spellName}].WornSlot[1].Name}
			/varset swapItemBack TRUE
			/varset needSwap TRUE
		}
	}
/next eqLoop
/if (${itemInBag}) {
	/if (${FindItem[${spellName}].WornSlot[1]} && ${FindItem[${spellName}].EffectType.Find[worn]}) {
	 	/varset slotName ${FindItem[${spellName}].WornSlot[1].Name}
	} else {
		/varset slotName pack8
	}
	/varset swapItemBack TRUE
	/varset needSwap TRUE
}
/if (${needSwap}) {
	/varset oldItemName ${Me.Inventory[${slotName}].Name}
	/call SwapItem "${spellName}" ${slotName}
}
|*/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
/delay 1s ${FindItem[${spellName}].Charges}!=${charges}
/call WaitCast ${mySub}
/call Event_BeginCast
/if (${FindItem[${spellName}].CastTime}<0.5) /delay 5
/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}
/delay 5 ${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}) {
    |---- Inventory Bag Slots
    /for i 1 to 10
    /if (!${InvSlot[pack${i}].Item.Container}) /nomodkey /itemnotify pack${i} leftmouseup
    /next i
    |---- Inventory Bag Slots    
  } else {
    /timed 5 /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}<23 || !${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}]}
/delay 5s ${Me.Inventory[${slotName}].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
/if (${Defined[castReturn]}) /varset castReturn CAST_NOTHOLD
/return

Sub Event_NoLOS
/if (${Defined[castReturn]}) /varset castReturn CAST_CANNOTSEE
/return

Sub Event_NoMount 
/if (${Defined[castReturn]}) /varset castReturn CAST_NOMOUNT 
/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
 
Last edited:
All the test I have done with default UI are solid for this solution. If you tell me an UI that doesnt work with this spell_routines.inc I will try to find a fix for it. But that may also require a change on MQ2 code for FindItem TLO.

I am using default_old from http://www.eqinterface.com/downloads/fileinfo.php?id=4615. The autoupdated from mmo and the one posted by you (el_nene) on mq2 will not work with clicks in bags. Will try the latest one tonight. Any thoughts in the meantime?
 
The /itemnotify pack${k} rightmouseup isn't actually opening the bags.

If i open the bags manually... it works fine to swap out the item and click it ...


But then it never swaps the original item back into the pack8 slot
 
Ok .. tested the replaced sub itemcast by devestator.


It gave an initial error because the /varset spellitemslot was made with no prior local declare.

Fixed that...

But it would not work ..

I realized the bags were not opening up as intended by the new code ....

So i tried opening all bags first... then that worked... but then it failed to swap the original item back into pack8 slot.

You can actually delete out the /varset spellItemSlot line, I deleted the /declare cause I ended up not using it, and just forgot to delete the /varset.


The /itemnotify pack${k} rightmouseup isn't actually opening the bags.

If i open the bags manually... it works fine to swap out the item and click it ...


But then it never swaps the original item back into the pack8 slot

You cannot use /itemnotify packX anymore, for the same reasons as constant InvSlot numbers. The only thing packX or any other word instead of number there did, was associate the word with a given InvSlot value. So pack1 for example would translate to 23, prior to the HoT patch.

You must now do this /itemnotify ${Me.Inventory[packX].InvSlot} rightmouseup

Don't ask me why they could map it there but not anywhere else, I don't know, haven't looked in the code to find out yet.

As for not exchanging the item back, my fault, forgot comment blocks in macros are two stars instead of the standard one.

Delete or change this section in ItemCast.

Code:
|**/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}
}**|
 
Actually, take this entire section out in cast

Code:
/if (!${FindItem[${spellName}].InvSlot}) {
     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	 /next k
  }
  /if (!${FindItem[${spellName}].InvSlot}) {
     /for k 1 to 10
	     /if (${Me.Inventory[pack${k}].ID} && ${Me.Inventory[pack${k}].Container}) /itemnotify pack${k} rightmouseup
	 /next k 
/return CAST_UNKNOWNSPELL
  }

replace it with this:

Code:
     /if (!${FindItem[${spellName}].ID}) {
          /return CAST_UNKNOWNSPELL
     }

No need to open the bags for the purpose of what it's doing. You can get info about any item in your inventory, you just can't get the InvSlot without the bags opened. Don't need the InvSlot to verify you have the item.

Beyond that make sure you are specifying the spell type, from the looks in the code the spell_routines.inc doesn't try to determine the type of spell it is if you don't specify it, it just assumes it is a spell.

If I get time I'll modify it to be more robust and figure out which kind it is, but for now it should work if you make the changes in this post and my last post.
 
Update

Ok devestator:

Made all the changes you specified.

results: It now successfully finds the item in my bag ... swaps it out to free inventory space pack8 ... casts the effect off the item clicky.

However... it does not return the item back to the original slot inside the bag it took it out of. The item remains in pack8.

If i initiate another item cast for a different item... ( first one was for skinspikes... this one now is for haste potion) ... it swaps out the skinspikes potion for the alclarity potion in the pakc8... casts it... but still leaves it in pack8 without swapping back the item that was formerly there ( the skinspikes potion).

Certainly is a big improvement .. and i could live with it for now... but would realy like to get it to return / swap out the item after clicky use for the item that was originally in pack8 before the swap occured. Or place the item back in its original pack and leave pack8 empty if it was empty before the transaction. (put it back where it belongs )
 
Last edited:
Ok devestator:

Made all the changes you specified.

results: It now successfully finds the item in my bag ... swaps it out to free inventory space pack8 ... casts the effect off the item clicky.

However... it does not return the item back to the original slot inside the bag it took it out of. The item remains in pack8.

If i initiate another item cast for a different item... ( first one was for skinspikes... this one now is for haste potion) ... it swaps out the skinspikes potion for the alclarity potion in the pakc8... casts it... but still leaves it in pack8 without swapping back the item that was formerly there ( the skinspikes potion).

Certainly is a big improvement .. and i could live with it for now... but would realy like to get it to return / swap out the item after clicky use for the item that was originally in pack8 before the swap occured. Or place the item back in its original pack and leave pack8 empty if it was empty before the transaction. (put it back where it belongs )

It sounds like you didn't remove the section between |* and *| in itemcast. That is what was breaking the swapping back because it should have been |** **|