I was recently inspired by this thread to play around with autohotkey to make some bots for better training room practice. I’ve got a couple of them functional so I thought I would post them here to see if anybody else could get them to run and get some use out of them.
The first one is general defense and reaction practice. Put the dummy on Ryu(or other Shoto), put yourself in the left corner and hit F1 to start(F4 to stop). The dummy will walk up, chain off a random number of light attacks and then do one of the following: go right into a cMK xx Fireball, or tick throw you, or walk up LP SRK, or walk up cLK xx Fireball, or overhead, or a delayed cMK xx Fireball, or cross-up jump, or neutral jump. The jumps are either MK or empty, and will be followed by either a sweep or throw. The basic idea is to sit there and block the mixup, tech the throws, AA the jumps, and punish the DPs without getting hit, though that proves to be roughly impossible for me. Don’t bother trying to fight back cause it’s totally free on defense(just like everybody >>)
The second one is for practicing safe-jumps. Put the dummy on Fei and just knock him down, he’ll reversal after cHP, HP Oroshi, Ex Oroshi, tHK, backthrow and Ultra 1. It’s set to only reversal 80% of the time so that you can make sure your jump attack would actually hit. It’s also not terribly smart so unless you’re backthrowing you’ll have to stay on the same side(I forgot the shortcut to mash out dps no matter what side the enemy is on), if a normal kick comes out just jump over him and go back to it. If you want to practice against a different champion you can change which reversal it’s using: edit the line that says DP(BACKWARD, HK). You can browse through the common.ahk file to see other things what you can make the dummy do, a couple examples are in the file already. You can also add in a slight delay to practice against Blanka, etc.
A Note: This one will require a little hand editing before it will work. You’ll have to change anywhere that it says JoyX to the correct button number on your layout, you can usually find out the correct numbers in Win7 under Devices and Printers > right click the controller > game controller settings > properties. The action associated with each button is always in comments right next to it. The timing autohotkey uses can also vary from computer to computer, so you may have to edit how long it waits by either changing delay at the top or manually editing the specific knockdown.
The third one is for practicing spacing and buffered pokes. This is just an edited version the footsie script taken from the thread above to use my version of the common.ahk. It makes the dummy move back and forth and kick out buffered cMKs and fireballs, with the occasional walk-up throw/yolo dp for the hell of it. F1 starts the dummy and F4 stops it.
To use the scripts go into training mode, set the dummy as human controlled(they’re set up to use the default keyboard 2 controls), and then run the script. Autohotkey is required, it adds a context menu to .ahk files so it’s pretty straightforward to run them. Cut and paste the scripts into notepad and save them all to the same directory.
Base file, you need to name the file common.ahk for the others to work.
Spoiler
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; Constant values
Global ONE_FRAME_IN_MS := 16.67
Global LEFT := "c"
Global RIGHT := "b"
Global UP := "f"
Global DOWN := "v"
Global LP := "1"
Global MP := "2"
Global HP := "3"
Global PPP := "4"
Global LK := "q"
Global MK := "w"
Global HK := "e"
Global KKK := "r"
wait(frames)
{
Sleep frames * ONE_FRAME_IN_MS
}
;Press and release a button, optional second argument to press two buttons.
tap(button, button2:=0)
{
SendInput {%button% down}
if(button2)
SendInput {%button2% down}
Sleep 30
SendInput {%button% up}
if(button2)
SendInput {%button2% up}
}
;Attempts to plink. Not 100% reliable.
plink(button, plink, button2:=0)
{
SendInput {%button% down}
if(button2)
SendInput {%button2% down}
Sleep 20
SendInput {%plink% down}
Sleep 30
SendInput {%button% up}
SendInput {%plink% up}
if(button2)
SendInput {%button2% up}
}
push(button)
{
SendInput {%button% down}
}
release(button)
{
SendInput {%button% up}
}
dash(direction)
{
tap(direction)
wait(2)
tap(direction)
}
walk(direction, frames)
{
push(direction)
wait(frames)
release(direction)
}
;no argument gives a neutral jump.
jump(direction:=0)
{
push(UP)
if (direction)
push(direction)
wait(2)
release(UP)
if (direction)
release(direction)
}
throw(direction)
{
push(direction)
push(LK)
push(LP)
wait(2)
release(direction)
release(LK)
release(LP)
}
FADC(direction)
{
push(MP)
push(MK)
wait(2)
dash(direction)
wait(2)
release(MP)
release(MK)
}
;Put in a third argument to do a double quarter-circle motion
QC(direction, button, double:=0)
{
push(DOWN)
wait(2)
push(direction)
wait(2)
release(DOWN)
if(double) {
wait(2)
release(direction)
push(DOWN)
wait(2)
push(direction)
wait(2)
release(DOWN)
}
tap(button)
release(direction)
}
;DP Motion. 8 frames. ;trying 6
DP(direction, button)
{
tap(direction)
push(DOWN)
wait(2)
push(direction)
; wait(2)
tap(button)
release(DOWN)
release(direction)
}
;Half circle motion using shortcut. 8 frames ;trying 6.
HC(direction, button)
{
if (direction = LEFT)
rev = RIGHT
else
rev = LEFT
push(rev)
push(DOWN)
wait(2)
release(rev)
push(direction)
wait(2)
release(DOWN)
tap(button)
release(direction)
}
;put in the double arguement to do a 720 instead. Not 100% reliable because game inputs suck.
;SPD motion, 10 frames for single, 14 frames for double.
SPD(direction, button, double:=0)
{
if (direction = LEFT)
rev := RIGHT
else
rev := LEFT
tap(direction)
tap(DOWN)
tap(rev)
tap(UP)
if (double) {
tap(direction)
tap(DOWN)
push(rev)
tap(button)
release(rev)
}
else
tap(button)
}
;Charge a direction for 55 frames and then attack, optional additional delay.
charge(direction, button, delay:=0)
{
if (direction = LEFT)
rev = RIGHT
else if (direction = RIGHT)
rev = LEFT
else if (direction = DOWN)
rev = UP
push(direction)
wait(55+delay)
release(direction)
push(rev)
push(button)
wait(2)
release(rev)
release(button)
}
;manage direction facing for easier scripting.
Global FORWARD := LEFT
Global BACKWARD := RIGHT
swap()
{
x:=FORWARD
FORWARD:=BACKWARD
BACKWARD:=x
}
p1()
{
FORWARD:=RIGHT
BACKWARD:=LEFT
}
p2()
{
FORWARD:=LEFT
BACKWARD:=RIGHT
}
Pressure bot
Spoiler
#include common.ahk
Global Pause := true
action_loop()
{
Pause:=false
Loop {
if Pause
break
ryu_pressure()
}
}
;Walk up, chain 1-3 low jabs/shorts into:
;cMK xx Fireball(link or delayed), throw, overhead, cross up or netural jump.
;Jumps can either be empty or MK and followed by either a throw or a sweep.
ryu_pressure()
{
walk(FORWARD,40)
push(DOWN)
;jab one to three times
Random x, 0, 2
if (x) {
Random y, 0, 1
if (y)
tap(LP)
else
tap(LK)
wait(14)
}
if (x=2) {
Random y, 0, 1
if (y)
tap(LP)
else
tap(LK)
wait(14)
}
tap(LP)
release(DOWN)
wait(20)
Random y, 0, 6
if (y = 0) {
;cMK xx Fireball
tap(MK,DOWN)
QC(FORWARD,HP)
} else if (y = 1) {
;Tick Throw
if (x) {
push(FORWARD)
wait(4*x)
}
wait(2)
throw(FORWARD)
} else if (y = 2) {
;Fake Tick Throw DP/Low
if (x) {
push(FORWARD)
wait(4*x)
}
wait(2)
Random z,0,1
if (z)
DP(FORWARD,LP)
else {
release(FORWARD)
push(DOWN)
tap(LK)
wait(20)
tap(MK)
QC(FORWARD,HP)
}
} else if (y = 3) {
;Over Head
tap(MP,FORWARD)
} else if (y = 4) {
;Delayed cMK xx Fireball
Random z, 2, 10
wait(z)
tap(MK,DOWN)
QC(FORWARD,HP)
} else if (y = 5) {
;Cross-up
wait(4)
ryu_jump(x,FORWARD)
} else if (y = 6) {
;Neutral-Jump
wait(4)
ryu_jump(x)
}
wait(60)
}
;Jump in, alternates between LK/MK/empty jump
;follow up with throw or low
ryu_jump(space, direction:=0)
{
jump(direction)
wait(30)
;empty jump or MK
Random x, 0, 1
if(x) {
tap(MK)
wait(9)
}
wait(9)
;sweep or throw
;maybe have this go right back into the pressure combos with a leading low or something.
Random y, 0, 1
if (y)
tap(HK,DOWN)
else {
if (space and not direction)
walk(FORWARD,12)
else if (x)
wait(12)
throw(FORWARD)
wait(20)
}
;reset position
wait(50)
if(direction) {
walk(BACKWARD,10)
jump(BACKWARD)
wait(45)
walk(FORWARD,20)
}
walk(FORWARD,15)
}
F1::
action_loop()
return
F4::
Pause := true
return
Safe-jump bot
Spoiler
#include common.ahk
Global delay:=0 ;Global delay, add here for blanka/etc practice.
reversal(frames)
{
wait(frames)
Random x, 0, 5
if (x)
DP(BACKWARD,HK)
;SRK
;DP(FORWARD,HP)
;Ex Headbutt, comment out where it says wait(frames)
;charge(BACKWARD,PPP,frames)
}
hp_and_what()
{
;Dpad right/left/down
GetKeyState dwn, Joy7
GetKeyState rht, Joy6
GetKeyState lft, Joy8
if (dwn="D") {
reversal(84+delay) ;Sweep
} else if (lft="D" or rht="D") {
reversal(124+delay) ;EX Oroshi
reversal(1) ;HP Oroshi
}
}
lp_and_what()
{
;LK
GetKeyState lk, Joy16
if (lk="D") {
swap()
reversal(174+delay) ;Throw
}
}
hk_and_what()
{
;Dpad right/left
GetKeyState rht, Joy6
GetKeyState lft, Joy8
if (lft="D" or rht="D") {
reversal(95+delay) ;t.HK
}
}
F1::
Suspend
return
;PPP
Joy9::
reversal(551+delay) ;Ultra1
return
;LP
Joy10::
lp_and_what()
return
;HP
Joy13::
hp_and_what()
return
;HK
Joy14::
hk_and_what()
return
Footsie script
Spoiler
#include common.ahk
MIN_WALK_FRAMES := 5
MAX_WALK_FRAMES := 30
Global Pause := true
action_loop()
{
Pause:=false
Loop {
if Pause
break
ryu_footsie()
}
}
ryu_footsie()
{
Global
Random howLong, MIN_WALK_FRAMES, MAX_WALK_FRAMES
guess := Round((howLong-5)/3)
if (guess = 1) {
walk(FORWARD, howLong)
wait(6)
tap(MK,DOWN)
QC(FORWARD,HP)
wait(14)
walk(BACKWARD, howLong*1.5)
} else if (guess = 2) {
QC(FORWARD,HP)
wait(58)
walk(BACKWARD, howLong*1.5)
} else if (guess = 3) {
walk(FORWARD, howLong+MAX_WALK_FRAMES)
throw(FORWARD)
wait(25)
walk(BACKWARD, howLong*1.5)
} else if (guess = 4) {
walk(FORWARD, howLong+MAX_WALK_FRAMES)
DP(FORWARD,LP)
wait(5)
FADC(FORWARD)
wait(18)
throw(FORWARD)
walk(BACKWARD, howLong*1.5)
} else {
walk(FORWARD, howLong)
walk(BACKWARD, howLong*1.5)
}
}
F1::
action_loop()
return
F4::
Pause := true
return