Skip to content

Warlock Scripting Language

Sean Proctor edited this page Dec 9, 2024 · 7 revisions

We call it WSL for Wizard Scripting Language or Warlock Scripting Language, you decide.

Overview

Our scripting language is designed to be a superset of the language from the Wizard and from Wrayth with some minor restrictions on variable names.

Basics

We've added a regex version of most matching commands. For the specifics of the regex syntax, see: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Commands

Most lines consist of a single command with some argument(s). Ex.

echo Hello, World.

or

match testLabel some text that you want to match

Commands are not case sensitive, and they can contain variables. Ex.

setVariable type re
setVariable exp /matches\s*a\s*(\w+)/
setVariable number /-?(\d+)(\.\d+)?/
match%type wordLabel %exp
match%type numberLabel %number
matchwait

Variables

You can use variables within any line. Variables start with "%" or "$", such as "%foo" or they are enclosed in them such as "%foo%". Always use the latter form when you want to give some text or concatenate variables, such as "%foo%World.". If "%foo" is set to "Hello," that would result in "Hello,World." Ex.

setVariable target World
setVariable var target
echo Hello, %target%.
echo Hello, %{var}.

Both echo statements would display "Hello, World."

Variables can contain any characters. Variable names must start with a letter or underscore, and they can contain letters, underscores, periods, and digits.

Labels

You can start any line with a name follow by a ":" to label that line. On any like preceding or following that line, you can "goto" that line. Ex.

goto myLabel
echo No!!

myLabel:
echo I hope you find this example useful

The first line will cause the execution of the script to jump to the 3rd line "myLabel:" and the execution will continue with the echo.

Labels may only contain letters, underscores, periods, and digits, but they don't have the same starting letter restriction of variables.

Functions

Functions are very much like labels. They are defined by labels, but instead of using "goto" to jump to them, you use "gosub". "gosub" can be passed any number of arguments, which will be stored in "%arg1", "%arg2", etc with the entire list being stored as a map in "%args". "return" brings execution back to the command after you called the function. Ex.

gosub printHello World
echo Good-bye
exit

printHello:
echo Hello, %arg1%.
return

The result of this would be printing "Hello, World." followed by "Good-bye".

IMPORTANT See NOTE under #Matchre

Conditions and expression

if <expression> then <command>

If the expression evaluates to true, the command is run. Expressions are rather complicated so I'll just put the definition here and try to use them in the examples. This is not a real definition, just an approximation. The actual definition is more complicated in order to preserve the order of operations.

   expression := expression infixOperator expression
       | ( "not" | "exists" ) expression
       | expression "[" expression "]"
       | "(" expression ")"
       | variable
       | string
       | boolean
       | number
    infixOperator := "and" | "or" | "=" | "!=" | "<" | "<=" | ">" | ">="

Local Variables

Local variables are scoped to their function. They can be accessed, but not changed from another function. "%arg" and "%args" are local variables. Other local variables can be set with the "local" command. Ex.

local var1 foo
gosub testing
echo The value in var1 is %var1
exit
testing:
local var1 bar
echo The value in var1 is %var1
return

They output of this sequence would be "The value in var1 is bar" followed by "The value in var1 is foo".

Conditionals

Sometimes you need to know whether a condition is true before deciding what to do. The if/then/else construct allows you to do this. It's done in the form: if then . Any subsequent command starting with "else" will be executed on if the "if" condition evaluates to false. Ex.

if %components[roomplayers] contains "Eanur" then put say Hello, Eanur
else put say I really wish Eanur were here.

Text listeners

Text listeners set a variable when text matches the output from the server.

VAR jugglies balls
UNSETVAR hello
UNSETVAR goodbye

SETTEXTLISTENER hello says, hello
SETTEXTLISTENER goodbye says, good-bye

GOTO JUGGLE

jugglew:
PAUSE
juggle:
MATCH no_balls referring to
MATCH talk_reset roundtime
MATCHRE jugglew /^Sorry,|\.\.\.wait/i
PUT juggle my %jugglies
IF EXISTS %HELLO THEN PUT say Hello
IF EXISTS %GOODBYE THEN PUT say Good-bye
MATCHWAIT

talk_reset:
UNSETVAR hello
UNSETVAR goodbye
GOTO juggle

no_balls:
ECHO You have no %jugglies to juggle with!
EXIT

Command List

addtextlistener

addtextlistener <variable name> <string>

When string matches part of a line, variable name is set to the entire line.

addtextlistenerre

addtextlistenerre <variable name> <regex>

Regex version of addtextlistener. variable name is set to the matched text.

addtohighlightstrings

addtohighlightstrings <args>

This is taken directly from Wrayth and should match the functionality from there.

cleartextlisteners

Removes all text listeners

counter

counter <operator> <argument>

The operand for counter is always %c.

Operators:

  • set - Sets the operand to the argument. Ex. counter set 10 Results in %c = 10
  • add - Adds the argument to the operand. Ex. counter add 5 Results in %c = 15
  • subtract - Subracts the argument from the operand. Ex. counter subtract 3 Results in %c = 12
  • multiply - Multiplies the operand by the argument. Ex. counter multiply 6 Results in %c = 72
  • divide - Divides the operand by the argument. Ex. counter divide 5 Results in %c = 14

Example:

SUB_RUNTIME:
Counter set %t
Counter divide 60
SetVariable RUNTIME %c
ECHO *****************************
ECHO Running for %RUNTIME% minutes.
ECHO *****************************
Return

debug

debug <string>

Writes a string to the debug log.

debuglevel

debuglevel <numeric value (0 - 50)>

Determines how much to send to the debug log.

delay

delay <seconds>

Same as pause, except does not wait for the end of a roundtime.

deletefromhighlightstrings

Follows the same format as Wrayth.

deleteVariable

deleteVariable <variableName>

deleteVariable removes the value stored in %variableName.

Caveat: As of the time of this writing it has no impact on the value stored on the server.

echo

echo

echo prints the text to the screen.

error

Sends a message to the debug log with error priority level.

exit

exit

exit stops the currently running script.

gosub

gosub <label> <argument1> <argument2> .. <argumentN>

gosub goes to the <label> and stores the arguments in args. argument in args[1], etc.

If you want to pass multi word variables enclose them in quotes.

EG:

GoSub SUB_TEST oneword "two words" "three long words" anotherword
Exit

SUB_TEST:
ECHO 1 = %args[1]
ECHO 2 = %args[2]
ECHO 3 = %args[3]
ECHO 4 = %args[4]
return

1 = oneword 2 = two words 3 = three long words 4 = anotherword

When the function returns, all local variables are reverted to the values they contained before the gosub.

Example:Multi-Nested GoSub

goto

goto <label>

goto moves execution to <label>.

if

if then

if executes the <command> only when <condition> is true.

<condition> can be:

  • <value> = <value> - is true when both values are equivalent. Ex. if %c = 5 then ... Alias: ==
  • <value> <> <value> - is true when both values are not equivalent. Ex. if %c <> 5 then ... Alias: !=
  • <value> > <value> - is true when the first value is greater than the second value. Ex. if %c > 5 then ...
  • <value> >= <value> - is true when the first value is greater than or equal to the second value. Ex. if %c >= 5 then ...
  • <value> < <value> - is true when the first value is less than the second value. Ex. if %c < 5 then ...
  • <value> <= <value> - is true when the first value is less than or equal to the second value. Ex. if %c <= 5 then ...
  • <condition> || <condition> - is true when either condition is true. Ex. if %c > 5 || $1 = "try" then ... Alias: or
  • <condition> && <condition> - is true when both conditions are true. Ex. if %c > 5 && $1 = "require" then ... Alias: and
  • <string> contains <string> - is true when the second string is a substring of the first string. Ex. if %roomexits contains "east" then put east Alias: indexof
  • <string> containsre <string> - is true when the second string is a substring of the first string as expressed in a regular expression. If %roomexits containsre "\beast|\bwest" then put search
  • !<value> - is true when value is false. Ex. if !%happy then put say I'm so unhappy. Alias: not
  • exists <variable> - is true when the variable exists. Ex. if exists %mood then put say I'm in a mood. If NOT - Here are some examples of using not.
  • If %monstercount != 0 then echo Monsters in the room!
  • If not (%monstercount = 0) then echo Monsters in the room!
  • If not (%MyVar contains "a word") then echo %MyVar does not have the string "a word" in it.
  • If not (%MyVar containsre "\d+") then echo %MyVar doesn't have any numbers in it.
  • If (not (%rhand contains "broadsword") || not (%rhand contains "scimitar")) && %lhand contains "shield" then echo I don't have a broadsword or a scimitar in my right hand, but I've got my shield in my left hand.
  • If not (%rhand containsre "broadsword|scimitar") && %lhand contains "shield" then echo I don't have a broadsword or a scimitar in my right hand, but I've got my shield in my left hand.

Example:

SetVariable WEAPON broadsword
SetVariable WIELD-STR wield my %WEAPON
If (%WIELD-STR containsre "(left|LEFT)" && %lhand contains %WEAPON) || (not (%WIELD-STR containsre "(left|LEFT)") && %rhand contains %WEAPON) then GoSub SUB_ECHO1
else ECHO You have a %WEAPON in your right hand.
exit

SUB_ECHO1:
ECHO Your right hand does not contain %WEAPON
return

if_#

if_# <command>

if_0 - if_9 execute <command> if the variable associated with that number, %0 - %9 is set.

match

match <label> <text>

Sets some text to match output against for the next matchwait. When there is a match, execution is restarted at <label>. Ex.

match rt Roundtime
match error referring
put juggle balls
matchwait

rt:
pause
echo Done juggling.
exit

error:
exit

matchre

matchre <label> <regex>

This follows very closely to match, except rather than matching with text, it matches with a regular expression. For constructing regular expressions, please see [http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html Java Patterns]. They must be given in the form: /text to match/ with an optional trailing i for case insensitive patterns. You may find downloading and useing [http://www.ultrapico.com/Expresso.htm this tool] of high value in attempting to understand and trouble shoot regular expressions.

The matched groups from regular expressions are stored in the variables $0, $1, etc. $0 is the entire match, $1 is the first group, etc. See the page on Java Patterns for more information about groups.

'''NOTE''' Take care when using capture groups in actions, you can inadvertently pass that capture to a sub. To avoid this you can specify a non-capture with this sytax:

action SetVariable MINDSTATE LOCKED when Overall state of mind:\s+(?:very murky|thick|very thick|dense|very dense)
action SetVariable MINDSTATE CLEAR when Overall state of mind:\s+(?:clear|fluid|murky)

The "?:" keeps the string inside the parens from becoming the local variable $1

Practical example of regular expression matching;

Example assumes you've set the variable DIR2GO in previous code

MOVE2NEW-ROOMW:
Pause
MOVE2NEW-ROOM:
Matchre CRITTERLOOKCOUNT /need to disengage first|You are engaged/i
Matchre MOVE-OCCUPIED /also here|CAUTION: SNIPERS|alfar avenger/i
Matchre MOVE-CLEANUP /Obvious\s(?:paths|exits)/i
Matchre MOVE2NEW-ROOMW /^Sorry,|\.\.\.wait/i
put %DIR2GO
MatchWait 5
ECHO ~~~ Match Failed MOVE2NEW-ROOM:
GoTo GET-MOVE-DIR

matchwait

matchwait

matchwait waits until one of the matches matches some text. An optional argument of timeout will force the matchwait to stop waiting after the given number of seconds and continue execution.

math

math

math is identical to counter, except the result is stored in rather than %c.

SUB_CALCRUNTIME:
SetVariable TIMENUM %t
SetVariable NUMINT %TIMENUM
SetVariable NUM %TIMENUM
Math NUM Modulus 60
Setvariable CNTSEC %NUM
Math NUMINT subtract %NUM
Math NUMINT divide 60
SetVariable CNTMIN %NUMINT
Pause
ECHO **********************************************
ECHO Running for %CNTMIN% minutes, %CNTSEC seconds.
ECHO **********************************************
Return
This ones a little easier to digest maybe...
**********************************************

SetVariable CRITTER-COUNT %monstercount
SetVariable DEAD-NUM 0
ECHO roomobjects = %roomobjects
If %roomobjects contains "appears dead" then SetVariable DEAD-NUM 1
ECHO DEAD-NUM = %DEAD-NUM
Math CRITTER-COUNT subtract %DEAD-NUM
ECHO CRITTER-COUNT = %CRITTER-COUNT
DeleteVariable DEAD-NUM
If %CRITTER-COUNT < 1 then return
Else put retreat
return

move

move

move is equivalent to put followed by nextroom.

A practical note on moving around in DR via script.

Experience has shown me that move will sometimes fail when round time occurs, the brook you cross in the NW section of Goblins/Hogs West of the Crossing is a good example. To avoid stalling out you may want to consider the following sub routine and or some derivation of it for those instances.

MAIN-SCRIPT:
move e
GoSub SUB_SWIM e
move e
Exit

SUB_SWIM:
SetVariable SWIM-DIR $1
GoTo SWIM-MOVE

SWIM-MOVEW:
Pause
SWIM-MOVE:
Matchre SUB_RETURN /Obvious\s(?:paths|exits)/i
Matchre SWIM-MOVEW /^Sorry,|\.\.\.wait/i
put %SWIM-DIR
MatchWait 15
ECHO Failed Match SWIM-MOVE:
Exit

SUB_RETURN:
return

nextroom

nextroom

nextroom waits for a signal the your character has moved into a new room.

pause

pause

pause waits the specified period of time, and then continues waiting until the current roundtime has expired. is an optional parameter and if omitted, pause waits for 1 second.

playsound

playsound playsound plays a sound file contained in the same directory as the script. Types of sound files supported depends on platform. WAV's are usually the best bet.

put

put

put sends to the server.

caveat: If you "put .scriptname", it will run the script "scriptname" and exit the current running script. This is for backwards compatibility with how stormfront does things. If you want to run the scripts concurrently, see the Run command.

random

random

random sets %r to a random value between and inclusive.

removetextlistener

removetextlistener <name>

Removes all text listeners associated with name.

return

return

return takes execution back to where it was before the function was called. The state of local variables is returned to what it was before the function was called.

run

run <script name>

run will attempt to run script name as a script. It is similar to using put .<script name> except run will leave the current script active whereas using put would cancel the current running script in favor for the new one.

This is not yet implemented in Warlock 3

save

save

save stores into %s.

send

send <string>

Exactly the same put except does not wait for round time.

setvariable

setVariable <variableName> <value>

setVariable stores <value> into variableName.

Caveat: As of the time this was written, we do not store variables on the server.

shift

shift

Removes the first argument and moves all of the others down one place. %2 becomes %1, etc.

timer

timer (start|stop|clear)

Uses variable %t to keep track of elapsed time. start begins/resumes the timer. stop pauses the timer. clear resets the timer to 0.

unsetlocal

unsetlocal <variableName>

Unsets the local variable variableName.

unsetvar

unsetvar <variableName>

Unsets the global script variable variableName.

var

var <variableName> <value>

Sets global script varible variableName to value.

wait

wait

Halts execution until a prompt is received.

waitfor

waitfor <text>

waitfor halts execution until <text> is received.

waitforre

waitforre <regex>

waitforre is identical to waitfor except it takes a regular expression and the groups are stored like matchre.

Predefined Variables

  • %t - variable used by the timer
  • %c - variable used by count
  • %s - variable modified by save
  • %r - variable modified by random
  • %rt - time remaining on the roundtime
  • %properties - map variable containing various changing elements. %properties["roundtime"] contains the current roundtime.
  • %components - map variable containing the stream components. %components["exp Appraisal"] contains the current value of the stream components for the exp of "Appraisal".
[Mistwood Forest, Treetop]
From your vantage point you can see a stone road below.  To the east, as the forest thins, the branches become less dense and tangled.  A series
of blue rags, tied to branches, marks a route through the thinning forest canopy to the east.  The trunk of one tree is scratched on one
side, as if it has been used frequently to climb between the ground and the treetops.  You also see some silver coins, some bronze coins, some
copper coins, a gold-taloned elder forest gryphon that is flying around, a scruffy leopard that is sitting, a fiery fissure and some junk.
Also here: Bogus who is surrounded by an opalescent cobalt blue ethereal shield.
Obvious paths: east, southeast, southwest, west, northwest.
[script started: 1]
[1]: ***************************************
[1]: ~~Title = Room - Mistwood Forest, Treetop
[1]: ***************************************
[1]: ~~roomdesc = From your vantage point you can see a stone road below.  To the east, as the forest thins, the branches become less
dense and tangled.  A series of blue rags, tied to branches, marks a route through the thinning forest canopy to the east.  The trunk
of one tree is scratched on one side, as if it has been used frequently to climb between the ground and the treetops.
[1]: ***************************************
[1]: ~~roomobjects = You also see some silver coins, some bronze coins, some copper coins, a gold-taloned elder forest gryphon that
is flying around, a yelith root, a bishop arrowhead, a scruffy leopard that is sitting and a fiery fissure.
[1]: ***************************************
[1]: ~~roomplayers = Also here: Bogus
[1]: ***************************************
[1]: ~~roomexits = Obvious paths: east, southeast, southwest, west, northwest
[1]: ***************************************
[script stopped: 1]