PDA

View Full Version : Spell Cycle Script



Ether Rael
04-21-2011, 11:22 PM
Here's some of the spell cycling stuff I've been playing with:

edit: requires AutohotKey_L - updated version with basic object support
http://www.autohotkey.net/~Lexikos/AutoHotkey_L/AutoHotkey_L_Install.exe

Main script
http://dl.dropbox.com/u/24189082/SpellBound.ahk

Support file
http://dl.dropbox.com/u/24189082/Array.ahk

(both required).

Run SpellBound.ahk, it will rebind a few keys, code pasted below for inspection and commentary :D



#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#InstallKeybdHook ;mouse and keyb performance
#InstallMouseHook
#Include Array.ahk ;library for array management - pretty poor but works (indexed from 1, not 0)
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

; location of currently selected skill. Used to check cooldown state
; use the MousePointerDebug function to get values for this (alt-b currently)
; todo: replace with image search technique
CurrentSkillX := 34
CurrentSkillY := 416
; how long to wait before resetting a cycle back to zero
CycleResetTime := 5000

; objects provide an associative array interface (requires AutoHotKey_L)
spells := Object()
skills := Object()

; Binds

; Shift = +, Ctrl = ^, Alt = !
; I have bound hotbars 6-10 to variations of the same keybinds
; todo: Use sinister technique to inspect df config and build bind/spell/skill list automatically

skills["whirlwind_greatsword"] := Object("key", "^!p")
skills["knockback_greatsword"] := Object("key", "^!{]}")
skills["power_attack_greatsword"] := Object("key", "^!o")
skills["disabling_blow_greatsword"] := Object("key", "^!{[}")

spells["pungent_mist"] := Object("key", "!{]}")
spells["impale"] := Object("key", "!{[}")
spells["unholy_caress"] := Object("key", "!p")
spells["lightning_bolt"] := Object("key", "!o")
spells["dragon_breath"] := Object("key", "!i")
spells["frost_bite"] := Object("key", "!+4")

spells["lay_on_hands"] := Object("key", "+y")
spells["heal_other"] := Object("key", "+t")
spells["sacrifice"] := Object("key", "+r")
spells["witches_brew"] := Object("key", "+u")

; keep track of what's been fired and when
cycle_fires := Object()
cycle_indexes := Object()

; Create and bind your cycles here
ray_cycle := SetupCycle(Array("impale", "pungent_mist", "frost_bite", "dragon_breath", "unholy_caress", "lightning_bolt"))
heal_other_cycle := SetupCycle(Array("heal_other", "sacrifice", "witches_brew", "lay_on_hands"))

; hotkeys
; plain fast loop through spells, no autoclicking
+f::CycleSpells(ray_cycle, false)

f::
; switch to staff before firing rays - see IMPORTANT below
if(current_weap <> "staff")
SwitchToStaff()
; could write a SwitchToSlowStaff() function
; try to fire the selected spell
CycleSpells(ray_cycle, true)
Return

; optional alt-use key
q::
if (current_weap = "staff")
CycleSpells(heal_other_cycle, false)
else
SelectSpell(skills["whirlwind_greatsword"])
Return

F12::Suspend

; IMPORTANT - i globally bind 1-3 for weapon switching so that AHK 'knows' my weap
; this means if you change weap by selecting in backpack, you need to hit the key for it
; each of the SwitchToX functions further down has the keybind in there, edit to suit
; if you don't want to use this script to manage weaps, delete these binds and the switching functions
; CycleSpells willwork without it
current_weap := "staff"

1::SwitchToStaff()
2::SwitchToSword()
!2::SwitchToShield()
3::SwitchToBow()
; delete above if not using weap tracking

; functions - can tweak Sleep timings in here
SelectSpell(ByRef spell)
{
key := spell.key
Send %key%
Sleep, 100
}

SwitchToStaff()
{
global
current_weap := "staff"
Send, +{]}
Sleep, 100
}

SwitchToSword()
{
global
current_weap := "greatsword"
Send, +{[}
Sleep, 100
}

SwitchToShield()
{
global
current_weap := "shield"
Send, +o
Sleep, 1000
Send, +i
Sleep, 200
}

SwitchToBow()
{
global
current_weap := "bow"
Send, +p
Sleep, 100
}

; initializes the global state tracking for a cycle
; array_of_titles is a list of strings which will be used to find the spell objects
SetupCycle(array_of_titles)
{
global
spell_string := array_of_titles.join("_")
cycle_indexes[spell_string] := 1
cycle_fires[spell_string] := 1
return array_of_titles
}

; spells_to_cycle is an array of spell names corresponding to the Objects at the top of the script
; click_spell boolean (true/false) whether to click the selected spell or not
CycleSpells(ByRef spells_to_cycle, ByRef click_spell)
{
global
spell_string := spells_to_cycle.join("_")
current_index := cycle_indexes[spell_string]
time_since_last := A_TickCount - (cycle_fires[spell_string])

; reset the cycle?
if (time_since_last > CycleResetTime)
{
current_index = 1
}

spell := spells[spells_to_cycle[current_index]]
SelectSpell(spell)
if (click_spell)
{
Click
Sleep, 500
; i have this at 1000 to allow for GCD on rays
}

; update globals for this cycle so we know where we are
; loop if we're at the end of a cycle. 1-based arrays are shit!
cycle_indexes[spell_string] := (current_index = (spells_to_cycle.len())) ? 1 : (current_index + 1)
cycle_fires[spell_string] := A_TickCount
}

; switch to staff ready for weap tracking and skill learning
SwitchToStaff()

Jake Dane
04-21-2011, 11:25 PM
Will definitely have a go with this. Awesome work! :D

Ether Rael
04-21-2011, 11:27 PM
Um noticed bits of code referring to stuff I haven't included in that version, so mine is here (it's got some experimental stuff im working on to detect spell availability). I'd like to move to a timing-based approach though, cos I think pixel searching is a bad idea during combat.




#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#InstallKeybdHook ;mouse and keyb performance
#InstallMouseHook
#Include Array.ahk ;library for array management - pretty poor but works
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

; location of currently selected skill. Used to check cooldown state
; use the MousePointerDebug function to get values for this (alt-b currently)
; todo: replace with image search technique
CurrentSkillX := 34
CurrentSkillY := 416
CycleResetTime := 3000

; objects provide an associative array interface (requires AutoHotKey_L)
spells := Object()
skills := Object()

; Shift = +, Ctrl = ^, Alt = !
; I have bound hotbars 6-10 to variations of the same keybinds
; todo: Use sinister technique to inspect df config and build bind/spell/skill list automatically

skills["whirlwind_greatsword"] := Object("key", "^!p")
skills["knockback_greatsword"] := Object("key", "^!{]}")
skills["power_attack_greatsword"] := Object("key", "^!o")
skills["disabling_blow_greatsword"] := Object("key", "^!{[}")

spells["lay_on_hands"] := Object("key", "+y")
spells["heal_other"] := Object("key", "+t")
spells["sacrifice"] := Object("key", "+r")
spells["witches_brew"] := Object("key", "+u")

spells["pungent_mist"] := Object("key", "!{]}")
spells["impale"] := Object("key", "!{[}")
spells["unholy_caress"] := Object("key", "!p")
spells["lightning_bolt"] := Object("key", "!o")
spells["dragon_breath"] := Object("key", "!i")
spells["frost_bite"] := Object("key", "!+4")
spells["fireball"] := Object("key", "!u")
spells["inferno"] := Object("key", "!y")
spells["magma_storm"] := Object("key", "!t")
spells["wall_of_fire"] := Object("key", "!r")
spells["cursed_bolt"] := Object("key", "!e")

spells["shrapnel"] := Object("key", "!{=}")
spells["wall_of_force"] := Object("key", "!{-}")
spells["launch"] := Object("key", "!0")
spells["confusion"] := Object("key", "!9")
spells["come_hither"] := Object("key", "!8")
spells["begone"] := Object("key", "!7")
spells["telekinesis"] := Object("key", "!6")
spells["gills"] := Object("key", "!5")
spells["lend_mana"] := Object("key", "!4")
spells["heal_mount"] := Object("key", "!3")

spells["hymn_of_vigor"] := Object("key", "+!{]}")
spells["hymn_of_might"] := Object("key", "+!{[}")
spells["hymn_of_skill"] := Object("key", "+!p")
spells["hymn_of_swiftness"] := Object("key", "+!o")
spells["fire_ward"] := Object("key", "+!i")
spells["acid_ward"] := Object("key", "+!u")
spells["haste"] := Object("key", "+!y")
spells["rapid_shot"] := Object("key", "+!t")
spells["arrow_ward"] := Object("key", "+!r")
spells["ironskin"] := Object("key", "+!e")

spells["pestilence"] := Object("key", "!{\}")
spells["weakening_blaze"] := Object("key", "!{'}")
spells["evil_eye"] := Object("key", "!{;}")
spells["slashing_weakness"] := Object("key", "!l")
spells["stupidity"] := Object("key", "!k")
spells["sluggish"] := Object("key", "!j")
spells["disease"] := Object("key", "!h")
spells["desecration"] := Object("key", "!g")
spells["piercing_weakness"] := Object("key", "!f")

spells["hasten_spells"] := Object("key", "+!{=}")
spells["unburden"] := Object("key", "+!{-}")
spells["adept"] := Object("key", "+!0")
spells["stoneskin"] := Object("key", "+!9")
spells["brawn"] := Object("key", "+!8")
spells["impetus"] := Object("key", "+!7")
spells["agility"] := Object("key", "+!6")
spells["max_stamina_bonus"] := Object("key", "+!5")


cycle_fires := Object()
cycle_indexes := Object()

ray_cycle := SetupCycle(Array("impale", "pungent_mist", "frost_bite", "dragon_breath", "unholy_caress", "lightning_bolt"))
heal_other_cycle := SetupCycle(Array("heal_other", "sacrifice", "witches_brew", "lay_on_hands"))
nuke_cycle := SetupCycle(Array("magma_storm", "inferno", "fireball", "wall_of_fire", "cursed_bolt"))
util_cycle := SetupCycle(Array("shrapnel", "wall_of_force", "launch", "confusion", "come_hither", "begone", "telekinesis", "gills", "lend_mana", "heal_mount"))
buff_other_cycle := SetupCycle(Array("ironskin","haste", "rapid_shot","hymn_of_vigor", "hymn_of_might", "hymn_of_skill", "hymn_of_swiftness", "fire_ward", "acid_ward", "arrow_ward"))
debuff_cycle := SetupCycle(Array("pestilence", "weakening_blaze", "evil_eye", "slashing_weakness", "stupidity", "sluggish", "desecration", "piercing_weakness"))
buff_cycle := SetupCycle(Array("hasten_spells", "unburden", "adept", "stoneskin", "brawn", "impetus", "agility", "max_stamina_bonus"))


f::
if(current_weap <> "staff")
SwitchToStaff()
CycleSpells(ray_cycle, true, true)
Return

+f::CycleSpells(ray_cycle, false, false)
q::
if (current_weap = "staff")
CycleSpells(heal_other_cycle, false, false)
else
SelectSpell(skills["whirlwind_greatsword"])
Return
e::
if (current_weap = "staff")
CycleSpells(nuke_cycle, false, true)
else
SelectSpell(skills["knockback_greatsword"])
Return
v::
if (current_weap = "staff")
CycleSpells(debuff_cycle, false, false)
else
SelectSpell(skills["power_attack_greatsword"])
Return
+e::
if(current_weap = "staff")
CycleSpells(nuke_cycle, false, false)
else
SelectSpell(skills["disabling_blow_greatsword"])
Return
+v::CycleSpells(util_cycle, false, false)
b::CycleSpells(buff_other_cycle, false, false)
+b::CycleSpells(buff_cycle, false, false)



current_weap := "staff"

1::SwitchToStaff()
2::SwitchToSword()
!2::SwitchToShield()
3::SwitchToBow()

*WheelDown::
if toggle := !toggle
Send, {F11 down}
else
Send, {F11 up}
return


F12::Suspend

SwitchToStaff()
{
global
current_weap := "staff"
Send, +{]}
Sleep, 100
}

SwitchToSword()
{
global
current_weap := "greatsword"
Send, +{[}
Sleep, 100
}

SwitchToShield()
{
global
current_weap := "shield"
Send, +o
Sleep, 1000
Send, +i
Sleep, 200
}

SwitchToBow()
{
global
current_weap := "bow"
Send, +p
Sleep, 100
}



+g::LearnColours(spells)
!b::MousePointerDebug()

MousePointerDebug()
{
xpos := 0
ypos := 0
skill_colour := 0
MouseGetPos, xpos, ypos
PixelGetColor, skill_colour, xpos, ypos
ToolTip %xpos% %ypos% %skill_colour%
return
}

CycleSpells(ByRef spells_to_cycle, ByRef click_spell, ByRef auto_cycle)
{
global
spell_string := spells_to_cycle.join("_")
current_index := cycle_indexes[spell_string]
time_since_last := A_TickCount - (cycle_fires[spell_string])

if (auto_cycle)
{
i := 1

while(i <= spells_to_cycle.len())
{
spell := spells[spells_to_cycle[i]]
if SpellAvailable(spell)
{
if (click_spell)
{
Click
Sleep, 50
}
Break
}
i++
}
}
else
{
if (time_since_last > CycleResetTime)
{
current_index = 1
}

spell := spells[spells_to_cycle[current_index]]

if SpellAvailable(spell)
{
if (click_spell)
{
Click
Sleep, 1000
}
}

cycle_indexes[spell_string] := (current_index = (spells_to_cycle.len())) ? 1 : (current_index + 1)
}

cycle_fires[spell_string] := A_TickCount
}

SetupCycle(array_of_titles)
{
global
spell_string := array_of_titles.join("_")
cycle_indexes[spell_string] := 1
cycle_fires[spell_string] := 1
return array_of_titles
}

SpellAvailable(ByRef spell)
{
SelectSpell(spell)
return (CurrentSkillColor() = spell.ready_sample)
}

LearnColours(ByRef spells)
{
global
For title, spell_obj in spells
{
SelectSpell(spell_obj)
col := CurrentSkillColor()
spell_obj.ready_sample := col
ToolTip, Learning %title% %col%, 100, 100
Sleep, 350
}
SetTimer, ClearToolTip, 3000
}

SelectSpell(ByRef spell)
{
key := spell.key
Send %key%
Sleep, 100
}

CurrentSkillColor()
{
global
col := 0
PixelGetColor, col, CurrentSkillX, CurrentSkillY
return col
}

ClearToolTip:
{
SetTimer, ClearToolTip, Off
ToolTip
}

MacroGrind()
{
Loop, 150
{
Send, 4
Sleep, 100
Click
Sleep, 3500
Send, 5
Sleep, 100
Click
Sleep, 3500
Send, 6
Sleep, 100
Click
Sleep, 3500
Send, 7
Sleep, 100
Click
Sleep, 3500
Send, 8
Sleep, 100
Click
Sleep, 3500
Send, 9
Sleep, 100
Click
Sleep, 3500
Send, 7
Sleep, 100
Click
Sleep, 3500
}
}

Bobby Boblit
04-21-2011, 11:38 PM
; Endoscript v1.6 Nice and simple.
#IfWinActive, Darkfall Online

End::Pause
Home::Suspend
Capslock::Alt

; Sword and board macro, adjust the sleep value depending on your ping
+3::
Send, {Numpad1}
Sleep, 550
Send, {Numpad2}
return

; Burst keys
v::
Send, {{}
Send, {}}
Send, .
Send, l
return

+v::
Send, {F10}
Send, {F11}
Send, {Up}
send, k
return

q::
Send, q
Send, {F7}
Send, {F8}
Send, {Left}
Send, {Numpad9}
return

e::
Send, e
Send, {Numpad7}
MouseClick, Left
return

+e::
Send, +e
MouseClick, Left
return

+q::
Send, +q
Send, {F7}
Send, {F8}
Send, {Left}
MouseClick, Left
return

c::
Send, c
Send, {Right}
return

+c::
Send, +c
Send, {Right}
return

x::
Send, {x}
Send, {Numpad4}
return

f::
Send, {f}
MouseClick, Left
return

+f::
Send, +{f}
MouseClick, Left
return

; Weapon swaps on mousewheel
wheeldown::
Send, {Numpad8}
return

wheelup::
Send, {Numpad5}
return

; Whirlwind script
+wheeldown::
Send, {}}
Send, {{}
Send, .
Sleep, 50
MouseClick, Left
return

+wheelup::
Send, +{NumPad6}
return

; Sprint toggle
toggle = 0

~Esc::
If toggle = 1
{
Keywait, Esc
Send, {F12 down}
}
else
{
toggle = 0
}
return

~Enter::
If toggle = 1
{
Keywait, Enter
Send, {F12 down}
}
else
{
toggle = 0
}
return


Rbutton::
if toggle := !toggle
Send, {F12 down}
else
Send, {F12 up}
return

+Rbutton::
Send, {F12 down}
return

Ether Rael
04-21-2011, 11:39 PM
Version for bob that has no weap tracking in it.




#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#InstallKeybdHook ;mouse and keyb performance
#InstallMouseHook
#Include Array.ahk ;library for array management - pretty poor but works (indexed from 1, not 0)
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

; how long to wait before resetting a cycle back to zero
CycleResetTime := 5000

; objects provide an associative array interface (requires AutoHotKey_L)
spells := Object()
skills := Object()

; Binds

; Shift = +, Ctrl = ^, Alt = !
; I have bound hotbars 6-10 to variations of the same keybinds
; todo: Use sinister technique to inspect df config and build bind/spell/skill list automatically

spells["pungent_mist"] := Object("key", "!{]}")
spells["impale"] := Object("key", "!{[}")
spells["unholy_caress"] := Object("key", "!p")
spells["lightning_bolt"] := Object("key", "!o")
spells["dragon_breath"] := Object("key", "!i")
spells["frost_bite"] := Object("key", "!+4")

spells["lay_on_hands"] := Object("key", "+y")
spells["heal_other"] := Object("key", "+t")
spells["sacrifice"] := Object("key", "+r")
spells["witches_brew"] := Object("key", "+u")

; keep track of what's been fired and when
cycle_fires := Object()
cycle_indexes := Object()

; Create and bind your cycles here
ray_cycle := SetupCycle(Array("impale", "pungent_mist", "frost_bite", "dragon_breath", "unholy_caress", "lightning_bolt"))
heal_other_cycle := SetupCycle(Array("heal_other", "sacrifice", "witches_brew", "lay_on_hands"))

; hotkeys
; plain fast loop through spells, no autoclicking
; put your own binds in here as well

+f::CycleSpells(ray_cycle, false)

f::CycleSpells(ray_cycle, true)

F12::Suspend

; functions - can tweak Sleep timings in here
SelectSpell(ByRef spell)
{
key := spell.key
Send %key%
Sleep, 100
}

; initializes the global state tracking for a cycle
; array_of_titles is a list of strings which will be used to find the spell objects
SetupCycle(array_of_titles)
{
global
spell_string := array_of_titles.join("_")
cycle_indexes[spell_string] := 1
cycle_fires[spell_string] := 1
return array_of_titles
}

; spells_to_cycle is an array of spell names corresponding to the Objects at the top of the script
; click_spell boolean (true/false) whether to click the selected spell or not
CycleSpells(ByRef spells_to_cycle, ByRef click_spell)
{
global
spell_string := spells_to_cycle.join("_")
current_index := cycle_indexes[spell_string]
time_since_last := A_TickCount - (cycle_fires[spell_string])

; reset the cycle?
if (time_since_last > CycleResetTime)
{
current_index = 1
}

spell := spells[spells_to_cycle[current_index]]
SelectSpell(spell)
if (click_spell)
{
Click
Sleep, 500
; i have this at 1000 to allow for GCD on rays
}

; update globals for this cycle so we know where we are
; loop if we're at the end of a cycle. 1-based arrays are shit!
cycle_indexes[spell_string] := (current_index = (spells_to_cycle.len())) ? 1 : (current_index + 1)
cycle_fires[spell_string] := A_TickCount
}