PC Players: Enhancing Training Mode using macro programs

ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
This technique can be applied to many different fighting games on PC, including emulated ones (as long as they're compatible with AutoIt) but since the script I created was for SSFIV I figured I'd just post it in this forum.

One of the problems with the training mode dummy is that it can only store 10 seconds of input, and because there's no scripting capability in the game, you're limited to one setup per recording. This is fine for testing canned stuff, but things get trickier if you want to test maybe something like a defensive technique that covers multiple mixup options.

We can simulate this behaviour with a tool like AutoIt.

AutoIt is a freeware program used for automating input (usually from keyboard or mouse). It's already widely known and used in the TA combo vid scene.

The idea is to set the dummy to human keyboard control, and run an AutoIt script containing the commands to execute the setup or behaviour you want to playback. The beauty of AutoIt is that it's completely scriptable, and you can create scripts that simulate unpredictable behaviour by using the Random function.

Here's a simple script that simulate Ryu walking back and forth a random distance within a defined range and then randomly doing cr.mk. You can playback this script to test your spacing and whiff-punishment against this move.

Install AutoIt and paste the following code into a file called "Ryu test.au3". Start SSFIV (in a Window) and go to training mode. Set player 2 keys accordingly (you can modify the script so the keys match your own settings). Then set a Ryu dummy to human control and select the keyboard for Player 2 (both players can use the keyboard). Right click on the au3 file and select "Run Script". Switch back to SSFIV and the Ryu dummy will start walking back and forth, doing cr.mk randomly. Try to space yourself out of range of the move and whiff punish it whenever possible.
; This script assumes that the dummy will always be facing left
 
; Constant values
Const $ONE_FRAME_IN_MS = 16.67
Const $MAX_WALK_FRAMES = 20
Const $MIN_WALK_FRAMES = 5

; Change these to match your own key configuration
Const $LEFT     = "c"
Const $RIGHT     = "b"
Const $UP         = "f"
Const $DOWN     = "v"
Const $MK        = "w"

; The "meat" of the script - it will loop forever
While(true)
   ; Walk left a random amount of time
   $howLong = Random($MIN_WALK_FRAMES, $MAX_WALK_FRAMES, 1) * $ONE_FRAME_IN_MS
   WalkLeft($howLong)
   
   ; Randomly do cr.mk
   If Mod(Round($howLong), 5) = 0 Then
      CrouchMediumKick()
   EndIf
   
   ; Walk backward roughly the same distance, but modify 
   ; the time because Ryu's backward speed is slower
   ; than his forward speed
   $howLong += $ONE_FRAME_IN_MS * 6
   WalkRight($howLong)
   
   ; Randomly do cr.mk
   If Mod(Round($howLong), 4) = 0 Then
      CrouchMediumKick()
   EndIf
WEnd

Func WalkLeft($howLong)
   Send ("{" & $LEFT & " down}")
   Sleep($howLong)   
   Send ("{" & $LEFT & " up}")
EndFunc

Func WalkRight($howLong)
   Send ("{" & $RIGHT & " down}")
   Sleep($howLong)   
   Send ("{" & $RIGHT & " up}")
EndFunc

Func CrouchMediumKick()
   Send ("{" & $LEFT & " down}")
   Send ("{" & $DOWN & " down}")
   Sleep($ONE_FRAME_IN_MS)
   Send ("{" & $MK & " down}")
   Sleep($ONE_FRAME_IN_MS)
   Send ("{" & $MK & " up}")
   Send ("{" & $LEFT & " up}")
   Send ("{" & $DOWN & " up}")
EndFunc

This is just a basic example, but it's fairly trivial to modify the code to do other stuff, like random fireballs, or whiffing stand short etc. Once you get used to the idea of scripting you can create more complex scripts, like 50/50 mixups, or tick throw/frame traps etc.

If you come up with something cool post it here.
«13

Comments

  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    Here's an example of a script that performs a 50/50 mixup. Ryu does f.throw, backdash, j.hp or x-up tatsu. The way to defend against this is to hold back, then down forward immediately. Holding back protects against the j.hp, while down forward will block the x-up tatsu. It works because the j.hp hits before the tatsu. It's not foolproof though cos Ryu can change the timing of the tatsu to hit in front.

    This script operates differently to the previous one in that the setup will only run when you press "8" or "9". Press "8" to perform the setup when the dummy is facing left, press "9" when they are facing right. You can press "0" to reload the script (useful for when you want to make changes on the fly).
    HotKeySet ("0", "Reload")
    HotKeySet ("9", "PerformSetupFacingRight")
    HotKeySet ("8", "PerformSetupFacingLeft")
     
    ; Constant values
    Const $ONE_FRAME_IN_MS = 16.67
    Const $AUTOIT_PATH = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir")
    Const $RELOAD_CMD = '"' & $AUTOIT_PATH & '\AutoIt3.exe "' & ' "' & @ScriptFullPath & '"'
     
    ; Change these to match your own key configuration
    Const $LEFT    = "c"
    Const $RIGHT    = "b"
    Const $UP        = "f"
    Const $DOWN    = "v"
     
    Const $LP        = "1"
    Const $MP        = "2"
    Const $HP        = "3"
    Const $LK        = "q"
    Const $MK        = "w"
    Const $HK        = "e"
     
    ; Keep the script running forever
    While(true)
      Sleep(100)
    WEnd
     
    Func PerformSetupFacingRight()
      PerformSetup($RIGHT, $LEFT)
    EndFunc
     
    Func PerformSetupFacingLeft()
      PerformSetup($LEFT, $RIGHT)
    EndFunc
     
     
    Func PerformSetup($forward, $backward)
      Walk($forward, 80 * $ONE_FRAME_IN_MS)
      Throw($forward)
      Wait(90)
      Dash($backward)
      Wait(28)
      Jump($forward)
      If (Random(0, 1, 1) = 0) Then
          Wait(28)
          HP()
      Else
          Wait(17)
          QC($backward)
          HK()
      EndIf
    EndFunc
     
    Func HK()
      SingleButtonPress($HK)
    EndFunc
     
    Func HP()
      SingleButtonPress($HP)
    EndFunc
     
    Func QC($direction)
      Send ("{" & $DOWN & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $direction & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $DOWN & " up}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $direction & " up}")
    EndFunc
     
    Func Throw($direction)
      Send ("{" & $direction & " down}")
      Send ("{" & $LP & " down}")
      Send ("{" & $LK & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $LP & " up}")
      Send ("{" & $LK & " up}")
      Send ("{" & $direction & " up}")
    EndFunc
     
    Func Walk($direction, $howLong)
      Send ("{" & $direction & " down}")
      Sleep($howLong)
      Send ("{" & $direction & " up}")
    EndFunc
     
    Func Dash($direction)
      Send ("{" & $direction & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $direction & " up}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $direction & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $direction & " up}")
    EndFunc
     
    Func Jump($direction)
      Send ("{" & $UP & " down}")
      Send ("{" & $direction & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $UP & " up}")
      Send ("{" & $direction & " up}")
    EndFunc
     
    Func SingleButtonPress($button)
      Send ("{" & $button & " down}")
      Sleep($ONE_FRAME_IN_MS)
      Send ("{" & $button & " up}")
    EndFunc
     
    Func Wait($frames)
      Sleep($frames * $ONE_FRAME_IN_MS)
    EndFunc
     
    Func Reload()
      Run($RELOAD_CMD)
      Exit 0
    EndFunc
    
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    Here's another cool hack: Letting the dummy react to things you do!

    eg. If you want to figure out "safe" spacing for projectiles against different characters, you can hack a script that will let the dummy jump immediately (or with some delay to simulate human reactions) as soon as you throw the projectile. The hack is to set the button used for the projectile eg. fireball (punch button in this case) to run the script. So every time you throw a fireball, the dummy will jump over it and attack (or do whatever the script tells it to do). The only snag is that it's slightly complicated to do something like this using AutoIt because it doesn't have built-in joystick/gamepad support (I have done it before though). However, you can use a program called AutoHotkey (which does have stick support) to do the same thing!

    As a proof-of-concept, I've created a modified AutoHotkey version of the footsie script that will cause the dummy to do cr.hk every time you press MK or HK. In practice, this means that every time you whiff MK or HK the dummy will attempt to counter-sweep, just like a skilled opponent will do. You can obviously do stuff like stand on the other side of the screen and whiff moves just to let the dummy go crazy but that's defeating the purpose.

    Here's what it looks like in practice:

    The reason the dummy wasn't doing anything at the start of the vid was because I hadn't started the script yet.

    It's not perfect and it has it's limitations, but it's a heck of a lot better than the standard dummy. (Discussion for another time and place: If I can do this with open source tools and a few hours of spare time, why can't publishers give us decent Tutorials and Training modes?)

    AutoHotKey script:
    Spoiler:
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    this is fucking brilliant mate.

    Summary and files here : bit.ly/ssfivtool
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    To be sure, I can work with Autohotkey only for any kind of patterns, blind or reacting to player 1 moves. Or does Autoit still have it's use ?
    I'm trying to figure out how to script a multi buttons press like down forward. It looked easy in Autoit scripts but that's not the same exactly in AutoHotKey.
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    To be sure, I can work with Autohotkey only for any kind of patterns, blind or reacting to player 1 moves. Or does Autoit still have it's use ?
    I'm trying to figure out how to script a multi buttons press like down forward. It looked easy in Autoit scripts but that's not the same exactly in AutoHotKey.
    You can use either one, but AutoHotKey has built-in joystick/pad support so you don't have to write User Defined Functions. Both tools have their pros and cons.

    Certain programs can be very finnicky about how much delay you need before inputs are registered. Here's cr.mk xx hadou in AutoHotKey:
    LEFT    := "c"
    RIGHT    := "b"
    UP        := "f"
    DOWN    := "v"
     
    LP        := "1"
    MP        := "2"
    HP        := "3"
    LK        := "q"
    MK        := "w"
    HK        := "e"
     
    CrMKxxExHadou(direction)
    {
        Global
        Send {%DOWN% down}
        Sleep 30
        ; This function is defined elsewhere but it just sends an MK input
        MK()
        Sleep 30
        Send {%direction% down}
        Sleep 30
        Send {%DOWN% up}
        Sleep 30
        Send {%LP% down}
        Send {%HP% down}
        Sleep 30
        Send {%direction% up}
        Send {%LP% up}
        Send {%HP% up}
    }
    

    Call it using:
    ; Facing Left
    CrMKxxExHadou(LEFT)
     
    ; Facing Right
    CrMKxxExHadou(RIGHT)
    

    I call Sleep after certain button presses to give the game a moment to recognize that I pressed the buttons. It's useful to test the script on P1's side first with input display on so that you can see what inputs are being generated.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    This script for the moment only should make the dummy walk 120 frames in a direction when I input a button on my stick. And it fails, double tapping make the dummy dash however…
    What's the use of "global" it's not documented on the website.
    "Global" means you're gonna access globally declared variables. When to use % signs for variables takes a bit of getting used to. If you use them with Send, then you always use % signs otherwise it's going to either send the raw data, or it's going to try to interpret it as a HotKey.
    http://www.autohotkey.com/docs/FAQ.htm#percent

    Here's a working 50/50 tatsu script for AutoHotkey (change the key/stick config accordingly):
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 0, 20
     
    ; Constant values
    ONE_FRAME_IN_MS := 16.67
     
    LEFT    := "c"
    RIGHT    := "b"
    UP        := "f"
    DOWN    := "v"
     
    LP        := "1"
    MP        := "2"
    HP        := "3"
    LK        := "q"
    MK        := "w"
    HK        := "e"
     
    Wait(frames)
    {
        Global
        Sleep frames * ONE_FRAME_IN_MS
    }
     
    PerformSetupFacingRight()
    {
        Global
        PerformSetup(RIGHT, LEFT)
    }
     
    PerformSetupFacingLeft()
    {
        Global
        PerformSetup(LEFT, RIGHT)
    }
     
    PerformSetup(forward, backward)
    {
        Global
        Walk(forward, 80)
        Throw(forward)
        Wait(90)
        Dash(backward)
        Wait(28)
        Jump(forward)
        Random, rand, 0, 1
        if (rand = 0)
        {
            Wait(28)
            HP()
        }
        else
        {
            Wait(17)
            QC(backward)
            HK()
        }
    }
     
    HK()
    {
        Global
        SingleButtonPress(HK)
    }
     
    HP()
    {
        Global
        SingleButtonPress(HP)
    }
     
    QC(direction)
    {
        Global
        Send {%DOWN% down}
        Wait(2)
        Send {%direction% down}
        Wait(2)
        Send {%DOWN% up}
        Wait(2)
        Send {%direction% up}
    }
     
    Throw(direction)
    {
        Global
        Send {%direction% down}
        Send {%LP% down}
        Send {%LK% down}
        Wait(2)
        Send {%LP% up}
        Send {%LK% up}
        Send {%direction% up}
    }
     
    Walk(direction, howLong)
    {
        Global
        Send {%direction% down}
        Wait(howLong)
        Send {%direction% up}
    }
    Dash(direction)
    {
        Global
        Send {%direction% down}
        Wait(2)
        Send {%direction% up}
        Wait(2)
        Send {%direction% down}
        Wait(2)
        Send {%direction% up}
    }
     
    Jump(direction)
    {
        Global
        Send {%UP% down}
        Send {%direction% down}
        Wait(2)
        Send {%UP% up}
        Send {%direction% up}
    }
     
    Sweep()
    {
        Global
        SingleButtonPress(HK)
    }
     
    SingleButtonPress(button)
    {
        Global
        Send {%button% down}
        Wait(2)
        Send {%button% up}
    }
     
    Joy7::
        PerformSetupFacingRight()
    

    You may have to play with the numbers a bit to get it working on your system, but this works fine on mine. For common functionality, I recommend using Sleep over wait as it gives you more control over the timing. AutoHotKey and AutoIt aren't frame-perfect.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Just found out that Send can be used to input several buttons, on a single line like :
    Send {%UP% up}{%RIGHT% up}…
    to do a jump in.

    Found it !
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    Just found out that Send can be used to input several buttons, on a single line like :
    Send {%UP% up} + {%RIGHT% up}
    to do a jump in.
    Nice, that's very useful to know.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Nice, that's very useful to know.
    I was wrong with the "+" just queue brackets one after another without spaces do the trick, + and maybe space between those brackets can still be used to input several commands that aren't simultaneous, like a QCF why not.

    edit : Not possible for such move because we need to release each button pressed AND there's a diagonal needed.
    It's weird that this code
    QC(direction)
    {
      Global
      Send {%DOWN% down}
      Wait(1)
      Send {%direction% down}
      Wait(1)
      Send {%DOWN% up}
      Wait(1)
      Send {%direction% up}
    }
    
    produce a :d: :db: :b: without the need to code the :db: , I don't get the mechanism behind this behavior.

    It's not 100% accurate I still got a plink sometimes instead of a clean throw and the timing will take a bit of experimentation to figure out. But this will definitely be handy to level up. Something I needed to add in order to avoid the setup to loop 1 extra time was "exit" at the end of the function. No idea why, I'll repost the final script later when I get time.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Short code for dashes :
    Dash(direction)
    {
      Global
      Send {%direction% down} + {%direction% up}
      Wait(2)
      Send {%direction% down} + {%direction% up}
    }
    
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    It's weird that this code
    
    produce a :d: :db: :b: without the need to code the :db: , I don't get the mechanism behind this behavior.
    Holding down + %direction% gives the diagonal. If you don't get accurate inputs then use a longer delay between button inputs.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    Make sure you included "Global" in the function otherwise it won't recognize %UP%. I had the same problem.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    And now with SetKeyDelay 0, %UP% works and output a "z" correctly.
    I love computers…
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Make sure you included "Global" in the function otherwise it won't recognize %UP%. I had the same problem.
    Yes I put Global all over the place to be sure.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Do you know a way to create a STOP button/hotkey ?
    I getting better result today with better wait() management but now that I can launch a loop for the dummy I want to be able to stop it and relaunch at will.
    So I use my 2 spare buttons on the right to launch Right or Left side loops, but want to use Select button to stop All (not the script as I need to be able to launch the loop again anytime without switching windows).
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Got it !
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    Footsies(forward, backward)
    {
    Global
    Pause := false
    Loop
    {
      if Pause
      break
      ; Walk forward a random amount of time
      Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
      Walk(forward, howLong)
     
      ; Randomly do cr.mk xx Fireball
      If (Mod(Round(howLong), 5) = 0) {
          Wait(6)
          LowMK_xx_HP(forward)
      }
     
      ; Walk backward roughly the same distance, but modify
      ; the time because Ryu's backward speed is slower
      ; than his forward speed
      howLong += 6
      Walk(backward, howLong)
     
      ; Randomly do cr.mk xx Fireball
      If (Mod(Round(howLong), 4) = 0) {
          Wait(6)
          LowMK_xx_HP(forward)
      }
    }
    }
     
    2Joy5::
      Footsies(RIGHT, LEFT)
     
     
    2Joy7::
      Footsies(LEFT, RIGHT)
     
    ; Push Select to stop ALL
    2Joy9::
      Pause := true
    

    We can also use "While (Pause = false){…"
    instead of loop
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    I duno if you already thought of doing this but I got tired of the Send syntax and I think the code is easier to read and debug with these PUSH and RELEASE functions :
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    I duno if you already thought of doing this but I got tired of the Send syntax and I think the code is easier to read and debug with these PUSH and RELEASE functions :
    It's a good idea, but I rarely call Send in the main script anyway, and I don't mind doing lower level calls in the common script because it's not something I modify very often.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Alright, there's the working version of the Ryu f.Throw Backdash j.HP/cross tatsu Setup, working both sides (you choose side with left and right keyboard arrows anytime during the session) and you launch the setup with the L1 button on your stick (4th punch)
    ; Ryu : cr.MK xx HP fireball xx FADC, LP Shoryu xx FADC, Ultra
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    do_the_setup()
    {
      Global
      Random, Guess, 0, 1
      Walk(forward, 50)
      Throw(forward)
      Wait(78)
      Dash(backward)
      Wait(25)
      Jump(forward)
      if (Guess = 1)
      {
          Wait(28)
          push(HP)
          Wait(2)
          release(HP)
      }
      else
      {
          Wait(17)
          Tatsu(backward, MK)
      }
    }
     
     
     
     
     
    ; controls for Cancel and side selection
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Cancel := true
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    and this is the common.ahk where I store the moves functions
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 12 ; Not sure about usefullness
    SendMode Input ; Not sure about usefullness
     
    ONE_FRAME_IN_MS = 16.67
    ; Edit these following var with your own keyboard mapping for Street Fighter Keyboard
    LEFT    := "q"
    RIGHT  := "d"
    UP    := "z"
    DOWN    := "s"
    LP      := "i"
    MP      := "o"
    HP      := "p"
    LK      := "k"
    MK      := "l"
    HK      := "m"
     
    Wait(frames)
    {
      Global
      Letimer := frames * ONE_FRAME_IN_MS
      Sleep, %Letimer%
    }
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    FADC(direction)
    {
      Global
      push(MP)
      push(MK)
      push(direction)
      Wait(3)
      release(direction)
      Wait(2)
      push(direction)
      Wait(3)
      release(direction)
      release(MP)
      release(MK)
    }
    Fireball(direction, punch)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(punch)
      Wait(2)
      release(direction)
      release(punch)
      Wait(6)
    }
    Tatsu(direction, kick)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(kick)
      Wait(2)
      release(direction)
      release(kick)
      Wait(6)
    }
    Jump(direction)
    {
      Global
      if(direction = "neutral")
      {
        push(UP)
        Wait(2)
        release(UP)
        Wait(2)
      }
      else
      {
        push(direction)
        push(UP)
        Wait(2)
        release(direction)
        release(UP)
        Wait(2)
      }
    }
    Throw(direction)
    {
      Global
      push(direction)
      push(LK)
      push(LP)
      Wait(2)
      release(direction)
      release(LK)
      release(LP)
      Wait(2)
    }
    Cr_MK_xx_Fireball(direction, punch)
    {
      Global
      push(DOWN)
      push(MK)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      release(MK)
      Wait(2)
      push(punch)
      release(direction)
      Wait(4)
      release(punch)
      Wait(2)
    }
    SRK(direction, punch)
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      push(punch)
      release(direction)
      release(DOWN)
      Wait(2)
      release(punch)
      Wait(2)
    }
    ULTRA_2X_QC_PPP(direction)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      Wait(2)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      push(LP)
      push(MP)
      push(HP)
      Wait(4)
      release(LP)
      release(MP)
      release(HP)
      Wait(6)
    }
    
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    This is the Footsies training. Loop is cr:mk: or cr:mk: xx Fireball randomly, plus Ryu will punish your whiffed sweep if at range.
    You can start and stop the dummy loop anytime, change the side with arrow keys anytime
    ; Ryu : cr.MK xx HP fireball Footsies training, try to Sweep his whiffed kicks
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    do_the_setup()
    {
    Global
    Run := "go"
      While(Run = "go")
      {
      ; Walk forward a random amount of time
        Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
        Walk(forward, howLong)
     
      ; Randomly do cr.mk
        Guess := Mod(Round(howLong), 5)
        If (Guess = 1) {
            push(backward)
            Wait(6)
            release(backward) ; to avoid SRK instead of fireball
            Cr_MK_xx_Fireball(forward, HP)
            Wait(14)
        }
         
      ; Walk backward roughly the same distance, but modify
      ; the time because Ryu's backward speed is slower
      ; than his forward speed
        howLong += 6
        Walk(backward, howLong)
     
      ; Randomly do cr.mk
        Guess := Mod(Round(howLong), 4)
        If (Guess = 0) {
            Cr_MK()
            Wait(14)
        }
     
      }
    }
     
    ; Set Ruy's punish if we whiff a sweep
    2joy8::
      Wait(12)
      Sweep()
      return
     
    ; controls for start/stop and sides live switch
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Run := "stop"
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    the common.ahk file
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 12 ; Not sure about usefullness
    SendMode Input ; Not sure about usefullness
     
    ONE_FRAME_IN_MS = 16.67
    LEFT    := "q"
    RIGHT   := "d"
    UP    := "z"
    DOWN     := "s"
    LP      := "i"
    MP      := "o"
    HP      := "p"
    LK      := "k"
    MK      := "l"
    HK      := "m"
     
    Wait(frames)
    {
      Global
      Letimer := frames * ONE_FRAME_IN_MS
      Sleep, %Letimer%
    }
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    FADC(direction)
    {
      Global
      push(MP)
      push(MK)
      push(direction)
      Wait(3)
      release(direction)
      Wait(2)
      push(direction)
      Wait(3)
      release(direction)
      release(MP)
      release(MK)
    }
    Fireball(direction, punch)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(punch)
      Wait(2)
      release(direction)
      release(punch)
      Wait(6)
    }
    Tatsu(direction, kick)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(kick)
      Wait(2)
      release(direction)
      release(kick)
      Wait(6)
    }
    Jump(direction)
    {
      Global
      if(direction = "neutral")
      {
        push(UP)
        Wait(2)
        release(UP)
        Wait(2)
      }
      else
      {
        push(direction)
        push(UP)
        Wait(2)
        release(direction)
        release(UP)
        Wait(2)
      }
    }
    Throw(direction)
    {
      Global
      push(direction)
      push(LK)
      push(LP)
      Wait(2)
      release(direction)
      release(LK)
      release(LP)
      Wait(2)
    }
    Cr_MK()
    {
      Global
      push(backward)
      push(DOWN)
      push(MK)
      Wait(2)
      release(MK)
      release(backward)
      release(DOWN)
    }
    Sweep()
    {
      Global
      push(backward)
      push(DOWN)
      push(HK)
      Wait(2)
      release(HK)
      release(backward)
      release(DOWN)
    }
    Cr_MK_xx_Fireball(direction, punch)
    {
      Global
      push(DOWN)
      push(MK)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      release(MK)
      Wait(2)
      push(punch)
      release(direction)
      Wait(4)
      release(punch)
      Wait(2)
    }
    SRK(direction, punch)
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      push(punch)
      release(direction)
      release(DOWN)
      Wait(2)
      release(punch)
      Wait(2)
    }
    ULTRA_2X_QC_PPP(direction)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      Wait(2)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      push(LP)
      push(MP)
      push(HP)
      Wait(4)
      release(LP)
      release(MP)
      release(HP)
      Wait(6)
    }
    
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Another training dummy using AutoHotKey application, Footsies + Cross up, anti air training
    The dummy will first ask you to set the side like in the other codes above so when you first start the loop by pushing the L1 button, don't forget to push the keyboard arrow corresponding to the forward for the dummy. Then it will automatically update the side when he cross you up. And if for some reason he ends on the wrong side you can still force the sides using the arrow keys.
    Select button cancels the loop, you may need to mash select a bit to register the command.

    So the loop is walking back and forth trying to land a cr:mk: xx fireball / or rush to you with cr:lp: cr:lp:, cr:mp: xx fireball / or rush to you with cr:lp: cr:lp:, jump cross up :mk:
    I could add a thick throw mixup but it's already a lot of mix up for a training, I'll put it in another file to train separately.
    ; Ryu : cr.MK xx HP fireball Footsies training, try to Sweep his whiffed kicks
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    ; cr.jab x 2, cr.mk xx fireball
    Jabs_to_ball(approach)
    {
      Global
      Walk(forward, approach)
      push(DOWN)
      push(backward)
      Wait(2)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(18)
      push(MP)
      Wait(1)
      push(LP)
      Wait(2)
      release(backward)
      release(MP)
      release(LP)
      Wait(2)
      push(forward)
      Wait(2)
      release(DOWN)
      Wait(2)
      push(HP)
      Wait(2)
      release(forward)
      release(HP)
    }
     
    Jabs_to_Cross_mk(approach)
    {
      Global
      Walk(forward, approach)
      push(DOWN)
      push(backward)
      Wait(2)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(22)
      release(DOWN)
      release(backward)
      push(forward)
      push(UP)
      Wait(2)
      release(forward)
      release(UP)
      Wait(28)
      push(MK)
      Switch_side()
      Wait(12)
      release(MK)
    }
     
     
     
    do_the_setup()
    {
    Global
    Run := "go"
      While(Run = "go")
      {
      ; Walk forward a random amount of time
        Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
        Walk(forward, howLong)
     
      ; Randomly do block string to fireball
        Guess := Mod(Round(howLong), 5)
        If (Guess = 1) {
            push(backward)
            Wait(6)
            release(backward) ; to avoid SRK instead of fireball
            Jabs_to_ball(30)
            Wait(40)
        }
       
      ; Walk backward roughly the same distance, but modify
      ; the time because Ryu's backward speed is slower
      ; than his forward speed
        howLong += 6
        Walk(backward, howLong)
     
      ; Randomly do cr.mk
        Guess := Mod(Round(howLong), 4)
        If (Guess = 0) {
            Cr_MK_xx_Fireball(forward, HP)
            Wait(14)
        }
     
      ; Randomly do Cross UP
        Guess := Mod(Round(howLong), 4)
        If (Guess = 3) {
            Jabs_to_Cross_mk(30)
            Wait(14)
        }
     
      }
    }
     
     
     
    ; Set Ruy's punish if we whiff a sweep
    2joy8::
      Wait(12)
      Sweep()
      return
     
     
    ; controls for Cancel and side selection
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Run := "stop"
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    common.ahk
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 12 ; Not sure about usefullness
    SendMode Input ; Not sure about usefullness
     
    ONE_FRAME_IN_MS = 16.67
    LEFT    := "q"
    RIGHT  := "d"
    UP    := "z"
    DOWN    := "s"
    LP      := "i"
    MP      := "o"
    HP      := "p"
    LK      := "k"
    MK      := "l"
    HK      := "m"
     
     
    Switch_side()
    {
      Global
      if(forward = RIGHT)
      {
        forward := LEFT
        backward := RIGHT
      }
      else
      {
        forward := RIGHT
        backward := LEFT
      }
    }
    Wait(frames)
    {
      Global
      Letimer := frames * ONE_FRAME_IN_MS
      Sleep, %Letimer%
    }
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    FADC(direction)
    {
      Global
      push(MP)
      push(MK)
      push(direction)
      Wait(3)
      release(direction)
      Wait(2)
      push(direction)
      Wait(3)
      release(direction)
      release(MP)
      release(MK)
    }
    Fireball(direction, punch)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(punch)
      Wait(2)
      release(direction)
      release(punch)
      Wait(6)
    }
    Tatsu(direction, kick)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      push(kick)
      Wait(2)
      release(direction)
      release(kick)
      Wait(6)
    }
    Jump(direction)
    {
      Global
      if(direction = "neutral")
      {
        push(UP)
        Wait(2)
        release(UP)
        Wait(2)
      }
      else
      {
        push(direction)
        push(UP)
        Wait(2)
        release(direction)
        release(UP)
        Wait(2)
      }
    }
    Throw(direction)
    {
      Global
      push(direction)
      push(LK)
      push(LP)
      Wait(2)
      release(direction)
      release(LK)
      release(LP)
      Wait(2)
    }
    Cr_MK()
    {
      Global
      push(backward)
      push(DOWN)
      push(MK)
      Wait(2)
      release(MK)
      release(backward)
      release(DOWN)
    }
    Sweep()
    {
      Global
      push(backward)
      push(DOWN)
      push(HK)
      Wait(2)
      release(HK)
      release(backward)
      release(DOWN)
    }
    Cr_MK_xx_Fireball(direction, punch)
    {
      Global
      push(DOWN)
      push(MK)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      release(MK)
      Wait(2)
      push(punch)
      release(direction)
      Wait(4)
      release(punch)
      Wait(2)
    }
    SRK(direction, punch)
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      push(punch)
      release(direction)
      release(DOWN)
      Wait(2)
      release(punch)
      Wait(2)
    }
    ULTRA_2X_QC_PPP(direction)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      Wait(2)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      push(LP)
      push(MP)
      push(HP)
      Wait(4)
      release(LP)
      release(MP)
      release(HP)
      Wait(6)
    }
    
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Thick throw / Cross up / low forward fireball Loop
    ; Ryu : cr.MK xx HP fireball Footsies training, try to Sweep his whiffed kicks
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    ; cr.jab x 2, cr.mk xx fireball
    Jabs_to_ball(approach)
    {
      Global
      Walk(forward, approach)
      push(DOWN)
      push(backward)
      Wait(2)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(18)
      push(MP)
      Wait(1)
      push(LP)
      Wait(2)
      release(backward)
      release(MP)
      release(LP)
      Wait(2)
      push(forward)
      Wait(2)
      release(DOWN)
      Wait(2)
      push(HP)
      Wait(2)
      release(forward)
      release(HP)
    }
     
    Jabs_Thick_Throw(approach)
    {
      Global
      Walk(forward, approach)
      push(DOWN)
      push(backward)
      Wait(2)
      push(LP)
      Wait(2)
      release(LP)
      Wait(14)
      release(backward)
      release(DOWN)
      Wait(2)
      Walk(forward, 10)
      Throw(forward)
    }
     
    Jabs_to_Cross_mk(approach)
    {
      Global
      Walk(forward, approach)
      push(DOWN)
      push(backward)
      Wait(2)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(12)
      push(LP)
      Wait(2)
      release(LP)
      Wait(22)
      release(DOWN)
      release(backward)
      push(forward)
      push(UP)
      Wait(2)
      release(forward)
      release(UP)
      Wait(24)
      push(MK)
      Switch_side()
      Wait(12)
      release(MK)
    }
     
     
     
    do_the_setup()
    {
     Global
     Run := "go"
      While(Run = "go")
      {
        Random, Guess, 0, 30
       ; Walk forward a random amount of time
        Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
        Walk(forward, howLong)
     
       ; Randomly do cr.mk xx fireball
        if (Guess > 15) {
            push(backward)
            Wait(8)
            release(backward)
            Cr_MK_xx_Fireball(forward, HP)
            Wait(14)
        }
        else
        {
           if(Guess < 8)
           {
            ; Randomly do block string to Thick throw
             push(backward)
             Wait(6)
             release(backward) ; to avoid SRK instead of fireball
             Jabs_Thick_Throw(30)
             Wait(80)
           }
           else
           {
            Jabs_to_Cross_mk(30)
            push(DOWN)
            push(backward)
            Wait(2)
            push(LK)
            Wait(2)
            release(LK)
            Wait(18)
            push(LK)
            Wait(2)
            release(LK)
            Wait(18)
            push(LP)
            Wait(2)
            release(LP)
            release(DOWN)
            release(backward)
            Wait(18)
            Dash(backward)
           }
        }
           
       ; Walk backward roughly the same distance, but modify
       ; the time because Ryu's backward speed is slower
       ; than his forward speed
        howLong += 6
        Walk(backward, howLong)
      }
    }
     
     
     
    ; Set Ruy's punish if we whiff a sweep
    2joy8::
      Wait(12)
      Sweep()
      return
     
     
    ; controls for Cancel and side selection
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Run := "stop"
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    common.ahk is the same than previous post
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    If I had time and was better at coding, I would probably make a "Script maker" that record inputs and create the corresponding .ahk file with timing and all.
    It's possible but would take a long time to cover all possibilities. Maybe I'll give it a try later.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Akuma fool damage combo jump HK Hp fireball FADC x2 Tatsu sweep, with plink HP and sweep
    ; Akuma jump HK cl.HP xx Fireball FADC cl.HP FADC Fireball FADC cl.HP xx LK Tatsu Sweep
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    do_the_setup()
    {
      Global
     
      Jump(forward)
      Wait(28)
      push(HK)
      Wait(2)
      release(HK)
     
      Wait(20)
      push(HP)
      Wait(1)
      push(MP)
      Wait(2)
      release(MP)
      release(HP)
      Wait(4)
     
      QC_X(forward, HP)
      Wait(10)
      FADC(forward)
     
      Wait(20)
      push(HP)
      Wait(1)
      push(MP)
      Wait(2)
      release(MP)
      release(HP)
      Wait(4)
     
      QC_X(forward, HP)
      Wait(10)
      FADC(forward)
     
      Wait(16)
      push(HP)
      Wait(1)
      push(MP)
      Wait(2)
      release(MP)
      release(HP)
      Wait(4)
     
      QC_X(backward, LK)
      Wait(43)
      Sweep()
    }
     
     
     
     
     
    ; controls for Cancel and side selection
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Cancel := true
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    The common.ahk updated
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 12 ; Not sure about usefullness
    SendMode Input ; Not sure about usefullness
     
    ONE_FRAME_IN_MS = 16.67
    LEFT    := "q"
    RIGHT   := "d"
    UP    := "z"
    DOWN     := "s"
    LP      := "i"
    MP      := "o"
    HP      := "p"
    LK      := "k"
    MK      := "l"
    HK      := "m"
     
     
    Switch_side()
    {
      Global
      if(forward = RIGHT)
      {
        forward := LEFT
        backward := RIGHT
      }
      else
       {
        forward := RIGHT
        backward := LEFT
      }
    }
    Wait(frames)
    {
      Global
      Letimer := frames * ONE_FRAME_IN_MS
      Sleep, %Letimer%
    }
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    FADC(direction)
    {
      Global
      push(MP)
      push(MK)
      push(direction)
      Wait(3)
      release(direction)
      Wait(2)
      push(direction)
      Wait(3)
      release(direction)
      release(MP)
      release(MK)
    }
    QC_X(direction, hit)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      push(hit)
      Wait(2)
      release(direction)
      release(hit)
      Wait(6)
    }
    Jump(direction)
    {
      Global
      if(direction = "neutral")
      {
        push(UP)
        Wait(2)
        release(UP)
        Wait(2)
      }
      else
      {
        push(direction)
        push(UP)
        Wait(2)
        release(direction)
        release(UP)
        Wait(2)
      }
    }
    Throw(direction)
    {
      Global
      push(direction)
      push(LK)
      push(LP)
      Wait(2)
      release(direction)
      release(LK)
      release(LP)
      Wait(2)
    }
    Cr_MK()
    {
      Global
      push(backward)
      push(DOWN)
      push(MK)
      Wait(2)
      release(MK)
      release(backward)
      release(DOWN)
    }
    Sweep()
    {
      Global
      push(backward)
      push(DOWN)
      Wait(2)
      push(HK)
      Wait(1)
      push(MK)
      Wait(2)
      release(MK)
      release(HK)
      release(backward)
      release(DOWN)
    }
    Cr_MK_xx_Fireball(direction, punch)
    {
      Global
      push(DOWN)
      push(MK)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      release(MK)
      Wait(2)
      push(punch)
      release(direction)
      Wait(4)
      release(punch)
      Wait(2)
    }
    SRK(direction, punch)
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      if(punch = "EXP")
      {
        push(LP)
        push(MP)
      }
      else if(punch = "EXK")
      {
        push(LK)
        push(MK)
      }
      else
      {
        push(punch)
      }
      release(direction)
      release(DOWN)
      Wait(2)
      if(punch = "EXP")
      {
        release(LP)
        release(MP)
      }
      else if(punch = "EXK")
      {
        release(LK)
        release(MK)
      }
      else
      {
        release(punch)
      }
      Wait(2)
    }
    ULTRA_2X_QC_PPP(direction)
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      Wait(2)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      push(LP)
      push(MP)
      push(HP)
      Wait(4)
      release(LP)
      release(MP)
      release(HP)
      Wait(6)
    }
    
  • TheMuffinManTheMuffinMan 「満」 「寸」 「越」 Joined: Posts: 504
    I've been trying to get this to work with MAME + Super Street Fighter 2 Turbo, but there has been a lack of success. Have you guys tested AutoHotkey with emulators at all?
    "That you float along in the ocean and live a life of peace does not come from your own resourcefulness." - Demon's Sermon on Martial Arts
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    I don't get why it would not work as it's only supposed to send the same info to the OS than a keyboard or stick, so as soon as your Emulator works with a keyboard and you use the same key map than your keyboard options in game, you should have no problem.
    But that's on paper, I never tried an emulator.
  • mrdhalsimmrdhalsim Joined: Posts: 378
    Hi everyone, XSPR here, I will use my time machine to go back in time and make this kind of thing, and call it TRUST
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    I've been trying to get this to work with MAME + Super Street Fighter 2 Turbo, but there has been a lack of success. Have you guys tested AutoHotkey with emulators at all?
    Yes, I've got it to work with FBA. I've tested the initital POC footsie script and it does work, but it needs needs some alteration because of game/emu timing etc. It's a useful tool though, and there's a lot of room for creativity.
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    Hi everyone, XSPR here, I will use my time machine to go back in time and make this kind of thing, and call it TRUST
    TRUST was in fact the main influence of me investigating the use of macro programs with SSFIV (especially the example of punishing Guile's sweep/mk) because no such things existed at the time.
  • MarceloAbansMarceloAbans The Fat Man Joined: Posts: 343
    I only ever trusted this for leveling up my fishing prof...
    ofcsd.com
    twitch.tv/ofcsd
    Where good things happen..
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    I assume it's normal I don't get a clue what you're talking about if I wasn't a gamer the past 10 years. :)
    Is this Trust a kind of advanced macro like it looks like ? Is this still available somewhere and worth the time if I don't have those old SF games ?
  • AckuAcku Representing Rose Joined: Posts: 826 ✭✭
    If I can figure out how to simulate keyboard actions in the Java system, I could write a nice DSL (domain specific language) in Groovy for this.
    Ryu ryu = new Ryu()
    ryu.hadoken(version: HP)
    wait(50.frames)
    ryu.jump(direction: forward)
    wait(10.frames)
    ryu.kick(version: HK)
    

    would become even better if you would import all frame data, which could make the script intelligent like
    Ryu ryu = new Ryu()
    ryu.hadoken(version: HARD).and(shoryuken(version: MEDIUM))
    walk(direction:forward, time: 120.frames)
    ryu.kick(version: MEDIUM, stance: CROUCH).cancel(hadoken(version: MEDIUM))
    

    could be more elegant, but it has possibilities. Still one would need to do a lot of experimentation to get the frames right, for example jumps look hard to me to get perfect.
  • C2QC2Q Joined: Posts: 1,162
    Is there any script for footsies and random jump ins? I would love to practice reaction demons to those.

    Also I'm getting an error using your footsies ahk script. Gives me an error saying that Cr_Mk() is a nonexistent function.
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
  • mrdhalsimmrdhalsim Joined: Posts: 378
    TRUST was in fact the main influence of me investigating the use of macro programs with SSFIV (especially the example of punishing Guile's sweep/mk) because no such things existed at the time.

    Awesome work with it... the best parts of our community are made by ourselves.
    (For more info on TRUST, more specific to ST, here's how to get started: http://www.kuroppi.com/t-r-u-s-t/ )

    XSPR
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    Is there any script for footsies and random jump ins? I would love to practice reaction demons to those.

    Also I'm getting an error using your footsies ahk script. Gives me an error saying that Cr_Mk() is a nonexistent function.

    Yes there is one against Ryu. check the thread in the main forum linked in first post above. If you want a specific one, just tell me.
  • C2QC2Q Joined: Posts: 1,162
    I can't get the scripts to work. Keeps saying Mk is an uncallable function or some error like that :(
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
  • ilitiritilitirit Joined: Posts: 5,203 ✭✭✭✭✭
    I can't get the scripts to work. Keeps saying Mk is an uncallable function or some error like that :(
    There are two files, common.ahk and the main script.

    common.ahk is where commonly used/called functions go, and it's most likely where you'll find the MK() function
  • C2QC2Q Joined: Posts: 1,162
    I have common.ahk as well as the normal script. However maybe I'm not using it right? I have common.ahk in the same folder as the script and I just run the script right?

    I dunno how to use autohotkey right.
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    in fact you just install it. and then you don't have to launch anything.
    You previously have copy pasted the script from the thread to text files using Notepad, one called "common" that you'll rename to common.ahk (instead of common.txt) and the other one call it whatever you want with the ahk extension. To launch a script just double click it. Autohotkey icon will show in tray bar near the clock and other running app.
    If you have this error message I assume you installed it properly. Be sure to copy paste exactly what is written in the code.

    And be sure to use the right "common" file. For each post I modified the common file's function so its not working with other scipt in other posts, you should always use the script + common that is in the same post.

    I left the files laying in the My Document folder, seems the default folder. both files should be in the same place.
  • C2QC2Q Joined: Posts: 1,162
    Ok well the script works but it doesn't do anything..I put the dummy on human, put the controls as what I have on the keyboard. I'm also using the keyboard though so do I need another controller or something for this to work? The Autoit script in the first post worked swimmingly.
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    well it was scripted to use with a stick. But you can edit the scripts to change those trigger keys.
    It's normal if the dummy don't do anything, you have to initiate the loop by pushing L1 button (after you have set the side using arrow keys of course).

    For you this :
    2joy5::
    do_the_setup()
    return

    Should be modified to

    "whatever key you want"::
    do_the_setup()
    return

    Example :
    g::
    do_the_setup()
    return

    Autohotkey is above Autoit only because it recognize fightstick inputs and that make it possible for the dummy to punish your moves. If you're not using stick, this make less sense of course ^^.

    Buy a stick ?

    Anyway there is your training course for anti air demon inside a fireball war session.
    ; Ryu : cr.MK xx HP fireball Footsies training, try to Sweep his whiffed kicks
    #include common.ahk
     
    MIN_WALK_FRAMES := 5
    MAX_WALK_FRAMES := 20
     
    Fireball_War()
    {
      Global
      Random, Guess, 0, 10
      if(Guess > 3)
      QC_X(forward, HP)
      else
      QC_X(forward, "EXP")
      Wait(20)
    }
     
    do_the_setup()
    {
    Global
    Run := "go"
      While(Run = "go")
      {
        Random, Guess, 0, 30
      ; Walk forward a random amount of time
        Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
        Walk(forward, howLong)
        Walk(backward, 5)
     
      ; Randomly throw fireballs
        if (Guess > 8) {
            Fireball_War()
        }
        else
        {
        Jump(forward)
        Wait(15)
        push(HK)
        Wait(4)
        release(HK)
        Wait(4)
        push(UP)
        Wait(30)
        release(UP)
        Wait(30)
        Dash(backward)
        Wait(14)
        Jump(backward)
        Wait(20)
        }
     
      ; Walk backward roughly the same distance, but modify
      ; the time because Ryu's backward speed is slower
      ; than his forward speed
        howLong += 20
        Walk(backward, howLong)
      }
    }
     
     
     
    ; Set Ruy's punish if we whiff a sweep
    2joy8::
      Wait(12)
      Sweep()
      return
     
     
    ; controls for Cancel and side selection
    2joy5::
      do_the_setup()
      return
     
    2joy9::
      Run := "stop"
      return
     
    LEFT::
      forward := LEFT
      backward := RIGHT
      return
     
    RIGHT::
      forward := RIGHT
      backward := LEFT
      return
    

    common.ahk file
    #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
    SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
    SetKeyDelay 12 ; Not sure about usefullness
    SendMode Input ; Not sure about usefullness
     
    ONE_FRAME_IN_MS = 16.67
    LEFT    := "q"
    RIGHT  := "d"
    UP    := "z"
    DOWN    := "s"
    LP      := "i"
    MP      := "o"
    HP      := "p"
    LK      := "k"
    MK      := "l"
    HK      := "m"
     
     
    Switch_side() ; instantly switch the value of LEFT and RIGHT so the dummy do the moves on the right side. Usefull when your setup involve a cross up.
    {
      Global
      if(forward = RIGHT)
      {
        forward := LEFT
        backward := RIGHT
      }
      else
      {
        forward := RIGHT
        backward := LEFT
      }
    }
    Wait(frames)
    {
      Global
      Letimer := frames * ONE_FRAME_IN_MS
      Sleep, %Letimer%
    }
     
    push(button)
    {
      Global
      Send {%button% down}
    }
    release(button)
    {
      Global
      Send {%button% up}
    }
     
    Walk(direction, howLong)
    {
      Global
      push(direction)
      Wait(howLong)
      release(direction)
      Wait(2)
    }
     
    Dash(direction)
    {
      Global
      push(direction)
      Wait(2)
      release(direction)
      Wait(2)
      push(direction)
      Wait(2)
      release(direction)
      Wait(6)
    }
    FADC(direction)
    {
      Global
      push(MP)
      push(MK)
      push(direction)
      Wait(3)
      release(direction)
      Wait(2)
      push(direction)
      Wait(3)
      release(direction)
      release(MP)
      release(MK)
    }
    QC_X(direction, hit) ; hit = "LP", "MP", "HK", etc. for ex , use "EXP" or "EXK"
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      if(hit = "EXP")
      {
      push(LP)
        push(MP)
      }
      else if(hit = "EXK")
    {
      push(LK)
        push(MK)
      }
      else
      {
      push(hit)
      }
      Wait(2)
      release(direction)
      if(hit = "EXP")
      {
      release(LP)
        release(MP)
      }
      else if(hit = "EXK")
    {
      release(LK)
        release(MK)
      }
      else
      {
      release(hit)
      }
      Wait(6)
    }
    Jump(direction)
    {
      Global
      if(direction = "neutral")
      {
        push(UP)
        Wait(2)
        release(UP)
        Wait(2)
      }
      else
      {
        push(direction)
        push(UP)
        Wait(6)
        release(direction)
        release(UP)
        Wait(2)
      }
    }
    Throw(direction)
    {
      Global
      push(direction)
      push(LK)
      push(LP)
      Wait(5)
      release(direction)
      release(LK)
      release(LP)
      Wait(2)
    }
    Cr_MK()
    {
      Global
      push(backward)
      push(DOWN)
      push(MK)
      Wait(2)
      release(MK)
      release(backward)
      release(DOWN)
    }
    Sweep() ; this sweep is plinked by default
    {
      Global
      push(backward)
      push(DOWN)
      Wait(2)
      push(HK)
      Wait(1)
      push(MK)
      Wait(2)
      release(MK)
      release(HK)
      release(backward)
      release(DOWN)
    }
    Cr_MK_xx_Fireball(direction, punch)
    {
      Global
      push(DOWN)
      push(MK)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      release(MK)
      Wait(2)
      push(punch)
      release(direction)
      Wait(4)
      release(punch)
      Wait(2)
    }
    SRK(direction, punch) ; works for any shoryu motion with punches or kicks : "EXP" to do an ex with punches, "EXK" for ex kicks, "LP", "MP", "HK", etc, for normals.
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      if(punch = "EXP")
      {
        push(LP)
        push(MP)
      }
      else if(punch = "EXK")
      {
        push(LK)
        push(MK)
      }
      else
      {
        push(punch)
      }
      release(direction)
      release(DOWN)
      Wait(2)
      if(punch = "EXP")
      {
        release(LP)
        release(MP)
      }
      else if(punch = "EXK")
      {
        release(LK)
        release(MK)
      }
      else
      {
        release(punch)
      }
      Wait(2)
    }
    Teleport(direction, punch) ; punch = "punch" or "kick" to do the specified teleport.
    {
      Global
      push(direction)
      Wait(4)
      release(direction)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      if(punch = "kick")
      {
        push(LK)
        push(MK)
        push(HK)
      }
      else
      {
        push(LP)
        push(MP)
        push(HP)
      }
      release(direction)
      release(DOWN)
      Wait(2)
      if(punch = "kick")
      {
        release(LK)
        release(MK)
        release(HK)
      }
      else
      {
        release(LP)
        release(MP)
        release(HP)
      }
      Wait(2)
    }
    ULTRA_2X_QC_PPP(direction) ; clean double quarter circle ultra, don't use it for kara ultra like those involving super jump cancels.
    {
      Global
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      Wait(2)
      push(DOWN)
      Wait(2)
      push(direction)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(direction)
      push(LP)
      push(MP)
      push(HP)
      Wait(4)
      release(LP)
      release(MP)
      release(HP)
      Wait(6)
    }
     
    HC_forward(punch) ; "EXP" for ex punch, "EXK" for ex kick, "LP", "MP", "HK", etc for normals
    {
      Global
      push(backward)
      push(DOWN)
      Wait(2)
      release(backward)
      Wait(2)
      push(forward)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(forward)
      if(punch = "EXP")
      {
        push(LP)
        push(MP)
      }
      else if(punch = "EXK")
      {
        push(LK)
        push(MK)
      }
      else
      {
        push(punch)
      }
      Wait(2)
      if(punch = "EXP")
      {
        release(LP)
        release(MP)
      }
      else if(punch = "EXK")
      {
        release(LK)
        release(MK)
      }
      else
      {
        release(punch)
      }
      Wait(2)
    }
     
    HC_backward(punch) ; "EXP" for ex punch, "EXK" for ex kick, "LP", "MP", "HK", etc for normal
    {
      Global
      push(forward)
      push(DOWN)
      Wait(2)
      release(forward)
      Wait(2)
      push(backward)
      Wait(2)
      release(DOWN)
      Wait(2)
      release(backward)
      if(punch = "EXP")
      {
        push(LP)
        push(MP)
      }
      else if(punch = "EXK")
      {
        push(LK)
        push(MK)
      }
      else
      {
        push(punch)
      }
      Wait(2)
      if(punch = "EXP")
      {
        release(LP)
        release(MP)
      }
      Wait(2)
      if(punch = "EXK")
      {
        release(LK)
        release(MK)
      }
      else
      {
        release(punch)
      }
      Wait(2)
    }
    
  • C2QC2Q Joined: Posts: 1,162
    Question, so 2joyx can be changed to any key? I'm not sure what key to change 2joy5 to for example. Is it my movement keys or the dummies?

    Also what's the L1 key?
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
  • ShabroutShabrout Joined: Posts: 1,199 ✭✭✭
    yes 2joyX mean joystick n°2 (because on my Windows 7 it's recognized as the n°2 [SIZE=13px]although there's no n°1…[/SIZE]
    [SIZE=13px]and JoyX X is the button. 1 2 3 4 5 6 7 8 9 10 for a 8 buttons stick + select start[/SIZE]

    [SIZE=13px]The key you are trying to modify do not interfere with the setup. You won't use the same keys you use on your game options. Choose a completely different key un-used. It's just a trigger to start the session.[/SIZE]
    [SIZE=13px]You could even use Fx keys or a combinaison of Ctrl + key etc but this is documented in the Autohotkey Help I'm not a specialist.You can set it to be DOWN arrow key. The LEFT and RIGHT arrow keys are already set to modify orientation of the setups while you're in the loop.[/SIZE]
    [SIZE=13px]DOWN::[/SIZE]
    do_the_setup()
    return
  • C2QC2Q Joined: Posts: 1,162
    Oh hmm, ok so I set the joy buttons to 3 keys I don't use at all right (your above script has 3 buttons to change I believe). So I went into training and just pushed those keys to start the session but the dummy did some random crap and then just stopped.
    AE 2012: Akuma (main), Evil Ryu, Guy, Yun, Yang, Ryu.
«13
Sign In or Register to comment.