WORK IN PROGRESS...................
Someone asked me if I could write a better version of my autowalk function. So I written this script that enables autowalking for most games. Both 3D and those with a isometric camera are supported. I thought to share it here, maybe you find it useful.
script features:
- Autowalk for any game
- option to enable ingame isometric camera to auto follow the player.
- All hotkey's and sendkeys are configurable
- Active edit controlls that insert key name uppon pressing one. Controllers are supported
- The abillity to add extra hotkey's and code to the script.
- Some handy functions for sending key's and stuff. To make life easy.
- Remebers perviouse added games and they can easilly be loaded from a listview with icons.
Work in progress:
- Fully configurable spamkey function
- Pixel based autopot
Code: Select all
/*
Autowalk v1.0.4.1 writen by Megnatar ⬖⬘⬗⬙
Everyone is free to use, add code and redistribute this script.
But you MUST always credit ME Megnatar for creating the source!
The source code for this script can be found on my Github repository:
https://github.com/Megnatar/AHK-Scripts/blob/master/Autowalk.ahk
Usage:
To add a new game, just drop the executable on the gui or use the browse button.
Click in a edit box to set a new hotkey. Any posible key will do. The script will write
the name of the key to the edit control. For example pressing numpad1 after a click inside a edit
control will write numpad1 to it, not 1. Game controllers are supported.
Enable the checkbox "RPG Games" for games with a isometric camera (top Down view).
All these games use left mouse button Down to move around. Thus, double click the left
mouse button to send LButton Down. Click again, once or twice, to stop.
The hotkey and the key to send, are both configurable.
When the camera does not automatically follow the player enable "Turn camera" and
specify the two keys used by the game to rotate the camera left or right.
A double click will now also enable auto rotation of the camera.
IMPORTANT:
- If the game does not accept input. Then enable admin mode and try again!
- Droping files will NOT work when the script is running in admin mode.
- You have to use the real executable for you're game, not a shortcut that looks like a exe.
This is usually the case with games build on the Unreal engine. Look for a folder named Binaries or Bin.
Great thanx to Turul1989 for helping me debug and undestand what needs to be added.
*/
#NoEnv
#SingleInstance force
#InstallKeybdHook
#KeyHistory 0
;#Include, Gdip_all.ahk
;ListLines off
SetBatchLines -1
SetTitleMatchMode 3
SetKeyDelay 5, 1
SetWorkingDir %A_ScriptDir%
sendmode Input
CoordMode, Mouse, screen
Global Wm_LbuttonDown := 0x201
, Wm_Mousemove := 0x200
, Wm_DraggGui := 0x5050
, WM_NCLBUTTONDOWN := 0xA1
, Ws_Caption := 0xC00000
, Ws_Border := 0x800000
, InputActive := 0
, TipsOff := 0
, ConfigFile := A_ScriptDir "\Settings.ini"
, Profiles := A_ScriptDir "\GameProfiles\GamesConfig.ini"
, IconLib := []
, hScriptGui
, ControlBelowMouse
, ControlOldBelowMouse
, ctrlTxt
, A_hotKey
, now_x
, now_y
, Title
MenuItems := {"Toggle Admin": "Admin", "Toggle Tooltips": "TipsOff", "Toggle OnTop": "OnTop", "Show Game List": "ShowGameList"}
DropNotice := "Drop you're game executable here"
OpenFolder_TT := "Open game installation dir.`nControl+Click to open script dir."
hKey_TT := "HOTKEY.`nClick then press a button to change."
sKey_TT := "SENDKEY.`nClick then press a button to change."
RunGame_TT := "Start a new game session.`nActivates it, if it's already running."
LeftKey_TT := "The key used by the game to turn camera left."
RightKey_TT := "The key used by the game to turn camera right."
Browse_TT := "Browse for a game to add."
LeftKey := "Left"
RightKey := "Right"
Gui_X := "Center"
Gui_Y := "Center"
KeyState := "Up"
sKey := "W"
hKey := "XButton2"
RPGGames := 0
TurnCamera := 0
Admin := 0
ShowGameList := 0
OnTop := 0
i := 0
If (FileExist(ConfigFile)) {
iniRead(ConfigFile)
}
if (Admin & !A_IsAdmin) {
Try {
if (A_IsCompiled) {
Run, *RunAs "%A_ScriptFullPath%"
} else {
Run, *RunAs "%A_AhkPath%" /ErrorStdOut "%A_ScriptFullPath%"
}
} Catch ThisError {
MsgBox % ThisError
}
ExitApp
}
GUI % "+LastFound " (tgl := !OnTop ? "-" : "+") "AlwaysOnTop +OwnDialogs +hWndhScriptGui -Theme"
Menu GameMenu, Add, Get Vars, MenuGame
Menu Menu, Add, &Game, :GameMenu
Menu OptionsMenu, Add, Toggle Tooltips, MenuToggleOptions
Menu OptionsMenu, Add, Toggle Admin, MenuToggleOptions
Menu OptionsMenu, Add, Toggle OnTop, MenuToggleOptions
Menu OptionsMenu, Add
Menu OptionsMenu, Add, Show Game List, MenuToggleOptions
Menu Menu, Add, &Options, :OptionsMenu
Menu ToolsMenu, Add, Add Code, MenuTools
Menu ToolsMenu, Add, Spy Glass, MenuTools
Menu Menu, Add, &Tools, :ToolsMenu
Gui Menu, Menu
Gui Add, CheckBox, x368 y1 w10 h10 Checked%ShowGameList% vShowGameList gShowGameList -theme +0x1020 +E0x20000
Gui Add, GroupBox, x8 y0 w362 h194 +Center, % Admin ? "" : DropNotice
Gui Add, GroupBox, x16 y8 w345 h64
Gui Font, s10 Bold
Gui Add, Text, x24 y36 w329 h19 +Center +BackgroundTrans +0x200 vTitle, %Title%
Gui Font
Gui Add, Picture, x20 y18 w50 h50 +0x09 vPic, % "HICON:*" hIcon := LoadPicture(FullPath, "GDI+ Icon1 w50", ImageType)
Gui Add, Button, x307 y18 w50 h18 vBrowse, Browse
Gui Add, Button, x16 y160 w70 h23 vRunGame, &Start Game
Gui Add, Button, x88 y160 w70 h23 vOpenFolder, Open Folder
Gui Add, Button, x304 y160 w60 h23 gGuiClose, Exit
Gui Add, Button, x160 y160 w70 h23 vDelConf gDelConf, Delete ini
Gui Add, Button, x232 y160 w70 h23 vEndGame gEndGame, End Game
Gui Add, GroupBox, x16 y72 w345 h83
Gui Add, Text, x24 y80 w99 h14, Autowalk keys
Gui Add, Edit, x24 y100 w63 h21 Limit1 -TabStop vhKey, %hKey%
Gui Add, Edit, x24 y126 w63 h21 Limit1 -TabStop vskey, %skey%
Gui Add, CheckBox, x120 y104 w82 h23 Checked%RPGGames% vRPGGames gRPGGames, RPG Games
Gui Add, CheckBox, x120 y128 w82 h23 +Disabled Checked%TurnCamera% vTurnCamera gTurnCamera, Turn Camera
Gui Add, Edit, x212 y128 w60 h21 +Disabled Limit1 -TabStop vLeftKey, %LeftKey%
Gui Add, Edit, x280 y128 w60 h21 +Disabled Limit1 -TabStop vRightKey, %RightKey%
Gui Add, GroupBox, x376 y0 w154 h193 +Hidden vGBGameList
Gui Add, ListView, x384 y16 w137 h169 vLoadGameSetting gLoadGameSetting hWndhLVItems +Hidden, Icon|Window Title
LoadIcons()
if (RPGGames) {
GuiControl([["Enable", "TurnCamera"]])
if (TurnCamera = 1) {
GuiControl([["Enable", "LeftKey"], ["Enable", "RightKey"]])
}
}
For MenuItemTxt, VariableName in MenuItems
{
if (%VariableName% = 1)
Menu OptionsMenu, ToggleCheck, % MenuItemTxt
}
if (ShowGameList) {
GuiControl([["Show", "GBGameList"], ["Show","LoadGameSetting"]])
Gui Show, % "w" (Gui_W := 538) " h201 x" Gui_X " y" Gui_Y, AutoWalk
} else {
Gui Show, % "w" (Gui_W := 378) " h201 x" Gui_X " y" Gui_Y, AutoWalk
}
OnMessage(Wm_MouseMove, "WM_Mouse"), OnMessage(Wm_LbuttonDown, "WM_Mouse"), OnMessage(Wm_DraggGui, "WM_Mouse"), OnExit("SaveSettings")
Return
;_______________________________________ Game Specific Code _______________________________________
#IfWinExist, AutoWalk
{
#IfWinNotActive, AutoWalk
{
#IfWinExist, ahk_group ClientGroup
{
#IfWinActive, ahk_group ClientGroup
{
; When this file "UserCode.ahk" resides in the same folder as where the script is.
; Then the code in that file is used by this script when the game window is active.
; Read comment on function ButtonSingleDouble() for more instructions.
;
#Include *i UserCode.ahk
HotKeyAutoWalk:
If (RPGGames) {
If (A_Hotkey := KeyWait()) {
If (ErrLvL := KeyWait(A_hotKey, "D T0.2", 1) = 0) {
keywait(A_hotKey), KeyState := KeyState != "Down" ? "Down" : "Up"
Send {%A_hotKey% %KeyState%}
If ((TurnCamera = 1) & (KeyState = "Down")) {
AutoTurnCamera(A_hotKey, LeftKey, RightKey, VirtualKey := 1)
}
} else {
if (KeyState = "Down") {
KeyState := "Up"
Send {%A_hotKey% %KeyState%}
}
}
}
} Else If (!RPGGames) {
InterruptDownState:
if (KeyState = "Down")
KeyWait()
KeyState := KeyState != "Down" ? "Down" : "Up"
Send {%sKey% %KeyState%}
if (KeyState = "Down") {
Hotkey, ~*Vk057, InterruptDownState, ON ; Vk057 = w
Hotkey, ~*Vk01, InterruptDownState, ON ; Vk01 = LButton
} else if (KeyState = "Up") {
Hotkey, ~*Vk057, InterruptDownState, OFF
Hotkey, ~*Vk01, InterruptDownState, OFF
}
Return
}
Return
}
}
}
}
Return
;_______________________________________ Script Lables _______________________________________
MenuGame:
If (A_ThisMenuItem = "Get Vars") {
Gosub, ButtonStartGame
}
Return
MenuToggleOptions:
; Check or uncheks the menuitem. Then toggles the value for the variable that is accosiated
; with the menuitem to the opsite. Saves or remove the variable to/from ini file.
For MenuItemTxt, VariableName in MenuItems
{
If (A_ThisMenuItem = MenuItemTxt) {
Menu %A_ThisMenu%, ToggleCheck, %MenuItemTxt%
if (%VariableName% := %VariableName% ? 0 : 1) {
IniWrite, % %VariableName%, %ConfigFile%, Settings, %VariableName%
} else {
IniDelete, %ConfigFile%, Settings, %VariableName%
}
}
}
; Menu specific actions. They pritty much speak for them self.
If (A_ThisMenuItem = "Toggle Admin") {
i := Admin ? Reload() : ExitApp()
}
else If (A_ThisMenuItem = "Toggle OnTop") {
tgl := OnTop = 0 ? "-" : "+"
Gui 1:%tgl%AlwaysOnTop
}
else If (A_ThisMenuItem = "Show Game List") {
if (ShowGameList) {
WinMove, AutoWalk,,,, 538
GuiControl([["Show", "GBGameList"], ["Show","LoadGameSetting"], ["", "ShowGameList", ShowGameList]])
} else {
GuiControl([["Hide", "GBGameList"], ["Hide","LoadGameSetting"], ["", "ShowGameList", ShowGameList]])
WinMove, AutoWalk,,,, 384
}
}
Return
MenuTools:
If (A_ThisMenuItem = "Add Code") {
if (!DefaultEditor) {
RegRead, DefaultEditor, HKEY_CLASSES_ROOT\AutoHotkeyScript\Shell\Edit\Command
if (ErrorLevel) {
MsgBox, 0x24, Missing default editor, % "It seems you're machine hase no default editor installed.`nDo you wish to select one?`n`nYes:`nFile association for *.ahk files will be configured for you're chosen tool.`n`nNo:`nThe script will use notepad to edit *.ahk files."
IfMsgBox Yes, {
FileSelectFile DefaultEditor, 2,, Select your editor, Programs (*.exe, *.ahk)
if ErrorLevel
return
RegWrite REG_SZ, HKCR, AutoHotkeyScript\Shell\Edit\Command,, "%DefaultEditor%" "`%1"
} Else IfMsgBox No, {
RegWrite REG_SZ, HKCR, AutoHotkeyScript\Shell\Edit\Command,, "Notepad.exe" "`%1"
}
} else if (!ErrorLevel) {
MsgBox, 0x24, Missing default editor, % "A script editor is installed on you're machine.`nDo you want to use it to add code, using #include, to the script?`n`nYes to use you're default editor.`nNo will enable a editbox to add code."
IfMsgBox Yes, {
IniWrite, % StrReplace(DefaultEditor, """" `%1 """"), %ConfigFile%, Settings, DefaultEditor
} else {
Return
}
}
}
}
Return
ShowGameList:
Menu OptionsMenu, ToggleCheck, Show Game List
if (ShowGameList := ShowGameList ? 0 : 1) {
WinMove, AutoWalk,,,, 538
GuiControl([["Show", "GBGameList"], ["Show","LoadGameSetting"]])
IniWrite, %ShowGameList%, %ConfigFile%, Settings, ShowGameList
} else {
GuiControl([["Hide", "GBGameList"], ["Hide","LoadGameSetting"]])
WinMove, AutoWalk,,,, 384
IniDelete, %ConfigFile%, Settings, ShowGameList
}
Return
LoadGameSetting:
Loop {
if (!(RowNumber := LV_GetNext(RowNumber)))
break
LV_GetText(GameTitle, RowNumber, 2)
}
if (!GameTitle)
Return
MsgBox,0x24, Load new settings, % "Do you want to load the settings for this game:`n " GameTitle ""
IfMsgBox Yes
{
If (FileExist(ConfigFile))
FileDelete %ConfigFile%
If (FileExist(Profiles)) {
Loop, parse, % FileOpen(Profiles, 0).read(), `n, `r
{
if ((InStr(A_LoopField, "[",, 1, 1)) = 1) {
SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
} else if (GameTitle = SectionName) {
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1), %VarRef% := SubStr(A_LoopField, InStr(A_LoopField, "=")+1)
if (%VarRef%)
IniWrite, % %VarRef%, %ConfigFile%, Settings, %VarRef%
}
}
Reload()
}
}
return
AddCode:
Return
SpyGlass:
SpyGlass := 1
OnMessage(Wm_LbuttonDown, ""), OnMessage(Wm_DraggGui, "")
CoordMode, Mouse, screen
zoom = 2
Ws_Caption := 0xC00000
Ws_Border := 0x800000
MouseGetPos, X, Y, hWndWinBelowCur
Gui 2:+AlwaysOnTop +ToolWindow +OwnDialogs -0xC00000 -0x800000 +0x40000000 +E0x80000 +HwndhWndScript
Gui 2:Show, w250 h250 x%X% y%Y%, Magnifier
OnMessage(Wm_Mousemove, "Wm_Mousemove")
WinGetClass, ClientGuiClass, ahk_id %hWndScript%
WinSet, Region, 0-0 W150 H150 E, ahk_class %ClientGuiClass%
WinSet, Transparent , 254, Magnifier
SetTimer, MoveWin, 10
;retrieve the unique ID number (HWND/handle) of that window
WinGet, hWndWinBelowCur, id
hdc_frame := DllCall("GetDC", UInt, hWndScript)
hdd_frame := DllCall("GetDC", UInt, hWndWinBelowCur)
hdc_buffer := DllCall("gdi32.dll\CreateCompatibleDC", UInt, hdc_frame) ; buffer
hbm_buffer := DllCall("gdi32.dll\CreateCompatibleBitmap", UInt,hdc_frame, Int,A_ScreenWidth, Int,A_ScreenHeight)
SystemCursor("Toggle")
Gosub, Repaint
return
Repaint:
if (GetKeyState("LButton", "D")) {
SetTimer, Repaint, Off
OnMessage(Wm_LbuttonDown, "WM_Mouse"), OnMessage(Wm_DraggGui, "WM_Mouse")
}
MouseGetPos, X, Y, hWndWinBelowCur ; position of mouse
WinGetPos, wx, wy, ww, wh, Magnifier
wh2 := wh
DllCall( "gdi32.dll\SetStretchBltMode", "uint", hdc_frame, "int", 0 ) ; No Antializing
DllCall("gdi32.dll\StretchBlt", UInt, hdc_frame, Int, 0, Int, 0, Int, ww, Int, wh, UInt, hdd_frame, Int, X-(ww / 2 / zoom), Int, Y-(wh/2/zoom), Int, ww/zoom, Int, wh2/zoom ,UInt,0xCC0020) ; SRCCOPY
SetTimer, Repaint , 0
Return
MoveWin:
MouseGetPos, now_x, now_y`
now_x -= 75
now_y -= 75
WinMove, Magnifier, , %now_x%, %now_y%
Return
!+WheelUp:: ; Alt+Shift+WheelUp to zoom in
If zoom != 16
zoom *= 2
Return
!+WheelDown:: ; Alt+Shift+WheelUp to zoom out
If zoom != 2
zoom /= 2
Return
!x::
SystemCursor("On")
DllCall("gdi32.dll\DeleteObject", UInt,hbm_buffer)
DllCall("gdi32.dll\DeleteDC", UInt,hdc_frame )
DllCall("gdi32.dll\DeleteDC", UInt,hdd_frame )
DllCall("gdi32.dll\DeleteDC", UInt,hdc_buffer)
Gui 2:Destroy
Return
GuiDropFiles:
Loop, parse, A_GuiEvent, `n, `r
FullPath := A_LoopField, Path := SubStr(A_LoopField, 1, InStr(A_LoopField, "\", ,-1)-1), ExeFile := SubStr(A_LoopField, InStr(A_LoopField, "\", ,-1)+1), FileDrop := 1
ButtonBrowse:
If (!FileDrop) {
FileSelectFile, FullPath, M3, , ,*.exe
Loop, parse, % FullPath, `n, `r
A_Index <= 1 ? Path := A_LoopField : ExeFile := A_LoopField
if (ErrorLevel)
Exit
}
FileGetSize, fileSize, %FullPath%, K
if ((FileSize < 1024) & (FileSize != ""))
MsgBox,,FileSize: %FileSize% KB, % "The size of you're file is less then 1MB`n`nAre you sure this is the real exe and not a shortcut`nto a ecxecutable some folders below`n`nFile size: " FileSize "KB"
If (FileExist(ConfigFile))
FileDelete %ConfigFile%
IniWrite, % Admin := 1, %ConfigFile%, Settings, Admin
IniWrite, % TipsOff := 1, %ConfigFile%, Settings, TipsOff
IniWrite % FullPath := Trim(Path) "\" Trim(ExeFile), %ConfigFile%, Settings, FullPath
IniWrite %Path%, %ConfigFile%, Settings, Path
IniWrite %ExeFile%, %ConfigFile%, Settings, ExeFile
IniWrite % Title := "Ready to start you're game", %ConfigFile%, Settings, Title
IniWrite, % OnTop := 0, %ConfigFile%, Settings, OnTop
Reload()
Return
RPGGames:
GUI, submit, nohide
IniWrite, %RPGGames%, %ConfigFile%, Settings, RPGGames
if (RPGGames) {
;sKey := hKey := "LButton"
GuiControl([[ , "hKey", "LButton"], [ , "sKey", "LButton"], ["Enable", "TurnCamera"]])
IniWrite, % hKey := "LButton", %ConfigFile%, Settings, hKey
IniWrite, % sKey := "LButton", %ConfigFile%, Settings, sKey
} else {
;TurnCamera := ""
GuiControl([["enable", "hKey"], ["Disable", "TurnCamera"], ["Disable", "LeftKey"], ["Disable", "RightKey"], [ , "TurnCamera", "0"]])
IniWrite, % TurnCamera := "", %ConfigFile%, Settings, TurnCamera
}
GUI, submit, nohide
Return
TurnCamera:
GUI, submit, nohide
IniWrite, %TurnCamera%, %ConfigFile%, Settings, TurnCamera
if (TurnCamera) {
GuiControl([["Enable", "LeftKey"], ["Enable", "RightKey"]])
} else {
GuiControl([["Disable", "LeftKey"], ["Disable", "RightKey"]])
}
GUI, submit, nohide
Return
ButtonStartGame:
; Is the game already running?
If (!(HwndClient := WinExist("ahk_exe " ExeFile))) {
Run %ExeFile%, %Path%
sleep, 10
loop {
; Keep on checking for our window to appear. This is untill var HwndClient holds some value.
If (!(HwndClient := WinExist("ahk_exe " ExeFile))) {
if (CheckWinExist < 60) {
CheckWinExist += 1
; Show a counter in the GUI when the script is waiting longer then 4 seconds.
if (CheckWinExist > 9)
GuiControl([[ , "Title", Title " " CheckWinExist ]])
; After 30 second a timeout will occur.
} else if ((!HwndClient) & (CheckWinExist > 59)) {
MsgBox,0x24, Something is not oke!?, % "Unable to find client GUI!`nDo you wish to wait a nother 30 seconds?"
IfMsgBox Yes, {
CheckWinExist := ""
Continue
} else {
HwndClient := "", CheckWinExist := "NotFound"
break
}
}
sleep, 500
}
else If (HwndClient) {
WinGetClass, GuiClass, ahk_exe %ExeFile%
if (GuiClass = "DIEmWin" || GuiClass = "D3DProxyWindow" || GuiClass = "DXGIWatchdogThreadWindow"){
HwndClient := ""
Continue
} else {
Break
}
}
}
; Whem a timeout occurred and while() broke. Then jump back to the last return because messagebox choise was No.
if (CheckWinExist = "NotFound") {
Return
} else {
; Remove timer from gui only when it started.
if (CheckWinExist > 9)
GuiControl([[ , "Title", Title]])
WinGet, WinState, MinMax, ahk_exe %ExeFile%, , AutoWalk
}
; When the game was already running.
} else if (HwndClient) {
WinGet, WinState, MinMax, ahk_exe %ExeFile%, , AutoWalk
}
sleep 5000
if (WinState = -1) {
WinSet, Bottom,, AutoWalk
WinRestore, ahk_id %hWndClient%,, AutoWalk
WinSet, Top,, ahk_id %hWndClient%
} else {
WinSet, Bottom,, AutoWalk
WinActivate, ahk_id %hWndClient%,, AutoWalk
WinSet, Top,, ahk_id %hWndClient%
}
; Is active window the game window? A top most window is not always the active one.
If (WinActive("A") != HwndClient)
WinActivate, ahk_id %hWndClient%, , AutoWalk
;If ((Wintitle) & (Wintitle != "Ready to start you're game"))
; Some games launch a different window first.
; A window must exist by now. But is it our window? A game GUI never contains any
; controls in it. So getting all controls of the window that was just launched.
WinGet, EmptyCtrlList, ControlList, ahk_exe %ExeFile%
; Eveluates true when var EmptyCtrlList is indeed empty.
; And if the game was not already launched by the script.
If (EmptyCtrlList ? 0 : 1) {
; Get the window title and it's class name when a new game is launched for the first time.
; Save class and title to setting.ini file and put the title on the gui.
If ((InStr(Title, "Ready to start you're game")) | (!Title)) {
WinGetTitle, Title, ahk_exe %ExeFile%
WinGetClass, ClientGuiClass, ahk_exe %ExeFile%
IniWrite %Title%, %ConfigFile%, Settings, Title
IniWrite %ClientGuiClass%, %ConfigFile%, Settings, ClientGuiClass
GuiControl([[ , "Title", Title], ["MoveDraw", "Pic"]])
}
} else if (!ClientGroup & !OddCLient) {
MsgBox,0x24, Game Window!?, % "This does not look like a game window!`n`nDo you want to Reload() the script?`nYou should then press the Start Game`nbutton once the game window is active."
IfMsgBox Yes, {
Reload()
} else If (!OddCLient) {
If ((InStr(Title, "Ready to start you're game")) | (!Title)) {
WinGetTitle, Title, ahk_exe %ExeFile%
WinGetClass, ClientGuiClass, ahk_exe %ExeFile%
IniWrite %Title%, %ConfigFile%, Settings, Title
IniWrite %ClientGuiClass%, %ConfigFile%, Settings, ClientGuiClass
IniWrite % OddCLient := 1, %ConfigFile%, Settings, OddCLient
GuiControl([[ , "Title", Title], ["MoveDraw", "Pic"]])
}
}
}
; Create ClientGroup only once. The "ahk_group ClientGroup" is used by #IfWin[Not]Exist
; and #IfWin[Not]Active. All directives are loaded before ahk runs a script. Thus they
; don't understand variables. However ahk_group is supported.
if (!ClientGroup, ClientGroup := 1)
GroupAdd, ClientGroup, ahk_class %ClientGuiClass%
Hotkey, ~%hKey%, HotKeyAutoWalk, On
Return
ButtonOpenFolder:
KeyWait("LButton")
If ((GetKeyState("LControl", "P")) | (GetKeyState("RControl", "P"))) {
Run, Explorer.exe "%A_ScriptDir%"
} else {
Run, Explorer.exe "%Path%"
}
Return
DelConf:
If (FileExist(ConfigFile))
FileDelete %ConfigFile%
Reload()
Return
EndGame:
WinClose, ahk_class %ClientGuiClass%
Reload()
Return
GuiEscape:
GuiClose:
ExitApp
;_______________________________________ Script Functions _______________________________________
LoadIcons() {
Global
Loop, parse, % FileOpen(Profiles, 0).read(), `n, `r
{
if ((InStr(A_LoopField, "[",, 1, 1)) = 1) {
i += 1, SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
IniRead, Iconfile%i%, %Profiles%, %SectionName%, FullPath
IconLib[i, 1] := Iconfile%i%, IconLib[i, 2] := SectionName
}
}
i := 0, IconList := IL_Create(IconLib.Length())
LV_SetImageList(IconList)
loop % IconLib.Length()
{
IL_Add(IconList, IconLib[A_Index, 1]), LV_Add("Icon" . A_Index, , IconLib[A_Index, 2])
}
LV_ModifyCol("Hdr")
}
; Read ini file and create variables. Sections are supported.
; Referenced variables are not local to functions. So %VarRef% represents global
; variables to which some value is added %VarRef% := "ValueOfVar"
;
iniRead(InputFile, LoadSection = 0) {
if (LoadSection) {
if (IsObject(LoadSection)) { ; Load multiple sections from object
for i, Name in LoadSection
{
Loop, parse, % FileOpen(InputFile, 0).read(), `n, `r
{
if (InStr(A_Loopfield, Name)) {
SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
Continue
}
if (SectionName) {
if (((InStr(A_LoopField, "[",, 1, 1)) = 1) | ((InStr(A_LoopField, "`;",, 1, 1)) = 1) | (!A_LoopField)) {
if (((InStr(A_LoopField, "`;",, 1, 1)) = 1) | (!A_LoopField)) {
Continue
} else {
SectionName := ""
break
}
}
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1), %VarRef% := SubStr(A_LoopField, InStr(A_LoopField, "=")+1)
}
}
}
} else if (!IsObject(LoadSection)) {
if ((InStr(LoadSection, " ")) > 1) { ; Load multiple sections
Sections := []
Loop, Parse, LoadSection, " ", A_Space
Sections[A_Index] := A_Loopfield
for i, Name in Sections
{
Loop, parse, % FileOpen(InputFile, 0).read(), `n, `r
{
if (InStr(A_Loopfield, Name)) {
SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
Continue
}
if (SectionName) {
if (((InStr(A_LoopField, "[",, 1, 1)) = 1) | ((InStr(A_LoopField, "`;",, 1, 1)) = 1) | (!A_LoopField)) {
if (((InStr(A_LoopField, "`;",, 1, 1)) = 1) | (!A_LoopField)) {
Continue
} else {
SectionName := ""
break
}
}
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1), %VarRef% := SubStr(A_LoopField, InStr(A_LoopField, "=")+1)
}
}
}
} Else { ; Load single section
Loop, parse, % FileOpen(InputFile, 0).read(), `n, `r
{
if (InStr(A_Loopfield, LoadSection)) {
SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
Continue
}
If (SectionName) {
if ((InStr(A_LoopField, "[",, 1, 1)) = 1)
Break
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1), %VarRef% := SubStr(A_LoopField, InStr(A_LoopField, "=")+1)
}
}
}
}
} else if (!LoadSection) { ; Load all variables from ini
Loop, parse, % FileOpen(InputFile, 0).read(), `n, `r
{
if (((InStr(A_LoopField, "[",, 1, 1)) = 1) | ((InStr(A_LoopField, "`;",, 1, 1)) = 1) | (!A_LoopField))
Continue
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1), %VarRef% := SubStr(A_LoopField, InStr(A_LoopField, "=")+1)
}
}
Return
}
; KeyWait as a function for more flexible usage. Returns the key it waited for or ErrorLevel.
; When no parameters are used, keywait will use the value in A_ThisHotkey as the key to wait for.
;
KeyWait(Key = 0, Options = 0, ErrLvL = 0) {
keywait, % ThisKey := Key ? Key : RegExReplace(A_ThisHotkey, "[~\*\$]"), % Options
Return ErrLvL = 1 ? ErrorLevel : ThisKey
}
; Returns the last hotkey used with all basic modifiers removed from it.
ThisHotKey() {
Return RegExReplace(A_ThisHotkey, "[~\*\$]")
}
/*
GuiControl as a function for more flexible usage. Parameter ControlID can be a array.
For example, if you want to use the GuiControl command 3 times in a row.
Then the array should look something like:
ControlID := [[SubCommand, ControlID, Value], [SubCommand, ControlID], [ , ControlID, Value]]
You can also insert objects directly on the parameter for ControlID.
GuiControl([[SubCommand, ControlID, Value], [SubCommand, ControlID], [ , ControlID, Value]])
Command options. See ahk manual for details.
• (Blank): Puts new contents into the control.
• Text: Changes the text/caption of the control.
• Move: Moves and/or resizes the control.
• MoveDraw: Moves and/or resizes the control and repaints the region occupied by it.
• Focus: Sets keyboard focus to the control.
• Disable: Disables (grays out) the control.
• Enable: Enables the control.
• Hide: Hides the control.
• Show: Shows the control.
• Delete: Not yet implemented.
• Choose: Selects the specified item number in a multi-item control.
• ChooseString: Selects a item in a multi-item control whose leading part matches a string.
• Font: Changes the control's font typeface, size, color, and style.
• Options: Add or remove various control-specific or general options and styles.
*/
GuiControl(ControlID, SubCommand = 0, Value = 0) {
If (IsObject(ControlID)) {
Loop % ControlID.Length() {
GuiControl % ControlID[A_index][1], % ControlID[A_index][2], % ControlID[A_index][3]
}
} else {
GuiControl % SubCommand, % ControlID, % Value
}
Return ErrorLevel
}
; Keep track of mouse movement and left mouse button state inside the GUI.
WM_Mouse(wParam, lParam, msg, hWnd) {
Static ClsNNPrevious, ClsNNCurrent, _TT, CurrControl, PrevControl
ListLines off ; Even when globaly enabled. Best to set it off here.
; ClsNNPrevious and ClsNNCurrent will hold the same value while the mouse moves inside a control.
ClsNNPrevious := ClsNNCurrent
MouseGetPos, , , , ClsNNCurrent
ControlBelowMouse := ClsNNCurrent
; When the mouse moved from one control to the other. ClsNNPrevious and ClsNNCurrent, both hold a different value.
if (ClsNNPrevious != ClsNNCurrent)
ControlOldBelowMouse := ClsNNPrevious
if (msg = WM_MOUSEMOVE) {
If (SpyGlass = 1) {
MouseGetPos, now_x, now_y
now_x -= 75
now_y -= 75
WinMove, Magnifier, , %now_x%, %now_y%
ToolTip % now_x " " now_y
}
if (!TipsOff) {
CurrControl := A_GuiControl
if ((ClsNNPrevious != ClsNNCurrent) & (!InStr(CurrControl, " "))) {
ToolTip ; Turn off any previous tooltip.
SetTimer, DisplayToolTip, 750
PrevControl := CurrControl
}
return
DisplayToolTip:
SetTimer, DisplayToolTip, Off
ToolTip % %CurrControl%_TT ; The leading percent sign tell it to use an expression.
SetTimer, RemoveToolTip, 5000
return
RemoveToolTip:
SetTimer, RemoveToolTip, Off
ToolTip
return
}
}
if (msg = Wm_LbuttonDown) {
SetTimer, RemoveToolTip, Off
ToolTip
; When some control under the mouse is a Edit control and the script is not already getting a key.
If ((InputActive = 0) & (InputActive := InStr(ControlBelowMouse, "Edit"))) {
GuiControlGet, IsControlOn, Enabled, %ControlBelowMouse%
; Ignore the windows used by autohotkey for ListVars, ListLines and so on.
If (WinGetActiveTitle() != "AutoWalk")
Return
; And when this control is not disabled.
If (IsControlOn = 1) {
; store it's text and give the control input focus (actually it's the other way around, hehe).
ControlFocus, %ControlBelowMouse%
ControlGetText, ctrlTxt, %ControlBelowMouse%
; Briefly enable this control to call function EditGetKey when it recieves some input.
GuiControl([["+gEditGetKey", ControlBelowMouse], [ , ControlBelowMouse], ["-gEditGetKey", ControlBelowMouse]])
} else {
InputActive := 0
}
}
if ((GetKeyState("LButton", "P")) & (!A_GuiControl)) {
PostMessage, Wm_DraggGui
}
Return
}
if (msg = Wm_DraggGui) {
if ((GetKeyState("LButton", "P")) & (!A_GuiControl)) {
FadeInOut(hScriptGui, 1)
PostMessage, WM_NCLBUTTONDOWN, 2
KeyWait("LButton")
FadeInOut(hScriptGui)
}
Return
}
}
WinGetActiveTitle() {
WinGetActiveTitle OutputVar
Return OutputVar
}
; Write back the name of any keyboard, mouse or joystick button to a edit control.
EditGetKey() {
static InputKeys := ["LButton", "RButton", "MButton", "XButton1", "XButton2", "Numpad0", "Numpad1", "Numpad2", "Numpad3", "Numpad4", "Numpad5", "Numpad6", "Numpad7", "Numpad8", "Numpad9","Numpad10","NumpadEnter", "NumpadAdd", "NumpadSub","NumpadMult", "NumpadDev", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Left", "Right", "Up", "Down", "Home","End", "PgUp", "PgDn", "Del", "Ins", "Capslock", "Numlock", "PrintScreen", "Pause", "LControl", "RControl", "LAlt", "RAlt", "LShift","RShift", "LWin", "RWin", "AppsKey", "BackSpace", "space", "Tab", "Esc", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N","O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "/", "[", "]", "\", "'", ";", "` ","Joy1", "Joy2", "Joy3", "Joy4", "Joy5", "Joy6", "Joy7", "Joy8", "Joy9", "Joy10", "Joy11", "Joy12", "Joy13", "Joy14", "Joy15", "Joy16", "Joy17","Joy18", "Joy19", "Joy20", "Joy21", "Joy22", "Joy23", "Joy24", "Joy25", "Joy26", "Joy27", "Joy28", "Joy29", "Joy30","Joy31", "Joy32"]
KeyWait("LButton")
; Prevent a right click from showing the context menu.
Hotkey, IfWinExist, AutoWalk
Hotkey, Vk02 Up, RbttnUp, On ; Vk02 = RButton
; Loop untill the user pressed some button or as long as the mouse is over some edit box.
Critical
loop {
; Getting user input from array Inputkeys.
For k, ThisKey in InputKeys {
if (GetKeyState(ThisKey, "P")) {
GuiControl(ControlBelowMouse, "", ThisKey)
ExitLoop := KeyWait(ThisKey)
Break
}
; When ControlBelowMouse does not contain the word "Edit". Then the mouse moved away from the control.
If (!InStr(ControlBelowMouse, "Edit") & InStr(ControlOldBelowMouse, "Edit")) {
ExitLoop := 1
GuiControl(ControlOldBelowMouse, "", ctrlTxt)
ControlFocus, %ControlBelowMouse%
Break
}
}
If (ExitLoop)
break
}
Critical Off
ControlFocus, Button2
GUI, submit, nohide
; Save new values to Settings.ini if the For loop didn't break when the mouse moved outside the control.
If (ExitLoop != 1)
IniWrite, %ThisKey%, %ConfigFile%, Settings, %A_GuiControl%
RbttnUp:
Hotkey, IfWinExist, AutoWalk
Hotkey, Vk02 Up, RbttnUp, Off
InputActive := 0
Return
}
; Send some key on a sinlge or double press of a button.
; The hotkey is optional and when ThisHotKey is empty Keywait() will return the last hokey used.
; This function can be used with the UserCode.ahk file e.g.:
; Below code would send A when F is pressed once. And B when F is pressed twice
; F::
; ButtonSingleDouble("A", "B")
; Return
;
; And this will send B when you double click the right mouse button
; ~RButton::
; ButtonSingleDouble("", "B")
; Return
;
ButtonSingleDouble(KeySingle, KeyDouble, ThisHotKey = 0, WaitRelease = 0) {
if (WaitRelease) {
Send {%KeySingle% Down}
A_hotKey := ThisHotKey ? keywait(ThisHotKey) : keywait()
Send {%KeySingle% Up}
if (keywait(A_hotKey, "D T0.1", 1) = 0) {
Send {%KeyDouble% Down}
KeyWait(A_hotKey)
Send {%KeyDouble% Up}
}
} else if (!WaitRelease) {
A_hotKey := ThisHotKey ? keywait(ThisHotKey) : keywait()
if (keywait(A_hotKey, "D T0.1", 1) = 0) {
Send {%KeyDouble% Down}{%KeyDouble% Up}
} else {
Send {%KeySingle% Down}{%KeySingle% Up}
}
}
Return
}
; Automaticly turn the ingame camera to follow the player when some key is down.
AutoTurnCamera(KeyDown, RotateL, RotateR, VirtualKey = 0, DownPeriod = 40, DeadZone = 35) {
Static Rad := 180 / 3.1415926
; The width and hight of the client gui might change in between calls, so getting them here.
WinGetPos, , ,gW, gH, A
; Check mouse position and turns the camera when the mouse moved outside a deadszone while the key in KeyDown has status Down.
; By default the physical key state is monitored. Set parameter VirtualKey to 1 to check the logical key state. Logical is when
; a key is send Down by the send command or in some other way.
;
While(GetKeyState(KeyDown, (!VirtualKey ? "P" : ""))) {
MouseGetPos, mX, mY
; Calculate cursor position, where the vertical/horizontal centre of the display are seen as zero. Both the left and right side
; of the display are seen as positive (Abs). A triangle (ATan) of 70 degrees (35*2) is created from the very centre to the top/bottom.
; These triangles will be the dead zone, where the camera does not turn.
;
if (((((X := mX - gW/2) * mX) + ((Y := gH/2 - mY) * mY) < 10000) | (Y > 0)) & ((Abs(ATan(X/Y)) * Rad) < DeadZone)) {
continue
}
; Turn the ingame camera left or right when the mouse moved outside the deadzone.
; I advice to make the value in DownPeriod not greater then the 50ms sleep. If you do,
; then also increase the sleep period to somthing greater then the down perdiod.
; This will result in a smoother turning of the camera.
;
if (X < 0) {
Send {%RotateL% Down}
Sleep, %DownPeriod%
Send {%RotateL% Up}
} else {
Send {%RotateR% Down}
Sleep, %DownPeriod%
Send {%RotateR% Up}
}
sleep 50
}
Return
}
; Fade transparency out or in while dragging the Gui.
FadeInOut(hWnd, dragg = 0) {
static Transparency := 250
if (dragg = 1) {
Loop {
If (A_TickCount >= WaitNextTick) {
WaitNextTick := A_TickCount+50
WinSet, Transparent, % Transparency -= 20, ahk_id %hWnd%
If (Transparency <= 210)
break
}
}
} else if (dragg = 0) {
Loop {
If (A_TickCount >= WaitNextTick) {
WaitNextTick := A_TickCount+50
WinSet, Transparent, % Transparency += 20, ahk_id %hWnd%
If (Transparency >= 255) {
WinSet, Transparent, Off, ahk_id %hWnd%
break
}
}
}
}
return
}
; Not mine, but borrowed from the ahk manual.
SystemCursor(OnOff=1) ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others
{
static AndMask, XorMask, $, h_cursor
, c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; system cursors
, b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13 ; blank cursors
, h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13 ; handles of default cursors
if (OnOff = "Init" or OnOff = "I" or $ = "") ; init when requested or at first call
{
$ := "h" ; active default cursors
VarSetCapacity( h_cursor,4444, 1 )
VarSetCapacity( AndMask, 32*4, 0xFF )
VarSetCapacity( XorMask, 32*4, 0 )
system_cursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650"
StringSplit c, system_cursors, `,
Loop %c0%
{
h_cursor := DllCall( "LoadCursor", "Ptr",0, "Ptr",c%A_Index% )
h%A_Index% := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 )
b%A_Index% := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int",0
, "Int",32, "Int",32, "Ptr",&AndMask, "Ptr",&XorMask )
}
}
if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
$ := "b" ; use blank cursors
else
$ := "h" ; use the saved cursors
Loop %c0%
{
h_cursor := DllCall( "CopyImage", "Ptr",%$%%A_Index%, "UInt",2, "Int",0, "Int",0, "UInt",0 )
DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt",c%A_Index% )
}
}
; Reload and below exit, the script without calling function SaveSettings() first.
; Also handy because functions can be called from shorthand operators like "?".
Reload() {
OnExit("SaveSettings", 0)
Reload
}
ExitApp() {
OnExit("SaveSettings", 0)
ExitApp
}
; This is called right before the script terminates. It saves the position of the GUI and copies
; all current variables from the settings.ini to \GameProfiles\GamesConfig.ini.
; GamesConfig.ini contains all variables from the previous used games.
SaveSettings() {
WinGetPos, Gui_X, Gui_Y, ,, AutoWalk
; Remember the position of the script GUI.
if ((Gui_X > -1) & (Gui_Y > -1)) {
IniWrite, %Gui_X%, %ConfigFile%, Settings, Gui_X
IniWrite, %Gui_Y%, %ConfigFile%, Settings, Gui_Y
}
if (Title) {
If (!FileExist(Profiles)) {
FileCreateDir, GameProfiles
FileAppend,, %Profiles%
}
If (Title != "Ready to start you're game") {
Loop, parse, % FileOpen(ConfigFile, 0).read(), `n, `r
{
if (InStr(A_Loopfield, "[")) {
SectionName := StrReplace(A_Loopfield, "["), SectionName := StrReplace(SectionName, "]")
IniDelete, %Profiles%, %Title%
FileAppend, % "[" Title "]", %Profiles%
}
Else If (SectionName && A_LoopField) {
VarRef := SubStr(A_LoopField, 1, InStr(A_LoopField, "=")-1)
IniWrite, % %VarRef%, %Profiles%, %Title%, %VarRef%
}
}
}
}
}