Bypass timers for endless splashing in OSRS with AutoIt

Learn how to make an AutoIt script to bypass timeout and keep your character splashing in Old School Runescape.

Article contents

Introduction to splashing
Requirements and design
Starting out
Building the GUI
Exit function & keeping the script running
Tooltip & format time functions
Random numbers & moving the camera
Defining the behaviour
Hotkeys & idling on start
Testing & conclusion
Script code snippet

Introduction to splashing

Splashing is a method of magic skill training in Old School RuneScape (OSRS). Splashing means auto-attacking a weak enemy with spells that constantly fail, or ‘splash’. The player character will gain experience points on every spell cast, even if the spell itself fails to land, while the enemy will never actually die. This is a popular training method because it requires minimal user input.

However, the game developers have implemented mechanisms to restrict players from going AFK for too long; without user input the player character will stop fighting back after about 20 minutes, and will log out shortly after. So, to keep their character fighting and gaining XP the player has to interact with the game regularily, approximately once every 20 minutes. These timers can be circumvented easily with an AutoIt script.

Requirements and design

Before we begin building the script we’ll define what features are required and what the script has to be able to achieve. I’ve added a “design specification” section after the requirements which try to explain the planned features and software logic a bit further.

Required script features:

  • Interaction with the game client in user defined intervals
  • Random interaction intervals instead of fixed time intervals
  • Option for user defined time limit
  • GUI for user defined settings
  • GUI needs to have simple instructions on how to use the script
  • Keyboard hotkeys to run, stop and exit the script
  • A way to view script progress while script is running (at least: time ran, time left, interaction count)

Script design specification based on the requirements:

  • Graphical user interface
    • Text field for minimum and maximum interval (minutes)
    • Text field for time limit (minutes)
    • Instructions including description of behavior, infinite time limit, hotkeys
  • No time limit when limit is set as 0
  • Hotkey F9 to start script, F10 to stop, ESC to exit program
  • Move camera at random intervals between min and max values by pressing random arrow keys
  • Arrow key press-down time is randomized
  • Tooltip when script is running showing the following information:
    • script name, script status
    • camera movement count
    • countdown to next camera movement
    • time ran, time limit
    • countdown to time limit (time left)
  • Tooltip times are formatted to show seconds, minutes and hours appropriately
  • Stop camera movements when time limit is exceeded
  • Show tooltip after time limit is exceeded: status, camera movements, time ran, time limit, time ended
  • Game window needs to be active for script to function; sending commands to in-active window not supported

Starting out

Note: You need to have AutoIt installed on your system to run AutoIt scripts.

First, we create a new file and name it SplashBypass.au3 (AutoIt script file), and open it in a text editor. Notepad++ works well because it supports syntax highlighting for AutoIt code.

At the top of our script file we import the needed AutoIt libraries and also store our script name in a global variable:

#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <Date.au3>
$scriptName = "SplashBypass"

Building the GUI

Building graphical user interfaces in AutoIt can be a bit clumsy. We’ll need 3 main settings which we can tweak using the GUI: the minimum and maximum time between camera movements, and a time limit after which the script will stop. Here’s the code for the whole GUI with all the needed features and the instructions:

GUICreate($scriptName, 450, 120)
Opt("GUICoordMode",1)
GUICtrlCreateGroup("Settings", 10, 5, 155, 90)

GUICtrlCreateLabel("Min interval:", 20, 23, 60, 20)
$minInterval = GUICtrlCreateInput ("10", 85, 19, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 23, 40, 20)

GUICtrlCreateLabel("Max interval:", 20, 45, 60, 20)
$maxInterval = GUICtrlCreateInput ("20", 85, 41, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 45, 40, 20)

GUICtrlCreateLabel("Stop after:", 20, 68, 60, 20)
$stopAfterMins = GUICtrlCreateInput ("60", 85, 64, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 68, 40, 20)

GUICtrlCreateGroup("Instructions", 170, 5, 250, 90)
GUICtrlCreateLabel("• Script moves cam between min/max intervals" & @CRLF & "• Cam is moved by pressing random arrow keys" & @CRLF & "• Enter 0 to time limit for infinite loop" & @CRLF & "• Press F9 to start, F10 to stop" & @CRLF & "• Press ESC to exit program" , 180, 22, 230, 70)

GUISetState()

We’ve defined 3 global variables which we’ll be using later in the script: minInterval, maxInterval and stopAfterMins. These are text fields in the GUI to which we can input our desired values when the script is done. The GUI elements use absolute positioning; Opt(“GUICoordMode”,1). Most of the GUI elements have 5 values given to them as parameters: content, xPos, yPos, width, height. This is how the GUI will look like once the script is finished and starts properly:

Exit function & keeping the script running

Next, we will need to define an exit function and an idle function with an endless while loop to keep the script (and the GUI) running instead of running only once and then exiting. At the moment we don’t need to read the user defined data from the GUI.

Func exitScript()
	msgbox (0,$scriptName, "Exiting...",0.30) ;show message box briefly for responsive feel
	exit
EndFunc

Func idle()
	While 1	;endless while loop to keep program running		
		Switch GUIGetMsg() 
			Case $GUI_EVENT_CLOSE ;if program is closed with red x
				exitScript()	
		EndSwitch
		sleep(40)	
	WEnd
EndFunc

The above code includes comments. Lines or text starting with a semicolon (;) are interpreted as comments in AutoIt and are ignored when the script is executed. Code snippets coming later in this tutorial will include comments as well.

Tooltip & format time functions

Next, we will define a small function to show a tooltip at a fixed position on the screen. The tooltip will be used to display information on the running script, such as time ran and how many interactions the script has performed so far. The tooltip function uses a parameter to define the contents of the tooltip. We use the script name as a title for the tooltip. We could use whatever position we want by changing the coordinate arguments, but as of now we use 10 and 100 to show the tooltip in the left side of screen.

Func showTooltip($str)
	ToolTip($str, 10, 100, $scriptName)
EndFunc

As most time values in AutoIt are handled as milliseconds, we need to define a function to format milliseconds to seconds, minutes and hours. This function is utilized when displaying the various timers on the tooltip. We define a formatMs function which accepts an argument (the parameter ms) and returns the appropriately formatted time:

Func formatMs($ms)
	$seconds = Round($ms/1000, 0) 
	$minutes =  Round($seconds/60, 0)
	$hours = Round($minutes/60, 0)
	If $seconds < 60 Then 
		return $seconds & " sec"
	ElseIf $minutes < 60 Then
		$remSec =  Mod($seconds,60)
		return $minutes & "min " & $remSec & "sec"
	Else 
		$remMin =  Mod($minutes,60)
		return $hours & "h " & $remMin & "min"
	EndIf
EndFunc

The formatMs function follows these rules:

  • If time is less than 60 seconds, show only seconds
  • If time is less than 60 minutes, show minutes and seconds
  • If time is 60 minutes or more, show hours and minutes

The formatMs function takes advantage of AutoIt’s Mod function, which performs the modulus operation on the 2 parameter values. With the Mod function we can calculate the whole minutes and hours, and show the remainder correctly.

Random numbers & moving the camera

We need to define a simple random number generator function which accepts the minimum and maximum output values as arguments, and returns a random integer between the arguments. Now we will also define the camera movement function which presses random arrow keys to move the game client camera. We define ranNum and and moveCamera functions as follows:

Func ranNum($min, $max)
	Return Random ($min, $max, 1) 
EndFunc

Func moveCamera()
	Local $arrowKey
	Switch ranNum(1,4)
		Case 1
			$arrowKey = "{UP}"
		Case 2
			$arrowKey = "{DOWN}"	
		Case 3
			$arrowKey = "{LEFT}"
		Case 4
			$arrowKey = "{RIGHT}"
	EndSwitch	
	Opt("SendKeyDownDelay", ranNum(50,400)) 	
	Send($arrowKey)
EndFunc

The moveCamera function uses the ranNum function to decide which arrow key to press. The ranNum function is also used to randomize the time to keep the key pressed. The keys need to be pressed briefly, so we use a value between 50 and 400 milliseconds. Finally the moveCamera function presses the arrow key using AutoIt’s Send function.

Defining the behaviour

We are doing fine with the script so far, but we still need to define its actual behaviour; when to move the camera, what to show on tooltip, when to stop. The general behaviour of the script can be broken down into the following:

  • Read user defined data from the GUI, convert minutes to milliseconds
  • Start 2 timers: one for action interval, one for the defined time limit
  • Generate 1st action interval
  • Enter the main loop:
    • calculate times
    • if action timer exceeded: move cam, reset action timer, get new action interval, increment action count
    • update tooltip
    • if time limit is not infinite, exit loop when time limit exceeded
    • sleep 2 seconds
    • repeat until time limit is exceeded or script is closed
  • Show tooltip after ending the script
  • Call idle function to return to idling state

With all that being said we go ahead and define our main function called splash as follows:

Func splash()	
	;read data from GUI and convert to milliseconds
	$minIntervalMs =  Number(GUICtrlRead($minInterval)) * 60 * 1000 
	$maxIntervalMs =  Number(GUICtrlRead($maxInterval))	 * 60 *  1000
	$timeLimitMs =  Number(GUICtrlRead($stopAfterMins)) * 60 *  1000
	
	$totalTimer = TimerInit()
	$actionTimer = TimerInit()
	$actionTimerLimit = ranNum($minIntervalMs, $maxIntervalMs) ;randomize the 1st action interval
	$actionsPerformed = 0 
	
	Local $timeRan, $timeLeft, $nextActionInMs
	
	While 1	
		;format the timers for the tooltip
		$timeRan = formatMs(TimerDiff($totalTimer))
		$timeLimit = formatMs($timeLimitMs)			
		$timeLeft = formatMs($timeLimitMs - timerDiff($totalTimer))
		$nextActionInMs = formatMs($actionTimerLimit - timerDiff($actionTimer))
				
		If timerDiff($actionTimer) >  $actionTimerLimit Then ;if action timer is exceeded
			moveCamera() ;perform action
			$actionTimer = TimerInit() ;reset action timer
			$actionTimerLimit = ranNum($minIntervalMs, $maxIntervalMs) ;randomize a new action interval
			$actionsPerformed += 1 ;increment action counter
		EndIf
	
		;update tooltip
		showTooltip(@CRLF &  "Status: waiting..." & @CRLF & "Camera movements: " & $actionsPerformed & @CRLF & "Next cam move in: " & $nextActionInMs & @CRLF & @CRLF & "Time ran: " & $timeRan & @CRLF & "Time limit: " & $timeLimit & @CRLF & "Time left: " & $timeLeft)
		
		;if time limit is not set as 0 (infinite) and time limit is exceeded, exit the loop
		If $timeLimitMs <> 0 And timerDiff($totalTimer) >  $timeLimitMs Then 	
			ExitLoop
		EndIf	
	
		sleep(2000) ;sleep 2 seconds between each interaction
	WEnd
		
	;show tooltip after script has ended	
	showTooltip(@CRLF &  "Status: time limit exceeded, idling..." & @CRLF & "Camera movements: " & $actionsPerformed & @CRLF & @CRLF & "Time ran: " & $timeRan & @CRLF & "Time limit: " & $timeLimit & @CRLF & @CRLF & "Script ended: " & _NowTime())
	
	idle() ;return to idling state
EndFunc

The tooltip will look like this in action:

The tooltip while script is running The tooltip when script has ended

Hotkeys & idling on start

Finally, we only need to define our hotkeys, and after that call the idle function. Now the script will start idling instead of running only once and exiting. We enter the following lines after the splash function we just defined above, and the script is finished and ready for use:

HotkeySet ("{F9}", splash)	
HotkeySet ("{F10}", idle)
HotkeySet ("{ESC}", exitScript)	
idle()

Testing & conclusion

The script is finished! As we run the script file (SplashBypass.au3) the GUI will appear. To test the camera movement behavior we can set the min and max intervals to 0.1 minutes (6 seconds) in the GUI, and press F9 to start camera movement operations. The tooltip should display the timers correctly, and when the cam movement countdown is 0, the script sends a random arrow key press to the active window. If the OSRS game client is the active window we can observe the key press as camera movement.

As this script sends the keypresses to the currently active window, this script is best used on a secondary computer or while you are away. 

Please note that using any kind of automation tools to circumvent gameplay mechanisms violates the Rules of Runescape.

Splashing with the script

Script code snippet

Click here to review the whole script in a single code snippet
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <Date.au3>
$scriptName = "SplashBypass"

GUICreate($scriptName, 450, 120)
Opt("GUICoordMode",1)
GUICtrlCreateGroup("Settings", 10, 5, 155, 90)

GUICtrlCreateLabel("Min interval:", 20, 23, 60, 20)
$minInterval = GUICtrlCreateInput ("10", 85, 19, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 23, 40, 20)

GUICtrlCreateLabel("Max interval:", 20, 45, 60, 20)
$maxInterval = GUICtrlCreateInput ("20", 85, 41, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 45, 40, 20)

GUICtrlCreateLabel("Stop after:", 20, 68, 60, 20)
$stopAfterMins = GUICtrlCreateInput ("60",  85, 64, 30, 20) 
GUICtrlCreateLabel("minutes", 120, 68, 40, 20)

GUICtrlCreateGroup("Instructions", 170, 5, 250, 90)
GUICtrlCreateLabel("• Script moves cam between min/max intervals" & @CRLF & "• Cam is moved by pressing random arrow keys" & @CRLF & "• Enter 0 to time limit for infinite loop" & @CRLF & "• Press F9 to start, F10 to stop" & @CRLF & "• Press ESC to exit program" , 180, 22, 230, 70)

GUISetState()

Func exitScript()
	msgbox (0,$scriptName, "Exiting...",0.30) ;show message box briefly for responsive feel
	exit
EndFunc

Func idle()
	While 1 ;endless while loop to keep program running
		Switch GUIGetMsg() 
			Case $GUI_EVENT_CLOSE ;if program is closed with red x
				exitScript()	
		EndSwitch
		sleep(40)	
	WEnd
EndFunc

Func showTooltip($str)
	ToolTip($str, 10, 100, $scriptName)
EndFunc

Func formatMs($ms)
	$seconds = Round($ms/1000, 0) 
	$minutes =  Round($seconds/60, 0)
	$hours = Round($minutes/60, 0)
	If $seconds < 60 Then 
		return $seconds & " sec"
	ElseIf $minutes < 60 Then
		$remSec =  Mod($seconds, 60)
		return $minutes & "min " & $remSec & "sec"
	Else 
		$remMin =  Mod($minutes, 60)
		return $hours & "h " & $remMin & "min"
	EndIf
EndFunc

Func ranNum($min, $max)
	Return Random ($min, $max, 1) 
EndFunc

Func moveCamera()
	Local $arrowKey
	Switch ranNum(1,4)
		Case 1
			$arrowKey = "{UP}"
		Case 2
			$arrowKey = "{DOWN}"	
		Case 3
			$arrowKey = "{LEFT}"
		Case 4
			$arrowKey = "{RIGHT}"
	EndSwitch	
	Opt("SendKeyDownDelay", ranNum(50,400)) 	
	Send($arrowKey)
EndFunc

Func splash()	
	;read data from GUI and convert to milliseconds
	$minIntervalMs =  Number(GUICtrlRead($minInterval)) * 60 * 1000 
	$maxIntervalMs =  Number(GUICtrlRead($maxInterval))	 * 60 *  1000
	$timeLimitMs =  Number(GUICtrlRead($stopAfterMins)) * 60 *  1000
	
	$totalTimer = TimerInit()
	$actionTimer = TimerInit()
	$actionTimerLimit = ranNum($minIntervalMs, $maxIntervalMs) ;randomize the 1st action interval
	$actionsPerformed = 0 
	
	Local $timeRan, $timeLeft, $nextActionInMs
	
	While 1	
		;format the timers for the tooltip
		$timeRan = formatMs(TimerDiff($totalTimer))
		$timeLimit = formatMs($timeLimitMs)			
		$timeLeft = formatMs($timeLimitMs - timerDiff($totalTimer))
		$nextActionInMs = formatMs($actionTimerLimit - timerDiff($actionTimer))
				
		If timerDiff($actionTimer) >  $actionTimerLimit Then ;if action timer is exceeded
			moveCamera() ;perform action
			$actionTimer = TimerInit() ;reset action timer
			$actionTimerLimit = ranNum($minIntervalMs, $maxIntervalMs) ;randomize a new action interval
			$actionsPerformed += 1 ;increment action counter
		EndIf
	
		;update tooltip
		showTooltip(@CRLF &  "Status: waiting..." & @CRLF & "Camera movements: " & $actionsPerformed & @CRLF & "Next cam move in: " & $nextActionInMs & @CRLF & @CRLF & "Time ran: " & $timeRan & @CRLF & "Time limit: " & $timeLimit & @CRLF & "Time left: " & $timeLeft)
		
		;if time limit is not set as 0 (infinite) and time limit is exceeded, exit the loop
		If $timeLimitMs <> 0 And timerDiff($totalTimer) >  $timeLimitMs Then 	
			ExitLoop
		EndIf	
	
		sleep(2000) ;sleep 2 seconds between each interaction
	WEnd
		
	;show tooltip after script has ended	
	showTooltip(@CRLF &  "Status: time limit exceeded, idling..." & @CRLF & "Camera movements: " & $actionsPerformed & @CRLF & @CRLF & "Time ran: " & $timeRan & @CRLF & "Time limit: " & $timeLimit & @CRLF & @CRLF & "Script ended: " & _NowTime())
	
	idle() ;return to idling state
EndFunc 

HotkeySet ("{F9}", splash)	
HotkeySet ("{F10}", idle)
HotkeySet ("{ESC}", exitScript)	
idle()

If you have any comments, feedback or questions, please leave a comment below or use the contact form found in the “contact” page at the top.

MacroForge blog author

Leave a comment

Website Powered by WordPress.com.

Up ↑

Design a site like this with WordPress.com
Get started