HamsterSpeak is the scripting language used by the OHRRPGCE. For historical reasons scripting is referred to as plotscripting. HamsterSpeak is compiled by HSpeak compiler which parses scripts and converts them into a binary format that can be executed by an interpreter such as the one built into Game. This article explains most of the syntax and reserved words for HamsterSpeak, though it is a bit out of date.
This document may appear ovewhelming to non-programmers, so instead, you will want to read the Plotscripting Tutorial, which is written for beginners, and the Dictionary of PlotScripting Commands, which also documents language features like flow control constructs and strings. On the other hand this document isn't written for programmers either.
- 1 Syntax
- 2 Declarations, directives and scripts
- 3 include
- 4 Operators
- 5 Variables
- 6 Flow control
- 7 Strings
- 8 Obsolete Features
- 9 Internals
HamsterSpeak function and variable names are case insensitive and whitespace insensitive. The following are all valid ways of writing the same command:
Suspend Player suspendplayer sUsPeNdPlAyEr Susp Endpla Yer
Remember this when you are naming your scripts and variables.
Statements are separated by commas or newlines. Blank lines are ignored, and double commas are treated as single commas. You can use commas and newlines interchangeably. For example, the following blocks of code are the same:
Suspend Player Suspend NPCs Suspend Obstruction
Suspend Player, Suspend NPCs, Suspend Obstruction
You can use the # symbol to put comments in your script. Anything from the # to the end of the line is ignored.
walk hero, begin me # who does the walking? Me! north # this is the direction we want to walk 3 # this is how many tiles we want to go end
HamsterSpeak has only integers, not floating point. Allowed values are from -2^31 = -2147483648 to 2^31-1 = 2147483647.
You can use the following prefixes to write non-decimal numbers:
- 0b binary (base 2, allowed digits are 0 and 1), eg. 0b100 == 4
- 0o octal (base 8, allowed digits are 0 to 7), eg. 0o20 == 16
- 0x hexidecimal (base 16, allowed digits are 0 to 9 and A to F), e.g. -0xf == -15
Just like all other tokens, the prefixes and hex digits are case insensitive and you can put spaces inside number literals, except a space inside only of the above prefixes isn't allowed! 0 x 1 is invalid.
-0042 == -42 - 1 2 == -12 1 000 000 == 1000000 -0B 1111 1111 == -255 0X0000F == 15 0o 00000000000000000000 0 00 0 == 0
Most HamsterSpeak functions take arguments. The arguments for a function follow it between parenthesis. The following are examples of HamsterSpeak functions:
walk hero (me,north,3) wait for hero (me) show text box (37)
Also, as an alternative to using parentheses, you can write begin and end. It's common to use begin and end for constructs like script and parantheses for function calls.
The following blocks of code do exactly the same thing
walk hero (me, north, 3)
walk hero, begin me north 3 end
If you pass no arguments to a command or script then you can omit the parentheses altogether:
wait, fade screen out, wait, fade screen in
However an empty pair of parentheses in other contexts, such as after case, may not be optional.
Argument lists are processed after processing operators. This is significant when operators require commas around their name, such as mod (modulus, written as %' in most programming languages). The following function invocation:
put hero(0, 100 + x, mod, 20, 200 + y, mod, 20)
is equivalent to:
put hero(0, (100 + modulus(x, 20)), (200 + modulus(y, 20)))
Obviously the first way is very unreadable and you should put parentheses around the expressions!
A few commands such as set timer need a reference to a script. Put an @ sign at the beginning of a script name to get the script's ID number. This reference can be stored in a variable or passed as an argument.
You can call a script using its ID number using the run script by ID command.
You can get the ID number of a global variable by putting @ in front of its name.
Declarations, directives and scripts
Documented in the plotscripting dictionary here: include
In older versions it was necessary to include the plotscr.hsd command manually, so don't be surprised if you see the following line at the top of a lot of old example scripts:
script and plotscript
Most of the code in HamsterSpeak is in plotscript statements. plotscripts can be triggered directly by various events in your game. scripts can be run by other scripts and plotscripts. The only difference between a script and a plotscript is that scripts are never shown in Custom.
Here is a sample script
plotscript, My Script, begin # code goes here end
Arguments are extra pieces of information that can be given to a script. Here is a sample script with arguments:
# This script has three arguments, the last two default to zero, # while the first is mandatory. plotscript, My Fancy Script, firstarg=0, secondarg=zero, begin # This script can use the arguments by name # just as if they were local variables end
You can call scripts by using their names, just like you call built-in functions.
plotscript, my script, begin my other script end plotscript, my other script, begin # this script is called by the other one end
Subscripts are scripts embedded inside another script (or plotscript or subscript). See subscript.
plotscr.hsd also has some constants to make life easier. Thanks to constants, there is no need to know what numbers plotscripting uses to internally represent things. The following are some of the constants defined in plotscr.hsd
zero, one, two, three, four, five, six, seven, eight, nine, ten, false, true, off, on, north, east, south, west, up, down, left, right, upkey, downkey, leftkey, rightkey, usekey, cancelkey, menukey, anykey, me, none...
Another use for constants is the ability to refer to heroes, maps, songs, items, and all sorts of other things in your RPG by name instead of by number. CUSTOM can export an include file from its Script Management menu that is full of constants that represent the names in your RPG. This file will have the same name as your RPG file, with the extension HSI (HamsterSpeak Include), and it will be automatically included into your script the exact same way that the plotscr.hsd file is automatically included.
In older versions, it was required that you manually include the hsi file yourself, so don't be surprised if you see old script examples with the line:
You can add your own constants to your script with a defineconstant statement
Define Constant (1000,thousand) plotscript, My Script, begin # now I can use the word thousand instead of 1000 in my script get money (thousand) end
Almost all of the math and logic operators can be written either infix or as functions. You can use whichever you prefer (the first version of HSpeak did not support infix operators). The exception to this is the and or and xor commands. You must use the infix style.
The correspondence between infix operators and functions is actually defined in plotscr.hsd (see #defineoperator) instead of built into HSpeak.
The following table groups together operators with the same precedence, and all operators are left-associative; for example * and / are in the same block, so a*b/c is (a*b)/c while a/b*c is (a/b)*c. However * is higher than +, so a+b*c is a+(b*c) as expected. Note that in other programming languages, exponentiation, :=, +=, and -= are usually right- instead of left-associative. In HamsterSpeak you have to write a := (b := 3) to assign the same value to two variables.
|Precedence blocks||Operator||Alternative Syntax|
|n ^ n||exponent(n,n)|
|n * n||multiply(n,n)|
|n / n||divide(n,n)|
|n, mod, n||modulus(n,n)|
|n + n||add(n,n)|
|n -- n||subtract(n,n)|
|n == n||equal(n,n)|
|n <> n||notequal(n,n)|
|n < n or n << n||lessthan(n,n)|
|n > n or n >> n||greaterthan(n,n)|
|n <= n||lessthanorequalto(n,n)|
|n >= n||greaterthanorequalto(n,n)|
|n, and, n|
|n, or, n|
|n, xor, n|
|a && b||logand(a,b)|
|a || b||logor(a,b)|
|a ^^ b||logxor(a,b)|
|v := n||set variable(v,n)|
|v += n||increment(v,n)|
|v -= n||decrement(v,n)|
|dest $+ src||concatenate strings(dest, src)|
|dest $= src||copy string(dest, src)|
Note that there are no unary operators at all, such as negation or logical and bitwise complement! ("-10" is a constant, not negation applied to "10".) However, there is the not() function for logical complement/negation.
The @ prefix to get a global or script reference is not an operator.
Math operators take the value on their left, and the value on their right, perform math on them, and return the result.
plotscript, Math Sample, begin variable (n) n := 100 # we start with 100 n := n + 5 # now n is 105 n := n * 2 # now n is 210 n := n -- 6 # now n is 204 n := n / 4 # now n is 51 show value (n) end
The complete list of math operators is documented in the Plotscripting Dictionary.
Notice that the symbol for subtract is --. This is necessary to avoid confusion with script names and constants that have hyphens in them. If you wanted to subtract a negative number, you should write n -- -6.
An important note is that all Hamsterspeak variables are 32 bit signed integers. For example, in Hamsterspeak, 26 / 4 will return 6, not 6.5. With creative workarounds a clever scripter can circumvent any problems this causes. (For example, multiplying everything by 10...)
Comparison and Logic
Comparison and logic operators take the value on their left, and the value on their right, compare them, and return 1 (true) or 0 (false) based on the comparison. They are most often used in if statements.
plotscript, Comparison Sample, begin if (5==7) then,begin # five is never equal to seven, so this can't be true end if (5<7) then,begin # five is always less than seven, so this is always true end if (5>7) then,begin # five is never greater than seven, so this can't be true end if (5<=random(1,10)) then,begin # there is a 50% chance that 5 will be less than or equal to # the random number between 1 and 10, so sometimes this will be # true and other times it will be false end if (1==1 && 2<>2) then,begin # one is always equal to one, but two is never not-equal to itself # so this can never be true end end
The complete list of comparison operators is documented in the Plotscripting Dictionary.
A variable is a named number-holder in your script that you can give any value to. Variables can be global, which means they are available to every single script, and are saved in your RPG, or they can be local, which means they only work in the script they where created in, and once that script ends, they go away.
Global variables are defined with the globalvariable statement. Like scripts, global variables need unique ID numbers. You have 50001 global variables to work with, numbered from 0 to 50000.
Global Variable (1,var) plotscript, one script, begin # I can set a global variable in one script... var:=100 end plotscript, one script, begin # ...and use it in another show value (var) end
Local variables are declared with the variable statement. A local variable always starts out as zero when the script starts. You can use the variable throughout the script, and when the script finishes, zap! the variable is gone. If you run the script a second time, it will be created all over again. Local variables do not need ID numbers.
plotscript, test script, begin variable (var) # this variable is only available to this script var:=100 end
Note that globalvariable always goes outside of your scripts. Variable always goes inside a script. Local variables are created as soon as the script starts, regardless of where in the script you define them (it makes absolutely no difference).
All flow control constructs are documented in the Plotscripting Dictionary.
Strings have ID numbers, and all string-related commands take at least one string ID. There are 100 strings available. They are numbered from 0 to 99.
Strings literals are assigned with the syntax:
$ID = "text"
Or appended with the syntax:
$ID + "more text"
For a list of all functions that work with strings, see: String Functions
There may be some confusion about displaying strings. The show string command can only display a single string at a time, but the show string at command and the center string at commands can be used to display all strings simultaneously anywhere on the screen.
Old scripts used to require an ID number, assigned with the definescript statement. You do not need to use definescript anymore, but in case you see them in someone else's scripts, it can be helpful to know what they look like:
Define Script (1,My Script,none) Define Script (2,My Other Script,none) script, My Script, begin # do nothing end script, My Other Script, begin # do nothing end
The first argument of definescript is the id number of the script. This is the number that the OHRRPGCE identifies the script by. No two scripts can have the same id number, and having an explicit id number made a script triggerable in your game just like a plotscript
You may also see autonumbered scripts, which are also obsolete. Here is a sample script that is autonumbered.
Define Script (autonumber,My Numberless Script,none) # this script will be hidden in CUSTOM.EXE, # but can be called by other scripts script, My Numberless Script, begin # blah blah blah end
This section documents stuff that noone needs to know, except for possibly engine developers.
definetrigger isn't really used. It might be used or removed in the future, but has no current useful purpose.
The defineoperator command substitutes an infix operator for a function or script that is defined elsewhere. Hamsterspeak uses this to support math and logic operators such as 1+2. If you don't know what "infix" means, or what "operators" are, don't worry. You will never use defineoperator for anything. I only mention it here for the sake of documentation. If you want to turn some of your scripts into operators, you can use plotscr.hsd as an example.
The important part is knowing how to use the infix operators that have already been defined for you. The most common use of these operators is for doing math, and checking equality.
Definefunction statements define one or more built-in functions that are hardcoded into the engine. The normal convention is to call built-in functions commands. (On the other hand, functions which are builtin to the interpreter itself are called "math functions", and are also builtin to hspeak, so don't need defining.)
Each command declaration has the syntax:
[attribute name [(attribute parameters)]]*, id, name, num args, [default argument,]*
Each attribute name starts with @, and must be recognised by HSpeak (see #Function attributes). The attribute may have parameters (which may or may not be optional, see the attribute documentation), enclosed in (/)/begin/end.
num args may be -1, in which case the command takes a variable number of arguments, and no default arguments are parsed.
define function, begin 0,noop,0 # no operation 1,wait,1,1 # wait(cycles) 176,runscriptbyid,-1 # run a script by its id number and pass any number of arguments 197,playsound,3,1,0,0 # plays an sfx (num, loop?, preempt?) @obsolete("This command can't be used with atk: constants. ", read attack name) 208,getattackname,2,0,0 end
The following attributes are implemented, and unless specified otherwise, can be applied to commands, math functions (by editing math_list in hspeak) and scripts.
Whenever this is used in a script, hspeak throws a warning (by default) or error.
Optionally takes a variable number of arguments, which can be one of:
- error: Throw an error instead of a warning.
- "message": if the parameter is a quoted string, it's appended to the warning/error message.
- anything else: the name of a replacement function to use (can appear multiple times). "Use replacement function anything else instead. " is appended to the warning/error message.