Anyone writing their own WoW bot with the intension to do anything beyond simple combat needs to be able to read spell cooldowns, and while there is a LUA function for this in order to get complete stability while calling that one would need to use an EndScene hook and wait for it to be called in order to use the return value. I decided that I wanted to get my returns instantly and did further reversing on the function to write my own for simply checking if a spell is ready. Not all of this information may be correct, so if one of the more experienced members would like to step in then I'd love to be corrected on anything that I **** up. All of this was found from the GetSpellIdByName and CastSpellById LUA functions so I'd encourage you to open up IDA and take a look at them for yourselves so that you know how to update this accross patches
.
WoW stores what seems to be a list of active cooldowns at DS:[1079998h+8], with the relevant offsets for each object being this:
4 - Pointer to the next item in the list, the end of the list is reached if [objBase+4] = 0 or if ([objBase+4] and 1 != 0)
8 - Spell Id attached to the cooldown
0Ch - I'm not entirely sure on this one, however for the player's spells it always seems to be 0, it is returned by a pointer passed to the function that GetSpellIdByName uses if you wanted to look anymore however I haven't bothered
10h - Start time of the cooldown which is internally held by the game in milliseconds. I'll talk more about this later
14h - Total cooldown time of the spell in milliseconds.
24h - Boolean value that tells whether the spell is enabled, 0 if enabled or nonzero if it isn't for. Ex: POM is enabled if the player has the buff, the cooldown hasn't started yet for the spell.
2Ch - Global Cooldown length of the spell (See Gorzul's post below for GCDs)
WoW will remove cooldowns from the list, but they are *not* removed immediately when the cooldown is complete. If the spell cooldown you're looking for isn't in the list then it is ready to be cast, otherwise we need to search the list to see if there are any cooldowns still out on that spell and whether or not they've been completed. First we'll need to get the current time in WoW for a reference point, the function which returns this is at 46E4C0h and from what I can tell is thread safe so you can call it at any time (I could be wrong but I've had no problems). This function will return the time and we can compare that time to the start time of the cooldown + the total time the cooldown takes to see if the cooldown is finished. If we make it all the way through the list without finding any unfinished cooldowns, then the spell is ready and if not then it isn't. I do this in process with the following MASM code (yes I code in assembler, it can't all be easy copypasta) :
Code:
IsSpellReady proc dwSpellId:dword
local dwCurrentTime, dwEndTime:dword
call PerformanceCounter ;declared in .const as dd 46E4C0h
mov dwCurrentTime, eax
mov eax, DS:[1079998h+8]
mov ecx, dwSpellId
@RepeatLoop:
cmp [eax+8], ecx ;SpellId
jnz @NoMatch
cmp dword ptr [eax+0Ch], 0
jnz @NoMatch
mov edx, [eax+10h] ;CD Start
add edx, [eax+14h] ;CD Length
cmp edx, dwCurrentTime
jb @CooldownComplete
xor eax, eax
ret 4
@CooldownComplete:
@NoMatch:
mov eax, [eax+4] ;Get next object pointer
test eax, eax
jz @BreakLoop
test al, 1
jz @RepeatLoop
@BreakLoop:
mov eax, 1
ret 4
IsSpellReady endp
The above code doesn't take into account whether or not the spell is activated, and could be easily changed to return the amount of time left on the cooldown if you so desired.
First time really trying to contribute anything here, hope someone finds it helpful.
Credits: Apoc for the IDA db he posted on 3.1.3 a while back and just about everyone else who has posted info has helped in same way or another so thanks guys
.
-Oowa