Spelunky v1.1 Trainer Tutorial Using AutoIt

This tutorial will show how to make a trainer for Spelunky v1.1 using the cheats from the Spelunky v1.1 Game Cheating Tutorial. The trainer is created using AutoIt v3.3.8.0. I had to modify the NomadMemory.au3 to work correctly with the new version of AutoIt, and have included it below.

The trainer uses the cheats as buttons - when clicked it will change the item value to 99 and freeze the value, if clicked again it will unfreeze the value.

The finished trainer is only 312 KB in size, and VirusScan.Jotti.org reports 0 false-positives for a virus (from 20 virus scanners). So no problems with users getting a false-positive virus warning.

Spelunky Tutorial - Part 4 of 5
  1. Game Cheating Tutorial
  2. GTS Trainer Tutorial
  3. Cheat Engine Trainer Tutorial
  4. AutoIt Trainer Tutorial
  5. FreeBASIC Trainer Tutorial

Programs Needed
To do this tutorial you will need --

Getting Started
For anyone that gets stuck in this tutorial, I have put the finished AutoIt trainer script online. Simply download my Spelunky +3 Trainer script and copy to a folder that has my modified NomadMemory.au3 script. To use just load the trainer script in SciTE.

If you haven't already installed the freeware programming scripting language AutoIt, install it now.

Here is the completed Spelunky AutoIt trainer code, just copy and paste into SciTE -- or you can also download the trainer script. Don't forget to download my modified NomadMemory.au3 file as well, placing both into the same folder.

Once you have the AutoIt trainer code you can follow the tutorial much easier, and not worry about copying the various codes (as it will be likely put into SciTE in the wrong places).
;Spelunky v1.1 game trainer
;Created by t2Eservo
;-------------------------------------------------------
;Part of my tutorials on my website, read it and more at
;http://t2eservo.blogspot.com

#include <NomadMemory.au3>       ;Advanced memory functions
#include <ButtonConstants.au3>   ;Used by GUI buttons
#include <GUIConstantsEx.au3>    ;Used by the trainer GUI
#Include <Timers.au3>           
;Timer delay functions
#include <WindowsConstants.au3>  ;Used by the trainer GUI
#RequireAdmin                      
;Give the trainer administrator rights
SetPrivilege("SeDebugPrivilege", 1) ;Ensure the trainer has administrator rights

$Form1 = GUICreate("Spelunky +3 Trainer", 125, 175, @DesktopWidth / 2 - 62, @DesktopHeight / 2 - 87) ;Create window with name and center
$Button1 = GUICtrlCreateButton("Bomb Max (Off)", 16, 18, 92, 44)                                    
;Create Bomb button
$Button2 = GUICtrlCreateButton("Health Max (Off)", 16, 66, 92, 44)                                  
;Create Health button
$Button3 = GUICtrlCreateButton("Rope Max (Off)", 16, 114, 92, 44)                                   
;Create Rope button

$process = "Spelunky.exe" ;The game name we want to cheat on
$button1status = 0        ;Button1 status if the button is On (True) 1 or Off (False) 0
$button2status = 0        ;Button1 status if the button is On (True) 1 or Off (False) 0
$button3status = 0        ;Button1 status if the button is On (True) 1 or Off (False) 0
$pid = 0                 
;Set game PID to 0

GUISetState(@SW_SHOW)      ;Show trainer window
$timedelay = _Timer_Init() ;Start delay timer

While 1                                                        
;Trainer loop
    $nMsg = GUIGetMsg()                                        
;Get which button is clicked if any
    Switch $nMsg                                               
;Check buttons
        Case $GUI_EVENT_CLOSE                                  
;Window X button clicked so exit
            Exit                                               
;Quit the trainer
        Case $Button1                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button1status Then                          
;Button is True (on) so turn it off
                  
$button1status = 0                          
;Change status to False
                  
GUICtrlSetData($Button1, "Bomb Max (Off)")   ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button1status = 1                          
;Change status to True
                  
GUICtrlSetData($Button1, "Bomb Max (On)")    ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf
        Case $Button2                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button2status Then                          
;Button is True (on) so turn it off
                  
$button2status = 0                          
;Change status to False
                  
GUICtrlSetData($Button2, "Health Max (Off)") ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button2status = 1                          
;Change status to True
                  
GUICtrlSetData($Button2, "Health Max (On)")  ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf
        Case $Button3                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button3status Then                          
;Button is True (on) so turn it off
                  
$button3status = 0                          
;Change status to False
                  
GUICtrlSetData($Button3, "Rope Max (Off)")   ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button3status = 1                          
;Change status to True
                  
GUICtrlSetData($Button3, "Rope Max (On)")    ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf
    EndSwitch

    If $pid = 0 And _Timer_Diff($timedelay) > 250 Then           
;Check if PID not found yet, and delay is more than 250 milliseconds
        $pid = ProcessExists($process)                           
;If game exists get the PID
        If $pid > 0 Then                                         
;Game exist?
            $hwnd = _MemoryOpen($pid)                            
;Opens a process and enables all possible access rights to the process
            $BaseAddr = _MemoryGetBaseAddress($hwnd, 1)          
;Base address of the game usually 400000(hex) so we can use "Spelunky.exe"+18F124
        EndIf
        $timedelay = _Timer_Init()                               
;Reset delay timer
    ElseIf $pid > 0 And _Timer_Diff($timedelay) > 250 Then       
;Check if PID found and delay is more than 250 milliseconds
        If $button1status Then                                   
;Bomb Cheat ------------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9176                            
;Address to write to -- Pointer read + 23D8 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        If $button2status Then                                   
;Health Cheat ----------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9136                            
;Address to write to -- Pointer read + 23B0 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        If $button3status Then                                   
;Rope Cheat ------------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9216                            
;Address to write to -- Pointer read + 2400 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        $timedelay = _Timer_Init()                               
;Reset delay timer
    EndIf
WEnd


Start up the AutoIt included editor SciTE. You will be greeted with a empty script, or any you had open previously. Load my trainer script, or paste the trainer code from above into the blank script.

The typical first step is to start Koda (FormDesigner) from SciTE to create the GUI, graphic user interface - which is the trainer window and buttons.

To start Koda (FormDesigner) go to the SciTE menu Tools, and select Koda (FormDesigner), or press the keys ALT M. I have however already built the simple trainer GUI, so we will use that code.

Code
;Spelunky v1.1 game trainer
;Created by t2Eservo
;-------------------------------------------------------
;Part of my tutorials on my website, read it and more at
;http://t2eservo.blogspot.com

#include <NomadMemory.au3>       ;Advanced memory functions
#include <ButtonConstants.au3>   ;Used by GUI buttons
#include <GUIConstantsEx.au3>    ;Used by the trainer GUI
#Include <Timers.au3>           
;Timer delay functions
#include <WindowsConstants.au3>  ;Used by the trainer GUI
#RequireAdmin                      
;Give the trainer administrator rights
SetPrivilege("SeDebugPrivilege", 1) ;Ensure the trainer has administrator rights


The first section of code with the semi-colons ; is the comment section. Which is used to hold any notes about the program (author, link, description, etc).

Following that the lines that start with #include are to include other program code into the trainer. This allows adding functions much easier, and are the libraries used by the trainer.

The remaining two lines set the permission/privilege level that is given to the trainer. The highest level is given to ensure that the trainer can change the game memory as needed.

Next is the trainer GUI, which is the code to show the buttons and trainer window itself.

Trainer GUI
Code
$Form1 = GUICreate("Spelunky +3 Trainer", 125, 175, @DesktopWidth / 2 - 62, @DesktopHeight / 2 - 87) ;Create window with name and center
$Button1 = GUICtrlCreateButton("Bomb Max (Off)", 16, 18, 92, 44)                                    
;Create Bomb button
$Button2 = GUICtrlCreateButton("Health Max (Off)", 16, 66, 92, 44)                                  
;Create Health button
$Button3 = GUICtrlCreateButton("Rope Max (Off)", 16, 114, 92, 44)                                   
;Create Rope button


$Form1 is the code for the trainer window itself. It creates a window 125 pixels wide, and 175 pixels tall. The window text caption is Spelunky +3 Trainer.

The code @DesktopWidth / 2 - 62, @DesktopHeight / 2 - 87 centers the window on any size screen. It does so by finding the screen width, @DesktopWidth, and dividing it by 2 to get the center pixel width location. Then that number is subtracted by half of the trainer window's width (125 / 2 = 62). The same is done for the screen height.

The next three lines of the code add the three cheat buttons. The button text captions are set, and the first two numbers set where the button will be placed in the window (left pixel, and top pixel respectively). The last two numbers set the button size of 92 pixels wide, and 44 pixels tall.

The next set of code will set the main program loop. Once this code has been added you can test the trainer; however, the buttons will not affect anything.

Code
GUISetState(@SW_SHOW)      ;Show trainer window
$timedelay = _Timer_Init() ;Start delay timer

While 1                                                        
;Trainer loop
    $nMsg = GUIGetMsg()                                        
;Get which button is clicked if any
    Switch $nMsg                                               
;Check buttons
        Case $GUI_EVENT_CLOSE                                  
;Window X button clicked so exit
            Exit                                               
;Quit the trainer
    EndSwitch
WEnd


GUISetState(@SW_SHOW) will show the trainer window once the program is run.

$timedelay = _Timer_Init() holds the current time-stamp so we can delay the trainer once it is running. I use a 250 millisecond delay between cheat updates, freezing the values.

The delay will make the trainer much more friendly - With the delay it uses 2 to 4% of the CPU, instead of nearly 40% of the CPU without a delay.

The While 1 ... WEnd code is the main program loop. It will continue this loop forever so the next few codes tell it when to exit.

$nMsg = GUIGetMsg() checks to see if any of the GUI has been changed (clicked, key presses, etc.)

Switch $nMsg ... EndSwitch code block is where we add the code to make the trainer respond when a button is clicked.

Case $GUI_EVENT_CLOSE is the code for what to do when the user clicks the top-right X in the window. The following code line tells the trainer to exit, once the X is clicked.

The next code block is to program the cheat buttons for On/Off functionality, and is the main trainer loop.

Trainer Loop
Code
        Case $Button1                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button1status Then                          
;Button is True (on) so turn it off
                  
$button1status = 0                          
;Change status to False
                  
GUICtrlSetData($Button1, "Bomb Max (Off)")   ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button1status = 1                          
;Change status to True
                  
GUICtrlSetData($Button1, "Bomb Max (On)")    ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf
        Case $Button2                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button2status Then                          
;Button is True (on) so turn it off
                  
$button2status = 0                          
;Change status to False
                  
GUICtrlSetData($Button2, "Health Max (Off)") ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button2status = 1                          
;Change status to True
                  
GUICtrlSetData($Button2, "Health Max (On)")  ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf
        Case $Button3                                          
;Button was clicked
            If $pid > 0 Then                                   
;Check if game is loaded
              
If $button3status Then                          
;Button is True (on) so turn it off
                  
$button3status = 0                          
;Change status to False
                  
GUICtrlSetData($Button3, "Rope Max (Off)")   ;Update the button text
              
Else                                            
;Button is False (off) so turn it on
                  
$button3status = 1                          
;Change status to True
                  
GUICtrlSetData($Button3, "Rope Max (On)")    ;Update the button text
              
EndIf
            Else
              
Beep(500, 500)                                  
;Game not loaded so beep as the cheat can not be used
            EndIf


The code includes all three buttons, but each button code is nearly the same so I will only walk you through the first button.

Case $Button1 is to check if the user clicked the button, if they did the trainer will do the following code lines.

If $pid > 0 Then code is to check that the game Spelunky is loaded. If the game is loaded it will change the button status and text caption.

If $button1status Then checks if the button is already On, and if it is on it will run the next code to switch it Off.

$button1status = 0 updates the button status to turn it Off. GUICtrlSetData($Button1, "Bomb Max (Off)") changes the $Button1 text caption.

Else tells the trainer to run the code to switch the button On, as it is currently Off.

$button1status = 1 updates the button status to turn it On. GUICtrlSetData($Button1, "Bomb Max (On)") changes the $Button1 text caption. The following EndIf is the end of one If code section.

Else tells the trainer the game is not loaded and do the next code.

Beep(500, 500) will make the trainer beep, telling the user the cheat is not activated (as the game is not loaded). The following EndIf is the end of one If code section, and the end of the $Button1 code.

The rest of the code is for the other two buttons and is the same, of course using different text and variables for the appropriate buttons.

The next code is the last of the AutoIt code and is what actually makes the trainer buttons give the game cheats.

Memory Read/Write
Code
    If $pid = 0 And _Timer_Diff($timedelay) > 250 Then           
;Check if PID not found yet, and delay is more than 250 milliseconds
        $pid = ProcessExists($process)                           
;If game exists get the PID
        If $pid > 0 Then                                         
;Game exist?
            $hwnd = _MemoryOpen($pid)                            
;Opens a process and enables all possible access rights to the process
            $BaseAddr = _MemoryGetBaseAddress($hwnd, 1)          
;Base address of the game usually 400000(hex) so we can use "Spelunky.exe"+18F124
        EndIf
        $timedelay = _Timer_Init()                               
;Reset delay timer
    ElseIf $pid > 0 And _Timer_Diff($timedelay) > 250 Then       
;Check if PID found and delay is more than 250 milliseconds
        If $button1status Then                                   
;Bomb Cheat ------------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9176                            
;Address to write to -- Pointer read + 23D8 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        If $button2status Then                                   
;Health Cheat ----------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9136                            
;Address to write to -- Pointer read + 23B0 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        If $button3status Then                                   
;Rope Cheat ------------------------------------------------
            $Static = "0x" & Hex($BaseAddr + 1634596)            
;Base address (usually 400000) + 18F124 (Pointer in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Static pointer address
            $Static = "0x" & Hex($Pointer + 4)                   
;Pointer + offset (in decimal)
            $Pointer = _MemoryRead($Static, $hwnd, 'dword')      
;Address pointer points to
            $Static = $Pointer + 9216                            
;Address to write to -- Pointer read + 2400 (offset in decimal)
            $Value = _MemoryWrite($Static, $hwnd, "99", 'double') ;Write decimal value 99 as a double value
        EndIf
        $timedelay = _Timer_Init()                               
;Reset delay timer
    EndIf


If $pid = 0 And _Timer_Diff($timedelay) > 250 Then code checks to make sure the game has not been loaded and that at least 250 milliseconds have passed since the last time the trainer was here.

$pid = ProcessExists($process) gets the Windows PID for the game if it is loaded.

If $pid > 0 Then checks if the game is loaded, and if loaded do the following two code lines.

$hwnd = _MemoryOpen($pid) opens the game process and gives the trainer all possible rights to it. The variable $hwnd is an array that is created, and has the information needed to change the game memory.

$BaseAddr = _MemoryGetBaseAddress($hwnd, 1) returns the base address of where the game is loaded into memory in decimal format. This is most often 4194304 or 400000 (HEX), but can change.

This function is what gives a programming language like AutoIt or the program Cheat Engine so much power when creating trainers - even if the program is loaded differently in memory the trainer will still work.

EndIf ends the If code block when the game is loaded. $timedelay = _Timer_Init() updates the timer delay to the new time.

ElseIf $pid > 0 And _Timer_Diff($timedelay) > 250 Then is the start of the memory cheats. The code ensures the game is loaded and the trainer has not updated the cheats in the last 250 milliseconds.

If $button1status Then ... EndIf checks that the first button is turned On, if so it will do the cheat for bombs. The cheat which is to update the bomb amount to 99 and will do so every 250 milliseconds freezing the value.

$Static = "0x" & Hex($BaseAddr + 1634596) this code creates the static address of the cheat pointer for bombs. It adds the decimal $BaseAddr for the game to the decimal offset of the original HEX of 0018F124. In other words this is doing the same Cheat Engine code as "Spelunky.exe"+0018F124.

The variable $Static will then hold the static address of the pointer which will probably be 58F124 (HEX).

To get the decimal offset simply enter the original offset in the Windows calculator, ensure it is set in HEX mode. Once the offset 18F124 is entered select the DEC option to convert it into decimal, which is 1634596.

A easy way to use the calculator is to CTRL+V paste the HEX into it, convert it, and then CTRL+C to copy the answer.

If you don't feel like converting the HEX numbers into decimal you could simply add a Dec("") code around it in AutoIt. For example 1634596 is the same as Dec("18F124") inside AutoIt; however, the Dec("") function requires more time and resources as it has to run another function to convert the numbers. So the function is repeated 4 times each second for each cheat line it is used in. I opted to simply convert it myself and help optimize the code.

$Pointer = _MemoryRead($Static, $hwnd, 'dword') code will read from the address that was specified in the $Static code - example 58F124 (HEX). This saves the level 1 pointer address to the variable $Pointer as a decimal - example is 39671424 (decimal).

$Static = "0x" & Hex($Pointer + 4) take the $Pointer value and adds the first offset 4, and turn it into HEX. Example take 39671424 + 4 = 39671428 converted 25D5684 (HEX).

$Pointer = _MemoryRead($Static, $hwnd, 'dword') code will read from the address that was specified in the $Static code - example  25D5684 (HEX).  This saves the level 2 pointer address to the variable $Pointer as a decimal - example is 185966808 (decimal).

$Static = $Pointer + 9176 takes the level 2 pointer address and adds the decimal offset 9176, or 23D8 (HEX). The example is 185975984 decimal, or B15C4B0 (HEX). This is the address where the value of the players bombs are stored in Spelunky (in Double format).

$Value = _MemoryWrite($Static, $hwnd, "99", 'double') this will write the decimal value of 99 in double format in the game memory address where the pointer points to. In the example it will write 99 as 0000000000C05840 (a double) into the address 185975984 decimal, or B15C4B0 (HEX).

That finishes the first cheat for the bombs, and is followed by the code for the other two cheat buttons. That code is the same as the previous except it has the appropriate button names, and the last offsets for both are different.

$timedelay = _Timer_Init() code is the last of the trainer, besides closing EndIf and WEnd statements. The code will update the timer delay with the current time.

Try out the trainer by loading the Spelunky game. Switch to SciTE and press F5, or menu Tools and Go menu - this will load/test the trainer. The trainer must be saved before it can be used, so be sure to save it.

Compile
The trainer coding is finished and you need to turn the code into a actual program, an EXE. The program needs to be saved first if it hasn't been already. Save it using the menu or the save icon image.

To compile the program use the menu Tools and Build menu, or press F7.

If you want to specify a trainer icon, or any other EXE or AutoIt settings for your program you can in the compile options. That is accessed from the menu Tools and Compile, or pressing CTRL+F7.

Finished Trainer
The completed trainer is saved in the the same folder as the trainer script, or if you specified another directory it will be there.

If you want to know how to create this trainer using other programs, view the links in the Spelunky Tutorial section near the beginning of this page.

0 comments:

Post a Comment