ABC (Always Be Casting) by RandallF(Combat Volcano)
;ABC_5 ;having tested a LOT of theories and practices this compilation is created ;ALWAYS BE CASTING - ALPHA 5 ;a combat helper for the world of warcraft ;By CombatVolcano 2010 ; ; #Persistent ;############################# ; AUTO EXECUTE ;############################# ;############################# ; SCRIPT VARIABLES ;############################# ;Key Related KeySends := "1" ;Tolerance Related ZeroTolerance := "1" ;BLACK SHADE TOLERANCE GCDTolerance := "3" ;WHITE GCD SHADE TOLERANCE LagTolerance := "250" ;GCD Related GCDX := "18" GCDY := "1035" ;See Also GCDTolerance := "1" ;Target Related HasTargetX := "327" HasTargetY := "43" ;variables for the coordinates of each ability ;ABILITIES IcyTouchX := "163" IcyTouchY := "993" PlagueStrikeX := "190" PlagueStrikeY := "993" HornOfWinterX := "429" HornOfWinterY := "993" TrinketX := "323" TrinketY := "991" ObliterateX := "217" ObliterateY := "992" BloodStrikeX := "243" BloodStrikeY := "992" BloodTapX := "270" BloodTapY := "992" FrostStrikeX := "296" FrostStrikeY := "992" UnbreakableArmorX := "349" UnbreakableArmorY := "992" KillingMachineX := "1163" KillingMachineY := "932" RaiseDeadX := "456" RaiseDeadY := "992" ;BUFFS AND DEBUFFS FrostFeverX := "1166" FrostFeverY := "905" BloodPlagueX := "1166" BloodPlagueY := "920" HornOfWinterBuffX := "1166" HornOfWinterBuffY := "959" ;variables for the keys for each ability (how they are bound in game) PlagueStrikeKey := "1" IcyTouchKey := "2" ObliterateKey := "3" BloodStrikeKey := "4" FrostStrikeKey := "5" BloodTapKey := "6" DeathStrikeKey := "7" EmpowerRuneWeaponKey := "8" HornOfWinterKey := "9" TrinketKey := "F10" RaiseDeadKey := "F11" UnbreakableArmorKey := "F12" ;rotation/combat related Running := "0" ;############################# ; USER INTERFACES ;############################# ;GCD DISPLAY Gui 2: Margin, 0,0 Gui 2: font, s16, Arial Gui 2: -Caption +AlwaysOnTop +Border Gui 2: Add, text, vGCDText, "GCD INIT" Gui 2: font, s5, Arial Gui 2: Show, AutoSize xCenter y0 NoActivate, GCD ;############################# ; END AUTO EXECUTE ;############################# ;############################# ; COMBAT LOGIC moved to top for ease of use ;############################# ;function that controls combat logic Attack() { Global If GCD() ;importante { Return } If Available("HornOfWinter") and Available("HornOfWinterBuff") { Send, {%HornOfWinterKey%} Messageup("Horn Of Winter", "750") Return 1 } Else If Available("Trinket") and !TrinketFiring { TrinketFiring := "1" SetTimer, Trinket, -3700 Messageup("Trinket", "750") Return 0 ;since the trinket doesn't even fire yet and/or has no cooldown when it does } Else If Available("UnbreakableArmor") { Send, {%BloodTapKey%} Sleep, 250 Send, {%UnbreakableArmorKey%} Messageup("Blood Tap and Unbreakable Armor", "750") Return 1 } Else If Available("RaiseDead") { Send, {%RaiseDeadKey%} Messageup("Raise Dead", "750") Sleep, 2000 ;raise dead has a delay built in Return 1 } Else If Available("IcyTouch") and Available("FrostFever") { Send, {%IcyTouchKey%} Messageup("Icy Touch Refresh", "750") Return 1 } Else If Available("PlagueStrike") and Available("BloodPlague") { Send, {%PlagueStrikeKey%} Messageup("Plague Strike Refresh", "750") Return 1 } Else If !Available("KillingMachine") and Available("FrostStrike") { Send, {%FrostStrikeKey%} Messageup("Killing Machine and Frost Strike", "750") Return 1 } Else If Available("Obliterate") { Send, {%ObliterateKey%} MessageUp("Obliterate", "750") Return 1 } Else If Available("BloodStrike") { Send, {%BloodStrikeKey%} MessageUp("Blood Strike", "750") Return 1 } Else If Available("FrostStrike") { Send, {%FrostStrikeKey%} MessageUp("Extra Frost Strike", "750") Return 1 } Else If Available("HornOfWinter") { Send, {%HornOfWinterKey%} MessageUp("Extra Horn Of Winter", "750") Return 1 } Return 0 } Trinket: Send, {%TrinketKey%} Sleep, 250 TrinketFiring := "0" Return ;############################# ; HUMAN INTERFACE ;############################# XButton2:: If Running { Running = 0 SetTimer, Rotation, Off } Else { WinActivate, World of Warcraft Running = 1 SetTimer, Rotation, -50 } Return ;############################# ; ROTATION TIMER ;############################# ;WITH WHAT IS HERE NOW I HAVE DONE 4200 DPS OVER ABOUT 500,000 DAMAGE TO THE BOSS TRAINING DUMMY Rotation: Sleep, 300 ;AS I ALWAYS FELT THIS PADDING AT THE FRONT IS VERY IMPORTANT - TIMES NEED TO BE ANALYZED BUT I AM DISCOVERING THE GCD DISPLAY FROM THE GAME IS ABOUT 300 MS FASTER THAN THE TIME DURING WHICH YOU CAN SEND A NEW COMMAND - TRY REMOVING IT. it GREATLY increases DPS to have it in because it keeps the timing correct - if the timing is off you are losing out HUGELY If !GCD() and HasTarget() { ;this might be wrong now... but it is fair to say the return 1 or 0 does have an impact on the program flow ;there are three types of abilities, for now i will focus on 2 (the third being casted spells) ; ;those which trigger the GCD - these should return 1 from the logic loop ;those which do not trigger the GCD - these should return 0 ;those spells which trigger the GCD should expect to see the GCD timer come up after they are cast ;spells which trigger.. hrm ;the below restarts this very timer 'rotation'... it literally rotates around this timer function in circles ;<black magic> If Attack() ;send an attack, and if the ability sent is expected to have triggered the GCD it should return a 1 { Sleep, %LagTolerance% ;lagtolerance should be the maximum delay between sending a key and the GCD pixel appearing If !GCD() ;if the attack did not trigger the GCD within the allowed lag tolerance time then the ability probably failed??????actually may no longer need this { SetTimer, Rotation, -50 ;try another ability - this tolerance is important Return } Else ;it did detect that the GCD is up { While GCD() ;hell why not - while the GCD is up { Sleep, 50 ;wait around } SetTimer, Rotation, -50 ;next rotation after waiting Return } } Else ;the ability does not trigger the GCD and we should go as fast as possible { SetTimer, Rotation, -50 Return } } SetTimer, Rotation, -50 ;if the GCD was up or we didn't have a target check again Return ;</black magic> ;Detector for has a target HasTarget() ;returns 1 when the player has a target { global If IsZero("HasTarget") { Return 1 } Return 0 } ;GCD detector GCD() ;returns 1 when the global cooldown is active - need's it's own detection since it's white and not black { global PixelSearch, a, b, %GCDX%, %GCDY%, %GCDX%, %GCDY%, 0xFFFFFF, %GCDTolerance%, Fast If !ErrorLevel { GCDmsg("GCD ACTIVE") Return 1 } Else { EL := ErrorLevel } string := "GCD DOWN EL: " . EL GCDmsg(string) Return 0 } ;function that checks to see if any particular ability is available ;in the context of this program this means 'should be considered castable by the logic' Available(ability) ;contains logic for determining the availability of abilities { global ;can still write your own routines for handling non-zero abilities If Ability = Trinket { Pixelsearch, a, b, 323, 991, 323, 991, 0x090A0D, 2, Fast ;color when down If !ErrorLevel ;it's down { Return 0 } Sleep, 1000 Return 1 ;it's up } ;For every other thing assume zero/black ;;MessageUp("Ability Is IcyTouch", 700) If IsZero(ability) { ;;MessageUp("IT NOT READY", 700) Return 0 } String := ability . " READY" ;MessageUp(String, 700) ;if it's black it's not available! Return 1 } IsZero(ability) ;detects if an ability is unavailable/within zero tolerance using the globally set coordinates for that ability { global abilityX := %ability%x abilityY := %ability%y ;String := "IZ - Ability: " . ability . " X: " . abilityx . " Y: " . abilityY ; ;MessageUp(string, "700") Pixelsearch, a, b, %abilityx%, %abilityy%, %abilityx%, %abilityy%, 0x000000, %ZeroTolerance%, Fast If !ErrorLevel ;it matched black within tolerance { ;MessageUp("IsZero found black", "700") Return 1 } string := ability . " not black" ;MessageUp(string, "700") Return 0 } ;########################### ; MESSAGE FUNCTIONS ;########################### GCDmsg(message) { GuiControl, 2:,GCDText, %message% ;Specify for Param3 the control's new text Return } MessageUp(Message, MessageDurationInMS, byref MessageIsUp = "") { Global If MessageIsUp { GoSub, MessageDown } MessageIsUp := 1 Gui 3: Margin, 0,0 Gui 3: +LastFound GUI_ID:=WinExist() Gui 3: font, s16, Arial Gui 3: -Caption +AlwaysOnTop +Border Gui 3: Add, text,,%message% Gui 3: font, s5, Arial Gui 3: Show, AutoSize xCenter y50 NoActivate, Working... DllCall("AnimateWindow","UInt",GUI_ID,"Int",1,"UInt","0xa0000") SetTimer, MessageDown, -%MessageDurationInMS% Return MessageDown: ;DllCall("AnimateWindow","UInt",GUI_ID,"Int",1,"UInt","0x90000") ;ommitted for speed reasons when spamming msgs Gui 3: Destroy MessageIsUp := 0 Return } F5:: GuiClose: ExitApp
Please let me know if you have any questions... this requires that you use DAB (dimmed action bars) and have unavailable abilities set to solid black. You also need to have the mod "GCD" or any mod that will create a solid white pixel for detecting when the GCD is active.
This is likely better used as an example for writing your own script, though if set up correctly it DOES work It's also VERY FAST... just about as fast as it can possibly be... for a death knight it will DPS at better than maximum human speed for your gear. I was crushing dps in raids with this when before using it I wasn't even registering top 10 - same gear. Additionally it's not really detectable by Warden, or at least I never got caught and I ran it through live retail for probably 150+ hours including testing and the raiding that I did with it.
It also keeps a perfect priority set - as I understand it the way runes work has changed and likely this won't work anymore without a lot of modifications since it's not a priority based class anymore. I know it is possible to modify this (use this sort of concept) for casters or healers but haven't made an attempt.
It is indescribably cool when it's working. You just point your toon at whatever you want to die and it does the rest.
One last edit, I will probably be playing Cataclysm ("some people" already are) so I'll revisit this myself soon for the 4.0 classes and engine changes. I'll share it again at that time.