Skip to content
AzaraelDR edited this page Oct 11, 2025 · 41 revisions

Scripting Basics

A script is a type of program that automates sending commands to the client to perform a variety of tasks. Scripts can take many forms from basic line-by-line procedures that perform one command after another to more sophisticated programs that include logic and decision making that responds to input from the game. The process of creating a script involves determining a sequence of commands you wish to run under certain circumstances and writing lines of code that will send those commands to the client, either sequentially or based upon interactive logic.

Typical starting scripts take the form of a linear series of commands designed to perform a specific set of actions in order to complete a task within the game. As you learn more about the process of writing scripts and the language used within the client, a script coder can add more complexity and control the flow of the script in such a way to perform intricate tasks that require interpreting the results of previous actions.

Advanced scripts often contain a variety of techniques and interactive components that work to change the flow of a script to adjust to changes in the results of actions taken in the game. This allows scripts to be used from simple things like repeatedly sending a single command over and over to heavily customized collections of smaller scripts used to automate complex systems like crafting and hunting.

Basic Script Commands

To note: items in angle braces (< >) are REQUIRED for the command. Items in square brackets ([ ]) are OPTIONAL.

debug <level>: Arguably the most important command in writing scripts as it will determine the amount of running script code you will see during script execution. This is used to diagnose script errors and troubleshoot failing code. The typical debug level that is used is 10 which shows all script code. Lower levels are not typically used. This should be placed at the start of your scripts and can be turned off by commenting the line out by proceeding it with a #.

Possible debug levels are:

0 = off
1 = goto, gosub, return, labels
2 = pause, wait, waitfor, waitformove
3 = if evaluations
4 = variables, math, evalmath, counter
5 = actions
10 = shows all script rows

put <command>: The put command is the most basic command available in the Genie 4 Scripting language. It will immediately send the specified command to the game. For example the line put look will send the look command to the game. It is important to know that this command does not take Roundtime into consideration and therefore if a command requires you to be out of Roundtime, the command will fail once sent to the game if you have any Roundtime remaining.

pause [duration]: The pause command will delay the execution of the script for the specified duration in seconds or until Roundtime is resolved. This command can be used to slow down the sending of commands to prevent issues with type-ahead lines and (not recommended) deal with Roundtime generated by the previous command sent to the game.

send <command> [duration]: The send command is similar to the put command in the sense that it will send the specified command to the game; however, it will do this while respecting any currently existing Roundtime automatically. Multiple send commands in a row will add each command to a queue which will be executed in the sequence it was sent. You may also add a duration to the command which will delay the sending of the command by that amount, though this will ignore Roundtime.

wait: Similar to the pause command, but it will delay the script until the next game prompt appears as well as for Roundtime to be resolved.

waitfor <text>: Similar to the wait command, but it will delay the script until it sees a specific text from the game. This is plain-text and therefore should be used with care as specified text may sometimes appear unexpectedly in other game text. The most common usage of this command has been waitfor Roundtime which will wait for the word Roundtime to be sent to the Game window.

waitforre <pattern>: Nearly the same as waitfor, but it will instead wait to match a specific Regular Expression pattern. This is much more reliable and can be used to trigger off of non-game text as well, which will be explained in a later section. Regular Expressions will be explained elsewhere.

waiteval <expression>: This command will wait until the value of the expression becomes True. This can be a comparison like $standing == 1 or a single variable such as $gametime. In the case of the first, the script will wait until you are standing, in the case of the second the script will wait until the value of gametime changes.

pause [duration]: Often times you will use commands that will generate in-game Roundtime and must wait to send the next command. The pause command on it's own will cause the script to wait for the duration of the Roundtime (plus the value set in the roundtime offset option found in #config) making it a good method for dealing with Roundtime. You may also specify a number of seconds to pause after which the script will resume.

echo [text]: The echo command will display text to the Game window that is only informational to the user. This is useful for things like posting instructions to the user, denoting when scripts are changing sections, etc.

Variables - Local vs Global

Variables are placeholders for other values that can be accessed by their specific name within a script. There are 2 types of variables available within the Genie 4 Client - Local and Global variables.

Local Variables

The process of creating a variable locally within a script utilizes the command var <name> [value]. To access the value of a variable within a script you use the format %<name>. It is important to note that Genie 4 Client is greedy when it returns the variable with the SHORTEST name first, evaluated from Right to Left. This means that if your variable name starts with another variable name you will return the value of the shorter-named variable and append the rest of the longer variable name.

Ex:

var spell Fireball
var spell.Prep 10
echo %spell.Prep

This code will echo the text Fireball.Prep as opposed to the value 10.

In addition to this, multiple uses of the % token will cause variables to be evaluated for their values from Right to Left. Ex:

var spell Fireball
var Fireball.Prep 10
echo %%spell.Prep

This code will first evaluate the value of the variable spell which returns the value of Fireball which and then evaluate %Fireball.Prep which then will echo the value 10.

Local variables are available ONLY within the script they were created in. They are not available to other scripts and do not persist past the closing of the script.

To change the value of a variable simply run the command var <name> [value] again.

Global Variables

Similar to Local variables, Global variables are placeholders for values. There are a couple processes for the creation of a Global variable but within a script you would run the command put/send #var <name> [value]. Because the command #var is a Client command, it is required that you use put/send otherwise the Global Variable will not be created. To access the value of a Global variable you utilize the format $<name>. Like with Local Variables, you may stack both Local and Global evaluations.

You may also add/edit/delete Global Variables through the GUI by going to Edit -> Configuration... -> Variables. To create a Global in this way you would click the Add button, place the Global name in the Variable box and the Value into the Action box then click Apply. To edit a Global, find it in the list, click on it, change the value in the Action box and then click Apply. To delete a Global, find it in the list, click on it and click Delete.

Remember: After creating/editing/deleting Global variables, either run the command #var save or click the save button in the Variables section of the GUI.

Global variables differ in 3 ways from Local variables - 1) Global variables are available to all Scripts in the client at the same time. 2) Global variables persist even after the client is closed. 3) Global variables are saved per character profile, therefore a set of Global variables of the same name can be created for each character while setting them to differing values.

Due to these 2 features of Global variables they are most valuable for sharing information between multiple scripts and saving values when the client is closed that you may want the next time it is open. A good example of this would be to set 'default' settings for a script such as specific containers, specific spells, preferred weapons, etc.

An alternate format of Global variables also exists in the form of Temporary Global Variables which are created with the command #tvar. Temporary Globals have all the same functionality as Global variables except that they are not saved when the client is closed. This makes them desirable to send information between scripts that doesn't need to be permanently stored.

Global variables are also able to be deleted, unlike Local variables which only are removed when their script ends. To remove a Global variable from within a script you would use the command put/send #unvar <name>.

Command Line Variables

When running a script from the Command Line in Genie 4 it is possible to pass values into the script that will be held in a special set of variables. These variables are named numerically by the position they are sent to the script where the variable %1 is in the first position, %2 is in the second and so-forth. The highest command line variable that can be referenced directly is %9, any number after that falls into the shortest variable name issue mentioned above where %10 will be evaluated as the variable %1 with a 0 appended to its value. The variable 0 holds the entire string of values (even those past 9).

The syntax to send values to a script is .<scriptname> <value 1> <value 2> ... <value n>.

In addition to the above variables, you may also quickly check to determine if any of those variables have a value stored within them by using the conditional statement if_# where # is the name of the Command Line variable you wish to check. For example the following code will only execute if a value has been supplied to the script in the first position: if_1 then echo Yes

It is possible, however, to break past the limitation of the variable name evaluation. When more than 9 values are sent to the Client, the extra values are actually assigned to the corresponding special variables. To access those values you will need to utilize the shift command or turn the 0 variable into an array that you can work through later. (Arrays will be addressed in a later section.)

Shift

The shift command is a special command within Genie 4 Scripting that only serves as a means to process through Command Line variables one by one without having to reference variables higher than %1. A side-effect of this process is that the first value is removed and the whole list is 'shifted' to the left, meaning if you miss capturing a value while shifting through the list that value is lost forever.

The function of shift occurs as following:

var first.pet %1
shift
var second.pet %1
shift
var third.pet %1
shift
  1. The script is called with a number of values: .sample cat dog fish
  2. The values cat, dog and fish are stored in the variables %1, %2 and %3 respectively.
  3. The first line takes the value cat stored in %1 and stores it into a variable: var first.pet %1
  4. The shift command executes and copies the value of %2 into %3 and the value of %3 into %2. Since there is no %4, the value in %3 becomes blank at this point.
  5. The third line takes the value dog that is now stored in %1 and stores it into a different variable: var second.pet %1
  6. The shift command executes and copies the value of %2 into %1 and the value in %2 becomes blank since %3 is blank.
  7. the last line takes the value fish that is now stored in %1 and stores it into yet another variable: var third.pet %1
  8. Finally, shift executes and the value of %1 becomes blank since %2 was blank.

Generally this process is not handled sequentially like this, but more often worked into a loop to process the whole list of Command Line variables until %1 becomes empty with if_1 being used to determine when you have gone through he whole list of values.

Eval and Evalmath

Sometimes you may want to assign or re-assign a value to a variable based upon a function or a mathematical expression. The var and #var commands do not support the processing of other functions or mathematical expressions and, as-such, you will need to use the commands eval and evalmath to perform this operation. Global variables will use send #eval and send #evalmath.

The command eval has the syntax eval <variable> <function> and will take the result of the function and save it into the variable (and create the variable if it does not exist. For example, the line eval pet tolower("CAT") will set the value of pet to cat having processed the tolower() function on the string CAT.

The command evalmath has the syntax evalmath <variable> <expression>. For example, the line evalmath average 100 / 5 would set the value of average to 20 having processed the division. It is possible to use more complicated mathematical expressions as well.

Functions available in eval:

cos(number)
sin(number)
tan(number)
floor(number)
ceiling(number)
max(number1, number2)
min(number1, number2)
arcsin(number)
arccos(number)
arctan(number)
sqrt(number)
log(number)
log10(number)
abs(number)
round(number[,decimals])
ln(number)
neg(number)
pos(number)

Additional Math Operators: Modulus division is available using the math function modulus. Use format and example are below:

var Num 22
var ModResult %Num
var divisor 5

math ModResult modulus %divisor
echo modulus of %Num and %divisor is %ModResult
Result: modulus of 22 and 5 is 2

Arrays/Lists

Variable most often contain single values; however, they may also contain a list of multiple values. Variables of this type are referred to as Arrays or Lists (depending upon the semantics you are used to). The process of creating a variable with multiple values follows nearly the exact same process as creating a variable with a single value, with the exception that you use the Pipe symbol | to separate variables.
Important note: That is the PIPE Symbol (the shift version of the \ key). A capital i or a lower-case L will not work!

For example, if you wished to create a variable named pets that contained a list of the values cat, dog and bird the syntax would be: var pets cat|dog|bird
This works identically for Global Variables with the same differences noted in the Globals section.

Accessing individual elements within the List can be accomplished by supplying the index of the value you want in Parenthesis after the variable name. It is important to note that Indexes start at 0 rather than 1, therefore to access the value dog from the preceding array you would use the code %pets(1)

To find the number of items in a list, you would use the count function to count the number of Pipes within the List, which will always provide the last index number in the list due to the fact that the indexes start at 0.

Examplea:

var pets cat
eval lastindex count("%pets","|")

The variable lastindex is set to 0, which is the first value in the List and can be accessed with %pets(%lastindex) -> cat

var pets cat|dog
eval lastindex count("%pets","|")

The variable lastindex is set to 1, which is the second value in the List and can be accessed with %pets(%lastindex) -> dog

var pets cat|dog|bird
eval lastindex count("%pets","|")

The variable lastindex is set to 2, which is the third value in the List and can be accessed with %pets(%lastindex) -> bird

It is possible to Loop through a List, though this functionality will be discussed in a later section.

Labels and Script Sections

Scripts in their most basic forms will execute all commands coded into them in sequential order. A script will execute perfectly fine with a string of commands stacked one after another, but in order to perform more complicated behaviors such as jumping around in a script based on logic or looping you must break a script up into smaller discreet sections.

The method to separate a script into smaller sections uses script Labels. Labels take the format <Name>:

It is important to note that Labels, on their own, have no direct impact on the script. They serve only as starting markers for the goto and gosub commands as well as match tables. They can, however, also be useful for subdividing your scripts up for your own reference so that you are aware what each section of your script is doing.

Goto vs Gosub

In order to manually jump to other sections (Labels) within a script you will utilize the Goto and Gosub commands. At the base level the two commands function very similarly, sending the script execution to Labeled section to continue from.

The syntax for goto is goto <Label>. This will immediately move script execution to the specified label, skipping any intervening code. For example:

var x 1
goto Skip

echo %x

Skip:
var x 2

echo %x

This script will not echo 1 to the game client and will instead only echo 2.

The function of gosub is a little more nuanced and offers some extra functionality compared to goto. There are also several considerations to be kept in mind when using the command, the format of which is gosub <Label> [value1] [value2] ... [value9] (Values are optional.)

Firstly, where goto only allows you to redirect a script to a specific label, it also allows you to store data within the special "command line" variables mentioned earlier (%1 - %9). In addition to this, when gosub jumps to a new point in the script it will record the specific line it was called from into the return queue.
It should be noted that the return queue is limited to a depth of 50, so any gosubs after this point will overflow the queue.

In order to return back to the point from which a gosub was used, you simply use the return command. If there are no more values stored in the return queue you will receive an error and the script will terminate, therefore it is important to make sure you do not process more return commands than you do gosubs.

Utilization of a goto within an action will clear the return queue. This is the most common reason that a return command will fail.

Matchtables - Match, Matchre and Matchwait

Matchtables are a method of controlling the flow of a script in response to game messaging that results from a command send to the game. A matchtable requires a matchwait command at the end in order to make the script wait for the messaging for the command to be displayed in your client, otherwise the script will continue on execution. The match command will create an entry that will point to a specified label on the exact text you set. This text must be visible in the Game window or the match will not function.

The basic form of a matchtable is as follows:

match <Label1> <text>
match <Label2> <text>
<command>
matchwait

It is strongly recommended that you place your matches before the command to allow the matchtable to be properly created. Match conditions placed after the command may not be recognized by the time the command is sent and you may either have a match you did not intend send you to an incorrect label or the script stalling.

The matchwait command also accepts an amount of time in seconds that it will wait before moving on. This is useful in error catching or when the result of the command is 'succeed' or 'fail', allowing you to match only one of the results and moving on afterwards. The format of this is matchwait <Seconds>

It is important to note that a successful match will clear the match table to avoid matching against text improperly later in the script; therefore, you will need to reconstruct the match table every time before a command you wish to match against.

Another option to build a matchtable is to use the command matchre in the place of match. The command matchre uses Regular Expressions in place of text, the benefit of which is it allows you to match against patterns. This means you can bind multiple outcomes to a single label (ie: multiple 'success' or 'failure' messages) as well as more complicated messaging.

Regular Expressions (aka: Regex) are beyond the scope of this Wiki entry, but there are many websites that can assist with learning and troubleshooting Regex patterns. One such site is: https://www.regex101.com . You may also request assistance on the Genie Client Discord in the Regex channel - Regex

If-Else

The main decision making process within a script involves the use of the 'If-Else' statement. This statement allows you to evaluate a specific condition and determine which actions you wish to take depending upon the result of that evaluation. Conditional expressions and operators are beyond the scope of this guide, but most traditional formats will work within Genie Scripts.

An 'If' statement may be used on its own to evaluate a Conditional expression and only take an action if the expression evaluates to True, otherwise skipping any code execution if the expression evaluates to False. An 'Else' statement is not required.

The most format for an 'If' statement is if <condition> then <code>. Not that this will only execute a single line of code based upon the evaluation. You may execute a code block based upon the evaluation, but that code must be on multiple lines enclosed by curly braces - { }

This format is:

if <condition> then
  {
  <code>
  }

The format for an Else statement is similar, but it must always be preceded with an If statement:

if <condition> then <code>
else <code>

Or:

if <condition> then
  {
  <code>
  }
else
  {
  <code>
  }

You may also use Else-if statements the same way you would use them in any other language:

if <condition> then
  {
  <code>
  }
else if <condition> then
    {
    <code>
    }
else
    {
    <code>
    }

Looping

While the standard loops, 'Do-While', 'While' and 'For' do not exist within Genie scripting, it is possible to emulate the function of a loop through the manipulation of variables and strategic use of Labels and the goto command. Mostly this is accomplished with If statements, but can also be accomplished with Match tables under the correct circumstances.

The code below is an example of a simple script that will loop continuously until the script is canceled by some means:

Loop:
  pause 1
  goto Loop

Note that the pause is important here, if the script engine sees too many script Labels in a period of time, it will assume the script has entered an infinite loop and will cause the script to crash out.

Counter variables can be utilized to cause a loop to run only a certain amount of times, or loops can run until a specific messaging is received such as in filling a favor orb. The following Loop is an example that will run 5 times before terminating:

var count 0

Loop:
  if %count < 5 then
    {
    math count add 1
    goto Loop
    }
  exit

Actions

Script Actions allow you to execute code depending on the appearance of certain text as it appears in the game client during any point of script execution. Actions can be used to accomplish many things from quickly rerouting to other script sections, capturing data or sending a command immediately in reaction to a message from the game. Actions are typically based upon Regular Expressions for their execution and properly formatting the triggers is important for the function of an Action. Actions may also be triggered upon evaluations of variables.

The basic syntax for an action is: action <commands> when <trigger>

Actions can execute multiple commands in a row as long as they are separated by a semi-colon, ;. The command will execute in the order in which they are listed.

One of the most useful functions of an Action is to capture game text with a Regular Expression and storing that data within a variable, either Local or Global. To do this you will need to craft your Regular Expressions with a Capture group with the appropriate Expression to match what you are looking for. A few example of common actions are as follows:

action var kronars $1 when Kronars\s+\: (\d+) - Will capture the number of Kronars displayed after the text Kronars :

action send stand when eval $standing = 0 - Will send the command stand when the Global Variable standing is set to 0

action var fullprep 1 when You feel fully prepared - Will set the variable 'fullprep' to 1 when you have fully prepared a spell.

Actions must be created in advance of the text that they will respond to, much like matchtables, but actions can be created at any point in the script. Generally it is recommended that you create Actions at the top of your script so that they will be available during script execution later on. If you want an Action to only be available during a specific section of the script you can assign classes to them and toggle them on and off within the script. You may assign the same class to multiple triggers to turn them all on and off at the same time. The syntax for this is as follows (note, the parentheses are required around the class name):

action (<class>) <command> when <trigger> - Creates the action with a class name.

action (<class>) off - Toggles all Actions with the same <class> off.

action (<class>) on - Toggles all Actions with the same <class> on.

Special care should be taken while using the command goto within an Action as it will cause the gosub queue to be cleared and result in any return commands to error and crash the script.

Special Methods

Genie Scripting contains a number of special methods that allow you to perform different operations within a script:

contains(source text, search text)
count(source text, search text)
element(source text, index)
endswith(match text)
indexof(source text, search text)
lastindexof(source text, search text)
len(source text)
match(source text, match text)
matchre(source text, pattern)
replace(source text, replace text)
replacere(source text, pattern, replacement text)
substr(source text, start index, end index)
tolower(source text)
toupper(source text)
trim(source text)

Note: Any function that ends with re denotes that it utilizes Regular Expressions and can be used with any functions and features inherent to Regex.

Advanced Techniques

Includes

It is possible to include code from other files within a script file through the use of the include keyword. These files can be any supported code type, either Genie Script or Javascript at this time. It is important to note that if you include Genie Script at the top of a script file, the code in that file will be executed immediately, therefore it is recommended only to include Genie Scripts that are a Library of labels which are added to the end of a script file so you can call them at your leisure. If your include is a number of actions, however, these will need to be added to the top of the script for them to function while the script is executing.

Javascipt files that are libraries of Functions can be included at the top of the script without worry as they are not automatically executed in the way Genie Script files are. Still, it is recommended that your Javascript files are composed of Functions that you can call from the script further down.

Scripts controlling Scripts

One of the more advanced Scripting techniques is to write scripts that can control and administer other scripts. There are a number of commands and techniques which can facilitate this process.

The #script command can be used to control the execution of other scripts and can be useful for moderating which scripts are running and which you want to end, pause or resume.

#script abort/pause/pauseorresume/resume/trace/vars <script>
#script abort/pause/pauseorresume/resume/trace/vars all
#script abort/pause/pauseorresume/resume all except <script>

The waitforre command is useful for setting up points where one script calls another and waits for that script to signal the end of its execution by sending a specified string of text with the #parse command. An example of this is as follows:

scripta:

Start:
  send .scriptb
  waitforre CONTINUE
  echo ScriptA Finished.
  exit

scriptb:

Start:
  echo ScriptB Finished.
  send #parse CONTINUE
  exit

In this example, running the command .scripta will result in it starting scriptb and waiting for the Regular Expression CONTINUE. When scriptb runs, it will echo ScriptB Finished and then send the text CONTINUE to the parsing engine which will be picked up by scripta's waitforre command and continue execution, echoing ScriptA Finished and exiting.

It is possible to pass information between these scripts as well, either through the use of #tvar or by sending command line variables to scriptb in the line that it's called from in scripta.

Utilizing other Scripting Languages

(Currently only Javascript to Augment basic scripting)

Currently Genie allows the use of Javascript in conjunction with the Genie Scripting language, but it must be utilized in specific methods. You can embed Javascript code directly in a Genie Script, but it must be bordered with <% %>. The following example shows Javascript embedded in this way:

echo Genie code
<%
echo("Javascript code.");
%>
echo Genie code

This script will produce the following output:

Genie code
Javascript code.
Genie code

Note that since the echo() command is Javascript command that is not contained in a function, it will execute immediately. If the command is placed within a function it will not execute immediately:

echo Genie code
<%
function doEcho(){
echo("Javascript code.");
}
%>
echo Genie code

This code will produce the output:

Genie code
Genie code

To call a Javascript function within a Genie script, you use the js command followed by the specific function you wish to call:

echo Genie code
<%
function doEcho(){
echo("Javascript code.");
}
%>
echo Genie code
js doEcho()

The above code will produce the following output:

Genie code
Genie code
Javascript code.

Javascript functions can also utilize paramaters which can be passed through to the function in the typical fashion:

echo Genie code
<%
function doEcho(text){
echo(text);
}
%>
echo Genie code
js doEcho("Javascript Code parameter")

The above code will produce the output:

Genie code
Genie code
Javascript Code parameter

Javascript has an inherent limitation where it cannot access the values of Script or Global Variables directly and you must utilize specific functions to read or write to them. The functions to do this are:
getVar(<variable>) - Retrieves the value of a Local Variable.
getGlobal(<global>) - Retrieved the value of a Global Variable.
setVar(<variable>, <value>) - Sets the value to a Local Variable.
setGlobal(<variable>, <value>) - Sets the to a Global Variable.

Javascript functions can also be set up to return a value back to Genie Script with the return keyword. For a Javascript function that returns a value you must use the jscall command in the Genie script with the syntax jscall <variable> <function>([parameters]):

<%
function sample(){
  return(1);
}
%>
jscall temp sample()
echo %temp

The above code will echo 1.

A major strength of the Javascript integration is that you can use the include command to load in a Javascript file of functions that you have created in advanced, allowing you to make standard libraries of functions to use in multiple scripts without having to recreate the code every time.

Clone this wiki locally