Training bots for Makoto on PC

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


I’m probably going to be making a couple more pressure bots in future when Ryu stops bodying me. Definitely Akuma with some demon flips added in because it’s easy, and see if I can mix it with the footsie bot and have it stand off fireballing and such not too… Yun and Sakura are also very likely candidates but we’ll see if I actually motivate to make any more, the current one has me pretty salty about defending in street fighter already though.

This is pretty awesome. Thanks for sharing.