winds.org
, port 8000
. The guide was formatted for WikiMARE by SluggyQBFreak. Please note that the guide is written from the perspective of Workaphobia and for the MARE SluggyMARE. Happy reading
<Arguments>
Command/coding examples |
Commands in sentences
[public]
, so if you don't tamper with your settings you can simply put an equals sign (=
) in front of any text to use it.
To join a channel: =
) will display a list of other users on that channel.
Tying this all into one example:
[public] Jason: anyone up for a schlock game? [public] Komo: sure =switch over to the schlock channel so we don't spam the other guys. [public] Workaphobia: switch over to the schlock channel so we don't spam the other guys. +ch schlock [schlock] * Workaphobia has joined this channel. Channel schlock is now default. =who Workaphobia is on channel schlock, idle 0s. Vermithrax(36m) is on channel schlock, idle 36m. Poltergeist is on channel schlock, idle 58s. Komo is on channel schlock, idle 1s. Honor is on channel schlock, idle 5s. Frost(6d) is on channel schlock, idle 6d. There are 6 players on channel 'schlock'. [schlock] Honor: How do you play? =I'll tell you after everyone gets on here. [schlock] Workaphobia: I'll tell you after everyone gets on here. +com public=last call [public] Workaphobia: last call [schlock] * Jason has joined this channel. |
public
channel.
The first is simply pub
. Typing pub message
will always send your message to the public
channel, regardless of your current channel (unless of course you left public
, but why would you do that?).
Next is a nifty way to do thought bubbles on public
, and that is pub.thought
. Please note that you cannot use pub .thought
(see that space in there) or =.thought
, you must use pub.thought
(no space, pub not =). This is due to reasons and that's just the way it is.
Lastly, a recent addition is cpub message containing *name
. This will allow you to include a player's colored name (cname) in chat, without jumping through a bunch of code hoops to make it happen. Note the *
before the name. This is how the cpub
command knows to expand the name into the colored name. You can also substitute player aliases instead of names to save a few characters when typing.
pub <message>pub Hey, everyone! I'm on the public channel now. [public] QBFreak: Hey, everyone! I'm on the public channel now. pub.It's awfully quiet in here, where IS everyone? [public] QBFreak . o O ( It's awfully quiet in here, where IS everyone? ) cpub Hmm, I wonder what *har is up to. [public] QBFreak: Hmm, I wonder what Harena is up to. |
com
. It works just like cpub
in that if your message contains one more more *name
or *alias
they will be expanded to the colored name of the player that matches.
com <channel>=<message>
com spam=Hey *nmb, I see you're on spam too. [spam] QBFreak: Hey NightMAREbot, I see you're on spam too. |
"
).
"<message>
Note that a closing quotation isn't needed.
To talk to a single player in the same room, you can use the whisper command.
whisper <player>=<message>
Other players will see that you used this command and who you sent it to, but not the actual message.
Alternatively, there's the page command, which will work across distances and not inform anyone else that you used it.
page <player>=<message>
<player>
in this case can also be a space-separated list of people.
You can block pages from a particular user:
@plock me=<lock code>
Lock code is explained in the builder section.
Posing, or emoting, is used to express a narration of what your character is doing. For room chat, the following command replaces say:
pose <message> ;
) instead.
;<message>
For pages or channels, put a colon or semicolon in front of your message but use the same command.
To direct a message to a single person but still allow multiple players to see it, use the to command. Just like posing, the word to is only used for room chat. In other commands, use its alias - a single quotation mark ('
) - followed by the name then a space.
to <player> <message> QBFreak has arrived. QBFreak walks from the north. QBFreak says "how do you get out of this maze?" pose is stumped. Workaphobia is stumped. [public] * Honor has joined this channel. ='honor any idea how to get out of the maze [public] Workaphobia [to Honor]: any idea how to get out of the maze [public] Honor: I dunno..didn't polt make it? p polt=how do you get out of here? You paged Poltergeist with: how do you get out of here? Poltergeist (polt) pages: Not telling. Take a look around. p polt=:has tried everything You paged Poltergeist with: Workaphobia has tried everything. |
.
shortcut.
.<message>
.I like fish QBFreak . o O ( I like fish ) |
look Cafe You are standing in a cafe, away from the bustle of the busy streets of the city. The interior is painted black and gold, and a large dark green chalkboard on which the menu has been written is hung on the wall behind the counter. There is a barista waiting behind the counter to take your order, reading a paperback novel to pass the time. The air smells pleasantly of coffee and cinnamon, and the murmur of the other customers is quiet and unintrusive. Contents: Komo the Demon lord on a rebound Plastic Sword is fake Bunbun the Mini-lop Giant eye Is here to help you try out your death scene.Ask Jason how to use @okill (Flying) Cronix Type 'talk cronix' for help and amusment.Will restore you for 20+5 p lvl. (Flying) Crystal waits for the next customer. Helpful Tribble V 2.0, coos gently. You could ask it for help if you wanted to. Dimensional Flux Agitator ATM is a lean green machine Jukebox Teleport Pad blinks Obvious exits: Room O' Stuff <W> Nexus <X>(dark) North <N> Door <S> News Room <E> OOC <Y> n You walk to the north. Kent Street The forest slowly engulfs Kent Street from both sides. To the south, you can barely make out a house at the end of a drive, in the trees. To the west off in the distance, you see some buildings and what might be a gate. The woods obscure your vision to the north. Contents: Mossy Rock Obvious exits: West <W> Cafe <S> East <E> l rock Mossy Rock Table It's covered in moss. What more do you need to know? get rock Mossy Rock has left. Mossy Rock has arrived. Taken. give table=rock You give Mossy Rock to Table. l table Table You see nothing special. Carrying: Mossy Rock |
who
, @whoflags me=name idle.
To block yourself from view in the wholist, use hlock: "
for the say command, =
for +com), or various alphabetic ones.
Rather than use names at all, you can substitute in the object's database reference identification number (prefixed by a pound sign (#)) for the name, which eliminates the possibility of selecting the wrong object (except through typo). To refer to a player who isn't in the room, you can use their full name, but generally not a shortened piece of text unless it's set as their alias. If the command isn't specifically intended for use with players (like the page or where commands are), you may need to insert an asterisk (*) in front of the name, which indicates you want the game to search for the person by the list of players and not through room contents from your perspective.
Finally, although you could refer to yourself by name, it's easier to use the keyword me
instead; for the room you are in, here
.
to top
Consider
will give you more detailed information. Common monsters build a reputation with the players for how strong they are, and you can normally ask another player if engaging in combat with a particular type of enemy is wise. Note: Consider
is a softcode command specific to SluggyMARE; it may not work elsewhere.
fight <enemy>
Combat on the MARE is based on simultaneous rounds of attacks. Each combatant's fight speed is dependant on its agility stat, and typically ranges from 3.0 - 6.0 seconds. You will automatically deal damage with your normal physical attack, but at any time you can type in a command to execute a special skill or tactic. Whenever you defeat a monster, you will gain experience and possibly gold. In your status window, you can see the number of experience points needed to advance to the next level. At each levelup your stats increase by a few points.
When your health reaches zero, your character is set Wounded. That is, you cannot move or fight back, and your health is reset to half your max. At this point you have to wait for the enemy to finish you off. If that is too slow for you, or the enemy has disappeared, you can kill your own character.
suicide Suicide
is another softcode command.
CORRECTION REQUIRED: Update to handle the regen chamber
When you die - and it will happen many times - you respawn at your save point, which can be either a room you own or a public room that is set with the Adobe flag. Use the save command: @create
. You'll find that almost all the building commands start with an at-symbol (@).
@create <object name>
The MARE creates a new object with a unique ID#, then gives you ownership and places it in your inventory. It is completely void of any interesting information until you edit its attributes. Attributes are adjustable properties that control how your object appears and reacts to events. Built-in attributes have one role only, but custom ones can be used in multiple ways, though they are somewhat less powerful.
To set attributes: @set
I'd delete the object instead.
Attributes can hold either values (such as numbers, letters, ID#, names, etc) or code. The parser makes the distinction based on how you use it, so there is no need to declare something as a certain "type", as people familiar with programming might assume - the closest thing to that would be declaring an attribute with certain Options, which limit or reformat the value. Built-in attributes are reserved for specific functions, such as @desc, @caption, and @color mentioned earlier. To clear an attribute, set it to blank -- put nothing after the equals sign or colon.
When naming Things, note that they generally shouldn't contain articles (a, an, the) or many adjectives - that's what @caption is for.
If you decide you no longer need an object and want to get rid of it, you can @destroy
it.
@destroy <object>=<countdown timer (in seconds)> | now @undestroy
the object. Objects awaiting destruction are marked with the Going flag.
The @decompile
command interprets every attribute on an object and prints back a series of commands you would need to enter to recreate it exactly.
@decompile <object>
Depending on the circumstance it may not work precisely, but it's good for backing up an object or trying to get the syntax for a particular statement.
Finally, you can give ownership of an object to another player with @chown
. For security reasons, the other person must enter the command, not you, to make sure they agree to the transaction. The object has to be set with the Chown_Ok flag by the owner first.
to top
@lock beach ball=me|*my_friend|*cool_guy @lock beach ball=!*jerk_I_don't_like @lock beach ball=+super key |
@create Magic Void @set magic void=enter_ok @elock magic void=me|*qbfreak @efail magic void=You can't fit into the void. @oefail magic void=tries to fit into the void and practically suffocates. @enter magic void=You are sucked into the empty void. @oenter magic void=is pulled into the vacuum void. @leave magic void=You find a rip in the space-time continuum and exit the void. @oleave magic void=materializes from the void. |
@dig
command.
@dig <roomname>=<exit to room;alias 1;alias 2;...>,<exit from room;alias 1;alias 2;...>
You will be notified of the ID# assigned to the new room. The exit arguments are optional, but any room that has no entrance will periodically alert you that it is unconnected. When naming exits, you should state the door and then the direction in angled brackets (<>). You can include as many aliases as you want, but generally all you need is the direction. Try not to alias exits to built-in commands (it once baffled me for quite some time when pressing "l" for look
pushed me into another room).
Example names: Window <E>;window;east;e Outdoors <S>;out;o;south;s Park <N>;park;north;n |
@name
it. To add aliases, you can either @name
or @alias it, the only difference being that with @alias you can't change the part the player sees.
To reconnect an exit to another existing room: @push
an exit to the front of the obvious exits list. Try to arrange them in this order to make them easily readable.
@push <object>
@push
can also be used on objects in a room, to bump them to the top of the contents list.
to top
Pose
and say
are not the only ways to display text in a room. The @emit
command will parse a message and print it to everyone in the room, without prefixing it with your name. This can have a number of uses, such as narrating events. Related commands:
To send a message to...
Your current room: @print
is similar to @pemit
, but automatically assumes the object to send the message to is the invoker (%#), and only does so if it is still in the room at the time it runs.
@echo
, @emit
, and @pemit
have counterparts @necho
, @nemit
, and @npemit
which do not parse the message at all. @nemit
is especially useful when you want to send someone a piece of code and don't want it to parse in the process.
You cannot begin any @emit
message with a player's name. This is called Spoof Protection, and prevents someone from impersonating another player.
to top
@zemit
), describing an event that is supposed to occur over a large area. Also, there are special functions relate to zones, and some events and attributes defined in a zone apply to all the rooms it holds.
To create a zone: @addzone
to @add
, which is the shorthand form of a @addparent
. Zones can be expensive to create, and should not be used for small areas. Though it depends on how they are going to be used, zones are ideal for areas 20-100 rooms large.
to top
A | Adobe | allows anyone to save in your room |
C | Chown_Ok | allows other players to assume ownership of the object |
D | Dark | when set on players, it prohibits tracking their movement with the where command. On rooms, it stops people from seeing objects or exits unless there is a light source. On objects, it stops that one alone from being seen. On exits, it completely removes them from the obvious exits list, even if there is a light source. |
J | Jump_Ok | allows people to @teleport to your room if teleportation is not restricted. It also allows players to see the ID# in a normal look command. |
L | Link_Ok | allows players who do not own the room to still @link exits to it (though particular players can be blocked with @llink. Exits can not be =@open=ed back. |
V | Visible | players other than the owner can examine the object to see all its attributes. If set on a player, it allows other players to use status to see full information. |
e | Enter_Ok | allows everyone to give this object another object or to enter it themselves. They still must pass @elock |
g | Grab_Ok | allows everyone to grab an object from this object, assuming they pass the @lgrab |
h | Haven | prevents any queued commands from executing on the object - this pretty much means it's incapable of running most code, and is useful for parent objects (explained later) |
%# | number of invoking object |
%n | name of invoking object |
%! | number of object using this pronoun |
%u | name of object using this pronoun |
%l | number of the location of the invoking object |
%s | grammatical subject pronoun of invoking object (he, she, it) |
%o | grammatical object pronoun of invoking object (him, her, it) |
%p | grammatical possessive pronoun of invoking object (his, her, its) |
%r | newline character |
%b | space character |
%g | beep character |
%0-%9 | arguments replaced by data |
%va-%vz | replace with contents of attribute |
%? | function invocation and recursion level (advanced) |
%x | additive color (advanced) |
@force
, on the other hand, will queue the command.
Whenever an object fails a command because it can't understand the syntax, you receive a message indicating the ID# and command. Admins also see this information.
Next, you can cause a particular attribute of code on an object to execute.
@trigger <object>/<attribute>=<argument 0>,<argument 1>,...,<argument 9>
Pronouns %0 - %9 found in the attribute will be replaced by the arguments. Only code attributes, not text attributes, should be triggered. Although I seldom use it, you can set an attribute with the haven option (similar to but not to be confused with the flag), to directly prevent it from being triggered.
In terms of parsing, all these methods of causing code to run preserver whatever %# caused them, and will not override it with their own ID#s.
to top
@defattr
.
@defattr <object>/<attribute>=<options> <options>
for now, but note that if you use @defattr
on an existing attribute you can reset its options.
Code itself is a series of commands like you would enter, separated with semicolons. A very simple example:
@create Balloon @defattr Balloon/Bounce @bounce balloon=move north;pose bounces around. |
move
command. Pose
can also be abbreviated to its normal alias of a colon.
to top
<delimiter>
character (which defaults to a space if left out)
Note: When you nest functions, you should generally avoid using %0-%1 (try to use v(0)-v(9) instead). Also, don't put hard brackets around the inner function. The reason will be explained in the parsing section.
This is only a small sample of the dozens of functions at your disposal. To see them all, @list
functions or type help function
list.
to top
@wait
delays a command in the queue for a number of seconds.
@wait <seconds>=<commands>
<seconds>
can be a constant integer or a number retrieved in code, but you cannot use fractional numbers.
@bounce balloon=@wait 2=pose bounces out of control.;@wait 5=pose starts to slow down;@wait 8=pose pops! |
@wait
does not affect the commands immediately following it (unless curly brackets are used to specifically nest one within the other), so the second part of that example is delayed 5 seconds, not 7.
Next is the @switch
command, which evaluates a statement and checks a list of possible matches, then executes the command right after it. If there is an extra command at the end without a corresponding value, that part will be considered a default command group if no matches are found.
@switch <expression>=<value 1>,<command 1>,<value 2>,<command 2>,...,<default command>
@bounce balloon=@switch rand(6)=0,@emit The balloon is untouched.,1,@emit The balloon bounces once.,2,@emit The balloon bounces twice.,3,@emit The balloon bounces three times.,4,@emit The balloon bounces four times.,5,@emit The balloon bounces five times. |
@foreach
.
@foreach <counter>=<commands>
<counter>
is any text consisting of words (space-separated text). Every word causes another execution of <commands>
, subbing in that particular part of <counter>
in any %0s or v(0)s found in <command>
. @foreach 5=... will not run five times, but only once, with a value of 5 inside %0. Instead, use the lnum() function.
@bounce balloon=@foreach lcon(here)=pose bounces off [name(v(0))]. |
@bounce Balloon=@foreach lnum(v(0))=@wait mul(v(0),3)=@switch rand(2)=0,{@oemit %# The balloon bounces around the room, hitting %n.;@pemit %#=The balloon bounces around the room, hitting you on the head!},{@emit The balloon narrowly misses %n!} |
@iterate
. It runs a command, then executes another command on every line it returns, using pattern-matching wildcards. In a way, it's a more complicated version of @foreach
.
@iterate <pattern>=<initial command>,<command to execute on results>
@iterate *:0=ex me,@echo v(0) |
@trigger
ing it manually. There are three event methods to activate code.
$events can be activated by players that are in range -- that is when a player is in the same room, within the object, or holding the object (and also within a zone if that's where the event is). It is set with a pattern, and triggered by the player whenever what they type matches the pattern.
To make a custom attribute a $event: <pattern>
can be any text that is not part of a hardcoded command. To add flexibility, "*" and "?" wildcards can be used, where "*" represents any amount of text and "?" can only mean a single character. When a player uses the event, %0-%9 are replaced in the commands by whatever fills each wildcard, in order.
Modify the previous example to:
@bounce Balloon=$throw =:@foreach lnum(v(1))=@wait mul(v(0),3)=@switch rand(2)=0,{@oemit %# The balloon bounces around the room, hitting [name(v(0))].;@pemit %0=The balloon bounces around the room, hitting you on the head!} ,{@emit The balloon narrowly misses [name(v(0))]!} |
@foreach
loop and is unchanged by this.
Here's a Sluggy example: @flick cycloptis intelehentay=$flick *:@switch num(v(0))=num(me),{@emit %N flicks the Cycloptis Intelehentay in the head.;@switch rand(5)=0,{say Oh you're just asking for it, buddy!;f %#},1,{say Stop it! I hate that!},2,{say Quit it!},3,{say I'm gonna get REAL MAD if you don't stop!},4,{say Keep away from me!;move randexit(me)}} |
@switch
takes the wildcard partial text and checks to see which object the player is referring to if there are many of these objects in the room (though there are better methods to do this). Only the first one in the room's contents list will match. Then a random response is selected.
Another way to trigger commands is the event. It works the same as $events, but it responds to text that it hears (from @emit
, pose
, say
, etc) instead of commands the player types. The syntax is exactly the same except that an exclamation point simply replaces the dollar sign.
The final type is the ^event, which is a version of $event that ends with a reference to the target object. This makes it work similar to a simple built-in command such as look
. ^kick: would be triggered upon the player typing "kick <object's name, alias, ID, etc>". Rewriting the previous example:
@flick cycloptis intelehentay=^flick *:@emit %N flicks the Cycloptis Intelehentay in the head.;@switch rand(5)=0,{say Oh you're just asking for it, buddy!;f %#},1,{say Stop it! I hate that!},2,{say Quit it!},3,{say I'm gonna get REAL MAD if you don't stop!},4,{say Keep away from me!;move randexit(me)} |
@force
and @trigger
your objects, they can do so back to you. Never make a public object that has something similar to $do *:@force *Your_Name=[v(0)] without setting @ulock on it, or anyone could force you to do anything, including fighting monsters, dropping gold, or worse. This is exceptionally bad if you have admin powers.
to top
colorlist
or colorhelp
. Both of these commands are specific to SluggyMARE.)
You should be familiar with the 16 basic colors:
0 | Normal | 8 | Dark Gray | |
1 | Red | 9 | Light Red | |
2 | Green | 1 | Light Green | |
3 | Brown | 1 | Yellow | |
4 | Blue | 1 | Light Blue | |
5 | Purple | 1 | Light Purple | |
6 | Cyan | 1 | Light Cyan | |
7 | Gray | 1 | White |
0 0 0 0 0 000 0000 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | \ \ | | | | \ \ -------- #1-4: Primary Color Value (Number 0-15) | | \ \ \ ----------- #5-7: Secondary Color Value (Number 0-7) \ \ \ \ \ \ \ \ \ --------------- #8: Flashing Text \ \ \ ----------------- #9: Underlined Text \ \ ------------------ #10:Primary Color is Background Instead of Foreground \ -------------------- #11:Primary Color is Rainbow --------------------- #12:Secondary Color is Bright Instead of DarkThe first (right) four represent the actual foreground color, as listed 0-15. The next three control the background color, which can be any of the 8 dark color versions. If the next bit is a 1, the text will flash. After that is underlined text. #10 switches the background color with the foreground color. The next makes the foreground follow a rainbow pattern. Finally, bit #12 makes the background color bright. Depending on your display settings and client limitations, you may not be able to see some formatting types. Unfortunatly, some clients have been known to horribly skew certain options making them unreadable. Many times the dark navy blue color is unreadable, and I've known one client that will display entire lines in rapidly blinking text. Go through each bit and decide what color options you want, then take the number and convert it to decimal. The alternative letter method of setting colors is to use symbols and letters, as follows:
Base Colors: | Formatting Flags |
r,1 - red | h,+: highlight |
g,2 - green | u,-: underline |
y,3 - yellow | f,#: flash |
b,4 - blue | /: half intensity |
p,5 - purple | i,!: invert |
c,6 - cyan | capital letter: set background color |
w,7 - white | *: rainbow (ansi() or @color only) |
look
at yourself - or for those of you that prefer the hard yet flexible way, @echo ctext(name(me),{<color code>}).
Although it's rare, sometimes ANSI escape patterns aren't turned off by the game for various reasons (brought about by something amiss in softcode), and you end up seeing text that would usually be grey in an odd color - "color flooding". Normally performing some sort of action that displays more color to you will turn off whatever tag was left over.
to top
@wait
commands are put in the wait queue, while most other commands go into the immediate queue.
To see pending commands:
@ps @halt
it. Note that as a non-builder, excessive amounts of queued commands may result in a monetary penalty, just as creating an object would cost gold.
Semaphores are an interesting concept. They are basically @wait
commands, but instead of storing a command in the queue under just a countdown timer and object ID#, they add on an identification string. This means that the command can now be manipulated before it's executed - it can be replaced, retrieved, and removed (without using @halt
, which is more for runaway objects than simple runtime procedure).
@wait <seconds>/<string>=<commands> @clone
(@clone <object>) it, which reproduces it exactly, or use object parenting. With @clone
, every time you wanted to make a single change, you would have to do so with many different objects. If you allow other players to @chown
them away, this means you would have to instruct the player how to make the change or get them to temporarily give it back to you. Meanwhile, child objects with parent code merely have a reference to one object with one block of code, and any changes there will filter down to all the others. Not only that, but it will also save memory.
Any object can be a parent.
@addparent <object>=<parent> @list attributes
). For a user-defined one, you must set the Inherit option.
Remember that the syntax for @defattr
is @defattr <object>/<attribute>=<options>
Simply add =inherit to the end of a normal statement. Using @defattr
on an already existing attribute will reset/change the options.
When examining the child, you will normally not see inherited attributes unless you examine <object>=all or examine that attribute specifically (examine <object>/<attribute>).
If the attribute is already set on the child, that value will override the one assigned by the parent.
You can also set the Dark option, which means if someone else owns the child they still cannot see or modify what is in the attribute, and the Wizard option, which means the child attribute can't be altered except by admins or changing the parent.
Parental controls (inheritance functions): <object>
<object>
<object>
has <parent>
, even if it's inherited indirectly through other parents
If you want to make your parent public so that any other player can use it, set it with the bearing flag. To then control who exactly may @addparent
from it, set its @lparent lock.
to top
help function list
- section number 8. <wordlist>
, starting at <start>
and continuing for <length>
words <word>
in <wordlist>
, using <delimiter>
to count wmatch()
, but it returns a space seperated list of all occurances <wordlist>
<position>
word with <replacement>
setdiff(<list1>,<list2>,<input delim>,<output delim>) - returns all words in <list1>
that are nowhere in <list2>
<list1>
that are also in <list2>
help function list
section 2: <string>
if <expression>
is true <expression>
is false <expression>
as the true string
eq(<number1>,<number2>) - this is a numerical equality test (1/0 return), as opposed to match() which tests string equality. For example, match(1,1.0) would be false, while eq(1,1.0) is true. I'll omit lt(), gt(), lteq(), and gteq(). They are the same as eq, but obviously test for less than, greater than, less than or equal, and greater than or equal.
truth(<expression>) - this converts <expression>
into its logical 0 or 1, if it's false or true. It is absolutely redundant to use this within another logical function, because it will automatically determine the truth value. This function is really intended for when you need to narrow down an expression into a one or zero, such as when you're doing a literal (not logical) comparison (such as in a @switch
) or are printing out a message. <string>
to one of the %0-%9 variables for use later in an expression. It only applies to the current command/expression, then goes out of "scope", that is, it's cleared. To get it to apply to multiple commands you can include it just before a @force
or some other command that groups other commands in {}, or in the attribute lock of an event. This is because queued commands carry over previously existing variables.
setr(<register>,<string>)
This is identical to setq(), but returns the value before copying it to the <register>
switch(<expression>,<value 1>,<string 1>,<value 2>,<string 2>,...<default string>)
The switch() function behaves very much like the @switch
command. Its first argument is an expression, and from then on it's alternating value to compare, value to return, ending with a possible default value to use if no matches are found. Remember to encase the return expressions with {} if they contain commas.
foreach(<expression>,<function>,<input delimiter>,<output delimiter>)
foreach() is a powerful function that cycles through every word in <counter>
, just like @foreach
, but can also be configured to accept different delimiters other than spaces. Expression is a function or text that uses v(0) to determine the current word in the cycle. After every cycle it appends the result to the previous result, separating them with spaces or an optional other output delimiter.
It can be difficult to get foreach() functions to parse right. In general you should include hard brackets around both the foreach() itself and the <function>
argument. This goes for oper() and the s_as() functions as well.
Any %0 from outside the foreach() is overwritten within the <function>
by the expression. To get around this, use setq() just outside the function to change it to an unused register.
oper(<expression>,<start value>,<function>,<delimter>)
This one is similar to foreach(), but rather than displaying the result each time, it stores it to v(1) for the next time around, and returns the final result. <delimiter>
is for the input. One key advantage to oper() is that you aren't forced to have a delimiter between output results as you are with foreach() - just make the third argument [v(1)]something... with no space in-between.
s_as(<expression>,<invoker>,<object>)
s_as() is a very useful function that parses <expression>
from the point of view of <object>
, as if <invoker>
were triggering it. For builders, it can be used to determine which object a player is referring to in a command ([s_as([num(v(0))],v(#),v(#)]), but this function can only be used on objects the
person controls - normal players are restricted to objects they own.
s(<expression>)
This is just like s_as(), but it assumes the object point-of-view is the one executing the function. Its primary use is handling advanced parsing problems, explained later.
s_as_with(<expression>,<invoker>,<object>,<argument 0>,<argument 1>,...)
Exactly like s_as() but also allows %0-%9 substitutions.
to top
@defattr
: the function option. This causes it to behave as a user-defined function that can be used within the object's own code. It is called by using its name followed by a comma-seperated argument list in parenthesis, just like every other function. It does not, however, make any hardcode checks for the number of arguments or return "#-" errors. The value returned is simply what the attribute contains, parsed using each successive argument as environmental variable 0-9. The function option acts like haven in that it prevents that attibute from being @trigger
ed.
This example takes a list of numbers and multiplies each by three: @defattr me/Example=function @example me=[foreach(v(0),[mul(v(0),3)])] @echo example(1 5 8) >>3 15 24 |
say
command is parsed, so if you want to literally say the phrase [add(1,1)] without it coming out as 2, you need to delay that statement by one parser level. Queued commands typically also parse, so if you wanted to @force me=say [add(1,1)] and have it come out that way, you'd have to delay it for two cycles.
Backslashes (\) and percent (%) signs are used as delay characters. They both have the exact same effect when delaying the parser, but percents also happen to be used for pronoun parsing. The number of delay characters you need is equal to 2^(levels)-1 (When counting delay characters for pronouns, remember not to include the rightmost one which makes it a pronoun to begin with). I prefer backslashes, but they should both work. So, to get the result You say, "[add(1,1)]" you need to type say \[add(1,1)]. Or for the other example, @force me=say \\\[add(1,1)].
Any @force
, @foreach
, @switch
, @wait
, or @iterate
command queues everything inside it, so it also takes up one parser level. If a command is being executed as part of an attribute (as opposed to being entered directly by you), that is also queued and adds on yet another level.
Looking back at the (modified) balloon example:
@bounce Balloon=$throw =:@foreach lnum(%1)=@wait mul(\%0,3)=@switch rand(2)=0,{@oemit %# The balloon bounces around the room, hitting [name(%0)].;@pemit %#=The balloon bounces around the room, hitting you on the head!} ,{@emit The balloon narrowly misses %n!} |
@force
to the statement to get it to parse before the actual command is executed. There is an exception here, however: the +com
form (and not its alias) will parse lone functions, though not full string expressions.
@force me=+com public=Cool Text: %|10|GREEN |
say
, pose
, and to
, messages are always parsed literally, so functions never parse in them without brackets. Channels and pages won't even parse pronouns, much less functions (excluding the exception mentioned above).
In nested (or even single, if they're stored in an attribute) @switch
es, @wait
s, @foreach
es, @iterate
s, or @force
s, brackets around functions make them parse immediately before the command is queued. By the time the individual commands contained in the statement are executed there is nothing left to parse. The alternative is to leave off the brackets, so that on the initial cycle your functions remain unchanged, and are only evaluated later in the context of a particular command.
This means that [setq(0,X)]@foreach 1 2 3=@emit [v(0)] will become @foreach 1 2 3=@emit X, and then the command will execute, emitting three Xs. Meanwhile, [setq(0,x)]@foreach 1 2 3=@emit v(0) will ignore v(0) because it has not been designated a function with brackets. The statement will then become @foreach 1 2 3=@emit v(0), which will queue three different commands of @emit v(0), each one having a different numeric value in register 0.
If the desired result is the numeric printout, you have the option of using brackets anyway, and then counting how many levels they are nested to determine how many backslashes you need. [setq(0,x)]@foreach 1 2 3=@emit \[v(0)] will do it. If you have to have brackets in there because you are mixing text and functions, you could always place each term in an unbracketed strcat(), which the parser sees as a single function, so nothing is truncated.
[setq(0,x)]@foreach 1 2 3=@emit [v(0)]a returns xa three times
[setq(0,x)]@foreach 1 2 3=@emit v(0)a returns three numbers - no "a"
[setq(0,x)]@foreach 1 2 3=@emit strcat(v(0),a) returns 1a, 2a, and 3a
[setq(0,x)]@foreach 1 2 3=@emit \[v(0)]a returns 1a, 2a, and 3a
[setq(0,x)]@foreach 1 2 3=@emit [strcat(v(0),a)] returns xa three times
When bracketed functions are nested, the inner one isn't parsed - or rather, a better way to explain this is that the inner term is always evaluated either as a function, or not parsed at all even with [] if it is considered literal. This is necessary in special cases such as foreach(), oper(), and s_as(). Looking individually at the function expression inside, it gets rewritten without altering its literal text, but with the proper 0 register. Without the brackets there, this function expression would be attacked by the parser before foreach() even got to consider the various loops, and it would end up with the outside %0 value.
[setq(0,x)][foreach(1 2,[v(0)])] becomes foreach(1 2,[v(0)]) becomes [v(0)] [v(0)] (where %0 is 1 in the first, 2 in the second) becomes 1 2 [ansi(11,s({[v(0)] plus [v(1)] equals [add(v(0),v(1))].}))] |
@destroy
ed something.
Remember that a function can be parsed before the command is executed, using hard brackets. It is possible that if the return value of the function includes a semicolon, another command can be slapped in there. va:$repeat *:@force me=@echo [v(0) |
@echo
.
The problem was that @force me=@echo [v(0)] became @force me=@echo aaa;@echo bbb, two seperate commands. To fix this you just need to make sure that [v(0)] does not parse before the @echo
command. This can be done with a backslash, or by removing the brackets.
The secure() function is very useful in some situations. It filters out all occurances of dangerous characters, not least among which, the semicolon. Also, as was stated before, the pronoun register form (%0-%9) automatically secure()s, so you don't need to worry about them.
If your code gathers information, stores it in an attribute, and displays it again, you have to worry twice about this sort of situation - in the retrieving attribute, and the setting attribute. Test it with a ;@echo a whenever you can.
Another issue that may come up is function perspective. Ignoring semicolon hazards for now, an unscrupulous player can enter in functions as arguments, and use the behavior or your object to determine its value. For example, let's say there's an admin-controlled mercenary that a player can order to move around using order <direction>. Instead of using a simple "west" or "n", someone might type in [ifelse(<Information I'm Not Supposed To Know>,west,east)], where that info could be a get() extracting private information, or a wiz function that checks out monster secrets. To guard against this, again, delay it or secure() it.
It's not always easy to determine which code can be a potential security hazard. It is highly unlikely that a player with many objects would be able to track down them all, but at least such abuse by another player is severely punished.
to top
Backslashes | Start | Cycle 1 | Cycle 2 | Cycle 3 |
1 | \ | Nothing | Nothing | Nothing |
2 | \\ | \ | Nothing | Nothing |
3 | \\\ | \ | Nothing | Nothing |
4 | \\\\ | \\ | \ | Nothing |
5 | \\\\\ | \\ | \ | Nothing |
6 | \\\\\\ | \\\ | \ | Nothing |
7 | \\\\\\\ | \\\ | \ | Nothing |
8 | \\\\\\\\ | \\\\ | \\ | \ |
9 | \\\\\\\\\ | \\\\ | \\ | \ |
10 | \\\\\\\\\\ | \\\\\ | \\ | \ |
11 | \\\\\\\\\\\ | \\\\\ | \\ | \ |
12 | \\\\\\\\\\\\ | \\\\\\ | \\\ | \ |
13 | \\\\\\\\\\\\\ | \\\\\\ | \\\ | \ |
14 | \\\\\\\\\\\\\\ | \\\\\\\ | \\\ | \ |
15 | \\\\\\\\\\\\\\\ | \\\\\\\ | \\\ | \ |
16 | \\\\\\\\\\\\\\\\ | \\\\\\\\ | \\\\ | \\ |
@trigger
. I needed a [v(0)] to parse right away, but then not parse afterwards until it is sent through the @trigger
. Six backslashes fit perfectly for this case.
Side note: there's an additional reason not to use % as a delay character. If it' not done exactly right, the function may parse while there are still free percents there, and if the return value begins with a pronoun character, it can be mistaken for one. $track *:[setq(0,s([s_as([num(v(0))],v(#),v(#))]))]@switch pos(v(0),get(me/monsterlist))=!0,@foreach children(v(0))=@pemit %#=%|15|[v(0)]:%t%|0| \\\[unparse(v(0))] - \\\[unparse(loc(v(0)))] |
@pemit
me the number I asked for in white, then a tab, and then the unparse view of the child monsters and their current locations.
#431: Snipe(#5692M) - Camp(#5533R) #431: Snipe(#5779M) - Forest(#5545R) #431: Snipe(#5866M) - Forest(#5580R) #431: Snipe(#5864M) - Forest(#5554R) #431: Snipe(#5448M) - Forest(#5575R) #431: Snipe(#5317M) - Forest(#5530R)The unparse is delayed twice -- 0 is the wildcard, 1 is the
@switch
, and 2 is the @foreach
that cycles through children.
TrackList: $tracklist:@pemit %#=[foreach(get(me/monsterlist),[ifelse(not(match(v(0),%r)),strcat(%r,unparse(v(0))),%r)])] |
[switch(mid(name(v(0)),pos(<,name(v(0))),sub(pos(>,name(v(0))), add(pos(<,name(v(0))),1))),w,8,nw,7,sw,6,n,5,s,4,ne,3,se,2,e,1,0)] |
$qpush *:@foreach lexits(%0)={@wait exitorder(\%0)={@push \%0;@pemit %#=name(\%0)} |
@push
that exit. The exit that is pushed last will be first in the list, so looking above you see why w is 8, nw is 7, etc.
If I had used v(0) instead of %0 I would not have needed backslashes.
to top
$qdig *:@dig [name(here)]=[switch(v(0),w,{West <W>;w,East <E>;e},nw,{Northwest <NW>;nw,Southeast <SE>;se},sw,{Southwest <SW>;sw,Northeast <NE>;ne},n,{North <N>;n,South <S>;s},s,{South <S>;s,North <N>;n},ne,{Northeast <NE>;ne,Southwest <SW>;sw},se,{Southeast <SE>;se,Northwest <NW>;nw},e,{East <E>;e,West <W>;w},X)] |
[setq(2,v(1))][oper(v(0),0,[lor(v(1),is_a(v(2),v(0)))])] |
@iterate
. This tool will search everything you own (or for admins, everything in the game) for a particular value in any attribute.
$searchfor :@iterate *(#)*={@search attribute=*:*[v(0)]*},{@iterate *:*[v(0)]*=ex strcat(#,v(1)),@pemit %#=strcat(ljust(strcat(unparse(\[strcat(#,v(1))]),:),40),%b%b,v(0))} |
@search
command returns a list of objects that match the criteria - in this case it searches for attribute matches. *:*[v(0)]* means it will search for all attributes that have any phrase containing [v(0)], the original wildcard argument of the attribute. The list consists of one line printed for every match found, and each line has the unparse name and ID of the object.
Next, the pattern clause of @iterate
captures the ID number of every object in register 1 (0 and 2 are disgarded). A second @iterate
is executed on that v(1) to examine it and find the specific attributes that contain the original search phrase. Notice that strcat() adds on a "#" to this ID - the hash was not originally captured since it was outside of the wildcard. I could have left out the "#" in the pattern to make it part of the wildcard, but there is a small possibility that it could be fooled into thinking "(5m)" was an ID. ("(5m)" means a player has been idle for that many minutes, and it appears before the player's ID in the unparse view.)
After that, it's just a matter of printing the ID, and then the name of the attribute it was found on. Notice that I used strcat() to combine parts of the output so I didn't have to use multiple brackets and backslashes. The only reason \[strcat(#,v(1))] has brackets is because it needs the first @iterate's v(1) and without them it would get the second's.
Here's a sample output for if I were to do a search on the word "nifty".
Maple Street(#1107R): Desc Zone Control(#731): Alias ascii_art(#1417): Desc Thingy(#1535): Desc Mr. Sock-lop(#1584w): Va Nifty(#1592): Desc Nifty(#1592): message Thingiemabob(#2111): Desc Message Master 2000(#2195): Desc Thingiemabob(#5024): Desc Martial Arts Master(#5072): Talk Help Guide Parent(#6487): com_cmds Magical Tutor(#7904): Talkto top
[setq(2,v(0))][oper(lnum(strlen(v(2))),,[setq(3,rjust(base( ascii(mid(v(2),v(0),1)),10,2),8,0))][strcat(v(1),v(3))])] |
[setq(2,v(0))][oper(lnum(div(strlen(v(2)),8)),,[setq(3,base(mid(v(2),mul(v(0),8),8),2,10))] [strcat(v(1),chr(v(3)))])] |
help function list
.
If you use a switch(), ifelse(), or anything else really, to return a certain text value (like a sentence that changes depending on the circumstances), you should definitely consider putting {} around each entry so sentence commas don't get confused as argument delimiters. Note that if the outer function has brackets (and it most likely does) you will need s() to parse pronouns and functions within the sentences. In this case the curly brackets would go just inside the s(). If you have many sentences that each need an s(), you can just combine them all into a single s() outside the ifelse() (or whatever else it is) and it'll work on all of them. Example: [ifelse(match(v(#),owner(me)),s({Hey [name(owner(me))], how are you?}),s({%N, what are you doing here?}))] |
[s(ifelse(match(v(#),owner(me)),{Hey [name(owner(me))], how are you?},{%N, what are you doing here?}))] |
@switch
like a good programmer.
The_Fool76 has an interesting method of carrying this idea even further. In many cases, instead of using @switch
at all, even in normal legitimate code, he uses [if()], [ifelse()], [switch()], etc. to determine which code piece will be executed; this removes the need to queue a @switch
command. I'm not sure if this is more efficient - it's mostly a matter of preference. Be prepared to add in a s({}) or two to the function or its arguments if you use this method though.
A side note about that: If you're trying to get multiple commands to run, this non-queue function method may not be the best choice. A semicolon inside the function will only be recognized after the command itself is queued as one entry - therefore you would have to put the semicolon between functions for it to work right. [if(...,{@emit a;@emit b})] will only send out "a;@emit b" as one message. You would have to use [if(...,{@emit a})];[if(...,{@emit b})] to get it to work properly.
to top
@switch
combo, remember that undelayed, the setq() will parse before the @switch
. If you use that register in your @switch
expression, it can easily be thrown off. Either delay it or store to another unused register.
@trigger
does not accept the object and attribute as two seperate arguments, nor do any of the other attribute-handling commands. Therefore, if you @trigger v(0)/va in code where v(0) is a dbref, it will return the standard "You must specify an attribute name." message. This is due to the same reason that @echo add(1,1) a only returns 2 - the text after a non-bracket function is truncated.
to top