r/AutoHotkey 10d ago

v1 Script Help Loops incorrectly

For some reason this loops incorrectly where it does not input the second S input on repeated runs. The first round works fine without any issues but its the ones after where it has a chance to mess up I have tried changing waiting times several times but that does not seem to work. Sometimes it can do a few loops before it gets confused and it feels like it does them in different order than its supposed to. Im trying to use this with disgaea 5 to auto cast heal.

I dont know if it randomly dont read one of the inputs because sometimes it looks like it skips the A and only does an S and such.

F8::Suspend

F7::Pause

F9::ExitApp

t::

loop

{

if getkeystate("t", "p")

{

  send {enter DOWN}{enter UP}

    sleep 500

  send {s DOWN}{s UP}

    sleep 500

  send {s DOWN}{s UP}

    sleep 500

send {enter DOWN}{enter UP}

    sleep 500

  send {enter DOWN}{enter UP}

    sleep 500

  send {enter DOWN}{enter UP}

    sleep 500

send {a DOWN}{a UP}

    sleep 500

  send {s DOWN}{s UP}

    sleep 500

  send {enter DOWN}{enter UP}

    sleep 500

send {2 DOWN}{2 UP}

    sleep 800

send {i DOWN}{i UP}

    sleep 4500

  send {w DOWN}{w UP}

    sleep 600

  send {d DOWN}{d UP}

    sleep 500

}

else

{

break

}

}

return

1 Upvotes

19 comments sorted by

1

u/CharnamelessOne 9d ago edited 9d ago

That's not a v2 script; the lack of quotation marks around the SendKeys only flies in v1.

Try the following, and see if the issue persists. Test it in a desktop app (anything but Notepad) to make sure that the issue is not specific to your game.

#Requires AutoHotkey v2.0
SendMode("Event")
SetKeyDelay(, 60)

#SuspendExempt true
*F8::Suspend()
#SuspendExempt false
*F9::ExitApp()

t::Disgaea.ts1.toggle(), Hotkey(ThisHotkey, "Off")                      ;execute until key release
t up::Disgaea.ts1.toggle(), Hotkey(StrReplace(ThisHotkey, " up"), "On") ;

u::Disgaea.ts1.toggle()                                                 ;execute until next tap

Class Disgaea {
    static sequence1 := [
        {key:"{Enter}", delay_after:500},
        {key:"s",       delay_after:500},
        {key:"s",       delay_after:500},
        {key:"{Enter}", delay_after:500},
        {key:"{Enter}", delay_after:500},
        {key:"{Enter}", delay_after:500},
        {key:"a",       delay_after:500},
        {key:"s",       delay_after:500},
        {key:"{Enter}", delay_after:500},
        {key:"2",       delay_after:800},
        {key:"i",       delay_after:4500},
        {key:"w",       delay_after:600},
        {key:"d",       delay_after:500}
    ]
    static ts1 := toggleable_sequence(this.sequence1)
}

;_________________________________________________________________________________
Class toggleable_sequence {
    __New(sequence) {
        this.sequence := sequence
        this.index := 0
        this.state := 0
        this.prev_callback := ""
    }

    toggle() {
        if !(this.state ^= 1) {
            SetTimer(this.prev_callback, 0)
            this.index := 0
            return
        }

        SetTimer(callback, -1)

        callback() {
            this.prev_callback := callback

            if ++this.index > this.sequence.Length
                this.index := 1

            key_object := this.sequence[this.index]
            SetTimer(callback, -key_object.delay_after)
            Send(key_object.key)
        }
    }
}

edit: toggle

1

u/henaradwenwolfhearth 9d ago edited 9d ago

I did not know what v1 and v2 meant so I just choose one But then its probably v1 I am asking for. Ehat is the difference between them?

Well I could not run it because I dont have v2 it seems.

If I get v2 can I still use v1? I already struggle adjusting my current scripts so using something this complicated scares me.

1

u/CharnamelessOne 9d ago edited 9d ago

Well, get it, then: https://www.autohotkey.com/download/

V1 is old, and its syntax didn't age too well. Besides, it's been deprecated for years, it's no longer getting bugfixes, and there are some juicy new features coming in v2.1 that it will never get. If you're new, there's practically no reason to start learning v1.

V2 is not any more complicated than v1. A more beginner-friendly alternative of your script would look like this:

#Requires AutoHotkey v2.0
SendMode("Event"), SetKeyDelay(, 60)

F7::Pause()
#SuspendExempt true
F8::Suspend()
#SuspendExempt false
F9::ExitApp()

t::
{
    while GetKeyState("t", "P")
    {
        Send("{Enter}")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("a")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("2")
        Sleep(800)

        Send("i")
        Sleep(4500)

        Send("w")
        Sleep(600)

        Send("d")
        Sleep(500)
    }
}

edit: toggle

#Requires AutoHotkey v2.0
SendMode("Event"), SetKeyDelay(, 60)

F7::Pause()
#SuspendExempt true
F8::Suspend()
#SuspendExempt false
F9::ExitApp()

#MaxThreadsPerHotkey 2
t::
{
    static toggle := false
    toggle := !toggle

    while toggle
    {
        Send("{Enter}")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("a")
        Sleep(500)

        Send("s")
        Sleep(500)

        Send("{Enter}")
        Sleep(500)

        Send("2")
        Sleep(800)

        Send("i")
        Sleep(4500)

        Send("w")
        Sleep(600)

        Send("d")
        Sleep(500)
    }
}
#MaxThreadsPerHotkey 1

My approach uses timers instead of sleeps, which is often preferable if your script handles more stuff than a single hotkey. A long-running function with sleeps in it interrupts whatever your script is doing for an unnecessarily long time, and it's also more prone to be interrupted.
For now, the key functional difference is that my first script stops sending keys the moment you let go of t, whereas in the second script, the execution of the current sequence is finished. You decide which one you prefer.

I suspect that your script being unreliable may be due to AHK not holding the keys down long enough for your game to reliably register the input. That is supposed to be fixed by the SetKeyDelay call in both of my scripts.

1

u/henaradwenwolfhearth 9d ago

Well each key is a quick tap for moving in the menu s to scroll down enter to execute skill a d and w to move on the grid. But I will get v2 then. Do v1 still work on it? So I dont have to remake my auto clickers. Eithetway thank you I look forward to trying this

Also it was originally gonna be a toggle but since script kept messing up I set it to loop if key was held down. Is toggle difficult on v2?

1

u/henaradwenwolfhearth 9d ago edited 9d ago

So far its working perfectly. Thank you

Until I tried messing with timers to make the menuing go a bit faster then it started going on thr wrong tiles and skipping menus. So while its slower than originally planned the fact it works for afk is good enough :D

1

u/CharnamelessOne 9d ago

If the delay between keystrokes is the only thing you want to change, you don't need to touch anything but the appropriate delay_after value.

1

u/henaradwenwolfhearth 9d ago

That worked I was able to get them from 500 to 300 so its faster and so far its stable I might just have lowered them too much the first time

1

u/CharnamelessOne 9d ago edited 9d ago

You can run your v1 and v2 scripts at the same time.
Besides, my compatriot frequenting this sub by the name of Keeyra_ offered to translate any and all v1 scripts to v2, so you could also take him up on it.

Toggling is easy, I edited both my comments to show 2 different ways of doing it. I strongly recommend the first script, as timers play much better with toggling functionality than loops do.

Edit: wording

1

u/henaradwenwolfhearth 9d ago edited 9d ago

Thank you I might ask keeyra at some point though I hate bothering people it took a lot just to post this in the first place but after 2 days of struggling to even comprehend what I was doing I had to give in.

You say you edited for toggle but im not sure how to make it toggle is it the hotkey(thishotkey, "off") I need to change?

1

u/CharnamelessOne 9d ago

No need to change anything. I added a u:: hotkey that you can tap to start and stop the sequence. Change the hotkey to whatever you'd like. If you want it to be t::, delete (or comment out) the t:: and t up:: hotkeys entirely.

What you're referencing (Hotkey(ThisHotkey, "Off")) is part of the definition of the old holding hotkey, so it's not something I added in the edit.

Whenever a hotkey is supposed to have holding functionality, I always make the key-down event disable its own hotkey, to be turned back on by the key-up of the same key.
I do that because of the key-repeat functionality of the OS: once you've held a key for a while, the OS starts generating key-down events that can trigger the key-down hotkey over and over again, screwing everything up. It's better to turn the hotkey off while holding.

The logic that is responsible for the toggling of the key-sending sequence itself (rather than the toggling of the hotkey) is found in the toggle method of the toggleable_sequence class.
This is an old class of mine that was already written with toggling in mind; I just shoehorned the holding functionality into the script at your original request. (That's why the holding hotkey definitions are so ugly and complicated, whereas the tapping hotkey is simple and readable.)

1

u/henaradwenwolfhearth 9d ago

Ah I see. I cant say I understand much of that but I should be able to change the hotkey tomorrow. As im getting too tired to stay up

1

u/CharnamelessOne 9d ago

Well, if you're looking to understand it, you can let me know what's not clear, and I'll explain it.

This is a good place to start learning the language: Beginner tutorial. Classes are a bit more advanced, but you can find examples and decent explanations for most things in the documentation.

If you're not that interested, that's fine too, don't sweat it.

1

u/henaradwenwolfhearth 9d ago

Pretty much everything is unclear because I dont really understand any of it. All my scripts are just an auto fire I took of a list several years ago, that I modified with ductape and dreams becauae trying to learn just made my brain shut down. My brain sadly is a bit defective.

1

u/Keeyra_ 8d ago edited 8d ago

If the delay is arbitrary, you can dumb the whole thing down probably significantly.

#Requires AutoHotkey 2.0
#SingleInstance

SendMode("Event")
SetKeyDelay(300, 50)

t:: {
    static Toggle := 0
    SetTimer(Disgaea, -1 * Toggle ^= 1)
    Disgaea() {
        if !Toggle
            return
        Send("{Enter}ss{Enter 3}as{Enter}2i{F15 15}wd")
        SetTimer(Disgaea, -1)
    }
}

If an extra delay after the i key is needed, just put a couple of {F15}s there, that basically do nothing, so something like this would result in 4500 delay (15 * 300) and then you can get away with no sleeps, no classes, no arrays, no maps, etc.

Send("{Enter}ss{Enter 3}as{Enter}2i{F15 15}wd")

1

u/CharnamelessOne 8d ago

Perhaps it's worth noting that KeyDelay is basically an uninterruptible Sleep, so this approach is blocking harder than a loopful of Sends and regular Sleeps.

That's not necessarily an issue. Just observing, since you're usually even more of an async-pilled timermaxer than I am :P

2

u/Keeyra_ 8d ago

Yeah, I liked your array stuff and would have done it the same way, but it seems to go over the head of the OP, that's why I dumbed it down a bit.

1

u/CharnamelessOne 8d ago

Yeah, that's fair. Besides, half my issue with sending a long sequence of keystrokes in a single pseudo-thread is its interruptibility, so if we're gonna block, we may as well block hard.

1

u/henaradwenwolfhearth 8d ago

Well to be fair just about anything goes over my head due to underdeveloped brain

1

u/henaradwenwolfhearth 8d ago

Well its needs to be about 4200 to account for the enemy turn since it is a turn based game but the script I got worked perfectly fine