Warlock Scripting LanguageEdit
We call it WSL for Wizard Scripting Language or Warlock Scripting Language. It's left purposefully ambiguous and could just as easily be Stormfront Scripting Language, but SSL is already taken.
Our scripting language is based very closely on the language from the Wizard and from StormFront, with some additions from other sources. (Add more stuff here)
In computing, regular expressions, also referred to as regex or regexp, provide a concise and flexible means for matching strings of text, such as particular characters, words, or patterns of characters. A regular expression is written in a formal language that can be interpreted by a regular expression processor, a program that either serves as a parser generator or examines text and identifies parts that match the provided specification. Warlock is just such a program, this link will provide you with a tool to assist you in understanding and using regex's!
Most lines consist of a single command with some argument(s). Ex.
echo Hello, World.
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
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 would display "Hello, World."
Variables can contain any characters. The first form given above ends the variable name on "%", "$", whitespace, "(", and ")". The second form can contain those characters, but "(", and ")" must be escaped with a backslash. We recommend only using A-Z, a-z, 0-9, and _, but for compatibility we allow symbols as well.
Concatenating variables: Sooner or later you’re going to want to do this and understanding the value as well as how to do it is important. With WSL there is no way to build an array, however you can build a poor mans array with inventive use of the “counter” and the concatenation of variables!
Suppose you want to cycle through a list and act on every item in the list? This example will demonstrate the concept.
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 contain any character other than ':' (colon). To keep anyone who looks at your script from getting a headache though, please try and stick to letters, numbers, and underscores. Although labels can contain % and $, they wont dereference variables. So if you had a variable "box" with the value "thing" and a label "%box:", the label wont evaluate to "thing". You can still use variables in gotos, or matches however and they will be dereferenced before the lookup.
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 "$1", "$2", etc with the entire list being stored in "$0". "return" brings execution back to the command after you called the function. Ex.
gosub printHello World echo Good-bye exit printHello: echo Hello, $1$. return
The result of this would be "Hello, World." followed by "Good-bye".
IMPORTANT See NOTE under Matchre
Variables that start with "$" are treated as local variables. Any local variables you create or change only have effect within the local scope. The scope is defined to be within the current function. (More about functions later.) Ex.
setLocalVariable 1 foo gosub testing bar echo The value in 1 is $1 exit testing: echo The value in 1 is $1 return
They output of this sequence would be "The value in 1 is bar" followed by "The value in 1 is foo".
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 <condition> then <expression>. Any subsequent command starting with "else" will be executed on if the "if" condition evaluates to false. Ex.
if %roomplayers contains "Eanur" then put say Hello, Eanur else put say I really wish Eanur were here.
Actions are commands that are execute whenever their text matches the output from the server. They are given in the form: action <expression> when <text>. You can remove an action with "action remove <text>" and remove all actions with "action clear". Ex.
action gosub sayHello when hello action gosub sayGoodbye when good-bye waitfor quit sayHello: action remove hello put say Hello. return sayGoodbye: action remove good-bye put say Good-bye. return
NOTE: My experience with Warlock informs me that using gosub or goto from an action command is not a 100% proposition. I’m not versed in the engines code and I can't tell you why technically. I have used WSL scripts since July of 2008. The script above will always work, it’s sitting there doing nothing but waiting until it sees “quit”. However if you are trying to say “hello” when someone or some thing (theres a difference) says it and your in the middle of juggling or some other activity I would suggest the following…
SetVariable JUGGLIES balls SetVariable HELLO FALSE SetVariable GOODBYE FALSE action SetVariable HELLO TRUE when says, hello action SetVariable GOODBYE TRUE when 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 %HELLO = “TRUE” then instant put say Hello If %GOODBYE = “TRUE” then instant put say Good-bye MatchWait TALK-RESET: SetVariable HELLO FALSE SetVariable GOODBYE FALSE GoTo JUGGLE NO-BALLS: ECHO You have no %JUGGLIES to juggle with! Exit
action <command> when <regex>
<command> whenever text matched by
<regex> is received.
action remove <regex>
Removes the action with the text
Removes all of the actions.
counter <operator> <argument>
The operand for
counter is always %c.
- set - Sets the operand to the argument. Ex.
counter set 10Results in
%c = 10
- add - Adds the argument to the operand. Ex.
counter add 5Results in
%c = 15
- subtract - Subracts the argument from the operand. Ex.
counter subtract 3Results in
%c = 12
- multiply - Multiplies the operand by the argument. Ex.
counter multiply 6Results in
%c = 72
- divide - Divides the operand by the argument. Ex.
counter divide 5Results in
%c = 14
- modulus - Divides the operand by the argument, and stores the remainer in the operand. Ex.
counter modulus 8Results in
%c = 6
- log - Takes the log with the base provided by the argument (default 10) or the operand.
- ln - Takes the natural log of the operand.
SUB_RUNTIME: Counter set %t Counter divide 60 SetVariable RUNTIME %c ECHO ***************************** ECHO Running for %RUNTIME% minutes. ECHO ***************************** Return
Also see; #MATH (Math handles operations on user created variables)
debug <numeric value (1 - 3)>
Echos varying levels of your script to screen starting with just setvariables and going up to every line executed. Use with caution, screen scroll becomes horrific in larger scripts!
Adds a delay of
<seconds> to the end of every roundtime before continuing on with the next command. Can be a fraction of a second as in
delay 0.5. As of sometime in Feb 2013 this appears to be bugged, will stall the script if used.
deleteVariable removes the value stored in
Caveat: As of the time of this writing it has no impact on the value stored on the server.
echo prints the text to the screen.
<command> if the last if condition was false.
Caveat: else cannot contain an action or another if at the time of this writing.
exit stops the currently running script.
getcomponent <variable> exp <experience name>
getcomponent returns the text of the exp requested as seen in the field experience window to
<experience name> is the full name as seen when you input exp all.
SetVariable EXP2CHECK Mechanical Lore GetComponent EXPVALUE exp %EXP2CHECK If %EXPVALUE > 0 then Echo EXPVALUE = >>>%EXPVALUE%<<< If %EXPVALUE < 1 then Echo You're not learning any %EXP2CHECK Exit
In the above example you get back something like;
EXP2CHECK = >>> Mechanical Lore: 567 44% intrigued <<<<
Note the inclusion of the spaces on the front and back of the text string.
You're not learning any Mechanical Lore
This sub routine, SUB_GET-EXP-VALUE will return a numerical value of the experince you request to a variable of your choice. This is the number you see that proceeds /34 when you input the DR exp command. Instructions are commented in the code.
getstatus <status type>
getStatus saves the status (true or false) to
getstatus <variable> <status type>
getStatus saves the status (true or false) to
StatusType's = bleeding | dead | hidden | invisible | joined | kneeling | prone | sitting | standing | stunned | webbed
GetStatus standing Echo standing = %standing GetStatus AM_I_SITTING sitting Echo AM_I_SITTING = %AM_I_SITTING exit
gettime Saves the number of 10ths of a second from the start of January 1, 1970 to
GetTime CURRENTTIME1 pause 10 GetTime CURRENTTIME2 math CURRENTTIME2 subtract %CURRENTTIME1 ECHO %CURRENTTIME2 exit
This should return 100 or very close to it.
getvital <Vital Name>
getvital saves the vital value to <Vital Name>
getvital <Variable> <Vital Name>
getvital saves the vital value to <variable>
Vital Name's = health | mana | stamina | spirit | concentration
GetVital health Echo health = %health GetVital MYHEALTH health Echo MYHEALTH = %MYHEALTH GetVital mana Echo mana = %mana GetVital MYMANA mana Echo MYMANA = %MYMANA GetVital stamina Echo stamina = %stamina GetVital MYSTAMINA stamina Echo MYSTAMINA = %MYSTAMINA GetVital spirit Echo spirit = %spirit GetVital MYSPIRIT spirit Echo MYSPIRIT = %MYSPIRIT GetVital concentration Echo spirit = %concentration GetVital MYCONCENTRATION concentration Echo MYCONCENTRATION = %MYCONCENTRATION exit
gosub <label> <argument1> <argument2> .. <argumentN>
gosub goes to the
<label> and stores the first argument in
$1, the second in
$2, etc, and the entire list in
If you want to pass multi word variables enclose them in quotes.
GoSub SUB_TEST oneword "two words" "three long words" anotherword Exit SUB_TEST: ECHO $0 ECHO $1 ECHO $2 ECHO $3 ECHO $4 return $0 = oneword "two words" "three long words" anotherword $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
goto moves execution to
if <condition> then <command>
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 eastAlias: 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.
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
<command> if the variable associated with that number,
%9 is set.
This will bypass the normal checks on a command, so that it can happen during RT.
instant put I don't care if this happens during RT
match <label> <text>
Sets some text to match output against for the next
matchwait. When there is a match, execution is restarted at
match rt Roundtime match error referring put juggle balls matchwait rt: waitRoundTime echo Done juggling. exit error: exit
match <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 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 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 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 <operand> <operator> <argument>
math is identical to
counter, except the result is stored in
<operand> rather than
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 is equivalent to
put <direction> followed by
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 waits for a signal the your character has moved into a new room.
pause waits the specified period of time, and then continues waiting until the current roundtime has expired.
<time> is an optional parameter and if omitted,
pause waits for 1 second.
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.
<text> 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 <min> <max>
%r to a random value between
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 <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.
setLocalVariable <variableName> <value>
Exactly the same as setVariable, except works on local variables rather than global variables.
setVariable <variableName> <value>
Caveat: As of the time this was written, we did not store variables on the server.
shift removes the first argument and moves all of the others down one place.
shift local does the same thing to $1, $2, etc. instead of %1, %2, etc.
timer (start|stop|clear) (optional variable)
%t to keep track of elapsed time, unless a variable is specified.
start begins/resumes the timer.
stop pauses the timer.
clear resets the timer to 0.
wait halts execution until a prompt is received.
waitfor halts execution until
<text> is received.
waitforre is identical to
waitfor except it takes a regular expression and the groups are stored like
- %t - variable used by the timer
- %c - variable used by
- %s - variable modified by
- %r - variable modified by
- %rt - time remaining on the roundtime
- %roundtime - alias to %rt
- %monstercount - contains the number of monster-bold things in the room, that includes monsters, familiars, dead monsters, alfar avengers, etc. You must have monsterBold set for this to work. If it's not set, this will always be 0.
- %rhand - contents of the right hand (returns "Empty" if nothing in hand)
- %lhand - contents of the left hand (returns "Empty" if nothing in hand)
- %spell - spell currently being prepared (returns "None" if no spell is being prepared)
- %roomdesc - description of current room (maybe room last looked at)
- %roomexits - room exits
- %roomplayers - uh, players in the room (the expression [If %roomplayers = " "] is true if there are no players visible in the room)
- %roomobjects - you know... stuff on the ground and also critters in the room.
- %roomtitle - As of 3/11/10 if the room title is [Crossing Bank] this will return (without the quotes) "Room - Crossing Bank"
- %lastcommand - The last command sent to the server
- %character - The named of the current character you're playing.
[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] : *************************************** : ~~Title = Room - Mistwood Forest, Treetop : *************************************** : ~~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. : *************************************** : ~~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. : *************************************** : ~~roomplayers = Also here: Bogus : *************************************** : ~~roomexits = Obvious paths: east, southeast, southwest, west, northwest : *************************************** [script stopped: 1]