You can toggle each of the 4 bunny rabbit players to automatically jump around,
effectively making a pvp only game a single player game with bots.
Great fun for my 4 year old son.
Could be fairly easy to modify for other simple games.
Code: Select all
#SingleInstance Force
#Warn
; --------------------------------------------------------------------------------
; SETTINGS:
; --------------------------------------------------------------------------------
program_window_title := "Jump n Bump"
; SetTitleMatchMode : used for WinActive(...) and #IfWinActive directive.
; 1: A window's title must start with the specified WinTitle to be a match.
; 2: A window's title can contain WinTitle anywhere inside it to be a match.
; 3: A window's title must exactly match WinTitle to be a match.
SetTitleMatchMode, 3
; --------------------------------------------------------------------------------
; --------------------------------------------------------------------------------
; TODO
; --------------------------------------------------------------------------------
; Sometimes when moving focus outside of the window it still sends keypresses elsewhere.
; It does not happen often, but it does happen sometimes.
; e.g. alt tabbing to a text editor might put random characters there, which is bad.
; Not sure how to fix this yet. Might be say() related.
; --------------------------------------------------------------------------------
is_windowactive := false
players := []
players[1] := {n: 1, enabled: false, in_action: false, keys: {up: "Up" , left: "Left" , right: "Right" } }
players[2] := {n: 2, enabled: false, in_action: false, keys: {up: "w" , left: "a" , right: "d" } }
players[3] := {n: 3, enabled: false, in_action: false, keys: {up: "i" , left: "j" , right: "l" } }
players[4] := {n: 4, enabled: false, in_action: false, keys: {up: "Numpad8", left: "Numpad4", right: "Numpad6"} }
say(str) {
; NB: saying things blocks execution for a while, could be quite annoying. Use sparingly.
voice := ComObjCreate("SAPI.SpVoice")
voice.Rate := 3
voice.Volume := 80
voice.Speak(str)
}
player_enable_toggle(n) {
global players
player_enable_set(n, players[n].enabled ? false : true)
}
player_enable_set(n, newvalue) {
global players
newvalue := !! newvalue
if (players[n].enabled != newvalue ) {
players[n].enabled := newvalue
player_reset(n)
info()
; say("player " n " : " (newvalue ? "enabled" : "disabled") . ".")
}
}
player_reset(n) {
global players
players[n].in_action := false
key_up := players[n].keys.up
key_left := players[n].keys.left
key_right := players[n].keys.right
Send {%key_up% up}
Send {%key_left% up}
Send {%key_right% up}
}
player_reset_all() {
player_reset(1)
player_reset(2)
player_reset(3)
player_reset(4)
global queue
queue := []
}
info() {
global players
p1 := players[1].enabled ? "enabled" : "disabled"
p2 := players[2].enabled ? "enabled" : "disabled"
p3 := players[3].enabled ? "enabled" : "disabled"
p4 := players[4].enabled ? "enabled" : "disabled"
str =
(
Player 1: %p1%
Player 2: %p2%
Player 3: %p3%
Player 4: %p4%
F1..F4 to toggle player.
~ to show this info.
)
; MsgBox % str
Tooltip % str, 20, 40
SetTimer, removetooltip, -1000
}
removetooltip() {
ToolTip
}
; show info once on startup:
; info()
getTime_freq := 0
getTime() {
; return amount of seconds sinds computer turn on.
; precision seems to be 1 / 10,000,000 seconds.
global getTime_freq
if (!getTime_freq) {
DllCall("QueryPerformanceFrequency", "Int64*", getTime_freq)
; MsgBox % getTime_freq ; e.g. 10000000 (10,000,000)
}
microtime := 0
DllCall("QueryPerformanceCounter", "Int64*", microtime)
; MsgBox % microtime ; e.g. 25878136383
return microtime / getTime_freq
}
; put tasks with a "when" (do after timestamp) value in here:
queue := []
player_loop() {
global players
global queue
now = getTime()
for k, q in queue {
if (q && now > q.when) {
queue.RemoveAt(k)
/*
if (q.send_arr) {
for k_, s in q.send_arr {
send_key := s.key
send_updown := s.updown
; MsgBox % "send_key:" . send_key . " send_updown:" . send_updown
; ToolTip % "send_key:" . send_key . " send_updown:" . send_updown
Send {%send_key% %send_updown%}
}
}
*/
if (q.player_reset && q.n) {
player_reset(q.n)
}
players[q.n].in_action := false
}
}
n := 0
while (n < 4) {
n := n + 1
if ( ! players[n].enabled ) {
continue
}
if (players[n].in_action ) {
continue
}
; action is just an arbitrary number for an action
Random, action, 0, 2
key_up := players[n].keys.up
key_left := players[n].keys.left
key_right := players[n].keys.right
if (action = 0) {
; do nothing for a while
player_reset(n)
Random, rndtime, 500, 3000
queue.push({"n": n, "when": now + rndtime, player_reset: true})
players[n].in_action := true
}
if (action = 1) {
; jump left
player_reset(n)
Send {%key_up% down}
Send {%key_left% down}
Random, rndtime, 500, 1000
; queue.push({"n": n, "when": now + rndtime, "send_arr": [{"key": key_up, "updown": "up"}, {"key": key_left, "updown": "up"}]})
queue.push({"n": n, "when": now + rndtime, player_reset: true})
players[n].in_action := true
}
if (action = 2) {
; jump right
player_reset(n)
Send {%key_up% down}
Send {%key_right% down}
Random, rndtime, 500, 1000
; queue.push({"n": n, "when": now + rndtime, "send_arr": [{"key": key_up, "updown": "up"}, {"key": key_right, "updown": "up"}]})
queue.push({"n": n, "when": now + rndtime, player_reset: true})
players[n].in_action := true
}
}
}
; ------------------------------------------------------------------------------------------------------------------------
; --- main loop ----------------------------------------------------------------------------------------------------------
; ------------------------------------------------------------------------------------------------------------------------
; Loop that checks if we have lost active window focus, and do a keyup on any keys still "down".
; This prevents odd behaviour outside active window when alt tabbing and some keys are still down.
Loop {
; if WinActive("Jump n Bump") {
if WinActive(program_window_title) {
if not is_windowactive {
is_windowactive := true
; window used to be inactive and is now active (only say once):
info()
; say("active")
}
; call player_loop() here for less chance of sending keyup/keydowns outside of the active window:
player_loop()
} else {
if is_windowactive {
is_windowactive := false
; window used to be active and is now inactive (only say once):
player_reset_all()
removetooltip()
; say("inactive")
}
}
Sleep 100
}
; Any keybindings below only active when in the correct window:
;#IfWinActive, Jump n Bump
;#IfWinActive, %program_window_title% ; no worky with variable
#If WinActive(program_window_title)
`::info()
F1::player_enable_toggle(1)
F2::player_enable_toggle(2)
F3::player_enable_toggle(3)
F4::player_enable_toggle(4)
t::Numpad8
f::Numpad4
g::Numpad2
h::Numpad6
#If