-
-
Save KarlRamstedt/758553272a042c4a94bef02ab5bdec2c to your computer and use it in GitHub Desktop.
#NoEnv ; For performance and compatibility with future AutoHotkey releases | |
SendMode Input ; For speed and reliability | |
SetBatchLines -1 ; No script sleep, for more consistent timing behavior. Default behavior is 10ms execution then 10ms sleep | |
ListLines Off ; Increase performance by a few percent by not logging the lines of code that are executed | |
; Modifiers: [+ = Shift] [^ = Ctrl] [# = Win] [! = Alt] [* = Ignores unspecified modifiers] [~ = Doesn't block normal function] [$ = Forces hook, preventing hotkey self-trigger] More info here: https://www.autohotkey.com/docs/KeyList.htm | |
; Time values are in ms(MilliSeconds), 1/1000 of a second. 1000/delay = activationsPerSecond. I.e: 50ms delay -> 1000/50 = 20 per sec | |
; Time values are typically rounded up to a multiple of 10ms by the Windows time-keeping system. So there's no point to Timer/Sleep values that aren't multiples of 10. Higher precision may be achieved via Loop+DllCall, but is rarely relevant and certainly doesn't matter for this script | |
global slideDelay := 110 ; 110 achieves max movement speed with Balla (with extremely high attack speed). Use higher delay for slower attack speeds. Too low a delay can yield normal, non-slide attacks. To find out the sweetspot for your weapon, see if you execute any non-slide attacks, then increase delay incrementally until they stop | |
global crouchDelay := 250 ; 125ms between notes for Octavia tracks. I recommend putting a purple "Melody" note in every column for best sync | |
global abilitySpam := [false, false, false, false] | |
global abilityDelay := [500, 9000, 15000, 2000] ; Delay between activations for ability 1, 2, 3 and 4, respectively | |
global delayToModify := 4 | |
global incrementIncrement := 50 | |
global abilityDelayIncrement := 500 | |
global abilityKeys := ["1", "2", "3", "4"] ; Keybind for each respective ability key. Change these to be the same as your ingame keybinds | |
#IfWinActive ahk_exe Warframe.x64.exe ; Only trigger hotkeys when Warframe is the active window | |
Hotkey, IfWinActive, ahk_exe Warframe.x64.exe ; Same, but for dynamically created hotkeys | |
global BoundFuncCache := {} ; A collection of bound functions for use in Timer stopping. Func(f).Bind(k) seems to create an object and return a reference to it, without caching the result, so manual caching is required to reference the same object | |
for i, key in abilityKeys { | |
toggleAbilityBF := Func("ToggleAbilitySpam").Bind(key) | |
Hotkey, % "$*<^>!" . key, % toggleAbilityBF ; AltGr+AbilityKey to toggle spam for that ability | |
selectBF := Func("SelectAbilityToModify").Bind(key) | |
Hotkey, % "#" . key, % selectBF ; Win+AbilityKey to select ability for modification of delay | |
BoundFuncCache[key] := Func("CastAbility").Bind(key) | |
} | |
SelectAbilityToModify(key){ | |
delayToModify := IndexOf(key, abilityKeys) | |
DisplayAbilityDelay() | |
} | |
ToggleAbilitySpam(key){ | |
i := IndexOf(key, abilityKeys) | |
abilitySpam[i] := !abilitySpam[i] | |
if (abilitySpam[i]){ | |
CenteredToolTip("Ability " . i . " Spam On (Delay: " . abilityDelay[i] . "ms)") ; Periods concatenate strings | |
Send, % "{Blind}{" . key . "}" | |
tmp := BoundFuncCache[key] ; SetTimer doesn't support function references in expression mode, requiring a temporary variable and regular variable dereferencing | |
SetTimer, %tmp%, % abilityDelay[i] | |
} else { | |
CenteredToolTip("Ability " . i . " Spam Off") | |
tmp := BoundFuncCache[key] | |
SetTimer, %tmp%, Off | |
} | |
} | |
CastAbility(key){ | |
if (WinActive("ahk_exe Warframe.x64.exe")) | |
Send, % "{Blind}{" . key . "}" ; {Blind} fixes issues with a combined Sprint+Roll key; Without {Blind}, holding down Shift during a Send command will send {Shift Up}, then the key and then {Shift Down}, causing unintentional rolling | |
} | |
global spam := false | |
spamHotkeys := ["LButton", "XButton2", "MButton"] ; Hold one of these to spam that key. Just add a key to the array to automatically make it a new spam hotkey (same goes for removing) | |
for i, key in spamHotkeys { ; Creates hotkeys for each key in the array above | |
BoundFuncCache[key] := Func("SendBlind").Bind(key) | |
Hotkey, IfWinActive ; Make StopSpam work outside of Warframe to avoid button getting stuck when clicking on a different window | |
stopSpamBF := Func("StopSpam").Bind(BoundFuncCache[key]) | |
Hotkey, % "~*" . key . " Up", % stopSpamBF | |
Hotkey, IfWinActive, ahk_exe Warframe.x64.exe ; Re-enable condition | |
spamBF := Func("Spam").Bind(key) ; Bind(BoundFunc) the Key to the Spam function to use it as input for the Hotkey Command | |
Hotkey, % "$*" . key, % spamBF ; $ to ensure Hotkeys can't trigger themselves | |
} | |
Spam(key){ | |
Send, % "{Blind}{" . key . " Down}" ; Required because ~ can't be used with KeyWait for blocking Auto-Repeat | |
if (spam){ | |
tmp := BoundFuncCache[key] ; SetTimer doesn't support function references in expression mode, requiring a temporary variable and regular variable dereferencing | |
SetTimer, %tmp%, 50 ; Delay between activations in ms. 50ms = 20 times per second. Should be good for most use-cases | |
KeyWait, % key | |
} | |
} | |
StopSpam(boundFunc){ | |
SetTimer, %boundFunc%, Off | |
} | |
SendBlind(key){ ; Function-wrapper for the Send Command | |
Send, % "{Blind}{" . key . "}" | |
} | |
^L:: ; Ctrl+L toggles Spam On/Off | |
spam := !spam | |
if (spam) | |
CenteredToolTip("Spam On") | |
else { | |
CenteredToolTip("Spam Off") | |
for i, func in BoundFuncCache | |
SetTimer, %func%, Off | |
} | |
return | |
MeleeAttack(){ | |
Send, {Blind}{XButton2} ; Melee key. Replace with the key you use | |
} | |
*!Q:: ; Alt+Q to throw Contagion. Most of the delays(Sleep) need to be longer than 2 frames, which at 60FPS is 2/60 = 33.33ms, i.e: 40 delay. Increase delay to 70 if you can't keep FPS above 60 | |
Send, {Blind}{Space} | |
Sleep, 40 ; Too short delay = throw fizzles (no throw) | |
Send, {Blind}{Space} | |
Sleep, 40 ; Only needed when melee isn't the active weapon. Too short delay = throw fizzles. Works with <2 frames delay, but not 100% reliably | |
Send, {Blind}{RButton Down} | |
Sleep, 40 ; Too short delay = aim-glide gets stuck | |
MeleeAttack() | |
Sleep, 40 ; ONLY NEEDED AS CLIENT. Too short delay = throw fizzles | |
Send, {Blind}{RButton Up} | |
return | |
; Shift+PageUp/Down to adjust delay between Slide-Attacks. Warframe uses a queue system for melee inputs; too low a delay can yield normal, non-slide attacks | |
+PgUp:: | |
slideDelay := slideDelay+10 | |
CenteredToolTip("SlideDelay: " . slideDelay . "ms") | |
return | |
+PgDn:: | |
if (slideDelay > 10) ; Avoid 0 and negative values | |
slideDelay := slideDelay-10 | |
CenteredToolTip("SlideDelay: " . slideDelay . "ms") | |
return | |
*+LAlt:: ; Triggers with Shift+LeftAlt, then keeps attacking while LeftAlt is held down | |
SlideAttack() | |
SetTimer, SlideAttack, %slideDelay% | |
KeyWait, LAlt | |
return | |
~*LAlt Up:: | |
SetTimer, SlideAttack, Off | |
return | |
SlideAttack(){ | |
Send, {LCtrl Down} ; Crouch key. {Blind} is not used because it causes Alt to sometimes get stuck logically down | |
MeleeAttack() | |
Send, {LCtrl Up} ; No delay needed between Crouch down and up. Has the bonus of removing the "shake" of spam-crouching | |
} | |
; Alt+PageUp/Down to adjust delay between crouches | |
!PgUp:: | |
crouchDelay := crouchDelay+10 | |
CenteredToolTip("CrouchDelay: " . crouchDelay . "ms") | |
return | |
!PgDn:: | |
if (crouchDelay > 10) | |
crouchDelay := crouchDelay-10 | |
CenteredToolTip("CrouchDelay: " . crouchDelay . "ms") | |
return | |
*!C:: ; Alt+C to spam crouch | |
Send, {Blind}{LCtrl Down} | |
SetTimer, CrouchSpam, %crouchDelay% | |
KeyWait, C | |
return | |
~*C Up:: | |
Send, {Blind}{LCtrl Up} | |
SetTimer, CrouchSpam, Off | |
return | |
CrouchSpam(){ | |
Send, {Blind}{LCtrl Up} | |
Sleep, 1 | |
Send, {Blind}{LCtrl Down} | |
} | |
DisplayAbilityDelay(){ | |
CenteredToolTip("Ability " . delayToModify . " Delay: " . abilityDelay[delayToModify] . "ms") | |
} | |
; AltGr+PageUp/Down to adjust delay between ability activations | |
<^>!PgUp:: | |
abilityDelay[delayToModify] := abilityDelay[delayToModify]+abilityDelayIncrement | |
DisplayAbilityDelay() | |
if (abilitySpam[delayToModify]){ | |
tmp := BoundFuncCache[abilityKeys[delayToModify]] | |
SetTimer, %tmp%, % abilityDelay[delayToModify] ; Update running timers | |
} | |
return | |
<^>!PgDn:: | |
if (abilityDelay[delayToModify] > abilityDelayIncrement) ; Avoid 0 and negative values | |
abilityDelay[delayToModify] := abilityDelay[delayToModify]-abilityDelayIncrement | |
DisplayAbilityDelay() | |
if (abilitySpam[delayToModify]){ | |
tmp := BoundFuncCache[abilityKeys[delayToModify]] | |
SetTimer, %tmp%, % abilityDelay[delayToModify] | |
} | |
return | |
; Win+PageUp/Down to adjust increment for adjusting delay between ability activations | |
#PgUp:: | |
abilityDelayIncrement := abilityDelayIncrement+incrementIncrement | |
CenteredToolTip("Ability Delay Increment: " . abilityDelayIncrement . "ms") | |
return | |
#PgDn:: | |
if (abilityDelayIncrement > incrementIncrement) | |
abilityDelayIncrement := abilityDelayIncrement-incrementIncrement | |
CenteredToolTip("Ability Delay Increment: " . abilityDelayIncrement . "ms") | |
return | |
!X:: ; Alt+X to skip transmission dialogue (AKA "Nightwave skip"). Made for 16:9 aspect ratios, change the MouseMove if your screen isn't 16:9 so the cursor lands on the Nightwave banner | |
Send, {Esc} | |
Sleep, 444 ; Wait for transition animation | |
MouseMove, % A_ScreenWidth*0.85, % A_ScreenHeight*0.87, 0 ; Use location relative to screen resolution so that it works with any 16:9 resolution. NOTE: Mouse Movement doesn't work in fullscreen mode | |
Sleep, 1 ; Needs delay between movement and Click | |
Click, down | |
Sleep, 1 ; Needs separate up and down events, otherwise the UI doesn't register the click | |
Click, up ; Essentially: Send, {Blind}{LButton Up} | |
Sleep, 444 ; Wait for transition animation | |
Send, {Esc} | |
return | |
CapsLock::5 ; Remaps CapsLock to 5. I'm using CapsLock as Transference key | |
#IfWinActive ; The next hotkeys work outside of Warframe too | |
^P::Suspend ; Ctrl+P toggles hotkeys On/Off | |
*#P::Pause ; Win+P toggles execution Pause | |
<^>!R::Reload ; AltGr+R reloads script | |
CenteredToolTip(text, duration = 999){ ; Duration in ms (MilliSeconds). Default value can be overridden | |
ToolTip, %text%, A_ScreenWidth/2, A_ScreenHeight/2 | |
SetTimer, RemoveToolTip, -%duration% ; Negative to only trigger once | |
} | |
RemoveToolTip(){ | |
ToolTip | |
} | |
IndexOf(item, array){ ; Returns the index of the first item matching the input item | |
for i in array | |
if (array[i] == item) | |
return i | |
} |
@Turboameeba I'm not too knowledgeable on Heavy throws, they're just Crouch+Heavy Attack instead of normal attack?
Try this quick edit(and change Heavy-attack key if needed ofc):
*!Q:: ; Alt+Q to throw Contagion. Most of the delays(Sleep) need to be longer than 2 frames, which at 60FPS is 2/60 = 33.33ms, i.e: 40 delay. Increase delay to 70 if you can't keep FPS above 60
Send, {Blind}{Space}
Sleep, 40 ; Too short delay = throw fizzles (no throw)
Send, {Blind}{Space}
Sleep, 40 ; Only needed when melee isn't the active weapon. Too short delay = throw fizzles. Works with <2 frames delay, but not 100% reliably
Send, {Blind}{RButton Down}{LCtrl Down}
Sleep, 40 ; Too short delay = aim-glide gets stuck
Send, {Blind}{MButton Down} ; Heavy-attack key
Sleep, 40 ; ONLY NEEDED AS CLIENT. Too short delay = throw fizzles
Send, {Blind}{RButton Up}{LCtrl Up}
return
@KarlRamstedt I appreciate your work!
Is it possible to bind the Slide-Attack to "XButton2" instead of Shift+LeftAlt (I changed my Melee default back to "e") and add a Bullet-Jump script to "XButton1"?
🙏🏽
@TheRealDjElite Changing slide attack trigger is easy enough for you to do on your own, so not gonna bother with the details on that one :P
As for a Bullet-Jump hotkey, try this:
*!XButton1:: ; Mouse 4 to bullet-jump
Send, {Blind}{Ctrl}{Space}
return
If the above doesn't work, try this:
*!XButton1:: ; Mouse 4 to bullet-jump
Send, {Blind}{Ctrl Down}
Send, {Blind}{Space}
Send, {Blind}{Ctrl Up}
return
@TheRealDjElite Changing slide attack trigger is easy enough for you to do on your own, so not gonna bother with the details on that one :P
As for a Bullet-Jump hotkey, try this:
*!XButton1:: ; Mouse 4 to bullet-jump Send, {Blind}{Ctrl}{Space} returnIf the above doesn't work, try this:
*!XButton1:: ; Mouse 4 to bullet-jump Send, {Blind}{Ctrl Down} Send, {Blind}{Space} Send, {Blind}{Ctrl Up} return
Thanks for the Bullet-Jump. Both actually work after I removed the "*!" from the *!XButton1 to get XButton1.
I got to bind the Slide-Attack to "Shift+Xbutton2" instead of Shift+LeftAlt.
Thanks for teaching me how to fish. :-)
Any advice for when SPAM attack buttons get stuck? It seems to go crazy even if I click outside of WF.
@TheRealDjElite just tap the button. Should work even outside of Warframe.
@claymen1 Try increasing the delays. You look like you have a low framerate.
@KarlRamstedt fixed it alread long ago, and the fps drop i get only from the recording tho ^^
I cannot change the delay for hability, only the 4
Alt + PGUP / PGDN
@PsykhoEX have you tried Win(WindowsKey)+1 to select ability one?
@TheRealDjElite Changing slide attack trigger is easy enough for you to do on your own, so not gonna bother with the details on that one :P
@KarlRamstedt Previously, I had figured out how to assign the XButton2 to be the Slide Attack Trigger. However, I completely wiped my desktop and lost my AHK file for it. I've been trying to figure out what to edit but it's not working.
It's in this part of the macro, right?
*+LAlt:: ; Triggers with Shift+LeftAlt, then keeps attacking while LeftAlt is held down
SlideAttack()
SetTimer, SlideAttack, %slideDelay%
KeyWait, LAlt
return
~*LAlt Up::
SetTimer, SlideAttack, Off
return
SlideAttack(){
Send, {LCtrl Down} ; Crouch key. {Blind} is not used because it causes Alt to sometimes get stuck logically down
MeleeAttack()
Send, {LCtrl Up} ; No delay needed between Crouch down and up. Has the bonus of removing the "shake" of spam-crouching
}
Could you help me out, please? I'd really appreciate it.
@TheRealDjElite yeah, it's in that part of the script. If you just want it to be XButton2 then you just replace *+LAlt::
with *XButton2::
@KarlRamstedt Does this look right?
*XButton2:: ; Triggers with Shift+LeftAlt, then keeps attacking while LeftAlt is held down
SlideAttack()
SetTimer, SlideAttack, %slideDelay%
KeyWait, LAlt
return
~*LAlt Up::
SetTimer, SlideAttack, Off
return
SlideAttack(){
Send, {LCtrl Down} ; Crouch key. {Blind} is not used because it causes Alt to sometimes get stuck logically down
MeleeAttack()
Send, {LCtrl Up} ; No delay needed between Crouch down and up. Has the bonus of removing the "shake" of spam-crouching
}
@TheRealDjElite you gotta change the "Up" button as well. So make that ~*XButton2 Up::
Well, that doesn't make sense to me. Pretty sure it should work. Try with a different button to verify? Could be an issue with your mouse.
The Exodia Contagion heavy throw you have to first have your setting for for Switch Weapon enabled.. When you hold down that button, it turns on melee mode.. which means you can press aim button without actually taking a gun in your hand. Then you have to jump in the air.. Do aim glide and press crouch button to do a Jump aim glide SLIDE... Slide in the air.. And when you then press your heavy attack button, your Cntagion will actually throw a heavy Contagion, which will get that 2x crit chance buff etc, like you can see from this video. Sorry for bad quality. It was recoded with some website screen capture
Exodia Contagion Heavy.webm
@Turboameeba That sounds like what I wrote, no?
The code I gave you before should do that, but you may ofc have to tweak timings and/or possibly add additional delays between the crouches and other buttons.
You'll have to do some trial and error testing :)
So far the code I tested was just a normal jump throw. Not the heavy attack throw in the video. The haavy attack throw produces orange and red crits every single time. You cannot even do the heavy throw without first turning the melee mode on by holding the button down so you see the small blink red light effect. Just having the melee in your hand is not enough to do it. I dont use macros tho, was just curious in past.. The heavy throw is not also possible without the air slide during aim glide.
Blink n Slide.webm
hey i cant get the exodia one to work without for some reason dashing
2023-05-30.07-01-09.mp4
@headasstommy could be a number of things causing this. Make sure all the keybinds ingame correspond to the buttons pressed by the script. If that doesn't fix it, try increasing the delays.
Also, looks like there's crouching happening in the script. Are you trying to do the heavy contagion throw?
been having this problem with the exodia contagion stand alone macro, only does ground slams no matter what delay i use, any idea what the problem is?
https://user-images.githubusercontent.com/131336927/267317079-1286647b-daf2-43da-add5-478745499e8c.mp4
nvm im stupid, forgot that xbutton2 was bound to heavy attack :/
Could you help make a Contagion heavy throw macro even when you have guns equipped please? This current macro does just the normal throw as far as what I have tested