My current code is different with 3 skills each with different behaviour
Wind Devil - cast as soon as cooldown ends when you hold Left Click (key sent every 200 ms)
War Cry - cast as soon as cooldown ends when you hold both Left Click and Shift (key sent every 200ms)
Wendigo Totem - cast only once as soon as cooldown ends when you hold both Left Click and Shift and then it waits for 14 seconds to cast it again unless you release, click and hold Shift again, then you can cast it sooner (as soon as cooldown ends if you click and release Shift frequently, i.e. if moving from pack to pack when you want Totems more often) [this is how I play - I hold Left Click permanently, hold Shift when fighting one pack, Right click for movement skill]
There’s a mechanism to ensure than Wendigo Totem is definitely cast and not interrupted by Primal Strike from Left Click or other skills
~*LButton::
KeyWait, LButton, T0.2
if ErrorLevel
{
counter := 0
while GetKeyState("LButton", "P")
{
if GetKeyState("Shift", "P")
{
if counter < 10 ;we try casting Totem 10 times (for 10 x 200 ms = 2s) for 100% chance
{
Send {7} ; Wendigo Totem
}
Send {6} ; War Cry
counter := Mod(counter + 1, 70) ;70 means 70 x 200 ms = 14s because Totem has 15s duration
}
else
counter := 0
Send {8} ; Wind Devil
Sleep, 200
}
}
Return
Longer version example (when you move with Left Click & fight with Left Click + Shift)
~*LButton::
KeyWait, LButton, T0.2
if ErrorLevel
{
items_hidden := false ;ITEMS SHOWN BEFORE THE FIGHT
while GetKeyState("LButton", "P")
{
;SKILLS CAST WHILE WALKING
if GetKeyState("Shift", "P") ;FIGHT MODE
{
if !items_hidden ;HIDING ITEMS IF SHIFT IS HELD
{
Send {LAlt}
items_hidden := true
}
;SKILLS CAST WHILE FIGHTING
}
else
{
if items_hidden ; SHOWING ITEMS IF SHIFT IS RELEASED FIRST
{
items_hidden := false
Send {LAlt}
}
}
Sleep, 200
}
}
Return
~*LButton UP:: ;SHOWING ITEMS IF LEFT CLICK IS RELEASED FIRST
if items_hidden
{
items_hidden := false
Send {LAlt}
}
Return
Thanks, ideas keep coming naturally when you are too lazy to practice execution/click many buttons/master piano builds and I really don’t like focusing on cooldowns while fighting
; first I've done it with external main loop and Sleep but
; setTimer function is actually simpler and more powerful
SendMode Input
#NoEnv
#SingleInstance Force
#MaxHotkeysPerInterval 1000
#MaxThreadsPerHotkey 1
#KeyHistory 50
SetWorkingDir %A_ScriptDir%
doom_bolt_allowed := true
AllowDoomBolt()
{
global doom_bolt_allowed
doom_bolt_allowed := true
}
~*RButton::
KeyWait, RButton, T0.2
if ErrorLevel
{
counter := 0
while GetKeyState("RButton", "P")
{
if doom_bolt_allowed
{
send {0}
doom_bolt_allowed := false
SetTimer, AllowDoomBolt, -13000
/*
'-13000' above makes AllowDoomBolt run only once after 13s
whereas with '13000' the function would run every 13s
*/
}
if !Mod(counter-5, 40) ;blood of dreeg
send {9}
if !Mod(counter-20, 100) ;seal of consumption
send {8}
Sleep, 100
counter := Mod(counter + 1, 2600)
}
}
Return
Code can be probably rewritten with Timers only instead of the counter.
OUTDATED there’s a better version without loop and sleeps using timers Automatic camera (following your character)
b - rotate left
n - rotate right
~*LButton::
KeyWait, LButton, T0.2 ;need to hold the button for 200ms to follow
if ErrorLevel
{
while GetKeyState("LButton", "P")
{
WinGetActiveStats, Title, Width, Height, X, Y
MouseGetPos, xpos, ypos
xpos := xpos - Width/2 ;vector from the middle of the screen to the cursor
ypos := Height/2 - ypos
if xpos*xpos + ypos*ypos < 40000 ;<200 pix from center -> no rotation
continue
if (ypos > 0) and ( Abs(ATan(xpos / ypos)) * 57.29578 < 20)
continue ; 20° degrees from 12 o'clock -> 40° no rotation sector
if xpos > 0 ;right half of screen -> rotate right
{
Send {n down}
Sleep, 100 ; haven't tested other values here
Send {n up}
}
else ;left half of screen -> rotate left
{
Send {b down}
Sleep, 100
Send {b up}
}
Sleep, 20
}
}
Return
[edit] added 200 pixel protection (no rotation if cursor is closer than 200 pixels to the middle of the screen) so that there’s no rotation during melee fights
[edit2] changing sector of no rotation near 12 o’clock from 10 x 2 = 20° to 20 x 2 = 40° degrees so that there’s less rotation and direction changes when moving upwards and changing direction only slightly; set this parameter to your liking
Fixed. The ‘;’ shouldn’t be right after the code, there should be ’ ’ (space) in between
BTW another thing that could be added to the script is blocking the rotation for some time after you press buttons responsible for using skills
For example when you use a Movement Skill, the rotation stops (because it’s a little bit weird when the screen is rotatin when you are in the middle of animation)
Because you mentioned it in the other thread.
If people get dizzy it is mostly because they play at a low framerate (30 for me) and have motion blur disabled.
I play with nearly stable 144 fps and adaptive sync enabled but I think even 60 fps should be enough.
GD does not have the motion blur option so I guess a high framerate is the only solution.
You may be on to something but I personally just never get dizzy (in any real life situation) so I think that the genetic factor plays a role as well. In Grim Dawn I have 40 - 50 FPS
Also try playing Grim Dawn with a controller. It’s great. And you can use controller for fighting and mouse for shopping and the game dynamically switches between them. Rotating the camera with the right stick is great and you can configure everything in Steam Big Picture (for example I set my analog to activate Wind Devil whenever I touch it so it’s cast kinda automatically when I move my character with this analog stick)
I unfortunately don’t know how to use AutoHotkey with gamepads, it’s definitely not straightforward.
Didn’t know you can play GD with controller just that well. Will definitly try that out.
Have you tried to remap the xinput inputs to other keys which work with AHK?
Just an idea.
Also depends on controller for sure. For the steam controller that shouldn’t be a problem in general.
Test failed. This makes script also work when you are using Grim Tools website -> because the tab in web browser start with “Grim Dawn”. However you can fix it with
SetTitleMatchMode, 3
#IfWinActive, Grim Dawn
The first line forces the window title to exactly match IfWinActive argument (not start with it)
That may have been the reason I ditched IfWinActive before
Haven’t tried anything yet but when I was browsing the internet for some code it seem like too much work/no guarantee it will work in the end.
However you can kinda use AHK scripts if you bind some keyboard key to gamepad button (in Steam Controller Configuration Legacy Keys submenu). Then it works like this
you press some gamepad button
it makes chosen keyboard key to be pressed
Grim Dawn switches automatically from Gamepad mode to Mouse & Keyboard mode (wish these two modes could work together)
And know you have to move the analog stick for Grim Dawn to go back to Gamepad mode again unless you don’t want your controller to work
The easiest way to use M&K actions without modifying xinput and staying in gamepad mode would be a hardware converter like CronusMAX.
But surely you have to buy it first.
a) From my experience, event mode is way better for games (esp on slower pcs) than input.
Input is ofc faster, but its TOO fast (since it has no inherit delay, + it buffers).
using my script(s) in input mode, the game(s) often fails to recognize an action or modifier states get fubar.
eventmode increased stability of scripts alot plus you can set a global delay and presstime
b) in gd at least, you can send the keys in blind mode what reduces strain on the games i/o. that reduces the chances for stalling shift modifier eg when you use mouse + shift combo for hold position casting. (gd doesnt care when you use modifiers on action keys) eg shift-5 fires slot5 as 5 does.
c) mind to explain the reasons for your autoexec choices?
i often play with them and im curious about why you chose those.
#NoEnv #SingleInstance Force
*#MaxHotkeysPerInterval 1000 * #MaxThreadsPerHotkey 1 #KeyHistory 50
p.s Setkeydelay, delay, pressduration
is crucial in messy situations (and individual dependent on machine specs)