SluggyMARE UNOFFICIAL Official Guide

This guide was written by Workaphobia for the MARE game engine, particularly SluggyMARE. If you have any questions or comments, you can occasionally find Workaphobia on SluggyMARE at 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 smile

Color Codes:

  • Command syntax - a bar ( | ) designates OR
  • <Arguments>
  • Optional arguments
  • Command/coding examples
  • Parts of code referred to in text
  • Commands in sentences
  • Built-in attributes and flags

Intro

With the exception of a brief stay on a ROM mud, I have never used any other online text adventure engine. However, from what I have gathered about them, the MARE certainly has it's advantages. You don't have to know C++ or modify the source code in any way to be able to craft creative worlds. Not only that, but building (usually) isn't restricted to admins. The first section explains basic commands. The sections after that apply to building, and then coding - that is, using the MARE softcode parser.

Skip Table Of Contents

to top

I. Player Basics

Ok, you've connected to the MARE and created a character. Where can you go, what can you do? How does the game work anyway?

As a user, you control a character with settings stored in the MARE database. You can use simple commands to move through rooms, interact with objects, and chat with other players. More complex commands allow you to alter the interactive world itself by creating new objects for other players to see. This section explores basic commands that every user needs to know.

to top

A. Communication

Talking to other players can be the most important skill on the MARE. Any questions you have can be answered by live admins and experienced players, as long as you know how to use these chat commands.

Channels are the easiest way to address many players in different locations at once. Text is printed in your color, and prefixed with the channel name in hard brackets ([]) and your name. You can be on as many as you like at one time.

To send a single message to a channel:
+com <channel name>=<message>
To send a message to your default channel:
=<message>

The default channel is normally [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:
+channel <channel name>
To leave a channel:
+channel -<channel name>

Using this command on a new channel enters it. If the name doesn't match an existing one (channels are one of the few systems on the mare that are case-sensitive), it is created automatically - so typos in the name can generate much confusion later. Channels are automatically destroyed as soon as the last person leaves it. Using this command on one you are already in sets it as your default channel. Finally, using +channel alone will give you a list of channels you are currently on, and sending the text "who" to any channel (using +com or =) 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.

The admins of SluggyMARE have added in a few additional shortcuts you can use on the 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.<message>
cpub <message>

So what does it all look like?

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.

Note that in the last line of the example, Harena's name would be colored with the same pattern you'd see when looking at her, or when she was sending a message on a channel.

There is a logical extension of cpub which allows you to use it on any channel (that you have joined). It is called 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.

Next is the say command, for localized chat. The text you type here can be seen by anyone in the same room as you.

say <message>

Simple enough, eh? But wait, it's even easier. Just like the +com command, this can be aliased to a single character: a double quotation mark (").

"<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>
:<message>

You can make the pose possessive by using a semicolon (;) 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>
'<player> <message>

Another example:

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.

You can send a message to an offline player using +mail.

+mail <player>=<message>

Mail is kept in an inbox and dated. A player may read their mail at any time, and clear old messages.

To see messages:
+mail
To read a message:
+mail <message #>
To clear messages:
+mail clear
+mail clear=<message #>

Also a part of communication, there are a series of @Emit variation commands that will be discussed later.

Lastly, you can do thought bubbles locally as well, with the . shortcut.

.<message>

.I like fish
QBFreak . o O ( I like fish )

to top

B. Moving around

As a character, you can move through different rooms and observe objects. To get a feel for your surroundings, use the look command.

look <object|exit|etc.>

To see the room you are currently in, use look by itself. To get a close look at a particular object, type the object's name after the command. Sometimes you can see through exits into the next room, by looking at an exit.

When looking at a room, you'll see its name, a description, and a list of "Contents" and "Obvious Exits". You can move through any of these exits into a new room.

move <exitname>
Or you can even type the exit name alone:
<exitname>

If you're not sure exactly what exits are available in a room, there's always the exits command, which will display each one's name, alias, and destination.

Sometimes you can pick up an object and move around with it. When you do so, you'll see a message indicating the object has left (meaning the room), immediatly followed by one that says it arrived (meaning your inventory).

get <object>
drop <object>

Objects can be given to other objects or players.

give <receiver>=<object>
grab <holder>=<object>
Within your own inventory:
put <receiver>=<object>

Occasionally you are allowed to enter an object.

enter <object>
leave <object>

There is a special @Teleport command which immediately transports you to a new room or object. While this is extremely useful when building, it is restricted in general from players because of its potential abuse. However, there are specific areas where teleport is allowed for everyone.

@teleport <destination>
@teleport <object>=<destination>

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

to top

C. Getting Information

The who list provides a list of all players online who have not chosen to block themselves. Along with it, you can display a variety of other properties associated with the player through whoflags.

To use the default flags:
who To use a specific set of whoflags:
who <whoflags>
To change the flags you see by default:
@whoflags me=<flags>
To get a list of all possible flags:
who ?

For example: who name alias would show you every player and their alias. If you wanted to only see name and idle time every time you type who, @whoflags me=name idle.

To block yourself from view in the wholist, use hlock:
@hlock me=<lock code>

To find out where a particular player is, again assuming they don't want privacy:
where <player>

You can again block yourself from where:
@set me=D (To turn it off: @set me=!D)

You can find out a lot about a player by using +finger:
+finger <player>

The examine command will give you detailed information about an object if you own it. For other people's objects you will only see its name and owner.

To see normal examine information:
examine <object>
To see one particular part of the object:
examine <object>/<attribute>
To see all attributes, including inherited ones (advanced)
examine <object>=all

to top

D. Referring to Objects

You do not need to use an object's full name in any command. You can normally specify the first few letters and let the game driver interpret it. Objects can also have an alias attribute set to associate text with it. In the event of an ambiguous match between two objects in a room, the game will select the first one in the list of contents. You can specify an object with an identical name further down the list by inserting a space and number after its name (look snipe 2, for example). If the object is in another player's inventory, you can append an apostrophe and "s", then a space and the name (look Some_Guy's Sword). If an ambiguous match occurs between an object in the room and in your inventory, the latter will be selected.

For exits, you would normally have to type the FULL name, but they should have aliases for a single letter representing a cardinal direction. Ambiguous commands prioritize exits over objects in the room or your inventory (so look n would look north rather than at an object in the room beginning with an "n"). Commands themselves can be abbreviated either by the MARE's symbolic aliases (such as " 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

E. The Combat System

The MARE's combat system is still in beta, and there are many bugs and unimplemented features. It is still usable, and remains a large part of interacting on the MARE. The first step in combat is to Know Thyself.

status

This will give you a table of information including your strength, health, gold, and many other combat stats.

You can also see a list of temporary conditions that are currently affecting your character, as well as more permenant condition attributes:

conditions

Now, Know Thy Enemy.

status <object>
consider <object>

If you control the object (it is little unusual for players to own objects that can fight), status will show you another table. Otherwise you will only see a message indicating its relative condition, but not its overall power. 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
Note: Suicide is another softcode command.

IDEA! 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:
save

You will also lose half the gold you are carrying to the creature that defeated you - or in the case of suicide, it will simply vanish from the face of the MARE. You can deposit your gold in a vault to protect it from this.

There are numerous combat-related objects. Combat items behave differently from the type of objects you see lying around a room, in the way they are found, used, and displayed.

To see all the items you are holding:
items
To see all the objects in your inventory:
inventory
To see which weapons you have equipped on your person:
equipment
To see assets you own in valuable items, your gold inventory, and vault:
money

Throughout the course of the game, you can gain various spells, skills, and techniques.
spells
skills
techs

Each of these display abilities you have learned. Skills are passive, but techs and spells need to be activated with the commands use and cast, respectively.

use <tech>=<target>
cast <tech>=<target>

Multiple players can group together in a party and fight monsters together as a team. This is the +party system. A player can create a party with a unique name, and invite other players into it. A brief list of the commands:

+party create=<name>
+party leader=<person>
+party list
+party status
+party invite=<player>
+party join
+party leave

Each party has its own channel similar to the normal channel system. A special command is used, and it cannot be exited without leaving the party.

+party com=<message>
-<message>

You can purchase equipment in shops. The commands to use them are relativly simple - equip <item> and unequip <item>. Everything you equip has the potential to raise or lower your stats - armor will increase your vitality for example, while heavy objects may reduce your agility.

Your particular character race has the most effect on your stats. @list races to see a full listing.

Note: Attacking other players without consent (known as PKilling), especially if you are stronger, is generally punishable by being jailed (restricted to a certain area for a period of time). Then again, we may just get the most powerful NPC in the game to return the favor...

to top

F. Character Customization

The following set of attributes affects how you appear to other players. Your description is what other players see when they use the look command on you. A caption is the trailing piece of text that comes after your name in the list of room contents (it is prefixed with your race). An alias allows other players to refer to you by a shortened version of your name (normally two or three characters).

Succverb, osuccverb, and odropverb affect the verb used to express your character's movement between rooms - the first one is displayed to you, the second to other people when you leave a room, and the third to them when you enter it.

You can set your color to change the way you appear in various contexts, and give yourself a cname to set a separate color pattern for your name alone. The color commands use either numbers or special letters. On SluggyMARE, you can type colorlist to get a list of the 16 basic color.

@desc me=<text>
@caption me=<text>
@alias me=<text>
@color me=<color #>
@cname me=<color #, color #, color #,...>
@succverb me=<word>
@osuccverb me=<word>
@odropverb me=<word>

The alias attribute is used with both players and other object types, but players can only have one at a time, while any other type can have multiple ones seperated by semicolons (;).

to top

II. Builder Basics

The MARE can be very interactive and enjoyable as a player, but the possibilities are extended so much further as a builder. A person doesn't necessarily have to be an admin to build. Any player can make objects, give them creative descriptions, and code in events, though it comes easier to some than others. Some building commands may cost an amount of gold from the owner. This is to discourage the pointless creation of useless objects.

Almost every object in the MARE is identified in the database by a unique number, called an ID number or DBref. These can be divided into five types of objects.

Players - are controlled by users and can own other objects
Rooms - can hold objects and link to other rooms via exits
Exits - link together rooms
Things - general objects that can be held by rooms, players, or other objects
Zones - are abstract and don't exist inside rooms, but contain and apply attributes to many rooms

A sixth type is occasionally added in, called "Garbage", which is merely an unused database number below the highest existing number. They occur when a number is left over from an old object being destroyed and will be filled in when more objects are created. Each of the first five types are very different, and while many attributes can be changed after creation (even the name), each type is created through a different command and cannot be interchanged without destroying it.

Note that when you look at your own objects you will always see the ID# and flags in parentheses (called the unparse view) after the name and before the caption. Other players will not see this unless they are builders.

to top

A. Creating Objects, Understanding Attributes

Let's focus on the type Thing. The command to make a new Thing is @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 <object>=<attribute name>:<value>
@<attribute name> <object>=<value>

Either syntax is acceptable, but I prefer the second. It does have a weakness though, in that sometimes custom attributes have conflicting names with commands that start with "@", and you end up altering some other part of the object. For example, if I have a custom one named "destroy", if I tried to adjust it without using @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 <object>

<Countdown timer> defaults to zero seconds for most objects, ten minutes for rooms, and one minute for parent objects. When you destroy an object, any objects within will be sent "home" (where they are @linked to) and players will be killed - beware.

If you change your mind before the countdown clock times out, you can @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

B. Locks

Lock attributes control who can successfully perform certain actions on your object. The most basic lock is - you guessed it - @lock. It has no meaning for zones, rooms, and players, but can be set on them nonetheless. For exits, it restricts who can move through them, and for objects it controls who can pick them up.

@lock <object>=<lock code>

For example, lets say you've created an object called Beach Ball. You want to make sure you're the only one that can pick it up and move around with it. You would type @lock beach ball=me. Upon examining it, you would see in the lock attribute your own name and ID#. To lock it so another specific player can pick it up, @lock beach ball=*<other person's name>. Remember from before that the asterisk is needed for the parser to understand you are talking about a player if they are not in the room. Alternatively you could use the person's ID# if you knew it. Locks can be limited to multiple people by setting it to a bar (|) separated list (the | symbol means logical OR). If you want to lock an object to everyone except a single person, put an exclamation mark (!) before their name (! is a logical NOT). A + before an object name will lock it to people who hold that object in their inventory.

Examples:
@lock beach ball=me|*my_friend|*cool_guy
@lock beach ball=!*jerk_I_don't_like
@lock beach ball=+super key

All locks evaluate to a Boolean expression -- that is they are either true or false. The previous example is a simplified method of locking objects, where the game automatically realizes it should compare the ID# of the invoker (the triggering player that wants to pick up the object) with each of the ID#s in your list. Only one of them in the list comes out as 1, because only one of them is the person's ID#. Since you use logical ORs to separate them, a single 1 is all that's needed for the entire expression to be true.

To allow everyone to pass, clear it as you would any other object. To lock it against everyone including yourself, you can set it to #0. On SluggyMARE, object #0 is the room Limbo, and by convention it represents permanent lock. Another method is to set it to "[0]". They both have the same affect.

The more complicated method of locking is to use functions, which return a 0 to indicate No/False/Fail and any other number to indicate Yes/True/Pass. Functions will be explained later.

to top

C. Lock-Related Attributes

Now that you understand how to set locks, it's time to discuss the different types and their related attributes. Some lock types include:

@lock - restricts movement through exits and getting objects
@ulock - restricts who can use the object through $events or events
@elock - restricts entry into an object (does not need to be set normally)
@llock - restricts leaving an object
@slock - say lock; restricts who is allowed to say or pose in a room

When a player activates a lock event, a corresponding built-in attribute is activated. If you tried to pick up an object locked against you, the attribute is @fail. Normally the letter in front of the word "lock" matches the letter in front of the @fail attribute, so @elock -> @efail, @llock -> @lfail, etc. If the person succeeds, the @succ, @enter, @leave, etc attributes are activated.

When I refer to @fail, @leave, @efail, and so on, there is actually a collection of three attributes for each, with different prefixes.

No prefix - the message printed to the invoker
Prefix "O" - the message seen by everyone else (the person's name automatically goes in front of the message)
Prefix "A" - the set of actions to be executed when this happens

The O or A prefix comes before the prefix in @elock, @llock, or other variations.

So, here's an example.

@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.

Note that @llock is a wizard attribute - it can't be set by players, as a security feature.

Sometimes attributes don't follow this pattern, like @lcost, where the "lock" is abbreviated to one letter and prefixes the word, rather than the other way around. Some attributes that follow the A/O pattern don't have a corresponding lock, such as @kill/@okill/@akill and @desc/@odesc/@adesc.

Objects without a set attribute for one of these will display a generic default message, unless you set it to a "\".

to top

D. Digging Rooms

Rooms are created with the @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

Rooms are not controlled by any sort of geographical grid. There can be spatial inconsistencies, and the only thing that defines position is the name of the exit. If you want to rename an exit, simply @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:
@link <exit>=<room ID#>
To disconnect an exit from a room:
@unlink <exit>
To create a new exit:
@open <exit name>=<room ID#>

Any unlinked exit will always fail when someone tries to use it.

When a person passes the @lock, the @succ attribute set is activated, just as objects in the previous section did. Likewise, @fail is triggered when a person doesn't pass the lock. In addition, a @drop set is activated in the destination room of an exit, after the @succ is triggered in the source room. Remember that exits do not necessarily have to have a counterpart taking the person back to the previous room.

There is a preferred exit order - arrange the directions of a compass, and list them from left to right, starting on the top. W NW SW N S NE SE E. You can @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:
@emit <message>
A single object or person only (must be in the same room):
@pemit <object>=<message>
A room or object you control but are not necessarily in:
@remit <ID#>=<message>
Everyone in a room except for a particular object:
@oemit <object>=<message>
Everyone but one object in that object's room:
@oremit <ID#>=<message>
Everything, across an entire zone:
@zemit <zone ID#>=<message>
Yourself:
@echo <message>

@print <message>
@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

F. Zones

Zones do not fit inside rooms or any other object, so they can only be addressed by ID#. They are abstract and provide a way of controlling a large number of rooms with features not readily available any other way. For example, you can send a message to every room in a zone (using @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:
@zone <name>
To add a room to a zone:
@addzone <room>=<zone ID#>
To delete a room from a zone:
@delzone <room>=<zone ID#>

Be careful not to abbreviate @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

G. Flags

Flags are settings that can be either enabled or disabled on an object. They appear after the ID# in the unparse view.

@set <object>=<flag>
@set <object>=!<flag>

Each flag has a unique letter, case sensitive. Most of the time you can use this letter, but if you want to assign an unexpected flag to an object type, you may need to use the full name (like haven to a room, where "h" by itself would mean Healing). Some flags like Going and Monster can't be set or unset directly, and others are restricted to admins.

Common Flags:
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)

to top

H. Pronouns

Pronouns are single characters in parts of text that are preceded by a percent sign (%). They get evaluated by the parser and inserted back into that part of the text.

%# 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)
Keep in mind that the case of the pronoun affects the result - a capital grammatical pronoun would force a capital, so you would use it at the beginning of a sentence.

to top

I. Controlling Objects

Any object you own can be ordered to execute a specific command. Most but not all commands that are available to players can also be used by their objects.

#<object (id number only)>=<command>
@force <object>=<command>
@force <object>={<command>;<command>;<command>;...}

The first method executes immedeatly and can even be used on objects set haven. @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

III. Coding Basics

Coding objects allows you to make them much more real, and have them respond to actions in ways not possible by simply giving them vivid descriptions. You could have an object react when it hears a player say a certain word, or give it instructions to move around when someone tries and fails to pick it up. Beyond that, you can do some pretty amazing stuff if you understand the parser.

to top

A. Custom Attributes

Until now you've seen built-in attributes that are common to all objects and reserved by the game. If you want to use your own attributes to store data or code, you have two choices: you can either pick from the 26 built-in attributes available for general data storage, named @va to @vz, or define your own via @defattr.

@defattr <object>/<attribute>=<options>
@undefattr <object>/<attribute>
@redefattr <object>/<attribute>=<new name>

The slash (/) is always used to refer to an attribute of an object.

I prefer the second method. Not only can you give a meaningful name to the attribute, but you can also set a number of useful options that cannot be manipulated using the @va system. You don't need to worry about the <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.

Not very interesting...yet. Like any player, objects can just use the exit alias/name alone without the move command. Pose can also be abbreviated to its normal alias of a colon.

to top

B. Functions

By definition, functions return text depending on what data arguments you send to them. Arguments are passed by including them in parentheses after the function name, separated by commas. To indicate to the game that you want to use a function and not the literal string equivalent, you sometimes need to enclose it in hard brackets ([]).

Some of the important ones are:

v(<attribute name>) - returns the value of an attribute on the object using it, or an argument pronoun such as %0 - %9 and %!, %n, etc.
get(<object>,<attribute name>) - works the same as v() but allows you to retrieve it from other objects. A slash can be substituted for the comma.

lnum(<number>,<start>,<increment>) - returns a space separated list of numbers
strcat(<string 1>,<string 2>,...) - combines the strings
pos(<substring>,<string>) - returns the first occurrence of <substring> within <string>, numbering the first character as 1; returns 0 if no matches are found

name(<object>) - returns the name of an object
num(<object>) - returns the number of an object
unparse(<object>) - gives you the unparse view of an object - its name, then number and flags in parentheses: Your_Object(#1234ABC)
lcon(<location>) - returns space seperated list of all objects or players within (ID#, not name)

rand(<number>) - generates a random integer between 0 and <number> minus 1
randword(<word list>,<delimiter>) - picks a random word from <wordlist>, where a "word" is defined as text seperated by the <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

C. Control Structures

These commands allow you to manipulate your object code and make more advanced decisions. If you want to include more than one sub-command within any of them, enclose the statements in curly brackets ({}). Curly brackets are used in code and functions alike to indicate that semicolons or commas are not to be applied to parts of code outside of them. Without them you would not be able to include the literal "," as part of a text message in a function, or a ";" in a sub-series of commands, without confusing the parser.

@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!

It is important to remeber that @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.

For switch, it's a very good idea to use {} around each command set, because both a comma and a semicolon can prematurely end the command. If you have functions in the value part, enclose them with hard brackets ([]).

To repeat a command a number of times, use @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))].

Let's combine these into a single command.

@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!}

Now if you @trigger balloon=5...

lnum(%0) will become 0 1 2 3 4, so 5 wait commands will be immediately created, each delayed 3 seconds longer than the last (mul() is the multiply function, it multiplies the 0 1 2 3 4 by 3, becoming 0 3 6 9 12). At those intervals, it will make a random number (rand(2) will either be 0 or 1). If it's 0 (50-50 chance), then the balloon will send a message to the player triggering it (which would be you) saying that it bounces off your head, and tell everyone else what happened.

One of the most interesting control structures is @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)

This one's neat. It will examine your character, looking for attribute definitions (which as you should know are in the format of <name>:<value>). When it finds one that has a value of "0", it will print the contents of the first (and in this case only) wildcard: the name.

to top

D. Events

Up until now the only way to trigger an event is either through a special built-in attribute (the ones beginning with "a"), or @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>:<commands>

<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))]!}

Now a player can type throw Some_Victim=5 to hit them in the head with a balloon. The first wildcard (which is the target) becomes %0, and the second one (the number of times to hit them) becomes %1. The v(0) of mul(v(0),3) refers to the @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)}}

The first @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)}

Nothing has changed, except that the ID check is no longer necessary.

You can set an attribute lock to control who can invoke an event. It works similar to @ulock (use-lock), except it only applies to a single attribute. The format is a simple lockcode encased in two foward slashes, right after the event:
<event pattern>:/<lock code>/<code>

Pay close attention to any possible security hazards in your code. Just as you can @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

IV. More Advanced Coding

This section goes over more powerful coding methods in detail, such as color options and advanced functions.

to top

A. Advanced Color

(For color help while connected, type 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
There are in reality many more colors than these. Consider a 12-bit binary number. Each bit controls a different formatting option.
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 Dark

The 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)
In the middle of any text, you can use %|<color>| to change the color. Blah blah %|10|yada yada will start in gray (0) and then print the next part in bright green (10). Adding a %x<color code> (where the code is alphabetic, not the first method) will apply that color aspect in addition to previous formatting. Alternatively, you can use the following functions:

ansi(<color>,<text>)
ctext(<text>,<pattern>)

When dealing with cname format, remember that each color piece is seperated by a comma, and to extend one color over many characters without retyping it you can tack on a :<length>. Thus, 14,12,6,6,6,6 can be represented as 14,12,6:4

In most cases, these functions will automatically revert the text following it to the previous color. This means that %|10|AAA[ansi(9,BBB)]CCC will yield three green As, then red Bs, and green Cs. When using ctext(), it is important to include {} around the second argument if it contains commas.

When setting your color, keep in mind that channels commonly distort the way they appear - They always highlight your color, and sometimes won't display others for various reasons. Also, since channels don't parse, you won't even be able to get any color shown unless you parse the functions before the command (see the parsing section). To test your color, just 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

B. The Queue and Semaphores

The queue is a waiting list for commands to be processed in an orderly manner. All @wait commands are put in the wait queue, while most other commands go into the immediate queue.

To see pending commands:

@ps
To cancel a command:
@halt <object>

You can only see and halt commands on objects you own. Whenever an object spirals out of control (it gets stuck in a loop and possibly spams you) you should @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>
Or this form, which is equivalent to waiting 0 seconds:
@semaphore <string>=<commands>

Any command queued on the same object with the same id string as an existing semaphore will override the old one. Consider this: I have a guard, who upon the asunset event, will wait 100 seconds and then head home. I also have it set so that when he is killed he remains in plain sight for a similar amount of time before teleporting away and respawning. What happens if he is killed, but before he teleports, the code to go home executes? Players would see a dead man emit a message about packing up his bags and leaving. Humor value aside, this is not desireable. Using semaphores, I can queue both the respawn code and quitting-time code under the same id, and use only one @switch on the qutting code to see if he is already wounded. That way, if he is killed just before packing up his bags, the old command is replaced.

To cancel a semaphore before it has completed:
@cancel <object>=<string>

Semaphore functions:
waittime(<object>,<string>) - returns countdown time until execution on the given queued command
lsema(<object>) - lists all active queued semaphores on a <object>

to top

C. Inherit Attributes

Let's say you make a fairly complex piece of code that you want to be available to a number of objects. You can either @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>
@delparent <object>=<parent>

Most built-in attributes will be inherited by the child (but not all - check with @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):
lchildren(<object>) - lists all children IDs of <object>
parents(<object>) - lists all parent IDs of <object>
is_a(<object>,<parent>) - determines if <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

D. Word Functions

A number of string manipulation functions rest on a system of words rather than characters -- that is, instead of specifying what character position you want to check, you can enter in a delimiter, and choose what word number you want. The default delimiter is a space. In this!would!be!a! word!test the second word is word!test, but if you set the delimiter as ! it is would. Any delimiters more than one character large are truncated and treated as if only the first were entered.

To get a full list of string functions, check out help function list - section number 8.
I'll list some of them here:
extract(<wordlist>,<start>,<length>,<delimiter>) - returns a subset of <wordlist>, starting at <start> and continuing for <length> words
wmatch(<wordlist>,<word>,<delimiter>) - returns the first occurance of <word> in <wordlist>, using <delimiter> to count
matchall(<wordlist>,<word>,<delimiter>) - exactly like wmatch(), but it returns a space seperated list of all occurances
wcount(<wordlist>,<delimiter>) - returns the number of words in <wordlist>
replace(<wordlist>,<position>,<replacement>,<delimiter>) - replaces <position> word with <replacement>

setdiff(<list1>,<list2>,<input delim>,<output delim>) - returns all words in <list1> that are nowhere in <list2>
setinter(<list1>,<list2>,<input delim>,<output delim>) - returns all words in <list1> that are also in <list2>
setunion(<list1>,<list2>,<input delim>,<output delim>) - returns all words in either list

Take note that all of these are case-insensitive, and the set*() functions will eliminate duplicate occurrences. Also, whenever the delimiter is not a space, consecutive delimiters are counted as separating 0-length words.

to top

E. Truth Functions

You want the truth?!? You can't HANDLE the truth!

Ok, enough cliche quotes. Boolean logic, that is, truth parsing, is very useful. All of the following functions deal with true and false values. An expression is considered false if it is either blank (0 length), the actual number "0", or prefixed with the standard function error return indicator: "#-". Everything else is true, no matter if it's a letter, word, or number.

These ones are from help function list section 2:
if(<expression>,<string>) - returns <string> if <expression> is true
ifelse(<expression>,<true string>,<false string>) - just like if(), but has an additional return string if <expression> is false
iftrue(<expression>,<false string>) - a form of ifelse(), which returns <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.
not(<expression>) - the opposite of truth, this returns either a 0 or 1
lor(<expression1>,<expression2>) - logical or - returns true if either expression is true
land(<expression1>,<expression2>) - logical and - returns true only if both expressions are true
lxor(<expression1>,<expression2>) - logical exclusive or - returns true only if the two expressions have different truth values

Binary functions are similar to logical ones, except that instead of operating on a single value, they convert each argument to a binary number and perform the operation on each corresponding column.

to top

F. Advanced Functions

Here are a few more functions that tend to be very useful.

setq(<register>,<string>)

This assigns <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

G. Custom Functions

There's a special option you can set with @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

to top

V. Parsing

Ah, the dreaded parser, probably the most frustrating yet powerful aspect of coding. Not for the faint of heart.

to top

A. The Parser

The parser makes pronoun and function substitutions and allows the game to evaluate expressions, but can be very difficult to predict. When dealing with the parser, anticipate how many cycles you want a term to be delayed before the substitution takes place. For example, everything used in the 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!}

At the top level, which is the attribute itself (and not one of the inner groups - @foreach, @wait, or @switch), %0 and %1 represent the two wildcards, respectively. Within any number of levels, the non-delayed form will always represent those top values, because they are parsed before the other values take affect. Inside the @foreach, a once-delayed \%0 indicates what %0 is inside of the loop - the current "word" iteration in the space-separated list. \%1 is the same as %1 because @foreach makes no change to that value. Deeper into the commands, adding more backslashes will have no affect since @wait and @switch do not affect either %0 or %1. The only critical change is noticing the difference between the wildcard's 0 register and @foreach's 0 register.

Keep in mind that channels do not parse text at all. If you want to get part of a channel message to display color, or the result of a function, you have to add a @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

Revisting events for a second, remember that "?", "*", and ":" have a special meaning in pattern matching. If you want to check for the actual character, delay it with a backslash. Patterns here are parsed not once, but twice, so you'll need 4 backslashes to include a check for a single backslash.

to top

B. Hard Brackets

Parsing can definitely be a nightmare when you're trying to create a complex function. Among the most confusing issues is when to use the hard brackets around functions ([]).

There are two ways a string can be parsed: as a function or as literal text. Generally the game will interpret which it is on its own. If the first phrase of text the parser encounters is not a function, the entire message is taken literally. Thus, @emit a add(1,1) displays a simple a add(1,1). If the first part is a function, that function is evaluated and the result is returned, regardless of what comes after it. @emit add(1,1) a will truncate it, leaving you with 2. In either case, when you need to combine literal strings and functions you should include the brackets around the function (@emit a [add(1,1)]). They signal where functions are located within a literal expression, and allow the two types of strings to be displayed together.

Pronouns are parsed as if they were functions with brackets. %0 is the same as [v(0)] and is useful for quick, short variables inside text. (Actually, %0 is more like [secure(v(0))], but for now you won't need to worry about that.)

In 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
[setq(0,x)][foreach(1 2,v(0))] becomes foreach(1 2,x) becomes x x

This also applies to other nested functions.
[strcat(add(1,1),x)] becomes [strcat(2,x)] becomes 2x
[strcat([add(1,1)],x)] becomes [add(1,1)]x (parsing doesn't occur)

[pos(8,s([foreach(1 2 3 4 5 6 7 8 9 10,[add(v(0),5)])]))] becomes [pos(8,6 7 8 9 10 11 12 13 14 15)] becomes 5 - (pos() includes all characters, even spaces)
[pos(8,[foreach(1 2 3 4 5 6 7 8 9 10,[add(v(0),5)])])] becomes 24 - (foreach() is never parsed, so it just counts all the way up to the literal location inside add()

Here's where s() comes in handy. You might have a mix of functions and text, all inside another function. To get these inner bracket functions to parse, the entire phrase can be enclosed in a s() function.
[ansi(11,s({[v(0)] plus [v(1)] equals [add(v(0),v(1))].}))]

In this case, since the expression also has commas, it's a good idea to use curly brackets.

The trick you have to watch out for here is when s() itself is delayed. Actually, this goes for any time you have nested bracket functions: remember to delay the inner ones as long as the outer ones are, unless you are specifically looking for a different effect.

Note that in general, s(\[....]) is redundant - the extra parsing and backslash cancel out.

to top

C. Security

With the exception of a few specific commands, your objects have the capability to run any command that you yourself can. Not only that, but with your permissions. This means that your own object can execute code to alter other objects you own, including your character itself. This is exceptionally dangerous if you have any admin powers that would affect other players as well.

Therefore, not only must you be careful with the code you write, but you must be careful with any holes in it that would allow someone else to run their own code from your perspective. The simplest example of this is va:$do *:@force me=[v(0)]. What if I came along and typed "do @desc owner(me)=LOSER"? Of course a more destructive example would be if I @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)

Looks safe, eh? Why does it matter what's in register 0, it will only be fed back as text, right? Wrong! What if I repeat aaa;@echo bbb? That echos the normal aaa without a problem, but then it runs a totally different command, which may not be as harmless as another simple @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

D. Partial Delay

When I use that term (which probably isn't that correct, I just made it up;), I mean using a number of delay characters that does not fit the 2^(levels)-1 formula. Although it is rare, it does come in handy occasionally.

To understand this, you must realize that whenever you include a delay character, either percent or backslash, its actual purpose is to stop the character immedeatly following it from parsing (or in the case of a bracketed function, it stops that one outside function from being touched). This means that the number of characters gets cut in (approximately) half, every cycle. Consider what happens then:

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 \\\\\\\\\\\\\\\\ \\\\\\\\ \\\\ \\
Now, what if you have a function (of course bracketed) delayed with 6 backslashes? The first one would delay the second, the third delays the fourth, and fifth the sixth - but nothing delays the function itself. When you have an even number of escape characters, there's nothing to stop the function from parsing once right away. The number of backslahes will still be cut in half but the function will still parse. Continuing with the example, you are left with a function that parsed once, then delayed by three backslashes. Those three preserve it for another two cycles.

Not too long ago, a change was made to the parser (and was promptly reversed) that made it so v()s on register variables 0-9 had to be parsed at the same time the setq() that modified it was. The registers for my particular piece of code actually were [] functions themselves, and the attribute passed them on as-is to another piece of code via @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.
@force me=@echo %%[strcat(n,Z)] to WorkaphobiaZ
@force me=@echo \\[strcat(n,Z)] to nZ

to top

VI. Coding Examples

These are a few examples of some of my code. Hopefully they should be understandable given what I have discussed up to this point.

to top

A. Monster Radar

First up, my Monster Radar. It is somewhat outdated - the various techniques I have learned since I made this render it a bit obsolete. This code tracks the position of common monsters. Don't get your hopes up though; it won't work for players because you don't own the parent or monster.

The "monsterlist" attribute on this object is a space-separated set of ID#s of monster parents.

Track:
$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)))]

First, the setq() replaces %0 with the ID# of the object I selected. s_as() determines what it was, parsing from my point of view, then the s() around it allows it to fit into the setq() while avoiding the nested bracket problem mentioned above. The @switch statement checks to make sure the ID# I specify in the wildcard is in the monster list using the pos() function (if it isn't found, pos() returns 0). children(v(0)) will return an ID# list of all monsters of that type, and then it will @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)])]

This one gives me a list of every monster parent I have in the list, making sure to interpret the occasional %r I throw in the monsterlist attribute to keep it neatly organized.

A couple things that could be improved upon: First, instead of using pos() to determine if a monster is in the tracklist, it should use wmatch() since it is a word/delimiter list after all. This would also eliminate the potential of getting a false positive if one dbref is contained within another. Next, the @switch check could be optimized by turning it into an attribute lock instead.

to top

B. QuickPush

The quickpush code detects the letter in-between the brackets in an exit name to determine what direction it is, then pushes it to the right spot according to the proper exit order. In case you don't remember, this order is W NW SW N S NE SE E.

ExitOrder ():
[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)]

ExitOrder () is a user attribute with the function option set. As mentioned before, attributes such as this can be called from any other attribute within the object, and the result is whatever the contents of the attribute are evaluated to - using the v(0) - v(9) supplied in its argument list. I combine several other functions into this one, and then can call it like any other function later.

I use pos() to find the first location of "<" and ">" in a name, then use mid() to take the part in-between. It then compares the result with a list to determine the order.

QuickPush:
$qpush *:@foreach lexits(%0)={@wait exitorder(\%0)={@push \%0;@pemit %#=name(\%0)}

This takes the result of the exitorder() function for every exit in the room I selected, and waits the specified amount of time to @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

C. QuickDig

Another building aid. This one will dig a room with the same name as the one I'm in, and name the exits, saving me a lot of typing.

QuickDig:
$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)]

Curly brackets are used around the names so the semicolon isn't mistaken for a command separator.

to top

D. Type_Lock

This user function accepts a space seperated list of parent ID#s and a single object ID#, and returns a 0 or 1 to indicate if it is a child object of any of them. It is especially useful to builders to prevent certain monsters from using an exit (it would be set to ![type_lock(<ID1> <ID2> <ID3>...,v(#))])

Type_Lock:
[setq(2,v(1))][oper(v(0),0,[lor(v(1),is_a(v(2),v(0)))])]

The function oper() replaces v(0) and v(1) with new values. setq() moves the 0 register into 2 so it can still be accessed within the oper(). Then oper() cycles through every ID# in the first arguement, and checks to see if it fits the requirements of the built-in is_a() function. If it does, the value 1 (true) is stored to v(1) and makes all the future values return 1 as well (because of the lor()). The last value (and the one that ends up being returned) is 0 only if none of the previous ID#s fit.

to top

E. Search Engine

Ah, finally, a good example of how to use @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))}

The @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):                   Talk

to top

F. Encryption

This is a rather pointless pair of functions, the product of boredom. wink It converts letters to their ASCII binary equivelent, and visa-versa.

Encrypt:
[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))])]

For every character in the argument, this uses mid() to extract it, ascii() to get its decimal number, and base to make it binary. Since most characters take up only 7 digits and characters are 8 bits, it pads it with an extra 0 using rjust. Then it simply combines it with the last character's results.

Decrypt:
[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)))])]

This cycles through every 8 characters, extracts it with mid, and uses base to make it decimal. Then it's just a matter of using ascii()'s inverse (chr()) and combining it with the previous result.

to top

VII. Coding Tips, Techniques, and Problems

A. Miscellaneous

Try to learn the uses of all the logic and string manipulation functions. And a little math wouldn't hurt either. I have listed some of them in the advanced coding section, but you can find the full list in 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?}))]

As opposed to
[s(ifelse(match(v(#),owner(me)),{Hey [name(owner(me))], how are you?},{%N, what are you doing here?}))]

to top

B. The Queue vs the Parser

This one's important: Try not to use a command when a function will do. Let's say you have some sort of pet object that can be either sleeping or awake - this information might be stored in the form of a 1 or 0 in an attribute called "sleeping". You then also have two different sets of code that turn it on or off. Now, if you want to have the description change along with its sleeping status, instead of having a "@desc me=..." in both of them, just keep the desc constant and have a hard bracket ifelse() function in there to display the different possibilities.

To build on the previous note, one of the very worst things you can do, in terms of code clarity, is actually set a whole block of code automatically within another set of code. This would be the previous situation, applied to a certain attribute that handles actions instead of text, and varies depending on whether or not the creature is sleeping or not. Trust me, you do NOT want to count up all your loops, delay just the right amount, then check to make sure once the code is set that it's still delayed the right amount. It is MUCH easier to just use @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

C. Problems

These issues have popped up once in a while, so I suppose it's worthwhile to mention them here.

When using a [setq()] inside one case for a @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

VIII. Building Standards

Certain guidelines should be followed when creating objects.

  • Try to avoid creating objects that serve no purpose other than to sit around and look cool. If you do want extra objects, at least @desc them nicely to make it worth the gold cost. A few fully-interactive objects with @talks, @afails, and so on are worth a dozen hollow ones.
  • Follow the standard naming conventions -- don't include articles (a, an, the) in a name, and don't include too many adjectives (save it for the @caption and @desc). Exits should have a direction in-between angled brackets and have a corresponding alias.
  • Descriptions should avoid information that is subject to change - the race of the player, the time of day (unless you use separate ones for day and night), etc. You should certainly make sure they are complete sentences and spell check them.

to top

In it's original form:
This page created and not maintained by Workaphobia - please send all questions, comments, and hate mail to me via +mail on the MARE.
(C) 2003 QBFreak / The_Fool76 / Workaphobia / SoaringDragon42, All rights reserved.

This page formatted for the SluggyMARE Wiki by SluggyQBFreak - 24 Jul 2005

--+++ Change Log

  • Search and replace to update non-linking links after Foswiki upgrade. Please note that most of the command links to the online HelpText are still broken as no one has taken the time to convert the topics yet.
  • Added info for some of the newer fancy comm commands

-- SluggyQBFreak - 24 Jul 2005

  • Initial creation
Topic revision: r11 - 07 Apr 2017, SolarQBFreak
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding WikiMARE? Send feedback