add versions of clubman and tokyo

This commit is contained in:
Bartek Dobrowolski-Nowakowski
2022-05-05 13:11:53 +02:00
parent b108e53f59
commit 12ab4bdb0c
91 changed files with 30652 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,497 @@
; https://github.com/berban/Gdip
#HotkeyInterval 99000000
#KeyHistory 0
#MaxHotkeysPerInterval 99000000
#NoEnv
#Persistent
#SingleInstance Force
#Include Lib\Gdip.ahk
CoordMode, Pixel, Client
CoordMode, ToolTip, Client
DetectHiddenWindows, On
ListLines Off
Process, priority, , High
SendMode Input
SetBatchLines, -1
SetDefaultMouseSpeed, 0
SetFormat, Float, 0.2
; SetFormat, IntegerFast, Hex
SetKeyDelay, 50
SetMouseDelay, -1
SetWorkingDir %A_ScriptDir%
; Variables
races_clean := 0
races_clean_percent := 0
races_completed := 0
races_completed_check := 0
credits_total := 0
credits_average := 0
time_start := A_TickCount
time_current := A_TickCount
window_width := 640
window_height := 360
; GUI
Gui, New, -MaximizeBox -Resize, ClubmanPlus 0.2
Gui, Font, S10
Gui, Add, Button, w150 h40 Default gStart, Start
Gui, Add, Button, w150 h40 x+10 gReset, Reset
Gui, Show
return
; GUI events
GuiClose:
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
OutputDebug % "Clubman> Terminated"
ExitApp
; GUI buttons
Start:
hwnd := 0
Gosub, Release_All
Gosub, GrabWindow
if (hwnd = 0) {
MsgBox, % "PS Remote Play not found"
return
}
SetTimer, Health, 600000
SetTimer, Summary, 3600000
time_start := A_TickCount
; ** AFK Loop
Loop {
; ** RACE
OutputDebug % "Clubman> Race: Waiting for position GUI to show"
while (!IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(90), TuneCoordinateY(90), 4, 75)) {
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Race: Starting race"
Gosub, Hold_X
Gosub, Hold_Down
OutputDebug % "Clubman> Race: Racing until position GUI disappears"
while (IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(90), TuneCoordinateY(90), 4, 75)) {
Sleep, 500
}
OutputDebug % "Clubman> Race: Race ended, releasing all buttons"
Gosub, Release_All
; ** GO TO LEADERBOARDS
OutputDebug % "Clubman> End race: Waiting for continue X icon to show"
while (!IsColor(hwnd, 0xDEDCDA, TuneCoordinateX(475), TuneCoordinateY(563), 4, 10)) {
Sleep, 500
}
OutputDebug % "Clubman> End race: Press X to continue"
while (IsColor(hwnd, 0xDEDCDA, TuneCoordinateX(475), TuneCoordinateY(563), 4, 10)) {
Gosub, Press_X
Sleep, 1000
}
OutputDebug % "Clubman> End race: Transitioning to leaderboard"
; ** LEADERBOARD
Loop {
OutputDebug % "Clubman> Leaderboard: Checking positions"
if (IsColor(hwnd, 0xBADD3E, TuneCoordinateX(675), TuneCoordinateY(169), 10, 10)) {
OutputDebug % "Clubman> Leaderboard: 1st position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, TuneCoordinateX(675), TuneCoordinateY(198), 10, 10)) {
OutputDebug % "Clubman> Leaderboard: 2nd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, TuneCoordinateX(675), TuneCoordinateY(227), 10, 10)) {
OutputDebug % "Clubman> Leaderboard: 3rd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, TuneCoordinateX(675), TuneCoordinateY(256), 10, 10)) {
OutputDebug % "Clubman> Leaderboard: 4th position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, TuneCoordinateX(675), TuneCoordinateY(285), 10, 10)) {
OutputDebug % "Clubman> Leaderboard: 5th position"
Gosub, Press_X
break
}
else {
Sleep, 500
}
}
; ** REWARDS
OutputDebug % "Clubman> Rewards: Waiting for Rewards screen to load (checking money earnt)"
while (!IsColor(hwnd, 0xBE140F, TuneCoordinateX(850), TuneCoordinateY(236), 10, 50)) {
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Rewards: Found Rewards screen"
races_completed++
Loop 100 {
if (IsColor(hwnd, 0x5C90FB, TuneCoordinateX(486), TuneCoordinateY(311), 4, 20)) {
OutputDebug % "Clubman> Rewards: Clean bonus"
races_clean++
PixelSearch(TuneCoordinateX(486), TuneCoordinateY(311), 1, hwnd, "clean")
break
}
if (A_Index == 100) {
OutputDebug % "Clubman> Rewards: No clean bonus"
PixelSearch(TuneCoordinateX(486), TuneCoordinateY(311), 1, hwnd, "no-clean")
}
}
; ** REPLAY
OutputDebug % "Clubman> Replay: Waiting for Replay screen to load (checking exit button)"
while (!IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(920), TuneCoordinateY(555), 4, 10)) {
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Pressing the Exit button"
while (IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(920), TuneCoordinateY(555), 4, 10)) {
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Leaving the Replay screen"
; ** RACE RESULTS
OutputDebug % "Clubman> Race Result: Waiting for Race Result screen to load (checking cursor)"
while (!IsColor(hwnd, 0xBB1C1A, TuneCoordinateX(664), TuneCoordinateY(540), 5, 10)) {
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Moving cursor to the Retry button"
while (!IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(525), TuneCoordinateY(550), 4, 10)) {
Gosub, Press_Right
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Pressing the Retry button"
while (IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(525), TuneCoordinateY(550), 4, 10)) {
Gosub, Press_X
Sleep, 500
}
; ** RACE START
OutputDebug % "Clubman> Race Start: Waiting for Race Start screen to load (checking cursor)"
while (!IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(300), TuneCoordinateY(550), 4, 10)) {
Sleep, 500
}
OutputDebug % "Clubman> Race Start: Pressing the Start button"
while (IsColor(hwnd, 0xFFFFFF, TuneCoordinateX(300), TuneCoordinateY(550), 4, 10)) {
Gosub, Press_X
Sleep, 500
}
OutputDebug % "--- Summary ---"
credits_total := (races_completed * 0.07 + races_clean * 0.035)
races_clean_percent := (races_clean / races_completed) * 100
time_current := A_TickCount
credits_average := credits_total / (time_current - time_start) * 3600000
OutputDebug % "Clubman> Summary: Races " races_completed
OutputDebug % "Clubman> Summary: Races Clean " races_clean
OutputDebug % "Clubman> Summary: Races Clean Rate " races_clean_percent "%"
OutputDebug % "Clubman> Summary: Earnings " credits_total "M"
OutputDebug % "Clubman> Summary: Earnings Rate " credits_average "M/Hr"
OutputDebug % "---------------"
}
return
; -------------------
; Coordinate tuning
; -------------------
TuneCoordinateX(coord) {
; 3840 because I used a 4K 16:9 monitor to get the values
Return Round((A_ScreenWidth * coord) / 3840)
}
TuneCoordinateY(coord) {
; 2160 because I used a 4K 16:9 monitor to get the values
Return Round((A_ScreenHeight * coord) / 2160)
}
Reset:
; Gosub, GrabWindow
; ; PixelSearch(TuneCoordinateX(850), TuneCoordinateY(236), 10, WinExist("PS Remote Play"), "test1")
; bolas := IsColor(hwnd, 0xBE140F, TuneCoordinateX(850), TuneCoordinateY(236), 10, 50)
; OutputDebug % "Clubman> is color " bolas
; OutputDebug % "Clubman> d1 " ColorDistance(0xBE140F, 0x87281D)
; OutputDebug % "Clubman> d2 " ColorDistance(0xBE140F, 0x6C1F16)
; OutputDebug % "Clubman> d2 " ColorDistance(0xBE140F, 0x862A1F)
; Gosub, GrabWindow
; X := (A_ScreenWidth / 2) + 1 ; X = 677 (On 1024) or 805 (On 1280)
; Y := A_ScreenHeight - 25 ; Y = 743 (On 768) or 999 (On 1024)
; OutputDebug % "Clubman> X " TuneCoordinateX(90)
; OutputDebug % "Clubman> Y " TuneCoordinateY(90)
; PixelSearch(90, 90, 10, WinExist("PS Remote Play"), "test1")
; PixelSearch(675, 256, 10, WinExist("PS Remote Play"), "l4")
; PixelSearch(675, 227, 10, WinExist("PS Remote Play"), "l3")
; PixelSearch(675, 198, 10, WinExist("PS Remote Play"), "l2")
; PixelSearch(675, 169, 10, WinExist("PS Remote Play"), "l1")
return
; -------------------
; Health Check
; -------------------
Health:
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
OutputDebug % "Clubman> Health: Checking health at " current_date
OutputDebug % "Clubman> Health: Races completed " races_completed
OutputDebug % "Clubman> Health: Races completed last time " races_completed_check
if (races_completed_check >= races_completed) {
OutputDebug % "Clubman> Health: Error dectected, sending notification"
SendNotification("ClubmanPlus", "Something went wrong", 2, "persistent")
} else {
OutputDebug % "Clubman> Health: Running healthy"
races_completed_check := races_completed
}
Return
; -------------------
; Summary Check
; -------------------
Summary:
OutputDebug % "Clubman> Summary: Sending summary notification"
message := ""
message := message "Races " races_clean " / " races_completed " (" races_clean_percent ")`n"
message := message "Earnings " credits_total "M (" credits_average "M/Hr)"
SendNotification("ClubmanPlus", message, 0, "cashregister")
Return
; -------------------
; Send Notification
; -------------------
SendNotification(title, message, level, sound) {
IniRead, token, %A_ScriptDir%\clubman.ini, pushover, token
IniRead, user, %A_ScriptDir%\clubman.ini, pushover, user_key
retries := 60
expires := 3600
url := "https://api.pushover.net/1/messages.json"
param := "token=" token "&user=" user "&title=" title "&message=" message "&sound=" sound "&priority=" level
if (level == 2) {
param := param "&retry=" retries "&expire=" expires
}
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("POST", url)
WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
WebRequest.Send(param)
Return
}
; -------------------
; Grab Window
; -------------------
GrabWindow:
OutputDebug % "Clubman> Looking for window"
hwnd := WinExist("PS Remote Play")
if (hwnd > 0) {
OutputDebug % "Clubman> Window found: " hwnd
WinMove, ahk_id %hwnd%,, 0, 0, %window_width%, %window_height%
WinActivate, ahk_id %hwnd%
ControlFocus,, ahk_id %hwnd%
}
return
; -------------------
; Is Color
; -------------------
IsColor(hwnd, target_color, x, y, b, tolerance) {
for i, c in PixelSearch(x, y, b, hwnd) {
if (ColorDistance(c, target_color) <= tolerance) {
Return True
}
}
Return False
}
; -------------------
; Color Distance
; -------------------
ColorDistance( c1, c2 ) {
r1 := c1 >> 16
g1 := c1 >> 8 & 255
b1 := c1 & 255
r2 := c2 >> 16
g2 := c2 >> 8 & 255
b2 := c2 & 255
return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
}
; -------------------
; Pixel Search
; -------------------
PixelSearch(x, y, b, hwnd, debugsave := "") {
WinGetPos,,, width, height, ahk_id %hwnd%
pToken := Gdip_Startup()
hbm := CreateDIBSection(width, height),
hdc := CreateCompatibleDC(),
obm := SelectObject(hdc, hbm)
RegExMatch(A_OsVersion, "\d+", version)
PrintWindow(hwnd, hdc, version >= 8 ? 2 : 0)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm),
DeleteObject(hbm),
DeleteDC(hdc)
pixs := []
Loop % b*2 + 1 {
i := (-1 * b) + (A_Index - 1)
Loop % b*2 + 1 {
j := (-1 * b) + (A_Index - 1)
pixs.Push(Gdip_GetPixel(pBitmap, x+i, y+j) & 0x00FFFFFF)
}
}
if (debugsave != "") {
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
filename := A_ScriptDir . "\" . current_date . "-" . debugsave . ".bmp"
; debugbitmap:=Gdip_CloneBitmapArea(pBitmap, x-b, y-b, b*2, b*2)
; Gdip_SaveBitmapToFile(debugbitmap, filename)
Gdip_SaveBitmapToFile(pBitmap, filename)
Gdip_DisposeImage(debugbitmap)
; Run % filename
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
; -------------------
; Release All
; -------------------
Release_All:
Gosub, Release_X
Gosub, Release_O
return
; -------------------
; Press x
; -------------------
Press_X:
Gosub, Hold_X
Gosub, Release_x
return
Hold_X:
ControlSend,, {Enter down}, ahk_id %hwnd%
return
Release_X:
ControlSend,, {Enter up}, ahk_id %hwnd%
return
; -------------------
; Press O
; -------------------
Press_O:
Gosub, Hold_O
Gosub, Release_O
return
Hold_O:
ControlSend,, {Esc down}, ahk_id %hwnd%
return
Release_O:
ControlSend,, {Esc up}, ahk_id %hwnd%
return
; -------------------
; Press Right
; -------------------
Press_Right:
Gosub, Hold_Right
Gosub, Release_Right
return
Hold_Right:
ControlSend,, {Right down}, ahk_id %hwnd%
return
Release_Right:
ControlSend,, {Right up}, ahk_id %hwnd%
return
; -------------------
; Press Left
; -------------------
Press_Left:
Gosub, Hold_Left
Gosub, Release_Left
return
Hold_Left:
ControlSend,, {Left down}, ahk_id %hwnd%
return
Release_Left:
ControlSend,, {Left up}, ahk_id %hwnd%
return
; -------------------
; Press Up
; -------------------
Press_Up:
Gosub, Hold_Up
Gosub, Release_Up
return
Hold_Up:
ControlSend,, {Up down}, ahk_id %hwnd%
return
Release_Up:
ControlSend,, {Up up}, ahk_id %hwnd%
return
; -------------------
; Press Down
; -------------------
Press_Down:
Gosub, Hold_Down
Gosub, Release_Down
return
Hold_Down:
ControlSend,, {Down down}, ahk_id %hwnd%
return
Release_Down:
ControlSend,, {Down up}, ahk_id %hwnd%
return
; Hotkeys
^Esc::ExitApp
@@ -0,0 +1,3 @@
[pushover]
user_key=your_key
token=your_token
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,490 @@
; https://github.com/berban/Gdip
#HotkeyInterval 99000000
#KeyHistory 0
#MaxHotkeysPerInterval 99000000
#NoEnv
#Persistent
#SingleInstance Force
#Include Lib\Gdip.ahk
CoordMode, Pixel, Client
CoordMode, ToolTip, Client
DetectHiddenWindows, On
ListLines Off
Process, priority, , High
SendMode Input
SetBatchLines, -1
SetDefaultMouseSpeed, 0
SetFormat, Float, 0.2
; SetFormat, IntegerFast, Hex
SetKeyDelay, 50
SetMouseDelay, -1
SetWorkingDir %A_ScriptDir%
; Variables
races_clean := 0
races_clean_percent := 0
races_completed := 0
races_completed_check := 0
credits_total := 0
credits_average := 0
time_start := A_TickCount
time_current := A_TickCount
window_width := 640
window_height := 360
; GUI
Gui, New, -MaximizeBox -Resize, ClubmanPlus 0.3
Gui, Font, S10
Gui, Add, Button, w150 h40 Default gStart, Start
Gui, Add, Button, w150 h40 x+10 gReset, Reset
Gui, Show
return
; GUI events
GuiClose:
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
OutputDebug % "Clubman> Terminated"
ExitApp
; GUI buttons
Start:
hwnd := 0
Gosub, Release_All
Gosub, GrabWindow
if (hwnd = 0) {
MsgBox, % "PS Remote Play not found"
return
}
SetTimer, Health, 600000
SetTimer, Summary, 3600000
time_start := A_TickCount
; ** AFK Loop
Gosub, Press_X
Loop {
; ** RACE
OutputDebug % "Clubman> Race: Waiting for position GUI to show"
while (!IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Race: Starting race"
Gosub, Hold_X
Gosub, Hold_Down
OutputDebug % "Clubman> Race: Racing until position GUI disappears"
while (IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Sleep, 500
}
OutputDebug % "Clubman> Race: Race ended, releasing all buttons"
Gosub, Release_All
Sleep, 5000
; ** GO TO LEADERBOARDS
OutputDebug % "Clubman> End race: Waiting for continue X icon to show"
while (!IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Sleep, 500
}
OutputDebug % "Clubman> End race: Press X to continue"
while (IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Gosub, Press_X
Sleep, 100
}
OutputDebug % "Clubman> End race: Transitioning to leaderboard"
; ** LEADERBOARD
Loop {
OutputDebug % "Clubman> Leaderboard: Checking positions"
if (IsColor(hwnd, 0xBADD3E, 671, 124, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 1st position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 153, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 2nd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 182, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 3rd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 211, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 4th position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 240, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 5th position"
Gosub, Press_X
break
}
else {
Sleep, 500
}
}
; ** REWARDS
OutputDebug % "Clubman> Rewards: Waiting for Rewards screen to load (checking money earnt)"
while (!IsColor(hwnd, 0xBE140F, 848, 192, 6, 100)) { ; money earn, the red text
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Rewards: Found Rewards screen"
races_completed++
Loop 100 {
if (IsColor(hwnd, 0x5C90FB, 451, 260, 10, 20)) { ; the 'R' in Clean Race Bonus
OutputDebug % "Clubman> Rewards: Clean bonus"
races_clean++
PixelSearch(486, 311, 1, hwnd, "clean", "")
break
}
if (A_Index == 100) {
OutputDebug % "Clubman> Rewards: No clean bonus"
PixelSearch(486, 311, 1, hwnd, "no-clean", "")
}
}
; ** REPLAY
OutputDebug % "Clubman> Replay: Waiting for Replay screen to load"
while (!IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Pressing the Exit button"
while (IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Leaving the Replay screen"
; ** RACE RESULTS
OutputDebug % "Clubman> Race Result: Waiting for Race Result screen to load (checking cursor)"
while (!IsColor(hwnd, 0xBE1E1C, 651, 497, 4, 20)) { ; the exit button
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Moving cursor to the Retry button"
while (!IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_Right
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Pressing the Retry button"
while (IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_X
Sleep, 500
}
; ** RACE START
OutputDebug % "Clubman> Race Start: Waiting for Race Start screen to load (checking cursor)"
while (!IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Sleep, 500
}
OutputDebug % "Clubman> Race Start: Pressing the Start button"
while (IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "--- Summary ---"
credits_total := (races_completed * 0.07 + races_clean * 0.035)
races_clean_percent := (races_clean / races_completed) * 100
time_current := A_TickCount
credits_average := credits_total / (time_current - time_start) * 3600000
OutputDebug % "Clubman> Summary: Races " races_completed
OutputDebug % "Clubman> Summary: Races Clean " races_clean
OutputDebug % "Clubman> Summary: Races Clean Rate " races_clean_percent "%"
OutputDebug % "Clubman> Summary: Earnings " credits_total "M"
OutputDebug % "Clubman> Summary: Earnings Rate " credits_average "M/Hr"
OutputDebug % "---------------"
}
return
Reset:
Gosub, GrabWindow
; PixelSearch(465, 519, 6, hwnd, "", "2")
; OutputDebug % "Clubman> has grey " IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)
return
; -------------------
; Health Check
; -------------------
Health:
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
OutputDebug % "Clubman> Health: Checking health at " current_date
OutputDebug % "Clubman> Health: Races completed " races_completed
OutputDebug % "Clubman> Health: Races completed last time " races_completed_check
if (races_completed_check >= races_completed) {
OutputDebug % "Clubman> Health: Error dectected, sending notification"
SendNotification("ClubmanPlus", "Something went wrong", 2, "persistent")
} else {
OutputDebug % "Clubman> Health: Running healthy"
races_completed_check := races_completed
}
Return
; -------------------
; Summary Check
; -------------------
Summary:
OutputDebug % "Clubman> Summary: Sending summary notification"
message := ""
message := message "Races " races_clean " / " races_completed " (" races_clean_percent ")`n"
message := message "Earnings " credits_total "M (" credits_average "M/Hr)"
SendNotification("ClubmanPlus", message, 0, "cashregister")
Return
; -------------------
; Send Notification
; -------------------
SendNotification(title, message, level, sound) {
IniRead, token, %A_ScriptDir%\clubman.ini, pushover, token
IniRead, user, %A_ScriptDir%\clubman.ini, pushover, user_key
retries := 60
expires := 3600
url := "https://api.pushover.net/1/messages.json"
param := "token=" token "&user=" user "&title=" title "&message=" message "&sound=" sound "&priority=" level
if (level == 2) {
param := param "&retry=" retries "&expire=" expires
}
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("POST", url)
WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
WebRequest.Send(param)
Return
}
; -------------------
; Grab Window
; -------------------
GrabWindow:
OutputDebug % "Clubman> Looking for window"
hwnd := WinExist("PS Remote Play")
if (hwnd > 0) {
OutputDebug % "Clubman> Window found: " hwnd
WinMove, ahk_id %hwnd%,, 0, 0, %window_width%, %window_height%
WinActivate, ahk_id %hwnd%
ControlFocus,, ahk_id %hwnd%
}
return
; -------------------
; Is Color
; -------------------
IsColor(hwnd, target_color, x, y, b, tolerance) {
for i, c in PixelSearch(x, y, b, hwnd) {
if (ColorDistance(c, target_color) <= tolerance) {
Return True
}
}
Return False
}
; -------------------
; Color Distance
; -------------------
ColorDistance( c1, c2 ) {
r1 := c1 >> 16
g1 := c1 >> 8 & 255
b1 := c1 & 255
r2 := c2 >> 16
g2 := c2 >> 8 & 255
b2 := c2 & 255
return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
}
; -------------------
; Pixel Search
; -------------------
PixelSearch(x, y, b, hwnd, debugsave := "", debugsavecropped := "") {
; Find out client area
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect)
client_width := NumGet(rect, 8, "int")
client_height := NumGet(rect, 12, "int")
; Recalculate the area desired to the current system scaling; values were taken using 150% scale
b := Floor((b * client_width) / 960)
; Convert x and y to currrent system; values were taken using 4K resolution
x := Floor((A_ScreenWidth * x) / 3840)
y := Floor((A_ScreenHeight * y) / 2160)
; Convert client to screen coordinates
VarSetCapacity(POINT, 8)
NumPut(x, &POINT, 0, "Int")
NumPut(y, &POINT, 4, "Int")
DllCall("user32\ClientToScreen", Ptr,hWnd, Ptr,&POINT)
x := NumGet(&POINT, 0, "Int")
y := NumGet(&POINT, 4, "Int")
WinGetPos,,, width, height, ahk_id %hwnd%
pToken := Gdip_Startup()
hbm := CreateDIBSection(width, height),
hdc := CreateCompatibleDC(),
obm := SelectObject(hdc, hbm)
RegExMatch(A_OsVersion, "\d+", version)
PrintWindow(hwnd, hdc, version >= 8 ? 2 : 0)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm),
DeleteObject(hbm),
DeleteDC(hdc)
pixs := []
Loop % b*2 + 1 {
i := (-1 * b) + (A_Index - 1)
Loop % b*2 + 1 {
j := (-1 * b) + (A_Index - 1)
pixs.Push(Gdip_GetPixel(pBitmap, x+i, y+j) & 0x00FFFFFF)
}
}
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
if (debugsave != "") {
Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . current_date . "-" . debugsave . ".bmp")
; Run % filename
}
if (debugsavecropped != "") {
debugbitmap:=Gdip_CloneBitmapArea(pBitmap, x-b, y-b, b*2, b*2)
Gdip_SaveBitmapToFile(debugbitmap, A_ScriptDir . "\" . current_date . "-" . debugsavecropped . ".bmp")
Gdip_DisposeImage(debugbitmap)
; Run % filename
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
; -------------------
; Release All
; -------------------
Release_All:
Gosub, Release_X
Gosub, Release_O
return
; -------------------
; Press x
; -------------------
Press_X:
Gosub, Hold_X
Gosub, Release_x
return
Hold_X:
ControlSend,, {Enter down}, ahk_id %hwnd%
return
Release_X:
ControlSend,, {Enter up}, ahk_id %hwnd%
return
; -------------------
; Press O
; -------------------
Press_O:
Gosub, Hold_O
Gosub, Release_O
return
Hold_O:
ControlSend,, {Esc down}, ahk_id %hwnd%
return
Release_O:
ControlSend,, {Esc up}, ahk_id %hwnd%
return
; -------------------
; Press Right
; -------------------
Press_Right:
Gosub, Hold_Right
Gosub, Release_Right
return
Hold_Right:
ControlSend,, {Right down}, ahk_id %hwnd%
return
Release_Right:
ControlSend,, {Right up}, ahk_id %hwnd%
return
; -------------------
; Press Left
; -------------------
Press_Left:
Gosub, Hold_Left
Gosub, Release_Left
return
Hold_Left:
ControlSend,, {Left down}, ahk_id %hwnd%
return
Release_Left:
ControlSend,, {Left up}, ahk_id %hwnd%
return
; -------------------
; Press Up
; -------------------
Press_Up:
Gosub, Hold_Up
Gosub, Release_Up
return
Hold_Up:
ControlSend,, {Up down}, ahk_id %hwnd%
return
Release_Up:
ControlSend,, {Up up}, ahk_id %hwnd%
return
; -------------------
; Press Down
; -------------------
Press_Down:
Gosub, Hold_Down
Gosub, Release_Down
return
Hold_Down:
ControlSend,, {Down down}, ahk_id %hwnd%
return
Release_Down:
ControlSend,, {Down up}, ahk_id %hwnd%
return
; Hotkeys
^Esc::ExitApp
@@ -0,0 +1,3 @@
[pushover]
user_key=your_key
token=your_token
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,521 @@
; https://github.com/berban/Gdip
#HotkeyInterval 99000000
#KeyHistory 0
#MaxHotkeysPerInterval 99000000
#NoEnv
#Persistent
#SingleInstance Force
#Include Lib\Gdip.ahk
CoordMode, Pixel, Client
CoordMode, ToolTip, Client
DetectHiddenWindows, On
ListLines Off
Process, priority, , High
SendMode Input
SetBatchLines, -1
SetDefaultMouseSpeed, 0
SetFormat, Float, 0.2
; SetFormat, IntegerFast, Hex
SetKeyDelay, 50
SetMouseDelay, -1
SetWorkingDir %A_ScriptDir%
; Variables
races_clean := 0
races_clean_percent := 0
races_completed := 0
races_completed_check := 0
credits_total := 0
credits_average := 0
time_start := A_TickCount
time_current := A_TickCount
window_width := 640
window_height := 360
; GUI
Gui, New, -MaximizeBox -Resize, ClubmanPlus 0.4
Gui, Font, S10
Gui, Add, Button, w150 h40 Default gStart, Start
Gui, Add, Button, w150 h40 x+10 gReset, Reset
Gui, Show
return
; GUI events
GuiClose:
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
OutputDebug % "Clubman> Terminated"
ExitApp
; GUI buttons
Start:
hwnd := 0
Gosub, Release_All
Gosub, GrabWindow
if (hwnd = 0) {
MsgBox, % "PS Remote Play not found"
return
}
SetTimer, Health, 600000
SetTimer, Summary, 3600000
time_start := A_TickCount
; ** AFK Loop
Gosub, Press_X
Loop {
; ** RACE
OutputDebug % "Clubman> Race: Waiting for position GUI to show"
while (!IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Race: Starting race"
Gosub, Hold_X
; Gosub, Hold_Down
OutputDebug % "Clubman> Race: Racing until position GUI disappears"
while (IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Sleep, 500
}
OutputDebug % "Clubman> Race: Race ended, releasing all buttons"
Gosub, Release_All
; Sleep, 5000
; ** GO TO LEADERBOARDS
OutputDebug % "Clubman> End race: Waiting for continue X icon to show"
while (!IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Sleep, 500
}
OutputDebug % "Clubman> End race: Press X to continue"
while (IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Gosub, Press_X
Sleep, 100
}
OutputDebug % "Clubman> End race: Transitioning to leaderboard"
; ** LEADERBOARD
Loop {
OutputDebug % "Clubman> Leaderboard: Checking positions"
if (IsColor(hwnd, 0xBADD3E, 671, 124, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 1st position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 153, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 2nd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 182, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 3rd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 211, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 4th position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 240, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 5th position"
Gosub, Press_X
break
}
else {
Sleep, 500
}
}
; ** REWARDS
OutputDebug % "Clubman> Rewards: Waiting for Rewards screen to load (checking money earnt)"
while (!IsColor(hwnd, 0xBE140F, 848, 192, 6, 100)) { ; money earn, the red text
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Rewards: Found Rewards screen"
races_completed++
Loop 100 {
if (IsColor(hwnd, 0x5C90FB, 451, 260, 10, 20)) { ; the 'R' in Clean Race Bonus
OutputDebug % "Clubman> Rewards: Clean bonus"
races_clean++
PixelSearch(486, 311, 1, hwnd, "clean", "")
break
}
if (A_Index == 100) {
OutputDebug % "Clubman> Rewards: No clean bonus"
PixelSearch(486, 311, 1, hwnd, "no-clean", "")
}
}
; ** REPLAY
OutputDebug % "Clubman> Replay: Waiting for Replay screen to load"
while (!IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Pressing the Exit button"
while (IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Leaving the Replay screen"
; ** RACE RESULTS
OutputDebug % "Clubman> Race Result: Waiting for Race Result screen to load (checking cursor)"
while (!IsColor(hwnd, 0xBE1E1C, 651, 497, 4, 20)) { ; the exit button
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Moving cursor to the Retry button"
while (!IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_Right
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Pressing the Retry button"
while (IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_X
Sleep, 500
}
; ** RACE START
OutputDebug % "Clubman> Race Start: Waiting for Race Start screen to load (checking cursor)"
while (!IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Sleep, 500
}
OutputDebug % "Clubman> Race Start: Pressing the Start button"
while (IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "--- Summary ---"
credits_total := (races_completed * 0.07 + races_clean * 0.035)
races_clean_percent := (races_clean / races_completed) * 100
time_current := A_TickCount
credits_average := credits_total / (time_current - time_start) * 3600000
OutputDebug % "Clubman> Summary: Races " races_completed
OutputDebug % "Clubman> Summary: Races Clean " races_clean
OutputDebug % "Clubman> Summary: Races Clean Rate " races_clean_percent "%"
OutputDebug % "Clubman> Summary: Earnings " credits_total "M"
OutputDebug % "Clubman> Summary: Earnings Rate " credits_average "M/Hr"
OutputDebug % "---------------"
}
return
Reset:
Gosub, GrabWindow
; PixelSearch(465, 519, 6, hwnd, "", "2")
; OutputDebug % "Clubman> has grey " IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)
; 960 / 296
; 540 / 134
; PixelSearch(3.243243, 4.029851, 20, hwnd, "", "test")
; pToken := Gdip_Startup()
; pBitmap := Gdip_BitmapFromScreen("hwnd:" hwnd)
; Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\bolas.bmp")
; Gdip_DisposeImage(pBitmap)
; Gdip_Shutdown(pToken)
return
; -------------------
; Health Check
; -------------------
Health:
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
OutputDebug % "Clubman> Health: Checking health at " current_date
OutputDebug % "Clubman> Health: Races completed " races_completed
OutputDebug % "Clubman> Health: Races completed last time " races_completed_check
if (races_completed_check >= races_completed) {
OutputDebug % "Clubman> Health: Error dectected, sending notification"
SendNotification("ClubmanPlus", "Something went wrong", 2, "persistent")
} else {
OutputDebug % "Clubman> Health: Running healthy"
races_completed_check := races_completed
}
Return
; -------------------
; Summary Check
; -------------------
Summary:
OutputDebug % "Clubman> Summary: Sending summary notification"
message := ""
message := message "Races " races_clean " / " races_completed " (" races_clean_percent ")`n"
message := message "Earnings " credits_total "M (" credits_average "M/Hr)"
SendNotification("ClubmanPlus", message, 0, "cashregister")
Return
; -------------------
; Send Notification
; -------------------
SendNotification(title, message, level, sound) {
IniRead, token, %A_ScriptDir%\clubman.ini, pushover, token
IniRead, user, %A_ScriptDir%\clubman.ini, pushover, user_key
retries := 60
expires := 3600
url := "https://api.pushover.net/1/messages.json"
param := "token=" token "&user=" user "&title=" title "&message=" message "&sound=" sound "&priority=" level
if (level == 2) {
param := param "&retry=" retries "&expire=" expires
}
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("POST", url)
WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
WebRequest.Send(param)
Return
}
; -------------------
; Grab Window
; -------------------
GrabWindow:
OutputDebug % "Clubman> Looking for window"
hwnd := WinExist("PS Remote Play")
if (hwnd > 0) {
OutputDebug % "Clubman> Window found: " hwnd
WinMove, ahk_id %hwnd%,, 0, 0, %window_width%, %window_height%
WinActivate, ahk_id %hwnd%
ControlFocus,, ahk_id %hwnd%
}
return
; -------------------
; Is Color
; -------------------
IsColor(hwnd, target_color, x, y, b, tolerance) {
for i, c in PixelSearch(x, y, b, hwnd) {
if (ColorDistance(c, target_color) <= tolerance) {
Return True
}
}
Return False
}
; -------------------
; Color Distance
; -------------------
ColorDistance( c1, c2 ) {
r1 := c1 >> 16
g1 := c1 >> 8 & 255
b1 := c1 & 255
r2 := c2 >> 16
g2 := c2 >> 8 & 255
b2 := c2 & 255
return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
}
; -------------------
; Pixel Search
; -------------------
PixelSearch(x, y, b, hwnd, debugsave := "", debugsavecropped := "") {
; ; Find out client area
; VarSetCapacity(rect, 16)
; DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect)
; client_width := NumGet(rect, 8, "int")
; client_height := NumGet(rect, 12, "int")
; ; Recalculate the area desired to the current system scaling; values were taken using 150% scale
; b := Floor((b * client_width) / 960)
; ; Convert x and y to currrent system; values were taken using 4K resolution
; x := Floor((A_ScreenWidth * x) / 3840)
; y := Floor((A_ScreenHeight * y) / 2160)
; ; Convert client to screen coordinates
; VarSetCapacity(POINT, 8)
; NumPut(x, &POINT, 0, "Int")
; NumPut(y, &POINT, 4, "Int")
; DllCall("user32\ClientToScreen", Ptr,hWnd, Ptr,&POINT)
; x := NumGet(&POINT, 0, "Int")
; y := NumGet(&POINT, 4, "Int")
x := (960 / x)
y := (540 / y)
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect)
x := floor(NumGet(rect, 8, "int") // x)
y := floor(NumGet(rect, 12, "int") // y)
b := floor((b * NumGet(rect, 8, "int")) / 960)
VarSetCapacity(POINT, 8)
NumPut(x, &POINT, 0, "Int")
NumPut(y, &POINT, 4, "Int")
DllCall("user32\ClientToScreen", Ptr, hwnd, Ptr,&POINT)
x := NumGet(&POINT, 0, "Int")
y := NumGet(&POINT, 4, "Int")
; OutputDebug % "Clubman> Reading screen at " x "x" y
; WinGetPos,,, width, height, ahk_id %hwnd%
; pToken := Gdip_Startup()
; hbm := CreateDIBSection(width, height),
; hdc := CreateCompatibleDC(),
; obm := SelectObject(hdc, hbm)
; RegExMatch(A_OsVersion, "\d+", version)
; PrintWindow(hwnd, hdc, version >= 8 ? 2 : 0)
; pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
; SelectObject(hdc, obm),
; DeleteObject(hbm),
; DeleteDC(hdc)
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen("hwnd:" hwnd)
pixs := []
Loop % b*2 + 1 {
i := (-1 * b) + (A_Index - 1)
Loop % b*2 + 1 {
j := (-1 * b) + (A_Index - 1)
pixs.Push(Gdip_GetPixel(pBitmap, x+i, y+j) & 0x00FFFFFF)
}
}
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
if (debugsave != "") {
Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . current_date . "-" . debugsave . ".bmp")
; Run % filename
}
if (debugsavecropped != "") {
debugbitmap:=Gdip_CloneBitmapArea(pBitmap, x-b, y-b, b*2, b*2)
Gdip_SaveBitmapToFile(debugbitmap, A_ScriptDir . "\" . current_date . "-" . debugsavecropped . ".bmp")
Gdip_DisposeImage(debugbitmap)
; Run % filename
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
; -------------------
; Release All
; -------------------
Release_All:
Gosub, Release_X
Gosub, Release_O
return
; -------------------
; Press x
; -------------------
Press_X:
Gosub, Hold_X
Gosub, Release_x
return
Hold_X:
ControlSend,, {Enter down}, ahk_id %hwnd%
return
Release_X:
ControlSend,, {Enter up}, ahk_id %hwnd%
return
; -------------------
; Press O
; -------------------
Press_O:
Gosub, Hold_O
Gosub, Release_O
return
Hold_O:
ControlSend,, {Esc down}, ahk_id %hwnd%
return
Release_O:
ControlSend,, {Esc up}, ahk_id %hwnd%
return
; -------------------
; Press Right
; -------------------
Press_Right:
Gosub, Hold_Right
Gosub, Release_Right
return
Hold_Right:
ControlSend,, {Right down}, ahk_id %hwnd%
return
Release_Right:
ControlSend,, {Right up}, ahk_id %hwnd%
return
; -------------------
; Press Left
; -------------------
Press_Left:
Gosub, Hold_Left
Gosub, Release_Left
return
Hold_Left:
ControlSend,, {Left down}, ahk_id %hwnd%
return
Release_Left:
ControlSend,, {Left up}, ahk_id %hwnd%
return
; -------------------
; Press Up
; -------------------
Press_Up:
Gosub, Hold_Up
Gosub, Release_Up
return
Hold_Up:
ControlSend,, {Up down}, ahk_id %hwnd%
return
Release_Up:
ControlSend,, {Up up}, ahk_id %hwnd%
return
; -------------------
; Press Down
; -------------------
Press_Down:
Gosub, Hold_Down
Gosub, Release_Down
return
Hold_Down:
ControlSend,, {Down down}, ahk_id %hwnd%
return
Release_Down:
ControlSend,, {Down up}, ahk_id %hwnd%
return
; Hotkeys
^Esc::ExitApp
@@ -0,0 +1,3 @@
[pushover]
user_key=your_key
token=your_token
@@ -0,0 +1,211 @@
#include %A_LineFile%\..\CLR.ahk
; Static class, holds ViGEm Client instance
class ViGEmWrapper {
static asm := 0
static client := 0
Init(){
if (this.client == 0){
this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
}
}
CreateInstance(cls){
return this.asm.CreateInstance(cls)
}
}
; Base class for ViGEm "Targets" (Controller types - eg xb360 / ds4) to inherit from
class ViGEmTarget {
target := 0
helperClass := ""
controllerClass := ""
__New(){
;~ this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
ViGEmWrapper.Init()
this.Instance := ViGEmWrapper.CreateInstance(this.helperClass)
if (this.Instance.OkCheck() != "OK"){
msgbox ViGEmWrapper.dll failed to load!
ExitApp
}
}
SendReport(){
this.Instance.SendReport()
}
SubscribeFeedback(callback){
this.Instance.SubscribeFeedback(callback)
}
}
; DS4 (DualShock 4 for Playstation 4)
class ViGEmDS4 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Ds4"
__New(){
static buttons := {Square: 16, Cross: 32, Circle: 64, Triangle: 128, L1: 256, R1: 512, L2: 1024, R2: 2048
, Share: 4096, Options: 8192, LS: 16384, RS: 32768 }
static specialButtons := {Ps: 1, TouchPad: 2}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
for name, id in specialButtons {
this.Buttons[name] := new this._SpecialButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _SpecialButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetSpecialButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
return this._Parent
}
ConvertAxis(state){
return round(state * 2.55)
}
}
class _DpadHelper {
__New(parent){
this._Parent := parent
this._Id := id
}
SetState(state){
static dPadDirections := {Up: 0, UpRight: 1, Right: 2, DownRight: 3, Down: 4, DownLeft: 5, Left: 6, UpLeft: 7, None: 8}
this._Parent.Instance.SetDpadState(dPadDirections[state])
this._Parent.Instance.SendReport()
return this._Parent
}
}
}
; Xb360
class ViGEmXb360 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Xb360"
__New(){
static buttons := {A: 4096, B: 8192, X: 16384, Y: 32768, LB: 256, RB: 512, LS: 64, RS: 128, Back: 32, Start: 16, Xbox: 1024}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
}
ConvertAxis(state){
value := round((state * 655.36) - 32768)
if (value == 32768)
return 32767
return value
}
}
class _DpadHelper {
_DpadStates := {1:0, 8:0, 2:0, 4:0} ; Up, Right, Down, Left
__New(parent){
this._Parent := parent
}
SetState(state){
static dpadDirections := { None: {1:0, 8:0, 2:0, 4:0}
, Up: {1:1, 8:0, 2:0, 4:0}
, UpRight: {1:1, 8:1, 2:0, 4:0}
, Right: {1:0, 8:1, 2:0, 4:0}
, DownRight: {1:0, 8:1, 2:1, 4:0}
, Down: {1:0, 8:0, 2:1, 4:0}
, DownLeft: {1:0, 8:0, 2:1, 4:1}
, Left: {1:0, 8:0, 2:0, 4:1}
, UpLeft: {1:1, 8:0, 2:0, 4:1}}
newStates := dpadDirections[state]
for id, newState in newStates {
oldState := this._DpadStates[id]
if (oldState != newState){
this._DpadStates[id] := newState
this._Parent.Instance.SetButtonState(id, newState)
}
this._Parent.SendReport()
}
}
}
}
@@ -0,0 +1,151 @@
; ==========================================================
; .NET Framework Interop
; https://autohotkey.com/boards/viewtopic.php?t=4633
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if assembly := AppDomain.Load_2(AssemblyName)
break
static null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, null, null, args)
break
if assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, null, null, args)
break
}
ComObjError(e)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, null, vargs, null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, null, null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,506 @@
; https://github.com/berban/Gdip
#HotkeyInterval 99000000
#KeyHistory 0
#MaxHotkeysPerInterval 99000000
#NoEnv
#Persistent
#SingleInstance Force
#Include Lib\Gdip.ahk
#Include Lib\AHK-ViGEm-Bus.ahk
CoordMode, Pixel, Client
CoordMode, ToolTip, Client
DetectHiddenWindows, On
ListLines Off
Process, priority, , High
SendMode Input
SetBatchLines, -1
SetDefaultMouseSpeed, 0
SetFormat, Float, 0.2
; SetFormat, IntegerFast, Hex
SetKeyDelay, 50
SetMouseDelay, -1
SetWorkingDir %A_ScriptDir%
; Variables
races_clean := 0
races_clean_percent := 0
races_completed := 0
races_completed_check := 0
credits_total := 0
credits_average := 0
time_start := A_TickCount
time_current := A_TickCount
window_width := 640
window_height := 360
; Create a new controller controller
controller := new ViGEmDS4()
; GUI
Gui, New, -MaximizeBox -Resize, ClubmanPlus 0.5.1
Gui, Font, S10
Gui, Add, Text, w300 vStatRace, Race Counts: %races_completed%
Gui, Add, Text, y+0 w300 vCleanRace, Clean Races: %races_clean%
Gui, Add, Text, y+0 w300 vCleanRate, Average Clean Runs: %races_clean_percent%`%
Gui, Add, Text, y+0 w300 vEarnings, Earnings: %credits_total%M
Gui, Add, Text, y+0 w300 vEarningsRate, Earnings Rate: %credits_average%M/hr
Gui, Add, Button, w150 h40 Default gStart, Start
Gui, Add, Button, w150 h40 x+10 gReset, Reset
Gui, Show
return
; GUI events
GuiClose:
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
OutputDebug % "Clubman> Terminated"
ExitApp
; GUI controls
Stats:
format_avg_clean_race := Format("{1:0.2f}", races_clean_percent)
format_earnings := Format("{1:0.2f}", credits_total)
format_earnings_rate := Format("{1:0.2f}", credits_average)
GuiControl,,StatRace, Race Counts: %races_completed%
GuiControl,,CleanRace, Clean Races: %races_clean%
GuiControl,,CleanRate, Average Clean Runs: %format_avg_clean_race%`%
GuiControl,,Earnings, Earnings: %format_earnings%M
GuiControl,,EarningsRate, Earnings Rate: %format_earnings_rate%M/hr
Return
Start:
hwnd := 0
Gosub, Release_All
Gosub, GrabWindow
if (hwnd = 0) {
MsgBox, % "PS Remote Play not found"
return
}
SetTimer, Health, 600000
SetTimer, Summary, 3600000
time_start := A_TickCount
; ** AFK Loop
Gosub, Press_X
Loop {
; ** RACE
OutputDebug % "Clubman> Race: Waiting for position GUI to show"
while (!IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Race: Starting race"
Gosub, Hold_X
; Gosub, Hold_Down
OutputDebug % "Clubman> Race: Racing until position GUI disappears"
while (IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Sleep, 500
}
OutputDebug % "Clubman> Race: Race ended, releasing all buttons"
Gosub, Release_All
; Sleep, 5000
; ** GO TO LEADERBOARDS
OutputDebug % "Clubman> End race: Waiting for continue X icon to show"
while (!IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Sleep, 500
}
OutputDebug % "Clubman> End race: Press X to continue"
while (IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Gosub, Press_X
Sleep, 100
}
OutputDebug % "Clubman> End race: Transitioning to leaderboard"
; ** LEADERBOARD
Loop {
OutputDebug % "Clubman> Leaderboard: Checking positions"
if (IsColor(hwnd, 0xBADD3E, 671, 124, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 1st position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 153, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 2nd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 182, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 3rd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 211, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 4th position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 240, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 5th position"
Gosub, Press_X
break
}
else {
Sleep, 500
}
}
; ** REWARDS
OutputDebug % "Clubman> Rewards: Waiting for Rewards screen to load (checking money earnt)"
while (!IsColor(hwnd, 0xBE140F, 848, 192, 6, 100)) { ; money earn, the red text
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Rewards: Found Rewards screen"
races_completed++
Loop 100 {
if (IsColor(hwnd, 0x5C90FB, 451, 260, 10, 20)) { ; the 'R' in Clean Race Bonus
OutputDebug % "Clubman> Rewards: Clean bonus"
races_clean++
PixelSearch(486, 311, 1, hwnd, "clean", "")
break
}
if (A_Index == 100) {
OutputDebug % "Clubman> Rewards: No clean bonus"
PixelSearch(486, 311, 1, hwnd, "no-clean", "")
}
}
; ** REPLAY
OutputDebug % "Clubman> Replay: Waiting for Replay screen to load"
while (!IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Pressing the Exit button"
while (IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Leaving the Replay screen"
; ** RACE RESULTS
OutputDebug % "Clubman> Race Result: Waiting for Race Result screen to load (checking cursor)"
while (!IsColor(hwnd, 0xBE1E1C, 651, 497, 4, 20)) { ; the exit button
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Moving cursor to the Retry button"
while (!IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_Right
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Pressing the Retry button"
while (IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_X
Sleep, 500
}
; ** RACE START
OutputDebug % "Clubman> Race Start: Waiting for Race Start screen to load (checking cursor)"
while (!IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Sleep, 500
}
OutputDebug % "Clubman> Race Start: Pressing the Start button"
while (IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "--- Summary ---"
credits_total := (races_completed * 0.07 + races_clean * 0.035)
races_clean_percent := (races_clean / races_completed) * 100
time_current := A_TickCount
credits_average := credits_total / (time_current - time_start) * 3600000
Gosub, Stats
OutputDebug % "Clubman> Summary: Races " races_completed
OutputDebug % "Clubman> Summary: Races Clean " races_clean
OutputDebug % "Clubman> Summary: Races Clean Rate " races_clean_percent "%"
OutputDebug % "Clubman> Summary: Earnings " credits_total "M"
OutputDebug % "Clubman> Summary: Earnings Rate " credits_average "M/Hr"
OutputDebug % "---------------"
}
return
Reset:
OutputDebug % "Clubman> Reloading"
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
Reload
return
; -------------------
; Health Check
; -------------------
Health:
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
OutputDebug % "Clubman> Health: Checking health at " current_date
OutputDebug % "Clubman> Health: Races completed " races_completed
OutputDebug % "Clubman> Health: Races completed last time " races_completed_check
if (races_completed_check >= races_completed) {
OutputDebug % "Clubman> Health: Error dectected, sending notification"
SendNotification("ClubmanPlus", "Something went wrong", 2, "persistent")
} else {
OutputDebug % "Clubman> Health: Running healthy"
races_completed_check := races_completed
}
Return
; -------------------
; Summary Check
; -------------------
Summary:
OutputDebug % "Clubman> Summary: Sending summary notification"
message := ""
message := message "Races " races_clean " / " races_completed " (" races_clean_percent ")`n"
message := message "Earnings " credits_total "M (" credits_average "M/Hr)"
SendNotification("ClubmanPlus", message, 0, "cashregister")
Return
; -------------------
; Send Notification
; -------------------
SendNotification(title, message, level, sound) {
IniRead, token, %A_ScriptDir%\clubman.ini, pushover, token
IniRead, user, %A_ScriptDir%\clubman.ini, pushover, user_key
retries := 60
expires := 3600
url := "https://api.pushover.net/1/messages.json"
param := "token=" token "&user=" user "&title=" title "&message=" message "&sound=" sound "&priority=" level
if (level == 2) {
param := param "&retry=" retries "&expire=" expires
}
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("POST", url)
WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
WebRequest.Send(param)
Return
}
; -------------------
; Grab Window
; -------------------
GrabWindow:
OutputDebug % "Clubman> Looking for window"
hwnd := WinExist("PS Remote Play")
if (hwnd > 0) {
OutputDebug % "Clubman> Window found: " hwnd
WinMove, ahk_id %hwnd%,, 0, 0, %window_width%, %window_height%
WinActivate, ahk_id %hwnd%
ControlFocus,, ahk_id %hwnd%
}
return
; -------------------
; Is Color
; -------------------
IsColor(hwnd, target_color, x, y, b, tolerance) {
for i, c in PixelSearch(x, y, b, hwnd) {
if (ColorDistance(c, target_color) <= tolerance) {
Return True
}
}
Return False
}
; -------------------
; Color Distance
; -------------------
ColorDistance( c1, c2 ) {
r1 := c1 >> 16
g1 := c1 >> 8 & 255
b1 := c1 & 255
r2 := c2 >> 16
g2 := c2 >> 8 & 255
b2 := c2 & 255
return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
}
; -------------------
; Pixel Search
; -------------------
PixelSearch(x, y, b, hwnd, debugsave := "", debugsavecropped := "") {
x := (960 / x)
y := (540 / y)
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect)
x := floor(NumGet(rect, 8, "int") // x)
y := floor(NumGet(rect, 12, "int") // y)
b := floor((b * NumGet(rect, 8, "int")) / 960)
VarSetCapacity(POINT, 8)
NumPut(x, &POINT, 0, "Int")
NumPut(y, &POINT, 4, "Int")
DllCall("user32\ClientToScreen", Ptr, hwnd, Ptr,&POINT)
x := NumGet(&POINT, 0, "Int")
y := NumGet(&POINT, 4, "Int")
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen("hwnd:" hwnd)
pixs := []
Loop % b*2 + 1 {
i := (-1 * b) + (A_Index - 1)
Loop % b*2 + 1 {
j := (-1 * b) + (A_Index - 1)
pixs.Push(Gdip_GetPixel(pBitmap, x+i, y+j) & 0x00FFFFFF)
}
}
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
if (debugsave != "") {
Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . current_date . "-" . debugsave . ".bmp")
}
if (debugsavecropped != "") {
debugbitmap:=Gdip_CloneBitmapArea(pBitmap, x-b, y-b, b*2, b*2)
Gdip_SaveBitmapToFile(debugbitmap, A_ScriptDir . "\" . current_date . "-" . debugsavecropped . ".bmp")
Gdip_DisposeImage(debugbitmap)
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
; -------------------
; Release All
; -------------------
Release_All:
Gosub, Release_X
Gosub, Release_O
Gosub, Release_Right
Gosub, Release_Left
Gosub, Release_Up
Gosub, Release_Down
return
; -------------------
; Press x
; -------------------
Press_X:
Gosub, Hold_X
Sleep, 50
Gosub, Release_x
return
Hold_X:
controller.Buttons.Cross.SetState(true)
return
Release_X:
controller.Buttons.Cross.SetState(false)
return
; -------------------
; Press O
; -------------------
Press_O:
Gosub, Hold_O
Sleep, 50
Gosub, Release_O
return
Hold_O:
controller.Buttons.Circle.SetState(true)
return
Release_O:
controller.Buttons.Circle.SetState(false)
return
; -------------------
; Press Right
; -------------------
Press_Right:
Gosub, Hold_Right
Sleep, 50
Gosub, Release_Right
return
Hold_Right:
controller.Dpad.SetState("Right")
return
Release_Right:
controller.Dpad.SetState("None")
return
; -------------------
; Press Left
; -------------------
Press_Left:
Gosub, Hold_Left
Sleep, 50
Gosub, Release_Left
return
Hold_Left:
controller.Dpad.SetState("Left")
return
Release_Left:
controller.Dpad.SetState("None")
return
; -------------------
; Press Up
; -------------------
Press_Up:
Gosub, Hold_Up
Sleep, 50
Gosub, Release_Up
return
Hold_Up:
controller.Dpad.SetState("Up")
return
Release_Up:
controller.Dpad.SetState("None")
return
; -------------------
; Press Down
; -------------------
Press_Down:
Gosub, Hold_Down
Sleep, 50
Gosub, Release_Down
return
Hold_Down:
controller.Dpad.SetState("Down")
return
Release_Down:
controller.Dpad.SetState("None")
return
; Hotkeys
^Esc::ExitApp
@@ -0,0 +1,3 @@
[pushover]
user_key=your_key
token=your_token
@@ -0,0 +1,211 @@
#include %A_LineFile%\..\CLR.ahk
; Static class, holds ViGEm Client instance
class ViGEmWrapper {
static asm := 0
static client := 0
Init(){
if (this.client == 0){
this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
}
}
CreateInstance(cls){
return this.asm.CreateInstance(cls)
}
}
; Base class for ViGEm "Targets" (Controller types - eg xb360 / ds4) to inherit from
class ViGEmTarget {
target := 0
helperClass := ""
controllerClass := ""
__New(){
;~ this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
ViGEmWrapper.Init()
this.Instance := ViGEmWrapper.CreateInstance(this.helperClass)
if (this.Instance.OkCheck() != "OK"){
msgbox ViGEmWrapper.dll failed to load!
ExitApp
}
}
SendReport(){
this.Instance.SendReport()
}
SubscribeFeedback(callback){
this.Instance.SubscribeFeedback(callback)
}
}
; DS4 (DualShock 4 for Playstation 4)
class ViGEmDS4 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Ds4"
__New(){
static buttons := {Square: 16, Cross: 32, Circle: 64, Triangle: 128, L1: 256, R1: 512, L2: 1024, R2: 2048
, Share: 4096, Options: 8192, LS: 16384, RS: 32768 }
static specialButtons := {Ps: 1, TouchPad: 2}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
for name, id in specialButtons {
this.Buttons[name] := new this._SpecialButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _SpecialButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetSpecialButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
return this._Parent
}
ConvertAxis(state){
return round(state * 2.55)
}
}
class _DpadHelper {
__New(parent){
this._Parent := parent
this._Id := id
}
SetState(state){
static dPadDirections := {Up: 0, UpRight: 1, Right: 2, DownRight: 3, Down: 4, DownLeft: 5, Left: 6, UpLeft: 7, None: 8}
this._Parent.Instance.SetDpadState(dPadDirections[state])
this._Parent.Instance.SendReport()
return this._Parent
}
}
}
; Xb360
class ViGEmXb360 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Xb360"
__New(){
static buttons := {A: 4096, B: 8192, X: 16384, Y: 32768, LB: 256, RB: 512, LS: 64, RS: 128, Back: 32, Start: 16, Xbox: 1024}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
}
ConvertAxis(state){
value := round((state * 655.36) - 32768)
if (value == 32768)
return 32767
return value
}
}
class _DpadHelper {
_DpadStates := {1:0, 8:0, 2:0, 4:0} ; Up, Right, Down, Left
__New(parent){
this._Parent := parent
}
SetState(state){
static dpadDirections := { None: {1:0, 8:0, 2:0, 4:0}
, Up: {1:1, 8:0, 2:0, 4:0}
, UpRight: {1:1, 8:1, 2:0, 4:0}
, Right: {1:0, 8:1, 2:0, 4:0}
, DownRight: {1:0, 8:1, 2:1, 4:0}
, Down: {1:0, 8:0, 2:1, 4:0}
, DownLeft: {1:0, 8:0, 2:1, 4:1}
, Left: {1:0, 8:0, 2:0, 4:1}
, UpLeft: {1:1, 8:0, 2:0, 4:1}}
newStates := dpadDirections[state]
for id, newState in newStates {
oldState := this._DpadStates[id]
if (oldState != newState){
this._DpadStates[id] := newState
this._Parent.Instance.SetButtonState(id, newState)
}
this._Parent.SendReport()
}
}
}
}
@@ -0,0 +1,151 @@
; ==========================================================
; .NET Framework Interop
; https://autohotkey.com/boards/viewtopic.php?t=4633
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if assembly := AppDomain.Load_2(AssemblyName)
break
static null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, null, null, args)
break
if assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, null, null, args)
break
}
ComObjError(e)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, null, vargs, null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, null, null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,502 @@
; https://github.com/berban/Gdip
#HotkeyInterval 99000000
#KeyHistory 0
#MaxHotkeysPerInterval 99000000
#NoEnv
#Persistent
#SingleInstance Force
#Include Lib\Gdip.ahk
#Include Lib\AHK-ViGEm-Bus.ahk
CoordMode, Pixel, Client
CoordMode, ToolTip, Client
DetectHiddenWindows, On
ListLines Off
Process, priority, , High
SendMode Input
SetBatchLines, -1
SetDefaultMouseSpeed, 0
SetFormat, Float, 0.2
; SetFormat, IntegerFast, Hex
SetKeyDelay, 50
SetMouseDelay, -1
SetWorkingDir %A_ScriptDir%
; Variables
races_clean := 0
races_clean_percent := 0
races_completed := 0
races_completed_check := 0
credits_total := 0
credits_average := 0
time_start := A_TickCount
time_current := A_TickCount
window_width := 640
window_height := 360
; Create a new controller controller
controller := new ViGEmDS4()
; GUI
Gui, New, -MaximizeBox -Resize, ClubmanPlus 0.5
Gui, Font, S10
Gui, Add, Text, vStatRace, Race Counts: %races_completed%
Gui, Add, Text, vCleanRace, Clean Races: %races_clean%
Gui, Add, Text, vCleanRate, Average Clean Runs: %races_clean_percent%`%
Gui, Add, Text, vEarnings, Earnings: %credits_total%M
Gui, Add, Text, vEarningsRate, Earnings Rate: %credits_average%M/hr
Gui, Add, Button, w150 h40 Default gStart, Start
Gui, Add, Button, w150 h40 x+10 gReset, Reset
Gui, Show
return
; GUI events
GuiClose:
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
OutputDebug % "Clubman> Terminated"
ExitApp
; GUI buttons
Stats:
GuiControl,,StatRace, Race Counts: %races_completed%
GuiControl,,CleanRace, Clean Races: %races_clean%
GuiControl,,CleanRate, Average Clean Runs: %races_clean_percent%`%
GuiControl,,Earnings, Earnings: %credits_total%M
GuiControl,,EarningsRate, Earnings Rate: %credits_average%M/hr
Return
Start:
hwnd := 0
Gosub, Release_All
Gosub, GrabWindow
if (hwnd = 0) {
MsgBox, % "PS Remote Play not found"
return
}
SetTimer, Health, 600000
SetTimer, Summary, 3600000
time_start := A_TickCount
; ** AFK Loop
Gosub, Press_X
Loop {
; ** RACE
OutputDebug % "Clubman> Race: Waiting for position GUI to show"
while (!IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Race: Starting race"
Gosub, Hold_X
; Gosub, Hold_Down
OutputDebug % "Clubman> Race: Racing until position GUI disappears"
while (IsColor(hwnd, 0xFFFFFF, 218, 490, 6, 20)) { ; top-right tire wear indicator
Sleep, 500
}
OutputDebug % "Clubman> Race: Race ended, releasing all buttons"
Gosub, Release_All
; Sleep, 5000
; ** GO TO LEADERBOARDS
OutputDebug % "Clubman> End race: Waiting for continue X icon to show"
while (!IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Sleep, 500
}
OutputDebug % "Clubman> End race: Press X to continue"
while (IsColor(hwnd, 0xC9C9C9, 465, 519, 6, 20)) { ; X icon
Gosub, Press_X
Sleep, 100
}
OutputDebug % "Clubman> End race: Transitioning to leaderboard"
; ** LEADERBOARD
Loop {
OutputDebug % "Clubman> Leaderboard: Checking positions"
if (IsColor(hwnd, 0xBADD3E, 671, 124, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 1st position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 153, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 2nd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 182, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 3rd position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 211, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 4th position"
Gosub, Press_X
break
}
else if (IsColor(hwnd, 0xBADD3E, 671, 240, 10, 20)) { ; venom green on the leaderboard
OutputDebug % "Clubman> Leaderboard: 5th position"
Gosub, Press_X
break
}
else {
Sleep, 500
}
}
; ** REWARDS
OutputDebug % "Clubman> Rewards: Waiting for Rewards screen to load (checking money earnt)"
while (!IsColor(hwnd, 0xBE140F, 848, 192, 6, 100)) { ; money earn, the red text
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Rewards: Found Rewards screen"
races_completed++
Loop 100 {
if (IsColor(hwnd, 0x5C90FB, 451, 260, 10, 20)) { ; the 'R' in Clean Race Bonus
OutputDebug % "Clubman> Rewards: Clean bonus"
races_clean++
PixelSearch(486, 311, 1, hwnd, "clean", "")
break
}
if (A_Index == 100) {
OutputDebug % "Clubman> Rewards: No clean bonus"
PixelSearch(486, 311, 1, hwnd, "no-clean", "")
}
}
; ** REPLAY
OutputDebug % "Clubman> Replay: Waiting for Replay screen to load"
while (!IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Pressing the Exit button"
while (IsColor(hwnd, 0xFFFFFF, 911, 510, 4, 20)) { ; the cursor on top the exit button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "Clubman> Replay: Leaving the Replay screen"
; ** RACE RESULTS
OutputDebug % "Clubman> Race Result: Waiting for Race Result screen to load (checking cursor)"
while (!IsColor(hwnd, 0xBE1E1C, 651, 497, 4, 20)) { ; the exit button
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Moving cursor to the Retry button"
while (!IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_Right
Sleep, 500
}
OutputDebug % "Clubman> Race Result: Pressing the Retry button"
while (IsColor(hwnd, 0xFFFFFF, 514, 504, 4, 20)) { ; cursor on top the retry button
Gosub, Press_X
Sleep, 500
}
; ** RACE START
OutputDebug % "Clubman> Race Start: Waiting for Race Start screen to load (checking cursor)"
while (!IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Sleep, 500
}
OutputDebug % "Clubman> Race Start: Pressing the Start button"
while (IsColor(hwnd, 0xFFFFFF, 287, 504, 4, 20)) { ; cursor on top the start button
Gosub, Press_X
Sleep, 500
}
OutputDebug % "--- Summary ---"
credits_total := (races_completed * 0.07 + races_clean * 0.035)
races_clean_percent := (races_clean / races_completed) * 100
time_current := A_TickCount
credits_average := credits_total / (time_current - time_start) * 3600000
Gosub, Stats
OutputDebug % "Clubman> Summary: Races " races_completed
OutputDebug % "Clubman> Summary: Races Clean " races_clean
OutputDebug % "Clubman> Summary: Races Clean Rate " races_clean_percent "%"
OutputDebug % "Clubman> Summary: Earnings " credits_total "M"
OutputDebug % "Clubman> Summary: Earnings Rate " credits_average "M/Hr"
OutputDebug % "---------------"
}
return
Reset:
OutputDebug % "Clubman> Reloading"
Gosub, Release_All
SetTimer, Health, Off
SetTimer, Summary, Off
Reload
return
; -------------------
; Health Check
; -------------------
Health:
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
OutputDebug % "Clubman> Health: Checking health at " current_date
OutputDebug % "Clubman> Health: Races completed " races_completed
OutputDebug % "Clubman> Health: Races completed last time " races_completed_check
if (races_completed_check >= races_completed) {
OutputDebug % "Clubman> Health: Error dectected, sending notification"
SendNotification("ClubmanPlus", "Something went wrong", 2, "persistent")
} else {
OutputDebug % "Clubman> Health: Running healthy"
races_completed_check := races_completed
}
Return
; -------------------
; Summary Check
; -------------------
Summary:
OutputDebug % "Clubman> Summary: Sending summary notification"
message := ""
message := message "Races " races_clean " / " races_completed " (" races_clean_percent ")`n"
message := message "Earnings " credits_total "M (" credits_average "M/Hr)"
SendNotification("ClubmanPlus", message, 0, "cashregister")
Return
; -------------------
; Send Notification
; -------------------
SendNotification(title, message, level, sound) {
IniRead, token, %A_ScriptDir%\clubman.ini, pushover, token
IniRead, user, %A_ScriptDir%\clubman.ini, pushover, user_key
retries := 60
expires := 3600
url := "https://api.pushover.net/1/messages.json"
param := "token=" token "&user=" user "&title=" title "&message=" message "&sound=" sound "&priority=" level
if (level == 2) {
param := param "&retry=" retries "&expire=" expires
}
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.Open("POST", url)
WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
WebRequest.Send(param)
Return
}
; -------------------
; Grab Window
; -------------------
GrabWindow:
OutputDebug % "Clubman> Looking for window"
hwnd := WinExist("PS Remote Play")
if (hwnd > 0) {
OutputDebug % "Clubman> Window found: " hwnd
WinMove, ahk_id %hwnd%,, 0, 0, %window_width%, %window_height%
WinActivate, ahk_id %hwnd%
ControlFocus,, ahk_id %hwnd%
}
return
; -------------------
; Is Color
; -------------------
IsColor(hwnd, target_color, x, y, b, tolerance) {
for i, c in PixelSearch(x, y, b, hwnd) {
if (ColorDistance(c, target_color) <= tolerance) {
Return True
}
}
Return False
}
; -------------------
; Color Distance
; -------------------
ColorDistance( c1, c2 ) {
r1 := c1 >> 16
g1 := c1 >> 8 & 255
b1 := c1 & 255
r2 := c2 >> 16
g2 := c2 >> 8 & 255
b2 := c2 & 255
return Sqrt( (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2 )
}
; -------------------
; Pixel Search
; -------------------
PixelSearch(x, y, b, hwnd, debugsave := "", debugsavecropped := "") {
x := (960 / x)
y := (540 / y)
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect)
x := floor(NumGet(rect, 8, "int") // x)
y := floor(NumGet(rect, 12, "int") // y)
b := floor((b * NumGet(rect, 8, "int")) / 960)
VarSetCapacity(POINT, 8)
NumPut(x, &POINT, 0, "Int")
NumPut(y, &POINT, 4, "Int")
DllCall("user32\ClientToScreen", Ptr, hwnd, Ptr,&POINT)
x := NumGet(&POINT, 0, "Int")
y := NumGet(&POINT, 4, "Int")
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen("hwnd:" hwnd)
pixs := []
Loop % b*2 + 1 {
i := (-1 * b) + (A_Index - 1)
Loop % b*2 + 1 {
j := (-1 * b) + (A_Index - 1)
pixs.Push(Gdip_GetPixel(pBitmap, x+i, y+j) & 0x00FFFFFF)
}
}
FormatTime, current_date,, % "yyMMdd-HHmm-ss"
if (debugsave != "") {
Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir . "\" . current_date . "-" . debugsave . ".bmp")
}
if (debugsavecropped != "") {
debugbitmap:=Gdip_CloneBitmapArea(pBitmap, x-b, y-b, b*2, b*2)
Gdip_SaveBitmapToFile(debugbitmap, A_ScriptDir . "\" . current_date . "-" . debugsavecropped . ".bmp")
Gdip_DisposeImage(debugbitmap)
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
; -------------------
; Release All
; -------------------
Release_All:
Gosub, Release_X
Gosub, Release_O
Gosub, Release_Right
Gosub, Release_Left
Gosub, Release_Up
Gosub, Release_Down
return
; -------------------
; Press x
; -------------------
Press_X:
Gosub, Hold_X
Sleep, 50
Gosub, Release_x
return
Hold_X:
controller.Buttons.Cross.SetState(true)
return
Release_X:
controller.Buttons.Cross.SetState(false)
return
; -------------------
; Press O
; -------------------
Press_O:
Gosub, Hold_O
Sleep, 50
Gosub, Release_O
return
Hold_O:
controller.Buttons.Circle.SetState(true)
return
Release_O:
controller.Buttons.Circle.SetState(false)
return
; -------------------
; Press Right
; -------------------
Press_Right:
Gosub, Hold_Right
Sleep, 50
Gosub, Release_Right
return
Hold_Right:
controller.Dpad.SetState("Right")
return
Release_Right:
controller.Dpad.SetState("None")
return
; -------------------
; Press Left
; -------------------
Press_Left:
Gosub, Hold_Left
Sleep, 50
Gosub, Release_Left
return
Hold_Left:
controller.Dpad.SetState("Left")
return
Release_Left:
controller.Dpad.SetState("None")
return
; -------------------
; Press Up
; -------------------
Press_Up:
Gosub, Hold_Up
Sleep, 50
Gosub, Release_Up
return
Hold_Up:
controller.Dpad.SetState("Up")
return
Release_Up:
controller.Dpad.SetState("None")
return
; -------------------
; Press Down
; -------------------
Press_Down:
Gosub, Hold_Down
Sleep, 50
Gosub, Release_Down
return
Hold_Down:
controller.Dpad.SetState("Down")
return
Release_Down:
controller.Dpad.SetState("None")
return
; Hotkeys
^Esc::ExitApp
@@ -0,0 +1,3 @@
[pushover]
user_key=your_key
token=your_token
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

@@ -0,0 +1,313 @@
#Persistent
#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#Include Lib\Gdip.ahk
#Include Lib\AHK-ViGEm-Bus.ahk
#Include Lib\__utility__.ahk
#Include Lib\__controller_functions__.ahk
#Include Mod\TokyoDetections.ahk
#Include Races\Tokyo.ahk
hModule := DllCall("LoadLibrary", "Str", A_LineFile "\..\Lib\SuperSleep.dll", "Ptr")
SuperSleep := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", A_LineFile "\..\Lib\SuperSleep.dll", "Ptr"), "AStr", "super_sleep", "Ptr")
ListLines Off
Process, Priority, , A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SendMode Input
SetWorkingDir %A_ScriptDir%
DetectHiddenWindows, On
#Persistent
Global script_start := A_TickCount
Global remote_play_offsetY := 71
Global racecounter := 0
Global resetcounter := 0
Global color_pitstop1 := 0xFFFFFF
Global color_restart := 0x6D5223
Global hairpin_delay := 0
Global TelegramBotToken := ""
Global TelegramChatID := ""
Global location := ""
Global TokyoLapCount := 1
SetFormat, integerfast, d
ps_win_width := 640
ps_win_height := 360
IniRead, hairpin_delay, config.ini, Vars, hairpin_delay, 0
IniRead, color_pitstop1, config.ini, Vars, color_pitstop1, 0
IniRead, RaceCounterTotal, config.ini, Stats, racecountertotal, 0
IniRead, ResetCounterTotal, config.ini, Stats, resetcountertotal, 0
IniRead, TelegramBotToken, config.ini, API, TelegramBotToken, 0
IniRead, TelegramChatID, config.ini, API, TelegramChatID, 0
SetFormat, FloatFast, 0.2
creditcountertotal := 835000*racecountertotal/1000000
Global controller := new ViGEmDS4()
controller.SubscribeFeedback(Func("OnFeedback"))
OnFeedback(largeMotor, smallMotor, lightbarColor){
}
;- GUI 1 (MAIN) -------------------------------------------------------------------------------------------------
Icon = Assets\GT7_Tokyo.ico
Menu, Tray, Icon, %Icon%
Gui, -Caption
Gui, Add, Picture, x0 y0 w650 h207 , Assets\tokyo_gui.png
Gui, Add, Button, x222 y82 w410 h80 default gButtonStart, START
Gui, Add, Progress, x0 y54 w641 h12 RaceProgress vRaceProgress -Smooth, 0
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x440 y3 w160 h20 RaceCounterTotal +BackgroundTrans, // ALL TIME
Gui, Font, ,
Gui, Add, Text, x440 y23 w160 h20 RaceCounterTotal vracecountertotal +BackgroundTrans, Races completed: %racecountertotal%
Gui, Add, Text, x440 y38 w160 h20 ResetCounterTotal vresetcountertotal +BackgroundTrans, Races failed: %resetcountertotal%
Gui, Add, Text, x550 y38 w160 h20 CreditCounterTotal vcreditcountertotal +BackgroundTrans, Credits: %creditcountertotal% M
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x220 y3 w300 h20 RaceSession vracesession +BackgroundTrans, // SESSION
Gui, Font, ,
Gui, Add, Text, x220 y23 w160 h20 RaceCounterSession vracecountersession +BackgroundTrans, Races completed: 0
Gui, Add, Text, x220 y38 w160 h20 ResetCounterSession vresetcountersession +BackgroundTrans, Races failed: 0
Gui, Add, Text, x330 y23 w160 h20 CreditCounterSession vcreditcountersession +BackgroundTrans, Credits: 0
Gui, Add, Text, x330 y38 w160 h20 CreditAVG vcreditavg +BackgroundTrans, Avg./h: 0
Gui, Add, Text, x10 y38 w150 h20 CounterLap vcurrentlap +BackgroundTrans, Current Lap: 0/12
Gui, Add, Text, x10 y23 w150 h20 CurrentLoop vcurrentloop +BackgroundTrans, Current Location: -
Gui, Add, Button, x222 y172 w300 h20 default gGUIReset, Reset
Gui, Add, Button, x531 y172 w101 h20 default gGUIClose, Exit
Gui, Add, Button, x12 y82 w200 h20 default gMachineSettingsWindow, Settings: Machine/Setup
Gui, Add, Button, x12 y112 w200 h20 default gIngameSettingsWindow, Settings: Ingame (wip)
Gui, Add, Button, x12 y142 w200 h20 default gRiskRewardWindow, Settings: Risk/Reward (wip)
Gui, Add, Button, x12 y172 w200 h20 default gNotificationsWindow, Settings: Notifications/API
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x10 y3 w620 h20 +BackgroundTrans, // TOKYO CONTROL CENTER
Gui, Add, Statusbar, -Theme Backgroundeeeeee ;#eeeeee, no typo
SB_SetParts(80,270,190)
SB_SetText(" beta 9.2 ",1)
SB_SetText(" by problemz.",4)
Gui, Show, x8 y532 h225 w640, GT7 Tokyo // by problemz
guicontrol,, CurrentLoop, Press START, go go!
;- GUI 2 (MACHINE/SETUP) ----------------------------------------------------------------------------------------
Gui, 2: Add, Picture, x0 y0 w650 h210 , Assets\tokyo_gui.png
Gui, 2: Add, Text, x10 y14 w200 h20 +BackgroundTrans , Hairpin Turn Delay:
Gui, 2: Font, ,
Gui, 2: Add, Text, x170 y14 w200 h20 +BackgroundTrans , (ms)
Gui, 2: Add, Slider, x220 y10 w300 h51 vsliderhairpindelay Range0-800 Thick40 +ToolTip TickInterval50 gSliderMove,%hairpin_delay%
Gui, 2: Add, Edit, x106 y11 w60 vtxthairpindelay gtextchanged, %hairpin_delay%
Gui, 2: Add, Text, x10 y40 w200 h20 +BackgroundTrans , Lower = slower PC // Higher = faster PC
Gui, 2: Add, Button, x530 y11 w100 h51 +BackgroundTrans gSaveToIni, Save
Gui, 2: Add, Button, x10 y80 w200 h40 gPit1Color, Stuck in pit `n(Only click when at tire selection menu)
;- GUI 3 (INGAME) -----------------------------------------------------------------------------------------------
Gui, 3: Add, Picture, x0 y0 w650 h177 , Assets\tokyo_gui.png
;- GUI 4 (RISK/REWARD) ------------------------------------------------------------------------------------------
Gui, 4: Add, Picture, x0 y0 w650 h177 , Assets\tokyo_gui.png
;- GUI 5 (NOTIFICATIONS/API) ------------------------------------------------------------------------------------
Gui, 5: Add, Picture, x0 y0 w650 h400 , Assets\tokyo_gui.png
Gui, 5: Add, Text, x10 y14 w205 h20 +BackgroundTrans , Telegram Bot Token:
Gui, 5: Add, Edit, x116 y11 w400 vTelegramBotToken Password, %TelegramBotToken%
Gui, 5: Add, Text, x10 y44 w205 h20 +BackgroundTrans , Telegram Chat ID:
Gui, 5: Add, Edit, x116 y41 w400 vTelegramChatID Password, %TelegramChatID%
Gui, 5: Add, Button, x530 y11 w100 h51 +BackgroundTrans gSaveToIni, Save
Return
MachineSettingsWindow:
if (GetKeyState("LShift", "P") AND GetKeyState("LAlt", "P")){
goto, MouseColor
}
else{
Gui, 2: Show, x6 y757 w639 h133, Settings: Machine/Setup
}
return
IngameSettingsWindow:
Gui, 3: Show, x6 y757 w639 h35, Settings: Ingame
return
RiskRewardWindow:
Gui, 4: Show, x6 y757 w639 h35, Settings: Risk/Reward
return
NotificationsWindow:
Gui, 5: Show, x6 y757 w639 h70, Settings: Notifications/API
return
SliderMove:
Gui, Submit, nohide
GuiControl,, txthairpindelay, %sliderhairpindelay%
Return
SaveToIni:
Gui, Submit, Hide
IniWrite, %txthairpindelay%, config.ini,Vars, hairpin_delay
IniWrite, %TelegramBotToken%, config.ini,API, TelegramBotToken
IniWrite, %TelegramChatID%, config.ini,API, TelegramChatID
return
TextChanged:
guiControlGet, txtvar,, txthairpindelay
if (txtvar > 800)
{
GuiControl,, txthairpindelay, 800
}
GuiControl,, sliderhairpindelay, %txtvar%
return
Pit1Color:
MsgBox, 4,, Do you really wanna set a new Pitstop color?
IfMsgBox Yes
{
gosub, GrabRemotePlay
color_pitstop1 := PixelColorSimple(199, 315+remote_play_offsetY)
IniWrite, %color_pitstop1%, config.ini,Vars, color_pitstop1
}
return
ButtonStart:
SetTimer, UpdateTimer, 1000
Gui, Submit, NoHide
id := ""
SetKeyDelay, 10
Process, priority, , High
gosub, GrabRemotePlay
if (id = "")
return
gosub, PauseLoop
CoordMode, Pixel, Screen
CoordMode, ToolTip, Screen
loop {
Press_X()
Race_Tokyo()
}
PixelTuning:
x_ratio := ps_win_width/640
y_ratio := ps_win_height/360
return
GrabRemotePlay:
WinGet, remotePlay_id, List, ahk_exe RemotePlay.exe
if (remotePlay_id = 0)
{
MsgBox, PS4 Remote Play not found
return
}
Loop, %remotePlay_id%
{
id := remotePlay_id%A_Index%
WinGetTitle, title, % "ahk_id " id
If InStr(title, "PS Remote Play")
break
}
WinMove, ahk_id %id%,, 0, 0, 640, 540
ControlFocus,, ahk_class %remotePlay_class%
WinActivate, ahk_id %id%
GetClientSize(remotePlay_id5, ps_win_width, ps_win_height)
gosub, PixelTuning
return
PauseLoop:
controller.Buttons.Cross.SetState(false)
controller.Buttons.Square.SetState(false)
controller.Buttons.Triangle.SetState(false)
controller.Buttons.Circle.SetState(false)
controller.Buttons.L1.SetState(false)
controller.Buttons.L2.SetState(false)
controller.Axes.L2.SetState(0)
controller.Buttons.R1.SetState(false)
controller.Buttons.R2.SetState(false)
controller.Axes.R2.SetState(0)
controller.Buttons.RS.SetState(false)
controller.Axes.RX.SetState(50)
controller.Axes.RY.SetState(50)
controller.Buttons.LS.SetState(false)
controller.Axes.LX.SetState(50)
controller.Axes.LY.SetState(50)
controller.Dpad.SetState("None")
return
ResetRace:
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime%: Race failed - Lap %TokyoLapCount% - %location%.`n, log.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race failed - Lap " TokyoLapCount " - " location ".&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
SB_SetText(" - RESET INITIATED -",2)
guicontrol,, CurrentLoop, Something went wrong, reseting.
controller.Axes.LX.SetState(50)
Press_Options()
Sleep(1000)
Press_Right()
Sleep(500)
Press_X()
controller.Axes.LX.SetState(65)
IniRead, ResetCounterTotal, config.ini, Stats, resetcountertotal, 0
SetFormat, integerfast, d
resetcounter++
resetcountertotal++
IniWrite, %resetcountertotal%, config.ini,Stats, ResetCounterTotal
guicontrol,, ResetCounterTotal, Races failed: %resetcountertotal%
guicontrol,, ResetCounterSession, Races failed: %resetcounter%
guicontrol,, RaceProgress, 0
Race_Tokyo()
return
MouseHelp:
coord=relative
sleep, 1000
CoordMode, ToolTip, %coord%
CoordMode, Pixel, %coord%
CoordMode, Mouse, %coord%
CoordMode, Caret, %coord%
CoordMode, Menu, %coord%
return
Refresh:
MouseGetPos, x, y
PixelGetColor, cBGR, %x%, %y%,, Alt RGB
WinGetPos,,, w, h, A
ToolTip,Location: %x% x %y%`nRGB: %cBGR%`nWindow Size: %w% x %h%
return
MouseColor:
gosub, MouseHelp
SetTimer, Refresh, 75
return
GuiClose:
gosub, PauseLoop
ExitApp
^Esc::ExitApp
GUIReset:
if (GetKeyState("LShift", "P") AND GetKeyState("LAlt", "P")){
MsgBox, 4,, Reset all data?
IfMsgBox Yes
{
IniWrite, 0, config.ini,Stats, RaceCounterTotal
IniWrite, 0, config.ini,Stats, ResetCounterTotal
}
}
Sleep(500)
gosub, PauseLoop
Reload
@@ -0,0 +1,211 @@
#include %A_LineFile%\..\CLR.ahk
; Static class, holds ViGEm Client instance
class ViGEmWrapper {
static asm := 0
static client := 0
Init(){
if (this.client == 0){
this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
}
}
CreateInstance(cls){
return this.asm.CreateInstance(cls)
}
}
; Base class for ViGEm "Targets" (Controller types - eg xb360 / ds4) to inherit from
class ViGEmTarget {
target := 0
helperClass := ""
controllerClass := ""
__New(){
;~ this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
ViGEmWrapper.Init()
this.Instance := ViGEmWrapper.CreateInstance(this.helperClass)
if (this.Instance.OkCheck() != "OK"){
msgbox ViGEmWrapper.dll failed to load!
ExitApp
}
}
SendReport(){
this.Instance.SendReport()
}
SubscribeFeedback(callback){
this.Instance.SubscribeFeedback(callback)
}
}
; DS4 (DualShock 4 for Playstation 4)
class ViGEmDS4 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Ds4"
__New(){
static buttons := {Square: 16, Cross: 32, Circle: 64, Triangle: 128, L1: 256, R1: 512, L2: 1024, R2: 2048
, Share: 4096, Options: 8192, LS: 16384, RS: 32768 }
static specialButtons := {Ps: 1, TouchPad: 2}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
for name, id in specialButtons {
this.Buttons[name] := new this._SpecialButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _SpecialButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetSpecialButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
return this._Parent
}
ConvertAxis(state){
return round(state * 2.55)
}
}
class _DpadHelper {
__New(parent){
this._Parent := parent
this._Id := id
}
SetState(state){
static dPadDirections := {Up: 0, UpRight: 1, Right: 2, DownRight: 3, Down: 4, DownLeft: 5, Left: 6, UpLeft: 7, None: 8}
this._Parent.Instance.SetDpadState(dPadDirections[state])
this._Parent.Instance.SendReport()
return this._Parent
}
}
}
; Xb360
class ViGEmXb360 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Xb360"
__New(){
static buttons := {A: 4096, B: 8192, X: 16384, Y: 32768, LB: 256, RB: 512, LS: 64, RS: 128, Back: 32, Start: 16, Xbox: 1024}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
}
ConvertAxis(state){
value := round((state * 655.36) - 32768)
if (value == 32768)
return 32767
return value
}
}
class _DpadHelper {
_DpadStates := {1:0, 8:0, 2:0, 4:0} ; Up, Right, Down, Left
__New(parent){
this._Parent := parent
}
SetState(state){
static dpadDirections := { None: {1:0, 8:0, 2:0, 4:0}
, Up: {1:1, 8:0, 2:0, 4:0}
, UpRight: {1:1, 8:1, 2:0, 4:0}
, Right: {1:0, 8:1, 2:0, 4:0}
, DownRight: {1:0, 8:1, 2:1, 4:0}
, Down: {1:0, 8:0, 2:1, 4:0}
, DownLeft: {1:0, 8:0, 2:1, 4:1}
, Left: {1:0, 8:0, 2:0, 4:1}
, UpLeft: {1:1, 8:0, 2:0, 4:1}}
newStates := dpadDirections[state]
for id, newState in newStates {
oldState := this._DpadStates[id]
if (oldState != newState){
this._DpadStates[id] := newState
this._Parent.Instance.SetButtonState(id, newState)
}
this._Parent.SendReport()
}
}
}
}
@@ -0,0 +1,151 @@
; ==========================================================
; .NET Framework Interop
; https://autohotkey.com/boards/viewtopic.php?t=4633
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if assembly := AppDomain.Load_2(AssemblyName)
break
static null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, null, null, args)
break
if assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, null, null, args)
break
}
ComObjError(e)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, null, vargs, null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, null, null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,188 @@
/**********************************************
* Controller methods for simplicity *
***********************************************/
*/
GoTo EndControllerFunctionsDef
;;;;;;;;;;;; Turning functions
;;;;;;;;;;;; For holding the stick in a specific position for a period of time
;;;;;;;;;;;; Note no other button may be pressed or released when these functions are ran
; Set the time you want to turn for in miliseconds and how hard (50, 100), 100 being the most, 50 being neutral
Turn_Right(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
; Set the time you want to turn for in miliseconds and how hard (0, 50), 0 being the most
Turn_Left(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
;;;;;;;;;;;; Simple button press functions
;;;;;;;;;;;; You can pass a delay amount or leave it blank
;;;;;;;;;;;; Longer delays hold the button longer
; Press X button
Press_X(delay:=200){
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Cross.SetState(false)
return
}
; Press O button
Press_O(delay:=200){
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Circle.SetState(false)
return
}
; Press Triangle button
Press_Triangle(delay:=200){
controller.Buttons.Triangle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Triangle.SetState(false)
return
}
; Press Square button
Press_Square(delay:=200){
controller.Buttons.Square.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Square.SetState(false)
return
}
; Press R1 button
Press_L1(delay:=200){
controller.Buttons.L1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.L1.SetState(false)
return
}
; Press R1 button
Press_R1(delay:=200){
controller.Buttons.R1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.R1.SetState(false)
return
}
; Press Right on D-pad
Press_Right(delay:=200){
controller.Dpad.SetState("Right")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Left on D-pad
Press_Left(delay:=200){
controller.Dpad.SetState("Left")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Up on D-pad
Press_Up(delay:=200){
controller.Dpad.SetState("Up")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Down on D-pad
Press_Down(delay:=200){
controller.Dpad.SetState("Down")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
;;;;;;;;;;; Other functions specific to GT7
; Turn on nitrous
Nitrous_On(){
controller.Buttons.RS.SetState(true)
}
; Turn off nitrous
Nitrous_Off(){
controller.Buttons.RS.SetState(false)
}
Accel_On(control:=100){
controller.Buttons.R2.SetState(true)
controller.Axes.RT.SetState(control)
}
Accel_Off(){
controller.Buttons.R2.SetState(false)
controller.Axes.RT.SetState(0)
}
Brake_On(control:=100){
controller.Buttons.L2.SetState(true)
controller.Axes.LT.SetState(control)
}
Brake_Off(){
controller.Buttons.L2.SetState(false)
controller.Axes.LT.SetState(0)
}
; given time t in miliseconds, turn right for that long, with intensity being how much the turn button is held for
Turn:
t0 := A_TickCount
tf := t0+t
loop {
Sleep(100)
} until A_TickCount > tf
return
Press_Options(){
controller.Buttons.Options.SetState(true)
Sleep, 50
controller.Buttons.Options.SetState(false)
}
PressX:
; Just for menuing, does not hold X down
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Cross.SetState(false)
return
PressO:
; Just for menuing, does not hold O down
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Circle.SetState(false)
return
PressRight:
; For turning
controller.Dpad.SetState("Right")
Sleep, 50
controller.Dpad.SetState("None")
return
PressShare:
controller.Buttons.Share.SetState(true)
Sleep, 50
controller.Buttons.Share.SetState(false)
return
EndControllerFunctionsDef:
@@ -0,0 +1,136 @@
/**********************************************
* Only place functions here, no sub routines *
***********************************************/
; Grabs the colors of the pixels (x-b, y-b) to (x+b, y+b)
; returns the array of colors
*/
BitGrab(x, y, b)
{
HWND := WinExist("PS Remote Play")
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromHWND2(hwnd)
pixs := []
for i in range(-1*b, b+1){
for j in range(-1*b, b+1){
pixel := Gdip_GetPixel(pBitmap,x+i,y+j)
rgb := ConvertARGB( pixel )
pixs.Push(rgb)
}
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
Gdip_BitmapFromHWND2(hwnd)
{
WinGetPos,,, Width, Height, ahk_id %hwnd%
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
RegExMatch(A_OsVersion, "\d+", Version)
PrintWindow(hwnd, hdc, Version >= 8 ? 2 : 0)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
return pBitmap
}
range(start, stop:="", step:=1) {
static range := { _NewEnum: Func("_RangeNewEnum") }
if !step
throw "range(): Parameter 'step' must not be 0 or blank"
if (stop == "")
stop := start, start := 0
; Formula: r[i] := start + step*i ; r = range object, i = 0-based index
; For a postive 'step', the constraints are i >= 0 and r[i] < stop
; For a negative 'step', the constraints are i >= 0 and r[i] > stop
; No result is returned if r[0] does not meet the value constraint
if (step > 0 ? start < stop : start > stop) ;// start == start + step*0
return { base: range, start: start, stop: stop, step: step }
}
_RangeNewEnum(r) {
static enum := { "Next": Func("_RangeEnumNext") }
return { base: enum, r: r, i: 0 }
}
_RangeEnumNext(enum, ByRef k, ByRef v:="") {
stop := enum.r.stop, step := enum.r.step
, k := enum.r.start + step*enum.i
if (ret := step > 0 ? k < stop : k > stop)
enum.i += 1
return ret
}
Sleep(ms=1)
{
global timeBeginPeriodHasAlreadyBeenCalled
if (timeBeginPeriodHasAlreadyBeenCalled != 1)
{
DllCall("Winmm.dll\timeBeginPeriod", UInt, 1)
timeBeginPeriodHasAlreadyBeenCalled := 1
}
DllCall("Sleep", UInt, ms)
}
PixelColorSimple(pc_x, pc_y)
{
WinGet, remotePlay_id, List, ahk_exe RemotePlay.exe
if (remotePlay_id = 0)
{
MsgBox, PS4 Remote Play not found
return
}
if remotePlay_id
{
pc_wID := remotePlay_id[0]
pc_hDC := DllCall("GetDC", "UInt", pc_wID)
pc_fmtI := A_FormatInteger
SetFormat, IntegerFast, Hex
pc_c := DllCall("GetPixel", "UInt", pc_hDC, "Int", pc_x, "Int", pc_y, "UInt")
pc_c := pc_c >> 16 & 0xff | pc_c & 0xff00 | (pc_c & 0xff) << 16
pc_c .= ""
SetFormat, IntegerFast, %pc_fmtI%
DllCall("ReleaseDC", "UInt", pc_wID, "UInt", pc_hDC)
return pc_c
}
}
GetClientSize(hWnd, ByRef w := "", ByRef h := "")
{
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hWnd, "ptr", &rect)
w := NumGet(rect, 8, "int")
h := NumGet(rect, 12, "int")
}
Distance(c1, c2)
{ ; function by [VxE], return value range = [0, 441.67295593006372]
return Sqrt((((c1>>16)-(c2>>16))**2)+(((c1>>8&255)-(c2>>8&255))**2)+(((c1&255)-(c1&255))**2))
}
ConvertARGB(ARGB, Convert := 0)
{
SetFormat, IntegerFast, Hex
RGB += ARGB
RGB := RGB & 0x00FFFFFF
if (Convert)
RGB := (RGB & 0xFF000000) | ((RGB & 0xFF0000) >> 16) | (RGB & 0x00FF00) | ((RGB & 0x0000FF) << 16)
return RGB
}
ToolTipper(msg, x := 100, y := 100)
{
if (debug_mode = 1)
ToolTip, %msg%, x, y, Screen
return
}
@@ -0,0 +1,367 @@
__enableTokyoDetections_mod__ := 1
IniRead, color_pitstop1, config.ini, Vars, color_pitstop1, 0
IniRead, color_pitstop2, config.ini, Vars, color_pitstop2, 0
class TokyoTurnContainer
{
__New(startX, startY, endX := 0, endY := 0)
{
this.startX := startX
this.startY := startY
this.endX := endX
this.endY := endY
}
}
GoTo EndTokyoDetectionsDef
CheckTokyoMFD(x,y, b_size := 1)
{
color_dot := 0xD3D2D0
TokyoMFD := false
tries := 1000 ; we shouldn't need more than 6 tries, but I have seen it loop passed
loop {
tc := BitGrab(x, y, b_size)
SB_SetText(" Searching... " td " < 5",2)
for i, c in tc
{
td := Distance(c, color_dot)
if (td < 5){
SB_SetText(" Found: " td " < 5",2)
TokyoMFD := true
break
}
else {
; Gonna try to automate the mfd checker, why not right?
if (tries > 0){
SB_SetText(" Searching Track/Course Map MFD " td " < 5",2)
Press_Left()
Sleep(200)
tries--
break
}
tries := 1000
TokyoMFD := true
break
}
}
} until TokyoMFD = true
return
}
CheckTokyoTurn(x,y, b_size := 1)
{
turnStart := A_TickCount
color_player := 0xDE6E70
TokyoTurnComplete := false
loop {
SB_SetText(" Searching... " td " < 50",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_player)
if (td < 50 ){
SB_SetText(" Found: " td " < 50",2)
TokyoTurnComplete := true
break
}
}
; add recovery so we don't kill run looking for turn. Gonna start with a high number, can adjust lower later.
; added some press down, x's and waits just in case we are in the pit stop
if (A_TickCount - turnStart > 90000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
break
}
} until TokyoTurnComplete = true
return
}
CheckTokyoPen1(x,y, b_size := 1)
{
pen1Start := A_TickCount
color_pen := 0xFFC10B
TokyoPen1 := false
loop {
SB_SetText(" Searching... " td " < 50",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pen)
if (td < 50 ){
SB_SetText(" Found: " td " < 50",2)
TokyoPen1 := true
break
}
}
; add recovery so we don't kill run looking for Pen1. Gonna start with a high number, can adjust lower later.
; started with 1.5 mins, i had these set to 3:33 on other file and still won.
if (A_TickCount - pen1Start > 90000) {
GoSub, ResetRace
break
}
} until TokyoPen1 = true
return
}
CheckTokyoHairpinTurn(x,y, b_size := 1)
{
hairpinStart := A_TickCount
color_hairpinturn := 0xB3B1B2
TokyoHairpinTurn := false
loop {
SB_SetText(" Searching... " td " < 5",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_hairpinturn)
if (td < 5){
SB_SetText(" Found: " td " < 5",2)
TokyoHairpinTurn := true
break
}
}
; add recovery so we don't kill run sitting in hairpin
; set to 1 minute to start, I had this at 3:33 (200000) on my other file and still won.
if (A_TickCount - hairpinStart > 90000) {
GoSub, ResetRace
break
}
} until TokyoHairpinTurn = true
return
}
CheckTokyoPen2(x,y, b_size := 1)
{
start := A_TickCount
color_pen := 0xFFC10B
RecoveryTried := false
TokyoPen2 := false
loop {
SB_SetText(" Searching... " td " > 60",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pen)
if (td > 60 ){
SB_SetText(" Found: " td " > 60",2)
TokyoPen2 := true
break
}
}
if (A_TickCount - start > 25000 AND RecoveryTried = false) {
SB_SetText(" We stuck? Starting recovery try.",2)
Accel_off()
controller.Axes.LX.SetState(50)
loop 7 {
Press_Square(delay:=50)
Sleep(100)
}
Accel_on(80)
Sleep(500)
loop 9 {
Press_Triangle(delay:=50)
Sleep(100)
}
controller.Axes.LX.SetState(30)
RecoveryTried := true
}
if (A_TickCount - start > 60000) {
gosub, ResetRace
break
}
} until TokyoPen2 = true
return
}
CheckTokyoPenServed(x,y, b_size := 1)
{
color_penserved := 0xAE1B1E
TokyoPenServed := false
loop {
SB_SetText(" Searching... " td " > 60",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_penserved)
if (td > 60 ){
SB_SetText(" Found: " td " > 60",2)
TokyoPenServed := true
break
}
}
} until TokyoPenServed = true
return
}
CheckTokyoPenReceived(x,y, b_size := 1)
{
start := A_TickCount
color_penreceived := 0xAE1B1E
TokyoPenReceived := false
loop {
SB_SetText(" Searching... " td " < 40",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_penreceived)
if (td < 40 ){
SB_SetText(" Found: " td " < 40",2)
guicontrol,, CurrentLoop, Pen received
TokyoPenReceived := true
break
}
if (TokyoLapCount != 6 AND A_TickCount - start > 36000)
{
SB_SetText(" Not found in time. Shifting up.",2)
loop 6 {
Press_Triangle(delay:=50)
Sleep(200)
TokyoPenReceived := true
break
}
break
}
if (TokyoLapCount = 6 AND A_TickCount - start > 46000)
{
SB_SetText(" Not found in time. Shifting up.",2)
loop 20 {
Press_Triangle(delay:=50)
Sleep(200)
TokyoPenReceived := true
break
}
break
}
}
} until TokyoPenReceived = true
return
}
CheckTokyoPitstopDone(x,y, b_size := 1)
{
pitstopDoneStart := A_TickCount
color_pitstopdone := 0xFFFFFF
TokyoPitstopDone := false
loop {
SB_SetText(" Searching... " td " > 10",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pitstopdone)
if (td > 10 ){
SB_SetText(" Found: " td " > 10",2)
TokyoPitstopDone := true
break
}
}
; add recovery so we don't kill run sitting in pit, havent tested if press down works to get us out
if (A_TickCount - pitstopDoneStart > 60000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
}
} until TokyoPitstopDone = true
return
}
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
{
if ( A_TickCount - loopStartTime > maxTime AND TokyoLapCount <= 10) {
gosub, ResetRace
}
else if (A_TickCount - loopStartTime > maxTime+90000 AND TokyoLapCount > 10)
{
gosub, ResetRace
}
}
CheckTokyoPitstop1(x,y, b_size := 1)
{
pitstop1Start := A_TickCount
;color_pitstop1 := 0xFFFFFF
;color_pitstop1 := 0x818002
;color_pitstop1 := 0xFBFB00 ; old color
TokyoPitstop := false
loop {
SB_SetText(" Searching... " td " < 10",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pitstop1)
if (td < 10 ){
SB_SetText(" Found: " td " < 10",2)
TokyoPitstop := true
break
}
}
; add recovery so we don't kill run sitting in pit, havent tested if press down works to get us out
if (A_TickCount - pitstop1Start > 60000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
}
guicontrol,, CurrentLoop, Stuck in pit? Press GUI Button.
} until TokyoPitstop = true
return
}
UpdateAVG(racecounter, script_start)
{
SetFormat, integerfast, d
creditcountersession := (835000*racecounter)/1000000
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditavg := creditcountersession/(A_TickCount-script_start)*3600000
guicontrol,, CreditAVG, Avg./h: ~%creditavg% M
return
}
UpdateTimer()
{
ElapsedTime := A_TickCount - script_start
VarSetCapacity(t,256),DllCall("GetDurationFormat","uint",2048,"uint",0,"ptr",0,"int64",ElapsedTime*10000,"wstr","d' day(s) 'h':'mm':'ss","wstr",t,"int",256)
SB_SetText("Runtime: " t,3)
return
}
EndTokyoDetectionsDef:
@@ -0,0 +1,86 @@
#Include Races\PanAm.ahk
#Include Races\Tokyo.ahk
GoTo EndRaceDef
Race:
Switch RaceChoice
{
case "PanAm":
Race_PANAM()
return
case "Tokyo":
Race_Tokyo()
return
}
return
SettingsSheet:
Gui, 4: Show, AutoSize, Settings Sheet
;/////////////////////////////////////////////////////////
; Add images to your setup here and in the Src folder
;
;/////////////////////////////////////////////////////////
Switch RaceChoice
{
case "PanAm":
assist_1 = %A_ScriptDir%\Src\PanAm\Assist1.jpg
assist_2 = %A_ScriptDir%\Src\PanAm\Assist2.jpg
tune_1 = %A_ScriptDir%\Src\PanAm\CarSetup.jpg
tune_2 = %A_ScriptDir%\Src\PanAm\CarGearRatio.jpg
controls = %A_ScriptDir%\Src\PanAm\Controller.jpg
return
case "Tokyo":
assist_1 = %A_ScriptDir%\Src\Tokyo\Assist_Settings.png
assist_2 = %A_ScriptDir%\Src\Tokyo\Misc_Settings.png
controls = %A_ScriptDir%\Src\Tokyo\Controller_Settings.png
tune_1 = %A_ScriptDir%\Src\Tokyo\Settings_Car1.png
tune_2 = %A_ScriptDir%\Src\Tokyo\Settings_Car2.png
tune_3 = %A_ScriptDir%\Src\Tokyo\Settings_Car3.png
return
}
return
Assists1:
GuiControl, 4:, CurrentPic, %assist_1%
gosub, Guisizer
return
Assists2:
GuiControl, 4:, CurrentPic, %assist_2%
gosub, Guisizer
return
Tune1:
GuiControl, 4:, CurrentPic, %tune_1%
gosub, Guisizer
return
Tune2:
GuiControl, 4:, CurrentPic, %tune_2%
gosub, Guisizer
return
Tune3:
GuiControl, 4:, CurrentPic, %tune_2%
gosub, Guisizer
return
ControllerSetting:
GuiControl, 4:, CurrentPic, %controls%
gosub, Guisizer
return
Guisizer:
GuiControl, 4: Move, CurrentPic, % "x" 10 "y" 40 "w" 1200 . " h" . 800
Gui, 4: Show, AutoSize, Settings Sheet
return
EndRaceDef:
@@ -0,0 +1,494 @@
GoTo EndRace_Tokyo_Def
Race_Tokyo()
{
SetFormat, integerfast, d
TokyoStart:
;- VARIABLES -----------------------------------------------------------------------------
SetFormat, integerfast, d
TokyoLapCount := 1
maxTime := 200000
;- COORDINATES: TURNS --------------------------------------------------------------------
TokyoTurn1 := new TokyoTurnContainer(611, 59+remote_play_offsetY, 622, 69+remote_play_offsetY)
TokyoTurn2 := new TokyoTurnContainer(618, 70+remote_play_offsetY, 601, 76+remote_play_offsetY)
TokyoTurn3 := new TokyoTurnContainer(599, 79+remote_play_offsetY, 591, 87+remote_play_offsetY)
TokyoTurn4 := new TokyoTurnContainer(589, 88+remote_play_offsetY, 571, 96+remote_play_offsetY)
TokyoTurn5 := new TokyoTurnContainer(567, 96+remote_play_offsetY, 556, 90+remote_play_offsetY)
TokyoTurn6 := new TokyoTurnContainer(554, 86+remote_play_offsetY, 543, 82+remote_play_offsetY)
TokyoTurn7 := new TokyoTurnContainer(538, 81+remote_play_offsetY, 530, 75+remote_play_offsetY)
TokyoTurn8 := new TokyoTurnContainer(530, 75+remote_play_offsetY, 510, 72+remote_play_offsetY)
;- COORDINATES: PENALTY WARNINGS ---------------------------------------------------------
TokyoPenWarning := new TokyoTurnContainer(360, 154+remote_play_offsetY, 408, 154+remote_play_offsetY)
TokyoPenIndicator := new TokyoTurnContainer(366, 132+remote_play_offsetY)
;- COORDINATES: HAIRPIN TURN -------------------------------------------------------------
TokyoHairpinTurn := new TokyoTurnContainer(606, 334+remote_play_offsetY)
;- COORDINATES: PENALTY WARNINGS ---------------------------------------------------------
TokyoPen := new TokyoTurnContainer(360, 154+remote_play_offsetY, 408, 154+remote_play_offsetY)
TokyoPenServed := new TokyoTurnContainer(366, 132+remote_play_offsetY)
;- COORDINATES: HAIRPIN TURN--------------------------------------------------------------
TokyoHairpinTurn := new TokyoTurnContainer(606, 334+remote_play_offsetY)
;- MISC ----------------------------------------------------------------------------------
TokyoPitstop := new TokyoTurnContainer(191, 316+remote_play_offsetY, 580, 383+remote_play_offsetY)
TokyoPitstopEnter := new TokyoTurnContainer(530, 70+remote_play_offsetY)
TokyoPitstopDone := new TokyoTurnContainer(57, 329+remote_play_offsetY)
TokyoRestartRace := new TokyoTurnContainer(405,465+remote_play_offsetY)
;- RACE START ----------------------------------------------------------------------------
controller.Axes.LX.SetState(65)
Sleep(7400)
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime%: Race started.`n, logs.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race started.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
guicontrol,, CurrentLoop, Race started. Good luck!
guicontrol,, CurrentLap, Current Lap: %TokyoLapCount% /12
Accel_On(100)
loop 3 {
Press_Triangle(delay:=50)
Sleep(200)
}
Sleep(800)
controller.Axes.LX.SetState(65)
;- 12 LAP LOOP ---------------------------------------------------------------------------
loop 12
{
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
loopStartTime := A_TickCount
; Turn 1
location := "T1 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn1.startX, TokyoTurn1.startY)
loop 3 {
Press_Triangle(delay:=50)
Sleep(200)
}
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(36)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
Sleep(1000)
location := "T1 End"
CheckTokyoTurn(TokyoTurn1.endX, TokyoTurn1.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(35)
Sleep(1000)
; Turn 2
location := "T2 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn2.startX, TokyoTurn2.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(52)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
Sleep(1000)
location := "T2 End"
CheckTokyoTurn(TokyoTurn2.endX, TokyoTurn2.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
; Turn 3
location := "T3 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn3.startX, TokyoTurn3.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
controller.Axes.LX.SetState(40)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn3.endX, TokyoTurn3.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
; Turn 4
location := "T4 Start"
Accel_On(85)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn4.startX, TokyoTurn4.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
controller.Axes.LX.SetState(68)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn4.endX, TokyoTurn4.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(60)
Accel_On(70)
Sleep(1000)
; Turn 5
location := "T5 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn5.startX, TokyoTurn5.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(42)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn5.endX, TokyoTurn5.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(63)
Sleep(1000)
; Turn 6
location := "T6 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn6.startX, TokyoTurn6.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
Accel_on(75)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn6.endX, TokyoTurn6.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
; Turn 7
location := "T7 Start"
Accel_On(100)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn7.startX, TokyoTurn7.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn7.endX, TokyoTurn7.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
; Turn 8
location := "T8 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn8.startX, TokyoTurn8.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(65)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn8.endX, TokyoTurn8.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(30)
Sleep(2000)
Brake_on(100)
Sleep(2200)
Brake_off()
Accel_On(35)
; Penalty Warning 1
location := "Hairpin Entrance"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPen1(TokyoPenWarning.startX, TokyoPenWarning.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Accel_On(32)
controller.Axes.LX.SetState(40)
Sleep(1000)
; Hairpin Turn
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
location := "Hairpin Turn"
CheckTokyoHairpinTurn(TokyoHairpinTurn.startX, TokyoHairpinTurn.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(hairpin_delay)
controller.Axes.LX.SetState(100)
Sleep(200)
Accel_Off()
Sleep(4200)
Accel_On(45) ;was 40
controller.Axes.LX.SetState(60)
Accel_Off()
Sleep(800)
controller.Axes.LX.SetState(40)
Accel_On(50)
Sleep(5000)
controller.Axes.LX.SetState(30)
Sleep(5500)
Accel_On(80)
loop 30 { ; failsafe, if we ever get a reset caused by a cone under the car
Press_Triangle(delay:=100)
Sleep(200)
}
; Penalty Warning 2
location := "Hairpin exit"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPen2(TokyoPen.endX, TokyoPen.endY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
if (TokyoLapCount <= 11)
{
location := "Pit entrance"
Accel_On(53)
controller.Axes.LX.SetState(30)
guicontrol,, CurrentLoop, Current Location: %location%
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoPitstopEnter.startX, TokyoPitstopEnter.startY)
controller.Axes.LX.SetState(0)
Accel_On(55)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPitstop1(TokyoPitstop.startX, TokyoPitstop.startY)
location := "In pit"
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(50)
if (TokyoLapCount = 1)
{
SetFormat, integerfast, d
lap01timing := 0
location := "In pit: Waiting " lap01timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap01timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 2)
{
SetFormat, integerfast, d
lap02timing := 0
location := "In pit: Waiting " lap02timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap02timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 3)
{
SetFormat, integerfast, d
lap03timing := 0
location := "In pit: Waiting " lap03timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap03timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 4)
{
SetFormat, integerfast, d
lap04timing := 0
location := "In pit: Waiting " lap04timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap04timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 5)
{
SetFormat, integerfast, d
lap05timing := 20000
location := "In pit: Waiting " lap05timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap05timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 6)
{
SetFormat, integerfast, d
lap06timing := 0
location := "In pit: Waiting " lap06timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap06timing)
Press_Up()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 7)
{
SetFormat, integerfast, d
lap07timing := 0
location := "In pit: Waiting " lap07timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap07timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 8)
{
SetFormat, integerfast, d
lap08timing := 0
location := "In pit: Waiting " lap08timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap08timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 9)
{
SetFormat, integerfast, d
lap09timing := 12000
location := "In pit: Waiting " lap09timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap09timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 10)
{
SetFormat, integerfast, d
lap10timing := 20000
location := "In pit: Waiting " lap10timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap10timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 11)
{
SetFormat, integerfast, d
lap11timing := 0
location := "In pit: Waiting " lap11timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap11timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 12)
{
SetFormat, integerfast, d
lap12timing := 0
location := "In pit: Waiting " lap12timing " Seconds."
guicontrol,, CurrentLoop, %location%
Sleep (lap12timing)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
controller.Axes.LX.SetState(20)
Accel_On(100)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPenReceived(TokyoPenServed.startX, TokyoPenServed.startY)
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(38)
Sleep (500)
loop 10 {
Press_Triangle(delay:=200)
sleep, 200
}
}
else {
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
Accel_On(100)
controller.Axes.LX.SetState(60)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPenServed(TokyoPenServed.startX, TokyoPenServed.startY)
}
SetFormat, integerfast, d
TokyoLapCount++
guicontrol,, CurrentLap, Current Lap: %TokyoLapCount% /12
ProgressRace := (100/13)*TokyoLapCount
guicontrol,, RaceProgress, %ProgressRace%
if(TokyoLapCount = "13")
{
location := "Finish line"
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime% Race finished.`n, logs.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race finished.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
guicontrol,, CurrentLoop, Current Location: %location%
guicontrol,, CurrentLap, GG!
controller.Axes.LX.SetState(50)
SetFormat, integerfast, d
racecounter++
SetFormat, integerfast, d
racecountertotal++
; // THIS SESSION
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditcountersession := (835000*racecounter)/1000000
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditavg := creditcountersession/(A_TickCount-script_start)*3600000
guicontrol,, RaceCounterSession, Races completed: %racecounter%
guicontrol,, ResetCounterSession, Races failed: %resetcounter%
guicontrol,, CreditCounterSession, Credits: %creditcountersession% M
guicontrol,, CreditAVGSession, Avg./h: %creditavg% M
; // ALL TIME
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditcountertotal := (835000*racecountertotal)/1000000
IniWrite, %racecountertotal%, config.ini,Stats, RaceCounterTotal
IniWrite, %resetcountertotal%, config.ini,Stats, ResetCounterTotal
guicontrol,, RaceCounterTotal, Races completed: %racecountertotal%
guicontrol,, ResetCounterTotal, Races failed: %resetcountertotal%
guicontrol,, CreditCounterTotal, Credits: %creditcountertotal% M
UpdateAVG(racecounter, script_start)
lapcounter =
ProgressRace =
guicontrol,, RaceProgress, %ProgressRace%
loop
{
restart_found := false
c2 := BitGrab(162, 43+remote_play_offsetY, 2)
for i, c in c2
{
d2 := Distance(c, color_restart)
SB_SetText(" Searching... " d2 " < 50",2)
if (d2 < 10 )
{
SB_SetText(" Found: Restart Color",2)
restart_found := true
break
}
}
if (restart_found)
break
Press_X()
Sleep(500)
}
SB_SetText("Found: Restart Color",2)
Sleep(260)
Press_O()
Sleep(200)
Press_Right()
Sleep(3000)
Press_X()
Sleep(4000)
Press_X()
Sleep(4000)
guicontrol,, CurrentLoop, Setting up next race.
Press_Options()
Sleep(1000)
Press_Right()
Sleep(500)
Press_X()
controller.Axes.LX.SetState(50)
UpdateAVG(racecounter, script_start)
Goto, TokyoStart
}
}
}
EndRace_Tokyo_Def:
Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

@@ -0,0 +1,498 @@
#Persistent
#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#Include Lib\Gdip.ahk
#Include Lib\AHK-ViGEm-Bus.ahk
#Include Lib\__utility__.ahk
#Include Lib\__controller_functions__.ahk
#Include Mod\TokyoDetections.ahk
#Include Races\Tokyo.ahk
hModule := DllCall("LoadLibrary", "Str", A_LineFile "\..\Lib\SuperSleep.dll", "Ptr")
SuperSleep := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", A_LineFile "\..\Lib\SuperSleep.dll", "Ptr"), "AStr", "super_sleep", "Ptr")
ListLines Off
Process, Priority, , A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SendMode Input
SetWorkingDir %A_ScriptDir%
DetectHiddenWindows, On
#Persistent
Global script_start := A_TickCount
Global remote_play_offsetY := 71
Global racecounter := 0
Global resetcounter := 0
Global color_pitstop1 := 0xFFFFFF
Global color_restart := 0x6D5223
Global hairpin_delay := 0
Global PitstopTimings := 0
Global TelegramBotToken := ""
Global TelegramChatID := ""
Global location := ""
Global TokyoLapCount := 1
Global PitstopTimingsArray :=
Global DynTurnDelay := 0
Global SaveResetClip := 0
SetFormat, integerfast, d
ps_win_width := 640
ps_win_height := 360
IniRead, hairpin_delay, config.ini, Vars, hairpin_delay, 0
IniRead, color_pitstop1, config.ini, Vars, color_pitstop1, 0
IniRead, RaceCounterTotal, config.ini, Stats, racecountertotal, 0
IniRead, ResetCounterTotal, config.ini, Stats, resetcountertotal, 0
IniRead, TelegramBotToken, config.ini, API, TelegramBotToken, 0
IniRead, TelegramChatID, config.ini, API, TelegramChatID, 0
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings0, 0
StringSplit, PitstopTimingsArray, PitstopTimings, `,
IniRead, DynTurnDelay, config.ini, Vars, DynTurnDelay, 0
IniRead, SaveResetClip, config.ini, Vars, SaveResetClip, 0
SetFormat, FloatFast, 0.2
creditcountertotal := 835000*racecountertotal/1000000
StringSplit, PitstopTimingsArray, PitstopTimings, `,
Global controller := new ViGEmDS4()
controller.SubscribeFeedback(Func("OnFeedback"))
OnFeedback(largeMotor, smallMotor, lightbarColor){
}
;- GUI 1 (MAIN) -------------------------------------------------------------------------------------------------
Icon = Assets\GT7_Tokyo.ico
Menu, Tray, Icon, %Icon%
Gui, -Caption
Gui, Add, Picture, x0 y0 w650 h207 , Assets\tokyo_gui.png
Gui, Add, Button, x222 y82 w410 h80 default gButtonStart, START
Gui, Add, Progress, x0 y54 w641 h12 RaceProgress vRaceProgress -Smooth, 0
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x440 y3 w160 h20 RaceCounterTotal +BackgroundTrans, // ALL TIME
Gui, Font, ,
Gui, Add, Text, x440 y23 w160 h20 RaceCounterTotal vracecountertotal +BackgroundTrans, Races completed: %racecountertotal%
Gui, Add, Text, x440 y38 w160 h20 ResetCounterTotal vresetcountertotal +BackgroundTrans, Races failed: %resetcountertotal%
Gui, Add, Text, x550 y38 w160 h20 CreditCounterTotal vcreditcountertotal +BackgroundTrans, Credits: %creditcountertotal% M
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x220 y3 w300 h20 RaceSession vracesession +BackgroundTrans, // SESSION
Gui, Font, ,
Gui, Add, Text, x220 y23 w160 h20 RaceCounterSession vracecountersession +BackgroundTrans, Races completed: 0
Gui, Add, Text, x220 y38 w160 h20 ResetCounterSession vresetcountersession +BackgroundTrans, Races failed: 0
Gui, Add, Text, x330 y23 w160 h20 CreditCounterSession vcreditcountersession +BackgroundTrans, Credits: 0
Gui, Add, Text, x330 y38 w160 h20 CreditAVG vcreditavg +BackgroundTrans, Avg./h: 0
Gui, Add, Text, x10 y38 w150 h20 CounterLap vcurrentlap +BackgroundTrans, Current Lap: 0/12
Gui, Add, Text, x10 y23 w220 h20 CurrentLoop vcurrentloop +BackgroundTrans, Current Location: -
Gui, Add, Button, x222 y172 w300 h20 default gGUIReset, Reset
Gui, Add, Button, x531 y172 w101 h20 default gGUIClose, Exit
Gui, Add, Button, x12 y82 w200 h20 default gRaceSettingsWindow, Settings: Race
Gui, Add, Button, x12 y112 w200 h20 default gMachineSettingsWindow, Settings: Machine/Setup
Gui, Add, Button, x12 y142 w200 h20 default gIngameSettingsWindow, Settings: Ingame (wip)
Gui, Add, Button, x12 y172 w200 h20 default gNotificationsWindow, Settings: Notifications/API
Gui, Font, S8 CDefault Bold, Verdana
Gui, Add, Text, x10 y3 w620 h20 +BackgroundTrans, // TOKYO CONTROL CENTER
Gui, Add, Statusbar, -Theme Backgroundeeeeee ;#eeeeee, no typo
SB_SetParts(80,270,190)
SB_SetText(" beta 9.4 ",1)
SB_SetText(" by problemz.",4)
Gui, Show, x8 y532 h225 w640, GT7 Tokyo // by problemz
guicontrol,, CurrentLoop, Press START, go go!
;- GUI 2 (MACHINE/SETUP) ----------------------------------------------------------------------------------------
;Gui, 2: Add, Picture, x0 y0 w650 h500 , Assets\tokyo_gui.png
Gui, 2: Add, Text, x10 y14 w200 h20 +BackgroundTrans , Hairpin Turn Delay:
Gui, 2: Add, Text, x170 y14 w200 h20 +BackgroundTrans , (ms)
Gui, 2: Add, Slider, x220 y10 w300 h51 vsliderhairpindelay Range0-800 Thick40 +ToolTip TickInterval50 gSliderMove,%hairpin_delay%
Gui, 2: Add, Edit, x106 y11 w60 vtxthairpindelay gtextchanged, %hairpin_delay%
Gui, 2: Add, Text, x10 y40 w200 h20 +BackgroundTrans , Lower = slower PC // Higher = faster PC
Gui, 2: Add, Button, x530 y11 w100 h73 +BackgroundTrans gSaveToIni, Save
Gui, 2: Add, Button, x10 y103 w200 h40 gPit1Color, Stuck in pit `n(Only click when at tire selection menu)
Gui, 2: Add, Checkbox, x320 y110 w300 gDynTurnDelay vDynTurnDelay +BackgroundTrans Checkbox Checked%DynTurnDelay%, Experimental: Use dynamic hairpin turn delays.
Gui, 2: Add, Checkbox, x320 y130 w300 gSaveResetClip vSaveResetClip +BackgroundTrans Checkbox Checked%SaveResetClip%, Experimental: Save clip (past 3 minutes) after a reset.
;- GUI 3 (INGAME) -----------------------------------------------------------------------------------------------
;Gui, 3: Add, Picture, x0 y0 w650 h177 , Assets\tokyo_gui.png
;- GUI 4 (RACE SETTINGS) ----------------------------------------------------------------------------------------
;Gui, 4: Add, Picture, x0 y0 w650 h450 , Assets\tokyo_gui.png
Gui, 4: Font, S8 CDefault Bold, Verdana
Gui, 4: Add, Text, x220 y20 w200 h20 vFightme +gFightMe +BackgroundTrans , (´)
Gui, 4: Add, Text, x30 y10 w200 h50 +BackgroundTrans vPitstopText , Pit stop wait timers in ms`n(Read-only):
Gui, 4: Font, ,
Gui, 4: Add, Text, xp yp+40 w100 h20 +BackgroundTrans , Lap 1:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray1, %PitstopTimingsArray1%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 2:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray2, %PitstopTimingsArray2%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 3:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray3, %PitstopTimingsArray3%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 4:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray4, %PitstopTimingsArray4%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 5:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray5, %PitstopTimingsArray5%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 6:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray6, %PitstopTimingsArray6%
Gui, 4: Add, Text, xp-540 yp+30 w100 h20 +BackgroundTrans , Lap 7:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray7, %PitstopTimingsArray7%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 8:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray8, %PitstopTimingsArray8%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 9:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray9, %PitstopTimingsArray9%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 10:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray10, %PitstopTimingsArray10%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 11:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray11, %PitstopTimingsArray11%
Gui, 4: Add, Text, xp+60 yp+3 w100 h20 +BackgroundTrans , Lap 12:
Gui, 4: Add, Edit, +ReadOnly xp+40 yp-3 w50 vNewPitstopTimingsArray12, %PitstopTimingsArray12%
Gui, 4: Add, Button, +hidden xp-540 yp+30 w590 h25 vNewPitstopTimingsButton gSaveNewTimings, Save pit stop timings
Gui, 4: Font, S8 CDefault Bold, Verdana
Gui, 4: Add, Text, x370 y10 w120 h20 +BackgroundTrans , Select Race pace:
Gui, 4: Font, ,
Gui, 4: Add, DropDownList, xp+125 yp-3 w125 vRacePaceChoice gRacePaceChoice, Select to change||Safe (slower)|Risky (faster)
Gui, 4: Add, Button, +hidden x230 yp+10 w120 h25 vLoadDevTimings gLoadDevTimings, Load last dev timings
;- GUI 5 (NOTIFICATIONS/API) ------------------------------------------------------------------------------------
;Gui, 5: Add, Picture, x0 y0 w650 h400 , Assets\tokyo_gui.png
Gui, 5: Add, Text, x10 y14 w205 h20 +BackgroundTrans , Telegram Bot Token:
Gui, 5: Add, Edit, x116 y11 w400 vTelegramBotToken Password, %TelegramBotToken%
Gui, 5: Add, Text, x10 y44 w205 h20 +BackgroundTrans , Telegram Chat ID:
Gui, 5: Add, Edit, x116 y41 w400 vTelegramChatID Password, %TelegramChatID%
Gui, 5: Add, Button, x530 y11 w100 h51 +BackgroundTrans gSaveToIni, Save
Return
DynTurnDelay:
return
SaveResetClip:
return
MachineSettingsWindow:
if (GetKeyState("LShift", "P") AND GetKeyState("LAlt", "P")){
goto, MouseColor
}
else{
Gui, 2: Show, x6 y757 w639 h150, Settings: Machine/Setup
}
return
IngameSettingsWindow:
Gui, 3: Show, x6 y757 w639 h35, Settings: Ingame
return
RaceSettingsWindow:
Gui, 4: Show, x6 y757 w639 h140, Settings: Race
return
NotificationsWindow:
Gui, 5: Show, x6 y757 w639 h70, Settings: Notifications/API
return
SliderMove:
Gui, Submit, nohide
GuiControl,, txthairpindelay, %sliderhairpindelay%
Return
SaveToIni:
Gui, Submit, Hide
IniWrite, %txthairpindelay%, config.ini,Vars, hairpin_delay
IniWrite, %TelegramBotToken%, config.ini,API, TelegramBotToken
IniWrite, %TelegramChatID%, config.ini,API, TelegramChatID
GuiControlGet, DynTurnDelay,,DynTurnDelay
IniWrite, %DynTurnDelay%, config.ini,VARS, DynTurnDelay
GuiControlGet, SaveResetClip,,SaveResetClip
IniWrite, %SaveResetClip%, config.ini,VARS, SaveResetClip
return
SaveNewTimings:
MsgBox, 4,, Do you really wanna save new pitstop timings?
IfMsgBox Yes
{
Gui, Submit, NoHide
NewPitStopTimings = %NewPitstopTimingsArray1%`,%NewPitstopTimingsArray2%`,%NewPitstopTimingsArray3%`,%NewPitstopTimingsArray4%`,%NewPitstopTimingsArray5%`,%NewPitstopTimingsArray6%`,%NewPitstopTimingsArray7%`,%NewPitstopTimingsArray8%`,%NewPitstopTimingsArray9%`,%NewPitstopTimingsArray10%`,%NewPitstopTimingsArray11%`,%NewPitstopTimingsArray12%
IniWrite, %NewPitStopTimings%, config.ini,VARS, PitStopTimings0
IniWrite, %NewPitStopTimings%, config.ini,VARS, PitStopTimings99
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings0, 0
StringSplit, PitstopTimingsArray, PitstopTimings, `,
}
return
RacePaceChoice:
Gui, Submit, NoHide
If (RacePaceChoice = "Safe (slower)")
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings1, 0
IniWrite, %PitstopTimings%, config.ini,VARS, PitStopTimings0
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings0, 0
StringSplit, PitstopTimingsArray, PitstopTimings, `,
guicontrol,, NewPitstopTimingsArray1, %PitstopTimingsArray1%
guicontrol,, NewPitstopTimingsArray2, %PitstopTimingsArray2%
guicontrol,, NewPitstopTimingsArray3, %PitstopTimingsArray3%
guicontrol,, NewPitstopTimingsArray4, %PitstopTimingsArray4%
guicontrol,, NewPitstopTimingsArray5, %PitstopTimingsArray5%
guicontrol,, NewPitstopTimingsArray6, %PitstopTimingsArray6%
guicontrol,, NewPitstopTimingsArray7, %PitstopTimingsArray7%
guicontrol,, NewPitstopTimingsArray8, %PitstopTimingsArray8%
guicontrol,, NewPitstopTimingsArray9, %PitstopTimingsArray9%
guicontrol,, NewPitstopTimingsArray10, %PitstopTimingsArray10%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
If (RacePaceChoice = "Risky (faster)")
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings2, 0
IniWrite, %PitstopTimings%, config.ini,VARS, PitStopTimings0
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings0, 0
StringSplit, PitstopTimingsArray, PitstopTimings, `,
guicontrol,, NewPitstopTimingsArray1, %PitstopTimingsArray1%
guicontrol,, NewPitstopTimingsArray2, %PitstopTimingsArray2%
guicontrol,, NewPitstopTimingsArray3, %PitstopTimingsArray3%
guicontrol,, NewPitstopTimingsArray4, %PitstopTimingsArray4%
guicontrol,, NewPitstopTimingsArray5, %PitstopTimingsArray5%
guicontrol,, NewPitstopTimingsArray6, %PitstopTimingsArray6%
guicontrol,, NewPitstopTimingsArray7, %PitstopTimingsArray7%
guicontrol,, NewPitstopTimingsArray8, %PitstopTimingsArray8%
guicontrol,, NewPitstopTimingsArray9, %PitstopTimingsArray9%
guicontrol,, NewPitstopTimingsArray10, %PitstopTimingsArray10%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
return
TextChanged:
guiControlGet, txtvar,, txthairpindelay
if (txtvar > 800)
{
GuiControl,, txthairpindelay, 800
}
GuiControl,, sliderhairpindelay, %txtvar%
return
Pit1Color:
MsgBox, 4,, Do you really wanna set a new Pitstop color?
IfMsgBox Yes
{
gosub, GrabRemotePlay
color_pitstop1 := PixelColorSimple(199, 315+remote_play_offsetY)
IniWrite, %color_pitstop1%, config.ini,Vars, color_pitstop1
}
return
ButtonStart:
SetTimer, UpdateTimer, 1000
Gui, Submit, NoHide
id := ""
SetKeyDelay, 10
Process, priority, , High
gosub, GrabRemotePlay
if (id = "")
return
gosub, PauseLoop
CoordMode, Pixel, Screen
CoordMode, ToolTip, Screen
loop {
Press_X()
Race_Tokyo()
}
PixelTuning:
x_ratio := ps_win_width/640
y_ratio := ps_win_height/360
return
GrabRemotePlay:
WinGet, remotePlay_id, List, ahk_exe RemotePlay.exe
if (remotePlay_id = 0)
{
MsgBox, PS4 Remote Play not found
return
}
Loop, %remotePlay_id%
{
id := remotePlay_id%A_Index%
WinGetTitle, title, % "ahk_id " id
If InStr(title, "PS Remote Play")
break
}
WinMove, ahk_id %id%,, 0, 0, 640, 540
ControlFocus,, ahk_class %remotePlay_class%
WinActivate, ahk_id %id%
GetClientSize(remotePlay_id5, ps_win_width, ps_win_height)
gosub, PixelTuning
return
FightMe:
if (A_GuiEvent = "DoubleClick")
{
guicontrol, -readonly, NewPitstopTimingsArray1
guicontrol, -readonly, NewPitstopTimingsArray2
guicontrol, -readonly, NewPitstopTimingsArray3
guicontrol, -readonly, NewPitstopTimingsArray4
guicontrol, -readonly, NewPitstopTimingsArray5
guicontrol, -readonly, NewPitstopTimingsArray6
guicontrol, -readonly, NewPitstopTimingsArray7
guicontrol, -readonly, NewPitstopTimingsArray8
guicontrol, -readonly, NewPitstopTimingsArray9
guicontrol, -readonly, NewPitstopTimingsArray10
guicontrol, -readonly, NewPitstopTimingsArray11
guicontrol, -readonly, NewPitstopTimingsArray12
guicontrol, -hidden, NewPitstopTimingsButton
guicontrol, -hidden, LoadDevTimings
guicontrol,, PitstopText, Pit stop wait timers in ms`ndevmode unlocked (´):
guicontrol, +hidden, FightMe
}
return
LoadDevTimings:
IniRead, PitstopTimings, config.ini, Vars, PitStopTimings99, 0
StringSplit, PitstopTimingsArray, PitstopTimings, `,
guicontrol,, NewPitstopTimingsArray1, %PitstopTimingsArray1%
guicontrol,, NewPitstopTimingsArray2, %PitstopTimingsArray2%
guicontrol,, NewPitstopTimingsArray3, %PitstopTimingsArray3%
guicontrol,, NewPitstopTimingsArray4, %PitstopTimingsArray4%
guicontrol,, NewPitstopTimingsArray5, %PitstopTimingsArray5%
guicontrol,, NewPitstopTimingsArray6, %PitstopTimingsArray6%
guicontrol,, NewPitstopTimingsArray7, %PitstopTimingsArray7%
guicontrol,, NewPitstopTimingsArray8, %PitstopTimingsArray8%
guicontrol,, NewPitstopTimingsArray9, %PitstopTimingsArray9%
guicontrol,, NewPitstopTimingsArray10, %PitstopTimingsArray10%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
guicontrol,, NewPitstopTimingsArray11, %PitstopTimingsArray11%
return
PauseLoop:
controller.Buttons.Cross.SetState(false)
controller.Buttons.Square.SetState(false)
controller.Buttons.Triangle.SetState(false)
controller.Buttons.Circle.SetState(false)
controller.Buttons.L1.SetState(false)
controller.Buttons.L2.SetState(false)
controller.Axes.L2.SetState(0)
controller.Buttons.R1.SetState(false)
controller.Buttons.R2.SetState(false)
controller.Axes.R2.SetState(0)
controller.Buttons.RS.SetState(false)
controller.Axes.RX.SetState(50)
controller.Axes.RY.SetState(50)
controller.Buttons.LS.SetState(false)
controller.Axes.LX.SetState(50)
controller.Axes.LY.SetState(50)
controller.Dpad.SetState("None")
return
ResetRace:
SB_SetText(" - RESET INITIATED -",2)
guicontrol,, CurrentLoop, Something went wrong, reseting.
controller.Axes.LX.SetState(50)
if(SaveResetClip)
{
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime%: Race failed - Lap %TokyoLapCount% - %location% - Clip saved.`n, log.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race failed - Lap " TokyoLapCount " - " location ". Clip saved.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
SB_SetText(" Saving clip (past 3 minutes)...",2)
Sleep(500)
PressShare()
Sleep(1000)
Press_Left()
Sleep(200)
Press_X()
Sleep(200)
Press_X()
Sleep(200)
Press_Down()
Sleep(200)
Press_Down()
Sleep(200)
Press_Down()
Sleep(200)
Press_X()
Sleep(1000)
PressShare()
Sleep(1000)
Press_O()
Sleep(200)
Press_Right()
Sleep(200)
Press_X()
}
else {
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime%: Race failed - Lap %TokyoLapCount% - %location%.`n, log.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race failed - Lap " TokyoLapCount " - " location ". Clip saved.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
SB_SetText(" Saving clip (past 3 minutes)...",2)
Sleep(500)
Press_Options()
Sleep(1000)
Press_Right()
Sleep(500)
Press_X()
}
controller.Axes.LX.SetState(65)
IniRead, ResetCounterTotal, config.ini, Stats, resetcountertotal, 0
SetFormat, integerfast, d
resetcounter++
resetcountertotal++
IniWrite, %resetcountertotal%, config.ini,Stats, ResetCounterTotal
guicontrol,, ResetCounterTotal, Races failed: %resetcountertotal%
guicontrol,, ResetCounterSession, Races failed: %resetcounter%
guicontrol,, RaceProgress, 0
Race_Tokyo()
return
MouseHelp:
coord=relative
sleep, 1000
CoordMode, ToolTip, %coord%
CoordMode, Pixel, %coord%
CoordMode, Mouse, %coord%
CoordMode, Caret, %coord%
CoordMode, Menu, %coord%
return
Refresh:
MouseGetPos, x, y
PixelGetColor, cBGR, %x%, %y%,, Alt RGB
WinGetPos,,, w, h, A
ToolTip,Location: %x% x %y%`nRGB: %cBGR%`nWindow Size: %w% x %h%
return
MouseColor:
gosub, MouseHelp
SetTimer, Refresh, 75
return
GuiClose:
gosub, PauseLoop
ExitApp
^Esc::ExitApp
GUIReset:
if (GetKeyState("LShift", "P") AND GetKeyState("LAlt", "P")){
MsgBox, 4,, Reset all data?
IfMsgBox Yes
{
IniWrite, 0, config.ini,Stats, RaceCounterTotal
IniWrite, 0, config.ini,Stats, ResetCounterTotal
}
}
Sleep(500)
gosub, PauseLoop
Reload
@@ -0,0 +1,211 @@
#include %A_LineFile%\..\CLR.ahk
; Static class, holds ViGEm Client instance
class ViGEmWrapper {
static asm := 0
static client := 0
Init(){
if (this.client == 0){
this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
}
}
CreateInstance(cls){
return this.asm.CreateInstance(cls)
}
}
; Base class for ViGEm "Targets" (Controller types - eg xb360 / ds4) to inherit from
class ViGEmTarget {
target := 0
helperClass := ""
controllerClass := ""
__New(){
;~ this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
ViGEmWrapper.Init()
this.Instance := ViGEmWrapper.CreateInstance(this.helperClass)
if (this.Instance.OkCheck() != "OK"){
msgbox ViGEmWrapper.dll failed to load!
ExitApp
}
}
SendReport(){
this.Instance.SendReport()
}
SubscribeFeedback(callback){
this.Instance.SubscribeFeedback(callback)
}
}
; DS4 (DualShock 4 for Playstation 4)
class ViGEmDS4 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Ds4"
__New(){
static buttons := {Square: 16, Cross: 32, Circle: 64, Triangle: 128, L1: 256, R1: 512, L2: 1024, R2: 2048
, Share: 4096, Options: 8192, LS: 16384, RS: 32768 }
static specialButtons := {Ps: 1, TouchPad: 2}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
for name, id in specialButtons {
this.Buttons[name] := new this._SpecialButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _SpecialButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetSpecialButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
return this._Parent
}
ConvertAxis(state){
return round(state * 2.55)
}
}
class _DpadHelper {
__New(parent){
this._Parent := parent
this._Id := id
}
SetState(state){
static dPadDirections := {Up: 0, UpRight: 1, Right: 2, DownRight: 3, Down: 4, DownLeft: 5, Left: 6, UpLeft: 7, None: 8}
this._Parent.Instance.SetDpadState(dPadDirections[state])
this._Parent.Instance.SendReport()
return this._Parent
}
}
}
; Xb360
class ViGEmXb360 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Xb360"
__New(){
static buttons := {A: 4096, B: 8192, X: 16384, Y: 32768, LB: 256, RB: 512, LS: 64, RS: 128, Back: 32, Start: 16, Xbox: 1024}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
}
ConvertAxis(state){
value := round((state * 655.36) - 32768)
if (value == 32768)
return 32767
return value
}
}
class _DpadHelper {
_DpadStates := {1:0, 8:0, 2:0, 4:0} ; Up, Right, Down, Left
__New(parent){
this._Parent := parent
}
SetState(state){
static dpadDirections := { None: {1:0, 8:0, 2:0, 4:0}
, Up: {1:1, 8:0, 2:0, 4:0}
, UpRight: {1:1, 8:1, 2:0, 4:0}
, Right: {1:0, 8:1, 2:0, 4:0}
, DownRight: {1:0, 8:1, 2:1, 4:0}
, Down: {1:0, 8:0, 2:1, 4:0}
, DownLeft: {1:0, 8:0, 2:1, 4:1}
, Left: {1:0, 8:0, 2:0, 4:1}
, UpLeft: {1:1, 8:0, 2:0, 4:1}}
newStates := dpadDirections[state]
for id, newState in newStates {
oldState := this._DpadStates[id]
if (oldState != newState){
this._DpadStates[id] := newState
this._Parent.Instance.SetButtonState(id, newState)
}
this._Parent.SendReport()
}
}
}
}
@@ -0,0 +1,151 @@
; ==========================================================
; .NET Framework Interop
; https://autohotkey.com/boards/viewtopic.php?t=4633
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if assembly := AppDomain.Load_2(AssemblyName)
break
static null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, null, null, args)
break
if assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, null, null, args)
break
}
ComObjError(e)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, null, vargs, null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, null, null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
/**********************************************
* Controller methods for simplicity *
***********************************************/
*/
GoTo EndControllerFunctionsDef
;;;;;;;;;;;; Turning functions
;;;;;;;;;;;; For holding the stick in a specific position for a period of time
;;;;;;;;;;;; Note no other button may be pressed or released when these functions are ran
; Set the time you want to turn for in miliseconds and how hard (50, 100), 100 being the most, 50 being neutral
Turn_Right(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
; Set the time you want to turn for in miliseconds and how hard (0, 50), 0 being the most
Turn_Left(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
;;;;;;;;;;;; Simple button press functions
;;;;;;;;;;;; You can pass a delay amount or leave it blank
;;;;;;;;;;;; Longer delays hold the button longer
; Press X button
Press_X(delay:=200){
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Cross.SetState(false)
return
}
; Press O button
Press_O(delay:=200){
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Circle.SetState(false)
return
}
; Press Triangle button
Press_Triangle(delay:=200){
controller.Buttons.Triangle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Triangle.SetState(false)
return
}
; Press Square button
Press_Square(delay:=200){
controller.Buttons.Square.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Square.SetState(false)
return
}
; Press R1 button
Press_L1(delay:=200){
controller.Buttons.L1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.L1.SetState(false)
return
}
; Press R1 button
Press_R1(delay:=200){
controller.Buttons.R1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.R1.SetState(false)
return
}
; Press Right on D-pad
Press_Right(delay:=200){
controller.Dpad.SetState("Right")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Left on D-pad
Press_Left(delay:=200){
controller.Dpad.SetState("Left")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Up on D-pad
Press_Up(delay:=200){
controller.Dpad.SetState("Up")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Down on D-pad
Press_Down(delay:=200){
controller.Dpad.SetState("Down")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
;;;;;;;;;;; Other functions specific to GT7
; Turn on nitrous
Nitrous_On(){
controller.Buttons.RS.SetState(true)
}
; Turn off nitrous
Nitrous_Off(){
controller.Buttons.RS.SetState(false)
}
Accel_On(control:=100){
controller.Buttons.R2.SetState(true)
controller.Axes.RT.SetState(control)
}
Accel_Off(){
controller.Buttons.R2.SetState(false)
controller.Axes.RT.SetState(0)
}
Brake_On(control:=100){
controller.Buttons.L2.SetState(true)
controller.Axes.LT.SetState(control)
}
Brake_Off(){
controller.Buttons.L2.SetState(false)
controller.Axes.LT.SetState(0)
}
; given time t in miliseconds, turn right for that long, with intensity being how much the turn button is held for
Turn:
t0 := A_TickCount
tf := t0+t
loop {
Sleep(100)
} until A_TickCount > tf
return
Press_Options(){
controller.Buttons.Options.SetState(true)
Sleep, 50
controller.Buttons.Options.SetState(false)
}
PressShare(){
controller.Buttons.Share.SetState(true)
Sleep, 50
controller.Buttons.Share.SetState(false)
}
PressX:
; Just for menuing, does not hold X down
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Cross.SetState(false)
return
PressO:
; Just for menuing, does not hold O down
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Circle.SetState(false)
return
PressRight:
; For turning
controller.Dpad.SetState("Right")
Sleep, 50
controller.Dpad.SetState("None")
return
EndControllerFunctionsDef:
@@ -0,0 +1,136 @@
/**********************************************
* Only place functions here, no sub routines *
***********************************************/
; Grabs the colors of the pixels (x-b, y-b) to (x+b, y+b)
; returns the array of colors
*/
BitGrab(x, y, b)
{
HWND := WinExist("PS Remote Play")
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromHWND2(hwnd)
pixs := []
for i in range(-1*b, b+1){
for j in range(-1*b, b+1){
pixel := Gdip_GetPixel(pBitmap,x+i,y+j)
rgb := ConvertARGB( pixel )
pixs.Push(rgb)
}
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
Gdip_BitmapFromHWND2(hwnd)
{
WinGetPos,,, Width, Height, ahk_id %hwnd%
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
RegExMatch(A_OsVersion, "\d+", Version)
PrintWindow(hwnd, hdc, Version >= 8 ? 2 : 0)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
return pBitmap
}
range(start, stop:="", step:=1) {
static range := { _NewEnum: Func("_RangeNewEnum") }
if !step
throw "range(): Parameter 'step' must not be 0 or blank"
if (stop == "")
stop := start, start := 0
; Formula: r[i] := start + step*i ; r = range object, i = 0-based index
; For a postive 'step', the constraints are i >= 0 and r[i] < stop
; For a negative 'step', the constraints are i >= 0 and r[i] > stop
; No result is returned if r[0] does not meet the value constraint
if (step > 0 ? start < stop : start > stop) ;// start == start + step*0
return { base: range, start: start, stop: stop, step: step }
}
_RangeNewEnum(r) {
static enum := { "Next": Func("_RangeEnumNext") }
return { base: enum, r: r, i: 0 }
}
_RangeEnumNext(enum, ByRef k, ByRef v:="") {
stop := enum.r.stop, step := enum.r.step
, k := enum.r.start + step*enum.i
if (ret := step > 0 ? k < stop : k > stop)
enum.i += 1
return ret
}
Sleep(ms=1)
{
global timeBeginPeriodHasAlreadyBeenCalled
if (timeBeginPeriodHasAlreadyBeenCalled != 1)
{
DllCall("Winmm.dll\timeBeginPeriod", UInt, 1)
timeBeginPeriodHasAlreadyBeenCalled := 1
}
DllCall("Sleep", UInt, ms)
}
PixelColorSimple(pc_x, pc_y)
{
WinGet, remotePlay_id, List, ahk_exe RemotePlay.exe
if (remotePlay_id = 0)
{
MsgBox, PS4 Remote Play not found
return
}
if remotePlay_id
{
pc_wID := remotePlay_id[0]
pc_hDC := DllCall("GetDC", "UInt", pc_wID)
pc_fmtI := A_FormatInteger
SetFormat, IntegerFast, Hex
pc_c := DllCall("GetPixel", "UInt", pc_hDC, "Int", pc_x, "Int", pc_y, "UInt")
pc_c := pc_c >> 16 & 0xff | pc_c & 0xff00 | (pc_c & 0xff) << 16
pc_c .= ""
SetFormat, IntegerFast, %pc_fmtI%
DllCall("ReleaseDC", "UInt", pc_wID, "UInt", pc_hDC)
return pc_c
}
}
GetClientSize(hWnd, ByRef w := "", ByRef h := "")
{
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hWnd, "ptr", &rect)
w := NumGet(rect, 8, "int")
h := NumGet(rect, 12, "int")
}
Distance(c1, c2)
{ ; function by [VxE], return value range = [0, 441.67295593006372]
return Sqrt((((c1>>16)-(c2>>16))**2)+(((c1>>8&255)-(c2>>8&255))**2)+(((c1&255)-(c1&255))**2))
}
ConvertARGB(ARGB, Convert := 0)
{
SetFormat, IntegerFast, Hex
RGB += ARGB
RGB := RGB & 0x00FFFFFF
if (Convert)
RGB := (RGB & 0xFF000000) | ((RGB & 0xFF0000) >> 16) | (RGB & 0x00FF00) | ((RGB & 0x0000FF) << 16)
return RGB
}
ToolTipper(msg, x := 100, y := 100)
{
if (debug_mode = 1)
ToolTip, %msg%, x, y, Screen
return
}
@@ -0,0 +1,376 @@
__enableTokyoDetections_mod__ := 1
IniRead, color_pitstop1, config.ini, Vars, color_pitstop1, 0
IniRead, color_pitstop2, config.ini, Vars, color_pitstop2, 0
class TokyoTurnContainer
{
__New(startX, startY, endX := 0, endY := 0)
{
this.startX := startX
this.startY := startY
this.endX := endX
this.endY := endY
}
}
GoTo EndTokyoDetectionsDef
CheckTokyoMFD(x,y, b_size := 1)
{
color_dot := 0x8D8B8C
TokyoMFD := false
tries := 1000 ; we shouldn't need more than 6 tries, but I have seen it loop passed
loop {
tc := BitGrab(x, y, b_size)
SB_SetText(" Searching... " td " < 120",2)
for i, c in tc
{
td := Distance(c, color_dot)
if (td < 120){
SB_SetText(" Found: " td " < 120",2)
TokyoMFD := true
break
}
else {
; Gonna try to automate the mfd checker, why not right?
if (tries > 0){
SB_SetText(" Searching MFD " td " < 110",2)
Press_Left()
Sleep(100)
tries--
break
}
tries := 1000
TokyoMFD := true
break
}
}
} until TokyoMFD = true
return
}
CheckTokyoTurn(x,y, b_size := 1)
{
turnStart := A_TickCount
color_player := 0xDE6E70
TokyoTurnComplete := false
loop {
SB_SetText(" Searching... " td " < 50",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_player)
if (td < 50 ){
SB_SetText(" Found: " td " < 50",2)
TokyoTurnComplete := true
break
}
}
; add recovery so we don't kill run looking for turn. Gonna start with a high number, can adjust lower later.
; added some press down, x's and waits just in case we are in the pit stop
if (A_TickCount - turnStart > 90000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
break
}
} until TokyoTurnComplete = true
return
}
CheckTokyoPen1(x,y, b_size := 1)
{
pen1Start := A_TickCount
color_pen := 0xFFC10B
TokyoPen1 := false
loop {
SB_SetText(" Searching... " td " < 50",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pen)
if (td < 50 ){
SB_SetText(" Found: " td " < 50",2)
TokyoPen1 := true
break
}
}
; add recovery so we don't kill run looking for Pen1. Gonna start with a high number, can adjust lower later.
; started with 1.5 mins, i had these set to 3:33 on other file and still won.
if (A_TickCount - pen1Start > 90000) {
GoSub, ResetRace
break
}
} until TokyoPen1 = true
return
}
CheckTokyoHairpinTurn(x,y, b_size := 1)
{
hairpinStart := A_TickCount
color_hairpinturn := 0xB3B1B2
TokyoHairpinTurn := false
loop {
SB_SetText(" Searching... " td " < 5",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_hairpinturn)
if (td < 5){
SB_SetText(" Found: " td " < 5",2)
TokyoHairpinTurn := true
break
}
}
; add recovery so we don't kill run sitting in hairpin
; set to 1 minute to start, I had this at 3:33 (200000) on my other file and still won.
if (A_TickCount - hairpinStart > 90000) {
GoSub, ResetRace
break
}
} until TokyoHairpinTurn = true
return
}
CheckTokyoPen2(x,y, b_size := 1)
{
start := A_TickCount
color_pen := 0xFFC10B
RecoveryTried := false
TokyoPen2 := false
loop {
SB_SetText(" Searching... " td " > 60",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pen)
if (td > 60 ){
SB_SetText(" Found: " td " > 60",2)
TokyoPen2 := true
break
}
}
if (A_TickCount - start > 35000 AND RecoveryTried = false) {
SB_SetText(" We stuck? Starting recovery try.",2)
Accel_off()
controller.Axes.LX.SetState(50)
loop 7 {
Press_Square(delay:=50)
Sleep(100)
}
Accel_on(80)
Sleep(500)
loop 9 {
Press_Triangle(delay:=50)
Sleep(100)
}
controller.Axes.LX.SetState(30)
RecoveryTried := true
}
if (A_TickCount - start > 60000) {
gosub, ResetRace
break
}
} until TokyoPen2 = true
return
}
CheckTokyoPenServed(x,y, b_size := 1)
{
color_penserved := 0xAE1B1E
TokyoPenServed := false
loop {
SB_SetText(" Searching... " td " > 60",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_penserved)
if (td > 60 ){
SB_SetText(" Found: " td " > 60",2)
TokyoPenServed := true
break
}
}
} until TokyoPenServed = true
return
}
CheckTokyoPenReceived(x,y, b_size := 1)
{
start := A_TickCount
color_penreceived := 0xAE1B1E
TokyoPenReceived := false
loop {
SB_SetText(" Searching... " td " < 40",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_penreceived)
if (td < 40 ){
SB_SetText(" Found: " td " < 40",2)
guicontrol,, CurrentLoop, Pen received
TokyoPenReceived := true
break
}
if (TokyoLapCount != 6 AND A_TickCount - start > 36000)
{
SB_SetText(" Not found in time. Shifting up.",2)
loop 6 {
Press_Triangle(delay:=50)
Sleep(200)
TokyoPenReceived := true
break
}
break
}
if (TokyoLapCount = 6 AND A_TickCount - start > 46000)
{
SB_SetText(" Not found in time. Shifting up.",2)
loop 20 {
Press_Triangle(delay:=50)
Sleep(200)
TokyoPenReceived := true
break
}
break
}
}
} until TokyoPenReceived = true
return
}
CheckTokyoPitstopDone(x,y, b_size := 1)
{
pitstopDoneStart := A_TickCount
color_pitstopdone := 0xFFFFFF
TokyoPitstopDone := false
loop {
SB_SetText(" Searching... " td " > 10",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pitstopdone)
if (td > 10 ){
SB_SetText(" Found: " td " > 10",2)
TokyoPitstopDone := true
break
}
}
; add recovery so we don't kill run sitting in pit, havent tested if press down works to get us out
if (A_TickCount - pitstopDoneStart > 60000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
}
} until TokyoPitstopDone = true
return
}
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
{
if ( A_TickCount - loopStartTime > maxTime AND TokyoLapCount <= 10) {
gosub, ResetRace
}
else if (A_TickCount - loopStartTime > maxTime+90000 AND TokyoLapCount > 10)
{
gosub, ResetRace
}
}
CheckTokyoPitstop1(x,y, b_size := 1)
{
pitstop1Start := A_TickCount
;color_pitstop1 := 0xFFFFFF
;color_pitstop1 := 0x818002
;color_pitstop1 := 0xFBFB00 ; old color
TokyoPitstop := false
loop {
SB_SetText(" Searching... " td " < 10",2)
tc := BitGrab(x, y, b_size)
for i, c in tc
{
td := Distance(c, color_pitstop1)
if (td < 10 ){
SB_SetText(" Found: " td " < 10",2)
TokyoPitstop := true
break
}
}
; add recovery so we don't kill run sitting in pit, havent tested if press down works to get us out
if (A_TickCount - pitstop1Start > 60000) {
Press_Down()
Sleep(300)
Press_X()
Sleep(500)
Press_X()
Sleep(7000)
GoSub, ResetRace
}
guicontrol,, CurrentLoop, Stuck in pit? Press GUI Button.
} until TokyoPitstop = true
return
}
UpdateAVG(racecounter, script_start)
{
SetFormat, integerfast, d
creditcountersession := (835000*racecounter)/1000000
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditavg := creditcountersession/(A_TickCount-script_start)*3600000
guicontrol,, CreditAVG, Avg./h: ~%creditavg% M
return
}
UpdateTimer()
{
ElapsedTime := A_TickCount - script_start
VarSetCapacity(t,256),DllCall("GetDurationFormat","uint",2048,"uint",0,"ptr",0,"int64",ElapsedTime*10000,"wstr","d' day(s) 'h':'mm':'ss","wstr",t,"int",256)
SB_SetText("Runtime: " t,3)
return
}
HexToDec(hex)
{
VarSetCapacity(dec, 66, 0)
, val := DllCall("msvcrt.dll\_wcstoui64", "Str", hex, "UInt", 0, "UInt", 16, "CDECL Int64")
, DllCall("msvcrt.dll\_i64tow", "Int64", val, "Str", dec, "UInt", 10, "CDECL")
return dec
}
EndTokyoDetectionsDef:
@@ -0,0 +1,86 @@
#Include Races\PanAm.ahk
#Include Races\Tokyo.ahk
GoTo EndRaceDef
Race:
Switch RaceChoice
{
case "PanAm":
Race_PANAM()
return
case "Tokyo":
Race_Tokyo()
return
}
return
SettingsSheet:
Gui, 4: Show, AutoSize, Settings Sheet
;/////////////////////////////////////////////////////////
; Add images to your setup here and in the Src folder
;
;/////////////////////////////////////////////////////////
Switch RaceChoice
{
case "PanAm":
assist_1 = %A_ScriptDir%\Src\PanAm\Assist1.jpg
assist_2 = %A_ScriptDir%\Src\PanAm\Assist2.jpg
tune_1 = %A_ScriptDir%\Src\PanAm\CarSetup.jpg
tune_2 = %A_ScriptDir%\Src\PanAm\CarGearRatio.jpg
controls = %A_ScriptDir%\Src\PanAm\Controller.jpg
return
case "Tokyo":
assist_1 = %A_ScriptDir%\Src\Tokyo\Assist_Settings.png
assist_2 = %A_ScriptDir%\Src\Tokyo\Misc_Settings.png
controls = %A_ScriptDir%\Src\Tokyo\Controller_Settings.png
tune_1 = %A_ScriptDir%\Src\Tokyo\Settings_Car1.png
tune_2 = %A_ScriptDir%\Src\Tokyo\Settings_Car2.png
tune_3 = %A_ScriptDir%\Src\Tokyo\Settings_Car3.png
return
}
return
Assists1:
GuiControl, 4:, CurrentPic, %assist_1%
gosub, Guisizer
return
Assists2:
GuiControl, 4:, CurrentPic, %assist_2%
gosub, Guisizer
return
Tune1:
GuiControl, 4:, CurrentPic, %tune_1%
gosub, Guisizer
return
Tune2:
GuiControl, 4:, CurrentPic, %tune_2%
gosub, Guisizer
return
Tune3:
GuiControl, 4:, CurrentPic, %tune_2%
gosub, Guisizer
return
ControllerSetting:
GuiControl, 4:, CurrentPic, %controls%
gosub, Guisizer
return
Guisizer:
GuiControl, 4: Move, CurrentPic, % "x" 10 "y" 40 "w" 1200 . " h" . 800
Gui, 4: Show, AutoSize, Settings Sheet
return
EndRaceDef:
@@ -0,0 +1,509 @@
GoTo EndRace_Tokyo_Def
Race_Tokyo()
{
IniRead, hairpin_delay, config.ini, Vars, hairpin_delay, 0
IniRead, RaceCounterTotal, config.ini, Stats, racecountertotal, 0
IniRead, ResetCounterTotal, config.ini, Stats, resetcountertotal, 0
SetFormat, integerfast, d
TokyoStart:
;- VARIABLES -----------------------------------------------------------------------------
SetFormat, integerfast, d
TokyoLapCount := 1
maxTime := 200000
StringSplit, PitstopTimingsArray, PitstopTimings, `,
;- COORDINATES: TURNS --------------------------------------------------------------------
TokyoTurn1 := new TokyoTurnContainer(611, 59+remote_play_offsetY, 622, 69+remote_play_offsetY)
TokyoTurn2 := new TokyoTurnContainer(618, 70+remote_play_offsetY, 601, 76+remote_play_offsetY)
TokyoTurn3 := new TokyoTurnContainer(599, 79+remote_play_offsetY, 591, 87+remote_play_offsetY)
TokyoTurn4 := new TokyoTurnContainer(589, 88+remote_play_offsetY, 571, 96+remote_play_offsetY)
TokyoTurn5 := new TokyoTurnContainer(567, 96+remote_play_offsetY, 556, 90+remote_play_offsetY)
TokyoTurn6 := new TokyoTurnContainer(554, 86+remote_play_offsetY, 543, 82+remote_play_offsetY)
TokyoTurn7 := new TokyoTurnContainer(538, 81+remote_play_offsetY, 530, 75+remote_play_offsetY)
TokyoTurn8 := new TokyoTurnContainer(530, 75+remote_play_offsetY, 510, 72+remote_play_offsetY)
;- COORDINATES: PENALTY WARNINGS ---------------------------------------------------------
TokyoPenWarning := new TokyoTurnContainer(360, 154+remote_play_offsetY, 408, 154+remote_play_offsetY)
TokyoPenIndicator := new TokyoTurnContainer(366, 132+remote_play_offsetY)
;- COORDINATES: HAIRPIN TURN -------------------------------------------------------------
TokyoHairpinTurn := new TokyoTurnContainer(606, 334+remote_play_offsetY)
;- COORDINATES: PENALTY WARNINGS ---------------------------------------------------------
TokyoPen := new TokyoTurnContainer(360, 154+remote_play_offsetY, 408, 154+remote_play_offsetY)
TokyoPenServed := new TokyoTurnContainer(366, 132+remote_play_offsetY)
;- COORDINATES: HAIRPIN TURN--------------------------------------------------------------
TokyoHairpinTurn := new TokyoTurnContainer(606, 334+remote_play_offsetY)
;- MISC ----------------------------------------------------------------------------------
TokyoPitstop := new TokyoTurnContainer(191, 316+remote_play_offsetY, 580, 383+remote_play_offsetY)
TokyoPitstopEnter := new TokyoTurnContainer(530, 70+remote_play_offsetY)
TokyoPitstopDone := new TokyoTurnContainer(57, 329+remote_play_offsetY)
TokyoRestartRace := new TokyoTurnContainer(405,465+remote_play_offsetY)
TokyoMFD := new TokyoTurnContainer(557, 382+remote_play_offsetY)
;- RACE START ----------------------------------------------------------------------------
controller.Axes.LX.SetState(65)
Sleep(7400)
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime%: Race started.`n, log.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race started.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
guicontrol,, CurrentLoop, Race started. Good luck!
guicontrol,, CurrentLap, Current Lap: %TokyoLapCount% /12
Accel_On(100)
loop 3 {
Press_Triangle(delay:=50)
Sleep(200)
}
Sleep(800)
controller.Axes.LX.SetState(65)
CheckTokyoMFD(TokyoMFD.startX, TokyoMFD.startY)
;- 12 LAP LOOP ---------------------------------------------------------------------------
loop 12
{
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
loopStartTime := A_TickCount
; Turn 1
location := "T1 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn1.startX, TokyoTurn1.startY)
loop 3 {
Press_Triangle(delay:=50)
Sleep(200)
}
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(36)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
Sleep(1000)
location := "T1 End"
CheckTokyoTurn(TokyoTurn1.endX, TokyoTurn1.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(35)
Sleep(1000)
; Turn 2
location := "T2 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn2.startX, TokyoTurn2.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(52)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
Sleep(1000)
location := "T2 End"
CheckTokyoTurn(TokyoTurn2.endX, TokyoTurn2.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
; Turn 3
location := "T3 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn3.startX, TokyoTurn3.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
controller.Axes.LX.SetState(40)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn3.endX, TokyoTurn3.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
; Turn 4
location := "T4 Start"
Accel_On(85)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn4.startX, TokyoTurn4.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
controller.Axes.LX.SetState(68)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn4.endX, TokyoTurn4.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(60)
Accel_On(70)
Sleep(1000)
; Turn 5
location := "T5 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn5.startX, TokyoTurn5.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(42)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn5.endX, TokyoTurn5.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(63)
Sleep(1000)
; Turn 6
location := "T6 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn6.startX, TokyoTurn6.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
Accel_on(75)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn6.endX, TokyoTurn6.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
; Turn 7
location := "T7 Start"
Accel_On(100)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn7.startX, TokyoTurn7.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(40)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn7.endX, TokyoTurn7.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(70)
Sleep(1000)
; Turn 8
location := "T8 Start"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn8.startX, TokyoTurn8.startY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(65)
Sleep(1000)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoTurn8.endX, TokyoTurn8.endY)
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(30)
Sleep(2000)
Brake_on(100)
Sleep(2200)
Brake_off()
Accel_On(35)
; Penalty Warning 1
location := "Hairpin Entrance"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPen1(TokyoPenWarning.startX, TokyoPenWarning.startY)
guicontrol,, CurrentLoop, Current Location: %location%
Accel_On(32)
if (TokyoLapCount=12) {
Accel_On(34)
}
controller.Axes.LX.SetState(40)
Sleep(1000)
; Hairpin Turn
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
location := "Hairpin Turn"
CheckTokyoHairpinTurn(TokyoHairpinTurn.startX, TokyoHairpinTurn.startY)
guicontrol,, CurrentLoop, Current Location: %location%
if (DynTurnDelay)
{
if ((ThairpinS - 6000) > 0) {
hairpin_delayn := HexToDec(hairpin_delay - 20 - ( 50 * Floor((ThairpinS - 6000)/1000)))
If ( hairpin_delayn <0 ){
hairpin_delayn := 0
}
guicontrol,, CurrentLoop, Turn delay: %hairpin_delayn% (Dynamic)
}
if ((ThairpinS - 5000) < 0) {
hairpin_delayn := HexToDec(hairpin_delay + 50 + ( 20 * Floor((5000 - ThairpinS)/1000) ))
guicontrol,, CurrentLoop, Turn delay: %hairpin_delayn% (Dynamic)
}
if (6000<=ThairpinS>=5000) {
hairpin_delayn := HexToDec(hairpin_delay)
guicontrol,, CurrentLoop, Turn delay: %hairpin_delayn% (Default)
}
Sleep(hairpin_delayn)
}
else
{
Sleep(hairpin_delay)
}
controller.Axes.LX.SetState(100)
Sleep(200)
Accel_Off()
Sleep(4200)
Accel_On(45) ;was 40
controller.Axes.LX.SetState(60)
Accel_Off()
Sleep(800)
controller.Axes.LX.SetState(40)
Accel_On(50)
Sleep(5000)
controller.Axes.LX.SetState(30)
Sleep(5500)
Accel_On(80)
loop 30 { ; failsafe, if we ever get a reset caused by a cone under the car
Press_Triangle(delay:=100)
Sleep(200)
}
; Penalty Warning 2
location := "Hairpin exit"
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPen2(TokyoPen.endX, TokyoPen.endY)
guicontrol,, CurrentLoop, Current Location: %location%
Sleep(1000)
if (TokyoLapCount <= 11)
{
location := "Pit entrance"
Accel_On(53)
controller.Axes.LX.SetState(30)
guicontrol,, CurrentLoop, Current Location: %location%
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoTurn(TokyoPitstopEnter.startX, TokyoPitstopEnter.startY)
controller.Axes.LX.SetState(0)
Accel_On(55)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPitstop1(TokyoPitstop.startX, TokyoPitstop.startY)
location := "In pit"
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(50)
if (TokyoLapCount = 1)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray1/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray1)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 2)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray2/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray2)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 3)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray3/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray3)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 4)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray4/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray4)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 5)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray5/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray5)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 6)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray6/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray6)
Press_Up()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 7)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray7/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray7)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 8)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray8/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray8)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 9)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray9/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray9)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 10)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray10/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray10)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 11)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray11/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray11)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
if (TokyoLapCount = 12)
{
SetFormat, integerfast, d
location := "In pit: Waiting " Round(PitstopTimingsArray12/1000) " seconds."
guicontrol,, CurrentLoop, %location%
Sleep (PitstopTimingsArray12)
Press_Up()
Sleep (100)
Press_X()
Sleep (100)
Press_X()
}
controller.Axes.LX.SetState(20)
Accel_On(100)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPenReceived(TokyoPenServed.startX, TokyoPenServed.startY)
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
controller.Axes.LX.SetState(38)
Sleep (500)
loop 10 {
Press_Triangle(delay:=200)
sleep, 200
}
}
else {
location := "Start/Finish"
guicontrol,, CurrentLoop, Current Location: %location%
Accel_On(100)
controller.Axes.LX.SetState(60)
CheckMaxTime(maxTime, loopStartTime, TokyoLapCount)
CheckTokyoPenServed(TokyoPenServed.startX, TokyoPenServed.startY)
}
SetFormat, integerfast, d
TokyoLapCount++
guicontrol,, CurrentLap, Current Lap: %TokyoLapCount% /12
ProgressRace := (100/13)*TokyoLapCount
guicontrol,, RaceProgress, %ProgressRace%
if(TokyoLapCount = "13")
{
location := "Finish line"
FormatTime, TGTime,, MM/dd hh:mm:ss
FileAppend, %TGTime% Race finished.`n, log.txt
url := "https://api.telegram.org/bot" TelegramBotToken "/sendMessage?text=" TGTime ": Race finished.&chat_id=" TelegramChatID
hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
hObject.Open("GET",url)
hObject.Send()
guicontrol,, CurrentLoop, Current Location: %location%
guicontrol,, CurrentLap, GG!
controller.Axes.LX.SetState(50)
SetFormat, integerfast, d
racecounter++
SetFormat, integerfast, d
racecountertotal++
; // THIS SESSION
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditcountersession := (835000*racecounter)/1000000
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditavg := creditcountersession/(A_TickCount-script_start)*3600000
guicontrol,, RaceCounterSession, Races completed: %racecounter%
guicontrol,, ResetCounterSession, Races failed: %resetcounter%
guicontrol,, CreditCounterSession, Credits: %creditcountersession% M
guicontrol,, CreditAVGSession, Avg./h: %creditavg% M
; // ALL TIME
SetFormat, integerfast, d
SetFormat, FloatFast, 0.2
creditcountertotal := (835000*racecountertotal)/1000000
IniWrite, %racecountertotal%, config.ini,Stats, RaceCounterTotal
IniWrite, %resetcountertotal%, config.ini,Stats, ResetCounterTotal
guicontrol,, RaceCounterTotal, Races completed: %racecountertotal%
guicontrol,, ResetCounterTotal, Races failed: %resetcountertotal%
guicontrol,, CreditCounterTotal, Credits: %creditcountertotal% M
UpdateAVG(racecounter, script_start)
lapcounter =
ProgressRace =
guicontrol,, RaceProgress, %ProgressRace%
loop
{
restart_found := false
c2 := BitGrab(162, 43+remote_play_offsetY, 2)
for i, c in c2
{
d2 := Distance(c, color_restart)
SB_SetText(" Searching... " d2 " < 50",2)
if (d2 < 10 )
{
SB_SetText(" Found: Restart Color " d2 " < 50",2)
restart_found := true
break
}
}
if (restart_found)
break
Press_X()
Sleep(500)
}
Sleep(400)
Press_O()
Sleep(500)
Press_Right()
Sleep(3000)
Press_X()
Sleep(4000)
Press_X()
Sleep(4000)
guicontrol,, CurrentLoop, Setting up next race.
Press_Options()
Sleep(1000)
Press_Right()
Sleep(500)
Press_X()
controller.Axes.LX.SetState(50)
UpdateAVG(racecounter, script_start)
Goto, TokyoStart
}
}
}
EndRace_Tokyo_Def:
Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,336 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GT7 - Tokyo X by problemz.</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800,900" rel="stylesheet">
<link rel="stylesheet" href="scribbler-global.css">
<link rel="stylesheet" href="scribbler-doc.css">
<link rel="author" href="humans.txt">
</head>
<body>
<div class="doc__bg"></div>
<nav class="header">
<h1 class="logo">Tokyo X <span class="logo__thin">Doc</br>by problemz.</span></h1>
<ul class="menu">
<div class="menu__item toggle"><span></span></div>
<li class="menu__item"><a href="https://discord.gg/CfppVp7VXV" target="_blank" class="link link--dark"><i class="fa-brands fa-discord"></i> Join our Discord server</a></li>
</ul>
</br>
<div class="position-relative marquee-container d-none d-sm-block">
<div class="marquee d-flex justify-content-around">
<span>Shoutout (alphabetic order) to all these <b>AMAZING PEOPLE</b> from the Discord Tokyo Beta Channel. Thank you for helping me bringing the <b>TOKYO X</b> script to life - it was a great time!</span>
</br>
<span><shadow2>andow</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Atoms4Piece</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>BeefSupreme</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>BobGT</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>CarapauCorrida</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Chester</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>🐐 </shadow2>(you know)</span>
<span><shadow>//</shadow></span>
<span><shadow2>GTMaster</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>heidi</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>hitomi</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>j0shjones</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>JordanD123</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Krazyy</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>NavS</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Rossey</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Scany</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Septomor</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Sevencuts</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Solisu</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>TheScythed</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>x34uvc</shadow2></span>
</div>
</div>
<hr>
</nav>
<div class="wrapper">
<aside class="doc__nav">
<ul>
<li class="js-btn selected">Welcome to Tokyo</li>
<li class="js-btn">The Masterplan</li>
<li class="js-btn">Setting everything up</li>
<li class="js-btn">FAQ/Changelog</li>
</ul>
</aside>
<article class="doc__content">
<section class="js-section">
<h3 class="section__title">Konnichiwa friend o/</h3>
<p>In this documentation you learn how the Tokyo WTC 600 race works and how to set up the <b>Tokyo X</b> AHK script to farm GT7 credits when you are away from your computer or busy doing other tasks.</br></br>Please <b><u>read carefully and double-check</u></b> everything in this documentation if something isn't working as described. The PSNProfiles Discord has many helpful members that will assist you in getting the script running for your configuration, provided you have read and followed the directions below first.</p></br>
<div class="callout">
<a href="https://discord.gg/CfppVp7VXV" target="_blank" class="button--primary"><i class="fa-brands fa-discord"></i>&nbsp;&nbsp;Join our Discord server</a></a>
</div>
</section>
<section class="js-section">
<h3 class="section__title">Problemz, what is happening and why does it all work? </h3>
<p>Some time ago i started to look for the race with the best credits per hour ratio. <i class="fa-solid fa-arrow-trend-up"></i></br>After an update, the WTC 600 - Tokyo Race became the clear winner and i started writing the script.</p><h4>For this race we have different obstacles:</h4>
<table id="obstacles">
<tr>
<th>Obstacle</th>
<th>Description</th>
</tr>
<tr>
<td>PP restriction</td>
<td>We are only allowed to enter a car with a maximum of 600 PP.</td>
</tr>
<tr>
<td>Tire/fuel consumption</td>
<td>Tire (9x) and fuel (3x) consumption is active. That means we must find the best way to finish the race with the least RNG possible. (Worn tires can lead to spinouts, we must not not run out of fuel, etc.)</td>
</tr>
<tr>
<td>Track condition</td>
<td>Track conditions There are 12 laps total, and the race starts with a very wet track. The track dries throughout the race and and we must react accordingly in order to not spin out or run into obstacles that we cant recover from (mainly barrels in the hairpin turn).</td>
</tr>
<tr>
<td>AI/Opponents</td>
<td>You start the race with 15 other opponents. We try to avoid them as much as possible in order to not spin out or miss set detection pixels (explained later).</td>
</tr>
<tr>
<td>Hairpin turn</td>
<td>There is a hairpin in this track. And it is here to make our scripting lives horrible.</br>The inner side is blocked by big cones, hindering us from just grinding the inner part of the turn.</br>On the outer side we have small cones and 90° walls. The walls are hindering us from just grinding the outside, the small cones often resets our car (when stuck under the car), spawning us back in the first gear.</td>
</tr>
</table>
<h2> Let's start explaining how we mastered this race to earn some good credits:</h2>
<div class="obstacles">
<h3 class="section__title">Overcoming the obstacles. 1 by 1.</h3>
</br>
<div class="tab__container">
<ul class="tab__menu">
<li class="tab active" data-tab="pp">PP restriction</li>
<li class="tab" data-tab="track">Track condition</li>
<li class="tab" data-tab="consumption">Tire/fuel consumptions</li>
<li class="tab" data-tab="ai">AI/Opponents</li>
<li class="tab" data-tab="hairpin">Final boss: Hairpin</li>
</ul>
<pre class="nohighlight code">
<code class="tab__pane active pp">We use a bug in the code to jump below the allowed PP, but still having the fastest car (<i class="fa-solid fa-car"></i> Dodge SRT Tomahawk X VGT). </br></br>We manipulate the gear ratios to a point, where the PP calculation shows <i class="fa-solid fa-triangle-exclamation"></i> PP.</br>From there we fiddle with values until the PP calculation is under 600 PP.</br></br>This still works after the PP-Patch. <i class="fa-solid fa-square-check"></i> </code>
<code class="tab__pane track"><i class="fa-solid fa-water"></i> The race starts with a very wet track. We have to start with <b>intermediates.</b></br></br>After a few laps, the track starts to get dryer, but we can't just switch to Hards. We are not driving the ideal line. <br>We hit some wet spots here and there, therefore we stay on <b>intermediates</b> for the whole race.</br></br> <i class="fa-solid fa-circle-exclamation"></i> Otherwise we would risk to RNG-Spin at many different spots, which endangers ours <b>consistency</b>.</code>
<code class="tab__pane pen"><i class="fa-solid fa-clock-rotate-left"></i> I found out, that there is an internal cooldown for the penalty counter.</br></br>If you receive a penalty and hit or grind a wall/part of the track within 6 seconds, the internal cooldown gets reset.</br>You still collect penalties in a internal penalty storage.</br></br>The first time you're not hitting something for 6 seconds, the penalty gets triggered and is added to your current penalty.</br></br>I also found out, that if you keep grinding the wall while serving a penalty, your penalty storage gets reset. <i class="fa-solid fa-square-check"></i></br></br>If we just keep collecting penalties and finish the race without ever triggering/serving them, we end in a blackscreen and have to close the game and never receive credits.<b></br></br>We use all of this to our advantage:</b></br>We only trigger and serve a 5 second penalty every lap and reset our internal penalty storage, even if we are grinding walls 90% of the time, filling our internal storage.</br></code>
<code class="tab__pane consumption"><b><i class="fa-regular fa-circle"></i> The tires consumption rate is at 9x.</b></br>We already know that we keep the Intermediates. We use the pit stop to always, <b>consistently</b>, trigger a new 5 second penalty</br>We're switching tires every lap - to always have the same behaviour on track, with our set timings/speeds.</br></br><i class="fa-solid fa-gas-pump"></i><b> The fuel consumtion rate is at 3x.</b></br>Because of our frequent pit visits, we can drive with the fuel map setting 1 (Power).</br>We fill up completely in Lap 6 and continiue driving until the race is finish, after lap 12.</code>
<code class="tab__pane ai">We mainly use the pit stops to control our distance to the AI cars.</br>We are using set wait times, depending on our current lap and AI position at this time of the race. There are 2 timings at the momement.</br></br><i class="fa-solid fa-shield"></i> <b>Safest:</b> This one always stays behind AI, therefore its slower but we never see AI.</br></br><i class="fa-solid fa-shield-halved"></i> <b>Risky:</b> With this timings, we overtake AI on different parts of the track, but never in the hairpin turn.</code>
<code class="tab__pane hairpin"><i class="fa-solid fa-radiation"></i> Welcome to the run/consisteny killer #1, the hairpin. <i class="fa-solid fa-skull-crossbones"></i></br></br>After many hours and iterations, our current most consistent way to handle the hairpin is this:</br></br>We place our car on the left wall, controlling our speed, when reaching the turn detection point. We then steer to the right, release acceleration and reach the other side's left wall. This reads so simple, but it's really much more complicated.</br></br>You will see why, pretty soon, running the script. <i class="fa-solid fa-person-harassing"></i></code>
</pre>
</div>
<h4>About pixel detection:</h4>This script relies on the detection of specific color pixels at given coordinates to determine the position of the car relative to the racetrack, also some UI elements and respond accordingly. Pixel detection can be affected by a number of factors such as PlayStation version, PC performance, and network throughput, latency and stability.</br></br>
There is also a degree of variance that happens with every race. Although we have tried to remove as much of this as possible by pitting every lap and avoiding AI in the hairpin, there is still randomness in AI behavior or in things like how the cones in the hairpin react when hit.</br></br>
As such, although we have included a number of variables that allow you to fine tune the script for your specific setup (hairpin turn delay/pit timings), but do not expect to see a 100% completion/win rate. A 75%-90% success is achievable for most people when the correct hairpin turn delay was found.
<hr>
</section>
<section class="js-section">
<h3 class="section__title">Requirements & Informations</h3>
<h3>Hardware:</h3>
<li>A computer running <i class="fa-brands fa-windows"></i> Microsoft Windows (must be X86 processor, ARM is not supported!)</li>
<li>Do <b>NOT</b> connect a <i class="fa-solid fa-gamepad"></i> Controller to your <i class="fa-brands fa-playstation"></i> Playstation or <i class="fa-solid fa-computer"></i> Computer</li>
<li><i class="fa-solid fa-network-wired"></i> Wired internet connection for stable operation of the script. If you do not have both, <i class="fa-solid fa-computer"></i> PC and <i class="fa-brands fa-playstation"></i> Playstation connected by <i class="fa-solid fa-network-wired"></i> wired internet, you may experience all kinds of different problems. If you use <i class="fa-solid fa-wifi"></i> WiFi, we cannot guarantee good operation.</li>
<hr>
<h3>Software:</h3>
<h4><i class="fa-solid fa-download"></i> Download and install:</h4>
<li><a href="https://remoteplay.dl.playstation.net/remoteplay/" target:"_blank"><i class="fa-brands fa-playstation"></i> PS Remote Play</a></br></li>
<li><a href="https://www.autohotkey.com/" target:"_blank"><i class="fa-regular fa-keyboard"></i> AutoHotkey</a></br></li>
<li><a href="https://github.com/ViGEm/ViGEmBus" target:"_blank"><i class="fa-solid fa-gamepad"></i> ViGEmBus Driver (including dependencies)</a></br></li></br>
<h4><i class="fa-brands fa-windows"></i> Windows Settings:</h4>
<li><i class="fa-brands fa-windows"></i> Windows scaling set to <b>100%</b> </li>
<li><i class="fa-solid fa-toggle-off"></i> HDR <b>off</b></li>
<li> Run <b>GT7-TokyoX.exe</b> as <i class="fa-solid fa-person-arrow-up-from-line"></i> Administrator</li>
<li><b>Do NOT</b> minimize <i class="fa-brands fa-playstation"></i> Remote Play. Having other windows or programs on top of it is okay, minimizing is <b>NOT</b>. </li>
<hr>
<h4><i class="fa-brands fa-playstation"></i> Playstation settings:</h4>
<li><b><i class="fa-solid fa-toggle-off"></i> Turn off <i class="fa-brands fa-playstation"></i> Playstation system notifications (these can cover the track map, causing issues with our detections)</br>[Example: "Your friend had come online"]</li></br>
<b><i class="fa-solid fa-triangle-exclamation"></i> <u>IMPORTANT FOR YOUR OWN SAFETY:</b></u></br>
<li><b>Turn ON</b> a password requirement for making any purchases on <i class="fa-brands fa-playstation"></i> PlayStation.</br>This way, when the script has any problems, it will not be possible to buy any MTX by accident.</li></br></br><b><i class="fa-solid fa-circle-exclamation"></i> THEREFORE, WE ARE NOT RESPONSIBLE FOR ACCIDENTAL PURCHASES IF YOU DONT TURN THIS ON AS A PRECAUTION. <i class="fa-solid fa-circle-exclamation"></i></b>
<hr>
<h3>Ingame:</h3>
<li>Player must have finished all Café Menu Books and the final championship (the one with 5 races). </br> This makes sure you have the <b>Tokyo WTC600 championship unlocked. <i class="fa-solid fa-lock-open"></i></b></li>
<li>Player has the <i class="fa-solid fa-car"></i> Dodge SRT Tomahawk X VGT. ($1.000.000)</li>
<li>Player has <i class="fa-solid fa-wrench"></i> tuning parts for the <i class="fa-solid fa-car"></i> Dodge SRT Tomahawk X VGT: </br>Ballast, customisable racing transmission, fully adjustable LSD, Racing Hard tires, Intermediate tires. (~$150.000)</li>
<hr>
<h2>GT7 Settings:</h2>
<h3>_car build:</h3>
<img class="enlarge-image" src="tokyo_car1.png" alt="Tokyo Car 1" /></br><b>//car settings - 1</b>
</br></br>
<img class="enlarge-image" src="tokyo_car2.png" alt="Tokyo Car 2" /></br><b>// car settings - 2</b>
</br></br>
<img class="enlarge-image" src="tokyo_car3.png" alt="Tokyo Car 2" /></br><b>// car settings - 3</b>
</section>
<h3>_misc settings:</h3>
<img class="enlarge-image" src="tokyo_difficulty.png" alt="Tokyo Difficulty" /></br><b>// difficulty Setting</b>
</br></br>
<img class="enlarge-image" src="tokyo_display.png" alt="Tokyo Display" /></br><b>// display settings</b>
</br></br>
<img class="enlarge-image" src="tokyo_drivinggear.png" alt="Tokyo Driving Gear" /></br><b>// driving gear</b>
</br></br>
<h3>_after race start:</h3>
<h4>_-controller settings:</h4>
<img class="enlarge-image" src="tokyo_controller1.png" alt="Tokyo Controller 1" /></br><b>// controller - 1</b>
</br></br>
<img class="enlarge-image" src="tokyo_controller2.png" alt="Tokyo Controller 2" /></br><b>// controller - 2</b>
</br></br>
<h4>_-assists settings:</h4>
<img class="enlarge-image" src="tokyo_assists1.png" alt="Tokyo Assists 1" /></br><b>// assists - 1</b>
</br></br>
<img class="enlarge-image" src="tokyo_assists2.png" alt="Tokyo Assists 2" /></br><b>// assists - 2</b>
</br></br>
<h4>_-cockpit:</h4>
<img class="enlarge-image" src="tokyo_cockpitview.png" alt="Tokyo Cockpit" /></br><b>// cockpit - 1</b>
</br></br>
<hr>
<h2>Tokyo X features:</h2>
<h3>The script offers you following features:</h3>
</br>
<div class="tab__container">
<ul class="tab__menu">
<li class="tab active" data-tab="main">Main GUI</li>
<li class="tab" data-tab="race">Settings: Race</li>
<li class="tab" data-tab="machine">Settings: Machine/Setup</li>
<li class="tab" data-tab="notifications">Settings: Notification</li>
<li class="tab" data-tab="endafter">End after X wins</li>
</ul>
<pre class="nohighlight code">
<code class="tab__pane active main">
<img class="enlarge-image" src="tokyo_script1.png" alt="Tokyo Script 1" /></br>You <b>start</b> after entering the WTC 600 Tokyo race, pause and hover over "Retry".</br>Tokyo WTC600 championship can be found in Asia, it is (currently) the last race option at the Tokyo Expressway track.</br><p>In the main GUI you can see your current location on the track, in which lap you are (also visualized by a progress bar) and check out your session/all time stats.</br></br></p></code>
<code class="tab__pane race"><img class="enlarge-image" src="tokyo_script2.png" alt="Tokyo Script 2" /></br>Select between 2 different pit stop timings.</br></br><img class="enlarge-image" src="tokyo_script3.png" alt="Tokyo Script 3" /></br>Safe (slower): You always stay behind the AI cars after you are in first place.</br>
</br></br><img class="enlarge-image" src="tokyo_script4.png" alt="Tokyo Script 4" /></br>Risky (faster): You overtake AI cars, exception: hairpin turn.</br></br><p>Select an option from the dropdown menu, the values are instantly saved and active.</br>You can check out both timings and decide whats suits you better.</p>
<p align = "right">...myths says there is even a 3rd option <i class="fa-solid fa-hand-fist"></i></p></code>
<code class="tab__pane machine"><img class="enlarge-image" src="tokyo_script5.png" alt="Tokyo Script 5" /></br><p><i class="fa-solid fa-u"></i> <b>Hairpin settings:</br></b></br>The <b>hairpin turn delay</b> in ms dictates how fast the script reacts and turns right after fining the pixel we defined. Start with default settings and watch how your hairpin turns look. In the first lap, the hairpin turn can be pretty wide, they will then be good/perfect for the remaining laps.</br></br>You can try out the option <b>"Dynamic Turn Delay"</b> and find your perfect setup. It measures the time between two detection points and increases/decreases the delay depending on your speed.</p></br><p><i class="fa-solid fa-eye-dropper"></i> <b>Set detection colors:</b></br></br><b>Grab: Pit stop Color</b> - here you can grab the current color when you are <b>stuck in the pit menu </b>(tire selection).</br>You can also manually enter the Hex-Color code when double-clicking on the colored rectangle.</br></br><b>Grab: Restart color</b> - here you can grab the current color when you are <b>stuck in the replay window.</b></br>You can also manually enter the Hex-Color code when double-clicking on the colored rectangle.</p></br><p><i class="fa-solid fa-video"></i> <b>Other Features:</b></br></br><b>Save clip after reset</b> - use the <i class="fa-brands fa-playstation"></i> Playstation feature to record a 3 minutes clip after a reset is triggered.</p></code>
<code class="tab__pane notifications"><img class="enlarge-image" src="tokyo_script6.png" alt="Tokyo Script 6" /><p>You can send race reports to your <i class="fa-brands fa-telegram"></i> Telegram Account.</br></br>Here is a <i class="fa-solid fa-book"></i> <b>quick guide</b> how to set it up:</br></br>
<ol><li>Open Telegram, and start a conversation with @BotFather</li>
<li>In the conversation with @BotFather, type /newbot.</li>
<li>Give your bot a nickname, like BotFather instructs you.</li>
<li>Pick a username for the bot as BotFather instructs you.</li>
<li>BotFather congratulates you and gives you the HTTP API token. This is what you plug into Telegram Bot Token inside the Notifications/API settings in the script.</li>
<li>Create a new group chat in Telegram, where you invite your bot and @RawDataBot</li>
<li>Type /start and the Raw Data Bot will spit out some data. Look for “chat” and specifically “id”. This is what you plug into Telegram Chat ID. Caution: the ID is not just a number, it also has a special character before the number that you <b>MUST include!</b></li></ol>
</p></code>
<code class="tab__pane endafter"><img class="enlarge-image" src="tokyo_script1.png" alt="Tokyo Script 1" /><p>You can set the number of wins until the script stops. Default value is 0 (infinite). </br></br>To activate this feature, enter your wanted number with the Up-Down control and HIT the button below. It is changing its text, depending on how many wins you set.</p></code>
</pre>
</div>
<hr>
<section class="js-section">
<h3 class="section__title">FAQ</h3>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;Can i change the pit stop timings while the script is running?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;Yes, you can do it and the script will pull the correct timing for the coming pit stop.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;My race failed. Is something wrong?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;No. Failures will happen due to Randomness. Script is designed to work most of the time, but failures are inevitable.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;I can't get my PP to match yours! Help?!</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;CHECK THE TOE!!!!!</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;Why do I pit every lap? Wouldn't it be faster to not pit so much?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;Faster, yes. But slow is more reliable and the benefit doesn't outweigh the risk.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;How long can I safely keep my Playstation running?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;That's not up to us. Your mileage may vary. Be responsible.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;What do I do with all these credits?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;You do you, pikachu.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;How long do I have before this gets fixed?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;Probably best to think of a patch coming immediately.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;Why are you doing this?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;To show that we can.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;Can I get a beta version of whatever you are working on next?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;If this lives long enough for updates to be made, they will be released as they are finished.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;Do starting grids matter?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;No.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;How fast are the laps?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;Anywhere between 2:00 and 3:00 depending on pit delay timings and if you happen to get stuck on something for a moment. Before you @ us... slow is reliable. Reliable is enriching.</p>
<p><i class="fa-solid fa-question"></i>&nbsp;&nbsp;What should I do if I can't get it to work?</br><i class="fa-solid fa-exclamation"></i>&nbsp;&nbsp;&nbsp;Clubman is great. Panam still works. Ask in the Discord, but know you have options.</p>
<hr>
<h3>Changelog</h3>
<div class="changelog__item">
<div class="changelog__meta">
<h4 class="changelog__title">Tokyo X</h4>
<small class="changelog__date"></small>
</div>
<div class="changelog__detail">
<ul>
<li>Initial public release</li>
Please provide as much information as possible when asking for help (last status text, lap, location - optimally with a video clip).
</ul>
</div>
</div>
</section>
</article>
</div>
</br>
<div class="position-relative marquee-container d-none d-sm-block">
<div class="marquee d-flex justify-content-around">
<span>Shoutout (alphabetic order) to all these <b>AMAZING PEOPLE</b> from the Discord Tokyo Beta Channel. Thank you for helping me bringing the <b>TOKYO X</b> script to life - it was a great time!</span>
</br>
<span><shadow2>andow</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Atoms4Piece</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>BeefSupreme</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>BobGT</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>CarapauCorrida</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Chester</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>🐐 </shadow2>(you know)</span>
<span><shadow>//</shadow></span>
<span><shadow2>GTMaster</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>heidi</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>hitomi</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>j0shjones</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>JordanD123</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Krazyy</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>NavS</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Rossey</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Scany</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Septomor</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Sevencuts</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>Solisu</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>TheScythed</shadow2></span>
<span><shadow>//</shadow></span>
<span><shadow2>x34uvc</shadow2></span>
</div>
</div>
<hr>
<footer class="footer">GG! - Tokyo X by problemz
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="scribbler.js"></script>
</body>
</html>
@@ -0,0 +1,115 @@
html, body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* layout */
.header {
border-bottom: 1px solid var(--code-bg-color);
grid-template-columns: 1fr 150px 60% 1fr;
}
.wrapper {
display: flex;
flex-grow: 1;
}
/* logo */
.logo {
font-weight: 900;
color: var(--primary-color);
font-size: 1.4em;
grid-column: 2;
}
.logo__thin {
font-weight: 300;
}
/* menu */
.menu {
grid-template-columns: 1fr 180px 60% 1fr;
}
.menu__item {
padding: 1.5rem 1rem;
}
/* doc */
.doc__bg {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 28%;
background-color: var(--bg-color);
z-index: -1;
}
.doc__nav {
flex-basis: 20%;
font-weight: 200;
}
.doc__nav ul {
list-style: none;
padding-left: 0;
line-height: 1.8;
}
.doc__nav ul.fixed {
position: fixed;
top: 2rem;
}
.doc__nav li:hover {
color: var(--primary-color-light);
cursor: pointer;
transition: color .3s ease-in-out;
}
.doc__nav .selected {
color: var(--accent-color);
position: relative;
}
.doc__nav .selected:after {
position: absolute;
content: "";
width: 1rem;
height: 1rem;
background-color: var(--accent-color);
left: -1.5rem;
top: 0.3rem;
}
.doc__content {
flex-basis: 80%;
padding: 0 0 5rem 1rem;
}
@media (max-width: 750px) {
.wrapper {
flex-direction: column;
}
.doc__content {
padding-left: 0;
}
.doc__nav ul {
border-bottom: 1px solid var(--code-bg-color);
padding-bottom: 0.5rem;
}
.doc__nav ul.fixed {
/* nutralized the fixed menu for mobile*/
position: relative;
top: 0;
}
.doc__nav li {
display: inline-block;
padding-right: 1rem;
}
.doc__nav .selected:after {
display: none;
}
}
@@ -0,0 +1,376 @@
/* css variables*/
:root {
--primary-color: #432E30;
--primary-color-light: #8E7474;
--accent-color: #FE6A6B;
--accent-color-light: #FFE4E4;
--accent-color-dark: #B94B4C;
--white-color: #FAFBFC;
--light-gray-color: #C6CBD1;
--medium-gray-color: #959DA5;
--dark-gray-color: #444D56;
--bg-color: #F8F8FA;
--code-bg-color: #F0E8E8;
}
/* normalized */
html, body {
padding: 0;
margin: 0;
font-family: 'Nunito Sans', sans-serif;
background-color: white;
}
p {
font-weight: 300;
color: #4A4A4A;
}
a, a:hover {
text-decoration: none;
color: var(--primary-color);
}
hr {
padding: 1rem 0;
border: 0;
border-bottom: 1px solid var(--bg-color);
}
* {
box-sizing: border-box;
}
/* global components */
/* typography */
.section__title {
color: var(--primary-color);
}
/* tabs */
.tab__container {
position: relative;
}
.tab__container > ul {
position: absolute;
list-style: none;
margin: 0;
right: 1rem;
top: -2rem;
padding-left: 0;
}
.tab__container .code {
white-space: normal;
padding: 1rem 1.5rem;
}
.tab {
display: inline-block;
padding: 0.3rem 0.5rem;
font-weight: 200;
cursor: pointer;
}
.tab.active {
border-bottom: 1px solid var(--primary-color);
font-weight: 700;
display: inline-block;
}
.tab__pane {
display: none;
}
.tab__pane.active {
display: block;
}
/* code */
.code {
border-radius: 3px;
font-family: Space Mono, SFMono-Regular, Menlo,Monaco, Consolas, Liberation Mono, Courier New, monospace;
background: var(--bg-color);
border: 1px solid var(--code-bg-color);
color: var(--primary-color-light);
}
.code--block {
white-space: pre-line;
padding: 0 1.5rem;
}
.code--inline {
padding: 3px 6px;
font-size: 80%;
}
/* buttons */
.button--primary {
padding: 10px 22px;
background-color: var(--accent-color);
color: white;
position: relative;
text-decoration: none;
border: 0;
transition: all .3s ease-out;
}
.button--primary:after {
position: absolute;
content: "";
width: 1rem;
height: 1rem;
background-color: var(--accent-color-light);
right: -0.4rem;
top: -0.4rem;
transition: all 0.3s ease-out;
}
.button--primary:hover {
text-shadow: 0px 1px 1px var(--accent-color-dark);
color: white;
transform: translate3D(0, -3px, 0);
}
.button--primary:hover::after {
transform: rotate(90deg);
}
.button--secondary {
padding: 10px 22px;
border: 2px solid var(--primary-color);
transition: all 0.5s ease-out;
}
.button--secondary:hover {
border-color: var(--accent-color);
color: var(--accent-color);
}
/* links */
.link {
text-decoration: none;
transition: all 0.3s ease-out;
}
.link:hover {
color: var(--accent-color);
}
.link--dark {
color: var(--primary-color);
}
.link--light {
color: var(--accent-color);
}
/* menu */
nav {
display: grid;
grid-template-columns: 70px auto;
}
.menu {
margin: 0;
text-align: right;
overflow: hidden;
list-style: none;
}
.toggle {
display: none;
position: relative;
}
.toggle span,
.toggle span:before,
.toggle span:after {
content: '';
position: absolute;
height: 2px;
width: 18px;
border-radius: 2px;
background: var(--primary-color);
display: block;
cursor: pointer;
transition: all 0.3s ease-in-out;
right: 0;
}
.toggle span:before {
top: -6px;
}
.toggle span:after {
bottom: -6px;
}
.toggle.open span{
background-color: transparent;
}
.toggle.open span:before,
.toggle.open span:after {
top: 0;
}
.toggle.open span:before {
transform: rotate(45deg);
}
.toggle.open span:after {
transform: rotate(-45deg);
}
.menu__item {
padding: 1rem;
display: inline-block;
}
.menu__item.toggle {
display: none;
}
/* table */
table {
border-collapse: collapse;
width: 100%;
transition: color .3s ease-out;
margin-bottom: 2rem;
}
table td, table th {
border: 1px solid var(--code-bg-color);
padding: 0.8rem;
font-weight: 300;
}
table th {
text-align: left;
background-color: white;
border-color: white;
border-bottom-color: var(--code-bg-color);
}
table td:first-child {
background-color: var(--bg-color);
font-weight: 600;
}
@media screen and (max-width: 600px) {
nav {
grid-template-columns: 70px auto;
}
.menu__item{
display: none;
}
.menu__item.toggle {
display: inline-block;
}
.menu {
text-align: right;
padding: 0.5rem 1rem;
}
.toggle {
display: block;
}
.menu.responsive .menu__item:not(:first-child) {
display: block;
padding: 0 0 0.5rem 0;
}
}
/* layout */
.wrapper {
margin: 0 auto;
width: 70%;
}
.footer {
text-align: center;
background-color: var(--primary-color);
padding: 2rem;
color: white;
}
@keyframes fadeUp {
0% {
opacity: 0;
transform: translate3d(0,30px,0);
}
100% {
transform: translate3d(0,0,0);
}
}
.enlarge-image {
margin-top: 0px;
width: 32%;
float: center;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
}
.enlarge-image:hover {
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
-moz-transform: scale(3);
-webkit-transform: scale(3);
-o-transform: scale(3);
-ms-transform: scale(3);
transform: scale(3);
}
.marquee-container {
height: 20px;
overflow: hidden;
line-height: 20px;
}
.marquee-container .marquee {
left: 100%;
width: 100%;
overflow: hidden;
position: absolute;
white-space: nowrap;
animation: marquee 25s linear infinite;
}
.marquee-container .marquee2 {
animation-delay: 20s;
}
.marquee-container shadow {
color: #ffffff;
color: #616161;
text-shadow: #e0e0e0 1px 1px 0;
font-size: 1em;
vertical-align: middle;
}
.marquee-container shadow2 {
color: #fe6a6b;
font-size: 1em;
text-shadow: rgba(255,255,255,.1) -1px -1px 1px,rgba(0,0,0,.5) 1px 1px 1px;
vertical-align: middle;
}
@keyframes marquee {
0% {
left: 100%;
}
100% {
left: -100%;
}
}
@@ -0,0 +1,145 @@
// utilities
var get = function (selector, scope) {
scope = scope ? scope : document;
return scope.querySelector(selector);
};
var getAll = function (selector, scope) {
scope = scope ? scope : document;
return scope.querySelectorAll(selector);
};
// setup typewriter effect in the terminal demo
if (document.getElementsByClassName('demo').length > 0) {
var i = 0;
var txt = `scribbler
[Entry mode; press Ctrl+D to save and quit; press Ctrl+C to quit without saving]
###todo for new year dinner party
- milk
- butter
- green onion
- lots and lots of kiwis 🥝`;
var speed = 60;
function typeItOut () {
if (i < txt.length) {
document.getElementsByClassName('demo')[0].innerHTML += txt.charAt(i);
i++;
setTimeout(typeItOut, speed);
}
}
setTimeout(typeItOut, 1800);
}
// toggle tabs on codeblock
window.addEventListener("load", function() {
// get all tab_containers in the document
var tabContainers = getAll(".tab__container");
// bind click event to each tab container
for (var i = 0; i < tabContainers.length; i++) {
get('.tab__menu', tabContainers[i]).addEventListener("click", tabClick);
}
// each click event is scoped to the tab_container
function tabClick (event) {
var scope = event.currentTarget.parentNode;
var clickedTab = event.target;
var tabs = getAll('.tab', scope);
var panes = getAll('.tab__pane', scope);
var activePane = get(`.${clickedTab.getAttribute('data-tab')}`, scope);
// remove all active tab classes
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.remove('active');
}
// remove all active pane classes
for (var i = 0; i < panes.length; i++) {
panes[i].classList.remove('active');
}
// apply active classes on desired tab and pane
clickedTab.classList.add('active');
activePane.classList.add('active');
}
});
//in page scrolling for documentaiton page
var btns = getAll('.js-btn');
var sections = getAll('.js-section');
function setActiveLink(event) {
// remove all active tab classes
for (var i = 0; i < btns.length; i++) {
btns[i].classList.remove('selected');
}
event.target.classList.add('selected');
}
function smoothScrollTo(element, event) {
setActiveLink(event);
window.scrollTo({
'behavior': 'smooth',
'top': element.offsetTop - 20,
'left': 0
});
}
if (btns.length && sections.length > 0) {
// for (var i = 0; i<btns.length; i++) {
// btns[i].addEventListener('click', function(event) {
// smoothScrollTo(sections[i], event);
// });
// }
btns[0].addEventListener('click', function (event) {
smoothScrollTo(sections[0], event);
});
btns[1].addEventListener('click', function (event) {
smoothScrollTo(sections[1], event);
});
btns[2].addEventListener('click', function (event) {
smoothScrollTo(sections[2], event);
});
btns[3].addEventListener('click', function (event) {
smoothScrollTo(sections[3], event);
});
}
// fix menu to page-top once user starts scrolling
window.addEventListener('scroll', function () {
var docNav = get('.doc__nav > ul');
if( docNav) {
if (window.pageYOffset > 63) {
docNav.classList.add('fixed');
} else {
docNav.classList.remove('fixed');
}
}
});
// responsive navigation
var topNav = get('.menu');
var icon = get('.toggle');
window.addEventListener('load', function(){
function showNav() {
if (topNav.className === 'menu') {
topNav.className += ' responsive';
icon.className += ' open';
} else {
topNav.className = 'menu';
icon.classList.remove('open');
}
}
icon.addEventListener('click', showNav);
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.
@@ -0,0 +1,211 @@
#include %A_LineFile%\..\CLR.ahk
; Static class, holds ViGEm Client instance
class ViGEmWrapper {
static asm := 0
static client := 0
Init(){
if (this.client == 0){
this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
}
}
CreateInstance(cls){
return this.asm.CreateInstance(cls)
}
}
; Base class for ViGEm "Targets" (Controller types - eg xb360 / ds4) to inherit from
class ViGEmTarget {
target := 0
helperClass := ""
controllerClass := ""
__New(){
;~ this.asm := CLR_LoadLibrary(A_LineFile "\..\ViGEmWrapper.dll")
ViGEmWrapper.Init()
this.Instance := ViGEmWrapper.CreateInstance(this.helperClass)
if (this.Instance.OkCheck() != "OK"){
msgbox ViGEmWrapper.dll failed to load!
ExitApp
}
}
SendReport(){
this.Instance.SendReport()
}
SubscribeFeedback(callback){
this.Instance.SubscribeFeedback(callback)
}
}
; DS4 (DualShock 4 for Playstation 4)
class ViGEmDS4 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Ds4"
__New(){
static buttons := {Square: 16, Cross: 32, Circle: 64, Triangle: 128, L1: 256, R1: 512, L2: 1024, R2: 2048
, Share: 4096, Options: 8192, LS: 16384, RS: 32768 }
static specialButtons := {Ps: 1, TouchPad: 2}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
for name, id in specialButtons {
this.Buttons[name] := new this._SpecialButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _SpecialButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetSpecialButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
return this._Parent
}
ConvertAxis(state){
return round(state * 2.55)
}
}
class _DpadHelper {
__New(parent){
this._Parent := parent
this._Id := id
}
SetState(state){
static dPadDirections := {Up: 0, UpRight: 1, Right: 2, DownRight: 3, Down: 4, DownLeft: 5, Left: 6, UpLeft: 7, None: 8}
this._Parent.Instance.SetDpadState(dPadDirections[state])
this._Parent.Instance.SendReport()
return this._Parent
}
}
}
; Xb360
class ViGEmXb360 extends ViGEmTarget {
helperClass := "ViGEmWrapper.Xb360"
__New(){
static buttons := {A: 4096, B: 8192, X: 16384, Y: 32768, LB: 256, RB: 512, LS: 64, RS: 128, Back: 32, Start: 16, Xbox: 1024}
static axes := {LX: 2, LY: 3, RX: 4, RY: 5, LT: 0, RT: 1}
this.Buttons := {}
for name, id in buttons {
this.Buttons[name] := new this._ButtonHelper(this, id)
}
this.Axes := {}
for name, id in axes {
this.Axes[name] := new this._AxisHelper(this, id)
}
this.Dpad := new this._DpadHelper(this)
base.__New()
}
class _ButtonHelper {
__New(parent, id){
this._Parent := parent
this._Id := id
}
SetState(state){
this._Parent.Instance.SetButtonState(this._Id, state)
this._Parent.Instance.SendReport()
return this._Parent
}
}
class _AxisHelper {
__New(parent, id){
this._Parent := parent
this._id := id
}
SetState(state){
this._Parent.Instance.SetAxisState(this._Id, this.ConvertAxis(state))
this._Parent.Instance.SendReport()
}
ConvertAxis(state){
value := round((state * 655.36) - 32768)
if (value == 32768)
return 32767
return value
}
}
class _DpadHelper {
_DpadStates := {1:0, 8:0, 2:0, 4:0} ; Up, Right, Down, Left
__New(parent){
this._Parent := parent
}
SetState(state){
static dpadDirections := { None: {1:0, 8:0, 2:0, 4:0}
, Up: {1:1, 8:0, 2:0, 4:0}
, UpRight: {1:1, 8:1, 2:0, 4:0}
, Right: {1:0, 8:1, 2:0, 4:0}
, DownRight: {1:0, 8:1, 2:1, 4:0}
, Down: {1:0, 8:0, 2:1, 4:0}
, DownLeft: {1:0, 8:0, 2:1, 4:1}
, Left: {1:0, 8:0, 2:0, 4:1}
, UpLeft: {1:1, 8:0, 2:0, 4:1}}
newStates := dpadDirections[state]
for id, newState in newStates {
oldState := this._DpadStates[id]
if (oldState != newState){
this._DpadStates[id] := newState
this._Parent.Instance.SetButtonState(id, newState)
}
this._Parent.SendReport()
}
}
}
}
@@ -0,0 +1,151 @@
; ==========================================================
; .NET Framework Interop
; https://autohotkey.com/boards/viewtopic.php?t=4633
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if assembly := AppDomain.Load_2(AssemblyName)
break
static null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, null, null, args)
break
if assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, null, null, args)
break
}
ComObjError(e)
return assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, null, vargs, null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, null, null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
/**********************************************
* Controller methods for simplicity *
***********************************************/
*/
GoTo EndControllerFunctionsDef
;;;;;;;;;;;; Turning functions
;;;;;;;;;;;; For holding the stick in a specific position for a period of time
;;;;;;;;;;;; Note no other button may be pressed or released when these functions are ran
; Set the time you want to turn for in miliseconds and how hard (50, 100), 100 being the most, 50 being neutral
Turn_Right(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
; Set the time you want to turn for in miliseconds and how hard (0, 50), 0 being the most
Turn_Left(sleept, inten){
t := sleept
controller.Axes.LX.SetState(inten)
gosub, Turn
controller.Axes.LX.SetState(50)
}
;;;;;;;;;;;; Simple button press functions
;;;;;;;;;;;; You can pass a delay amount or leave it blank
;;;;;;;;;;;; Longer delays hold the button longer
; Press X button
Press_X(delay:=200){
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Cross.SetState(false)
return
}
; Press O button
Press_O(delay:=200){
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Circle.SetState(false)
return
}
; Press Triangle button
Press_Triangle(delay:=200){
controller.Buttons.Triangle.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Triangle.SetState(false)
return
}
; Press Square button
Press_Square(delay:=200){
controller.Buttons.Square.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.Square.SetState(false)
return
}
; Press R1 button
Press_L1(delay:=200){
controller.Buttons.L1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.L1.SetState(false)
return
}
; Press R1 button
Press_R1(delay:=200){
controller.Buttons.R1.SetState(true)
DllCall("Sleep", "UInt", delay)
controller.Buttons.R1.SetState(false)
return
}
; Press Right on D-pad
Press_Right(delay:=200){
controller.Dpad.SetState("Right")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Left on D-pad
Press_Left(delay:=200){
controller.Dpad.SetState("Left")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Up on D-pad
Press_Up(delay:=200){
controller.Dpad.SetState("Up")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
; Press Down on D-pad
Press_Down(delay:=200){
controller.Dpad.SetState("Down")
DllCall("Sleep", "UInt", delay)
controller.Dpad.SetState("None")
return
}
;;;;;;;;;;; Other functions specific to GT7
; Turn on nitrous
Nitrous_On(){
controller.Buttons.RS.SetState(true)
}
; Turn off nitrous
Nitrous_Off(){
controller.Buttons.RS.SetState(false)
}
Accel_On(control:=100){
controller.Buttons.R2.SetState(true)
controller.Axes.RT.SetState(control)
}
Accel_Off(){
controller.Buttons.R2.SetState(false)
controller.Axes.RT.SetState(0)
}
Brake_On(control:=100){
controller.Buttons.L2.SetState(true)
controller.Axes.LT.SetState(control)
}
Brake_Off(){
controller.Buttons.L2.SetState(false)
controller.Axes.LT.SetState(0)
}
; given time t in miliseconds, turn right for that long, with intensity being how much the turn button is held for
Turn:
t0 := A_TickCount
tf := t0+t
loop {
Sleep(100)
} until A_TickCount > tf
return
Press_Options(){
controller.Buttons.Options.SetState(true)
Sleep, 50
controller.Buttons.Options.SetState(false)
}
PressShare(){
controller.Buttons.Share.SetState(true)
Sleep, 50
controller.Buttons.Share.SetState(false)
}
PressX:
; Just for menuing, does not hold X down
controller.Buttons.Cross.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Cross.SetState(false)
return
PressO:
; Just for menuing, does not hold O down
controller.Buttons.Circle.SetState(true)
DllCall("Sleep", "UInt", 200)
controller.Buttons.Circle.SetState(false)
return
PressRight:
; For turning
controller.Dpad.SetState("Right")
Sleep, 50
controller.Dpad.SetState("None")
return
EndControllerFunctionsDef:
@@ -0,0 +1,136 @@
/**********************************************
* Only place functions here, no sub routines *
***********************************************/
; Grabs the colors of the pixels (x-b, y-b) to (x+b, y+b)
; returns the array of colors
*/
BitGrab(x, y, b)
{
HWND := WinExist("PS Remote Play")
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromHWND2(hwnd)
pixs := []
for i in range(-1*b, b+1){
for j in range(-1*b, b+1){
pixel := Gdip_GetPixel(pBitmap,x+i,y+j)
rgb := ConvertARGB( pixel )
pixs.Push(rgb)
}
}
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return pixs
}
Gdip_BitmapFromHWND2(hwnd)
{
WinGetPos,,, Width, Height, ahk_id %hwnd%
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
RegExMatch(A_OsVersion, "\d+", Version)
PrintWindow(hwnd, hdc, Version >= 8 ? 2 : 0)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
return pBitmap
}
range(start, stop:="", step:=1) {
static range := { _NewEnum: Func("_RangeNewEnum") }
if !step
throw "range(): Parameter 'step' must not be 0 or blank"
if (stop == "")
stop := start, start := 0
; Formula: r[i] := start + step*i ; r = range object, i = 0-based index
; For a postive 'step', the constraints are i >= 0 and r[i] < stop
; For a negative 'step', the constraints are i >= 0 and r[i] > stop
; No result is returned if r[0] does not meet the value constraint
if (step > 0 ? start < stop : start > stop) ;// start == start + step*0
return { base: range, start: start, stop: stop, step: step }
}
_RangeNewEnum(r) {
static enum := { "Next": Func("_RangeEnumNext") }
return { base: enum, r: r, i: 0 }
}
_RangeEnumNext(enum, ByRef k, ByRef v:="") {
stop := enum.r.stop, step := enum.r.step
, k := enum.r.start + step*enum.i
if (ret := step > 0 ? k < stop : k > stop)
enum.i += 1
return ret
}
Sleep(ms=1)
{
global timeBeginPeriodHasAlreadyBeenCalled
if (timeBeginPeriodHasAlreadyBeenCalled != 1)
{
DllCall("Winmm.dll\timeBeginPeriod", UInt, 1)
timeBeginPeriodHasAlreadyBeenCalled := 1
}
DllCall("Sleep", UInt, ms)
}
PixelColorSimple(pc_x, pc_y)
{
WinGet, remotePlay_id, List, ahk_exe RemotePlay.exe
if (remotePlay_id = 0)
{
MsgBox, PS4 Remote Play not found
return
}
if remotePlay_id
{
pc_wID := remotePlay_id[0]
pc_hDC := DllCall("GetDC", "UInt", pc_wID)
pc_fmtI := A_FormatInteger
SetFormat, IntegerFast, Hex
pc_c := DllCall("GetPixel", "UInt", pc_hDC, "Int", pc_x, "Int", pc_y, "UInt")
pc_c := pc_c >> 16 & 0xff | pc_c & 0xff00 | (pc_c & 0xff) << 16
pc_c .= ""
SetFormat, IntegerFast, %pc_fmtI%
DllCall("ReleaseDC", "UInt", pc_wID, "UInt", pc_hDC)
return pc_c
}
}
GetClientSize(hWnd, ByRef w := "", ByRef h := "")
{
VarSetCapacity(rect, 16)
DllCall("GetClientRect", "ptr", hWnd, "ptr", &rect)
w := NumGet(rect, 8, "int")
h := NumGet(rect, 12, "int")
}
Distance(c1, c2)
{ ; function by [VxE], return value range = [0, 441.67295593006372]
return Sqrt((((c1>>16)-(c2>>16))**2)+(((c1>>8&255)-(c2>>8&255))**2)+(((c1&255)-(c1&255))**2))
}
ConvertARGB(ARGB, Convert := 0)
{
SetFormat, IntegerFast, Hex
RGB += ARGB
RGB := RGB & 0x00FFFFFF
if (Convert)
RGB := (RGB & 0xFF000000) | ((RGB & 0xFF0000) >> 16) | (RGB & 0x00FF00) | ((RGB & 0x0000FF) << 16)
return RGB
}
ToolTipper(msg, x := 100, y := 100)
{
if (debug_mode = 1)
ToolTip, %msg%, x, y, Screen
return
}