Start of topic | Skip to actions
SluggyMARE UNOFFICIAL Official GuideThis 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 atwinds.org, port 8000. The guide was formatted for TWiki MARE by SluggyQBFreak. Please note that the guide is written from the perspective of Workaphobia and for the MARE SluggyMARE. Happy reading
Color Codes:
IntroWith 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 ContentsI. Player BasicsOk, 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 topA. CommunicationTalking 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 .TinyMARE.+channel alone will give you a list of channels you are currently on, and sending the text "who" to any channel (using .TinyMARE.+com or =) will display a list of other users on that channel.
Tying this all into one example:
").
"<message>
Note that a closing quotation isn’t needed.
To talk to a single player in the same room, you can use the .TinyMARE.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 .TinyMARE.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 .TinyMARE.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 .TinyMARE.say:
pose <message> :<message> You can make the .TinyMARE.pose possessive by using a semicolon ( ;) instead.
;<message>
For .TinyMARE.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 .TinyMARE.to command. Just like posing, the word .TinyMARE.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:
To read a message: +mail <message #> To clear messages: +mail clear +mail clear=<message #> Also a part of communication, there are a series of .TinyMARE.@Emit variation commands that will be discussed later. to top B. Moving aroundAs a character, you can move through different rooms and observe objects. To get a feel for your surroundings, use the .TinyMARE.look command. look <object|exit|etc.> To see the room you are currently in, use .TinyMARE.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 .TinyMARE.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 .TinyMARE.@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>
C. Getting InformationThe .TinyMARE.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 .TinyMARE.where a particular player is, again assuming they don’t want privacy: where <player> You can again block yourself from .TinyMARE.where: @set me=D (To turn it off: @set me=!D) You can find out a lot about a player by using .TinyMARE.+finger: +finger <player> The .TinyMARE.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 ObjectsYou 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 .TinyMARE.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 .TinyMARE.say command, = for .TinyMARE.+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 .TinyMARE.page or .TinyMARE.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 SystemThe 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), .TinyMARE.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 .TinyMARE.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 .TinyMARE.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.
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 .TinyMARE.use and .TinyMARE.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 .TinyMARE.+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 .TinyMARE.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 CustomizationThe following set of attributes affects how you appear to other players. Your description is what other players see when they use the .TinyMARE.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 BasicsThe 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 objectsRooms - 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 AttributesLet’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. LocksLock 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:
C. Lock-Related AttributesNow 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.
D. Digging RoomsRooms 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:
@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
E. @Emit Related CommandsPose 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. ZonesZones 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. FlagsFlags 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:
H. PronounsPronouns 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.
I. Controlling ObjectsAny 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 BasicsCoding 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 topA. Custom AttributesUntil 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:
move command. Pose can also be abbreviated to its normal alias of a colon.
to top
B. FunctionsBy 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 StructuresThese 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.
@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>
@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.
@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>
D. EventsUp 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:
@foreach loop and is unchanged by this.
Here’s a Sluggy example:
@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:
<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 CodingThis section goes over more powerful coding methods in detail, such as color options and advanced functions. to topA. Advanced Color(For color help while connected, typecolorlist or colorhelp. Both of these commands are specific to SluggyMARE.)
You should be familiar with the 16 basic colors:
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:
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 SemaphoresThe 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 AttributesLet’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 FunctionsA 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 outhelp 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 FunctionsYou 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 fromhelp 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 FunctionsHere 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 FunctionsThere’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:
V. ParsingAh, the dreaded parser, probably the most frustrating yet powerful aspect of coding. Not for the faint of heart. to topA. The ParserThe 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 thesay 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:
@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.
B. Hard BracketsParsing 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 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||