Claim Building on CrystalMUSH

Puzzles and Pitfalls

Puzzles and pitfalls are the bane of a Singer's existence. A good puzzle keeps the Singer searching a claim for hours, until the puzzle is solved and the crystal vein found. Pitfalls cause cutter repairs, sled haulings, destroyed crystal, and injuries. However, pitfalls - especially injuries - are something that should be used sparingly. It's no fun for the Singer if every time he or she turns around something else is broken or destroyed.

Ideally, if you have a pitfall set up on a claim, you should include a way to avoid that pitfall. Make it possible for the Singer to reach the crystal vein safely by another route, or by using an object to get through the exit safely. This is particularly important for injuries. A statement in the @desc of an exit that says something like, "You think you can make it up there, but getting down without climbing equipment might be a challenge" warns the character that if he or she is not wearing climbing equipment, there's a chance they could be injured -- and gives them a chance to avoid it. (If the character is stupid enough to walk through an exit without looking at it first, they deserve what they get!)

The following sections explain how to set up the most common pitfalls on your claim:

Injuries

Preventing a Sled from Taking Off

Damaging a Crystal Cutter

Destroying a Carton of Crystal


Rooms and exits can also be locked to objects or commands in order to make it harder for a Singer to reach the crystal vein. Refer to Room Guidelines and Exit Guidelines for specific locks.

 

Injuries

There are two kinds of injuries that can occur in the ranges. One of them is a cutter injury, which occurs when a Singer is cutting crystal. These are the common missing fingers, eyes and feet; shattered elbows and shoulders; and bumps on the head. These are randomly calculated each time the Singer cuts a crystal, and can occur regardless of what claim the Singer is cutting. The builder does not set these injuries.

The other kind of injury is specific to a claim, and these are the ones that you, as the claim builder, are concerned with. Injury code can be set up on an object, but it is usually set up on an exit. When someone passes through the exit, they trigger the code. Usually, you will want to have a chance that the character going through the exit will escape unscathed. You can also have several different possible injuries that can be received from the same exit, from which one is selected randomly each time someone passes through the exit.

Important note: although the ranges are meant to be dangerous, the majority of injuries that a Singer receives should normally be relatively minor, like scratches or sprains. Injury exits, on the whole, should be used sparingly - remember that the random cutter injuries already occur frequently. If you decide your claim requires an injury exit, do provide a way for a savvy Singer to avoid the injury, or at the least make the odds of sustaining an injury low (i.e., one chance in 25, as opposed to one chance in four). The chance of receiving an injury that can set the Singer inactive should be very low.


When setting up the @succ, @osucc and @odrop messages, remember that these messages will occur whether the Singer receives the injury or not, so keep them general -- don't refer to any injuries.

In order for injury code to function it needs to be wiz-owned, so you won't be able to test it.

Remember to list the dbref of the injury exit in the &wiz attribute of your master claim object, and explain it in the &note attribute. Refer to "Registers to Include on your Master Claim Object" in Getting Started.


Single Injury Exits

For simple injury exits where there is only one possible injury (anyone passing through either receives that injury or escapes), Aria has developed a parent injury exit object (#2339) that is visual and parentable. It determines whether an injury occurs, checks whether the Singer already has the injury in their medical_state, then (assuming the injury occurs and the Singer doesn't already have it) adds the injury to the Singer's medical_state. The process and code are discussed in more detail in "Multiple Injury Exits", below, or you can type ex #2339 to view the code on the parent injury exit object.

To use the parent injury exit, first @parent your exit to the parent injury exit object:

@parent <exit> = #2339


Your exit will inherit all of the code from the parent injury exit. There are several attributes that you will then need to add to your exit in order for it to work:

&medical_control Set this attribute to #25. (This applies to all injury exits.)
&injury This is the message that you want appended to the Singer's medical_state. You can include pronouns like %s and %p in this message, and the others here. (For more information on how pronouns work, refer to the Exit Guidelines.)
&injmess This is the message that the Singer will see when the injury occurs.
&oinjmess This is the message that people in the room the Singer is entering will see.
&oxinjmess This is the message that people in the room the Singer has left will see.
&injchance This is the number out of which there is 1 chance of injury (for example, 2 means a 50% chance of injury, 4 means a 25% chance of injury).
&majorinjury If this attribute is set to "yes" on your exit, the Singer will also be marked "inactive". This means they will not be able to continue to cut, and they will also not be able to pick up a carton or fly their sled.


In the following example, the Singer has a one in three chance of spraining their ankle going through the exit. It will not set the Singer inactive.

&medical_control <exit> = #25

&injury <exit> = %P ankle is swollen to twice its normal size, and won't take any weight on it for long. Looks like a nasty sprain.

&injmess <exit> = %r%r%rYou try to squeeze through the gap, but you get stuck! Easing through, you feel a sharp pain in your ankle as your foot is caught and twisted in a most unpleasant manner.%r%r%r

&oinjmess <exit> = %N limps in, %p face twisted in pain.

&oxinjmess <exit> = You hear a yelp of pain as %N disappears through the gap!

&injchance <exit> = 3

&majorinjury <exit> = no


On the &injmess attribute, the "%r%r%r" at the beginning and end of the statement will add blank lines before and after the message when it is @pemitted to the Singer. This isolates the warning from the rest of the text on the player's screen, and makes it easier to see. Otherwise, it's possible to miss the message when the exit's @succ and the @desc of the next room scroll onto the screen, and the Singer may not realize he or she is injured unless they look at themselves.


Multiple Injury Exits

The code for a multiple injury exit is not really any more complex than that of a single injury exit. The only additional step in the code itself is that when the character going through the exit is injured, the code must determine which of the possible injuries occurs. Unfortunately there is no exit parent, so you have to add the code to your own exit. The main task is keeping track of the additional messages that will be @pemitted to the character going through the exit and the text that will be appended to his or her medical_state.

Each of these steps must occur every time someone passes through the exit:

  1. Determine whether an injury occurs.
  2. If an injury does occur, determine which of the possible injuries occurs.
  3. Check the Singer's medical_state to determine whether the Singer already has this injury.
  4. If the Singer does not have the injury yet, append the injury to their medical_state and, if the injury is severe, inactivate them.
  5. If no injury occurs, or the Singer already has the same injury in their medical state, do nothing.


The code for most of this is stored in the @asucc attribute. When the @asucc attribute is set up on an exit, it triggers each time someone successfully goes through. The messages will be stored in separate attributes, to make it easier to read the code.

First, set the &medical_control attribute on the exit to "#25". This is required for all injury exits:

&medical_control <exit> = #25


Then, document what will happen when someone passes through the exit. This is important if someone else has to look at the code, and it also helps you if you come back to it after a long absence and don't remember what the heck it was supposed to do. Since the code will be stored in the @asucc attribute, store the documentation in &doc-asucc:

&doc-asucc <exit> = ***** Anyone passing through this exit has a 1 in 5 chance of not being injured, and a 4 in 5 chance of injuries, ranging from mild to severe. If they are already injured with that injury, nothing else happens.


There are four possible injuries in this example, although you can set up more or less as you see fit. The fourth injury is severe enough to set the Singer inactive, so he or she will not be able to continue to cut, pick up a carton or fly a sled. Here's the code:

@asucc <exit>=@switch rand(<#injuries+1>) = 0, {@pemit %#=[u(lucky)]}, {@switch [setq(1,rand(<#injuries>))] [strmatch([get(%#/medical_state)], *[u(ouch-%q1)]*)] = 0, {@trigger v(medical_control)/append_medical_state = num(me), %#, [u(ouch-%q1)], [switch(%q1,<#injuries-1>,INACTIVE)]; @pemit/contents [where(me)] = [u(oxinjmess)]; @pemit %# = [u(tumble-%q1)]; @oemit %# = [u(oinjmess)]}}


In our example, <#injuries+1> would equal 5, <#injuries> would equal 4, and <#injuries-1> would equal 3. This is what the statement actually does:

  1. Selects a random number between 0 and <#injuries>.
  2. If the random number is 0, the Singer is @pemitted the message stored in the &lucky attribute on the exit, and the rest of the code is ignored. The Singer has passed through without an injury.
  3. If the random number is anything other than 0, another random number between 0 and <#injuries-1> is generated and stored in the variable %q1.
  4. The contents of the attribute &ouch-%q1 (i.e., &ouch-0, &ouch-1, &ouch-2 or &ouch-3, if there are four possible injuries) are compared to the contents of the Singer's medical_state.
  5. If a match is detected, the Singer already has the same injury, and the rest of the code is ignored.
  6. If no match is detected, the contents of the attribute &ouch-%q1 is added on to the end of the Singer's medical_state, the Singer is @pemitted the message stored in the &tumble-%q1 attribute (i.e., &tumble-0, &tumble-1, etc.), anyone in the room the Singer left is @pemitted the contents of the &oxinjmess attribute, and anyone in the room the Singer enters is @oemitted the contents of the &oinjmess attribute.
  7. If the last injury is received, which is a severe one (in our example it would be injury 3 -- the mildest injury is 0), the Singer will also be set inactive.


In the interests of keeping the @asucc as uncluttered as possible, the injury states and the @pemit/oemit messages will be stored in separate attributes on the exit. First, set up the @pemit/oemit messages. They should be accompanied by a &doc- attribute, explaining their purpose:

&doc-lucky <exit> = ***** This is the message that will be @pemitted to the Singer if they make it through the exit without an injury.

&lucky <exit> = %r%r%rYou must be out of your mind to try it, but you close your eyes and allow your hands and feet to intuitively seek a path down the mountainside. Somehow, you arrive safely on the beach.%r%r%r

&doc-injmess <exit> = ***** These are the messages that anyone left in the room behind the character descending, and anyone waiting below, will see if there is an injury.

&oinjmess <exit> = %r%rAs %N begins to descend above you, %s slips, letting out a yell as %s falls down the cliff side!%r%r

&oxinjmess <exit> = %r%rAs %N begins to descend %s loses %p grip, letting out a yell as %s falls down the cliff side!%r%r


The &tumble- attributes are the messages the character falling sees. You will need one for each possible injury that could be sustained. It's a good idea to start with the mildest injury and increase in severity with each:

&doc-tumble <exit> = ***** These are the messages the character falling sees.

&tumble-0 <exit> = %r%r%rA rock slips beneath your foot, and you slide a few meters against the cliff face before managing to grab a handhold. You make it the rest of the way down safely, but you've picked up some bumps and scratches.%r%r%r

&tumble-1 <exit> = %r%r%rA rock that your hand was gripping pulls out of the side of the cliff, leaving you to tumble helplessly down its face! Your entire body aches as you pull yourself to your feet, but no serious damage is evident.%r%r%r

&tumble-2 <exit> = %r%r%rYour foot slips on some loose stones, and before you can regain your balance you are sent plummeting down the cliff face. You feel a sharp pain in your left wrist as you land awkwardly upon it.%r%r%r

&tumble-3 <exit> = %r%r%rThe rock disappears beneath your feet, and you feel yourself plummeting through the air, occasionally cracking against a jutting boulder. Thankfully, you are unconscious when you hit the ground, but you awake to a seering pain in your right arm.%r%r%r


Finally, the &ouch- attributes contain the text that will be appended to the faller's medical_state. Again, you will need one for each injury. The injuries should match the severity of the &tumble- messages:

&doc-ouch <exit> = ***** These are the messages appended to the injured character's medical_state after the fall.

&ouch-0 <exit> = %P clothes are ripped in various places, revealing some minor, diry scratches on %p arms and legs, and a particularly nasty (but non-life-threatening) one on %p forehead, above the left eye.

&ouch-1 <exit> = %S walks slowly, %p entire body stiff and aching. Several large, purplish bruses are evident on %p face, back and legs.

&ouch-2 <exit> = %P left wrist is swollen, and appears to be slightly sprained. %S also suffers from light bruises and scrapes almost everywhere else.

&ouch-3 <exit> = %P right arm dangles uselessly at %p side, cleanly broken in two places.


Injuring Someone Who Does Not Pass an Object Lock

Exit Guidelines discussed locking an exit to an object so that anyone who does not have that object cannot pass through the exit. It is also possible to lock an exit to an object so that a character who does not have the object can still go through, but triggers injury code on the exit. Any character who has the object will pass through safely.

This will not work with the parent injury exit, you will have to use the code for the multiple injury exit.

First, lock your master claim object to the object. For example, to lock the claim master to the Katz lamp:

@lock <master> = @#3987 & +status:active


The command is the same as for locking an exit, except that you are locking your master claim object instead. Similarly, to lock the claim master to the climbing equipment:

@lock <master> = @#8316 & +status1:worn & +status2:secured


All of the injury code on the exit itself is the same as in "Multiple Injury Exits", except for the @asucc statement. Here you will add an extra switch statement that checks the status of the lock on the master claim object with the function:

elock(<master claim object dbref>, %#)


If the character passing through the exit fails this lock, it returns a 0. If they pass, it returns a 1. So the @asucc statement becomes:

@asucc <exit>=@switch elock(<master claim object dbref>, %#)=0, {@switch rand(<#injuries+1>) = 0, {@pemit %# = [u(lucky)]}, {@switch [setq(1,rand(<#injuries>))] [strmatch([get(%#/medical_state)], *[u(ouch-%q1)]*)] = 0, {@trigger v(medical_control)/append_medical_state = num(me), %#, [u(ouch-%q1)], [switch(%q1,<#injuries-1>,INACTIVE)]; @pemit/contents [where(me)] = [u(oxinjmess)]; @pemit %# = [u(tumble-%q1)]; @oemit %# = [u(oinjmess)]}}},{@@ do nothing, passed lock}

 

Preventing a Sled from Taking Off

If you have a marshy or muddy claim, or rocky area where the landing gear on the sled could become jammed in the rocks, then you may want to randomly prevent the sled from launching. This is accomplished by setting four extra attributes on the landing_site room.

First, set the &launch_allowed attribute on the room to "yes" or "no". It doesn't matter which, because it will be set randomly to one or the other each time a sled lands on the claim.

&launch_allowed <room> = yes


For the room to realize that a sled has landed and it should reset the &launch_allowed attribute, we tell it to @listen for the message generated whenever a sled lands:

@listen <room> = A sled * slides precariously in for a landing.


When the room "hears" this message, it will execute a switch statement in the @ahear attribute:

@ahear <room> = &launch_allowed me = switch(rand(<#>), 0, no, yes)

where there is one chance out of <#> chances that the sled will not be able to take off (i.e., 4 if the sled has a 25% chance of not being able to take off, 2 if the sled has a 50% chance of not being able to take off). The rand(<#> ) statement randomly selects a number between 0 and <#-1>. If the random number is 0, the &launch_allowed attribute is set to "no" and the sled is stuck. Otherwise, the &launch_allowed attribute is set to "yes".


Finally, store the reason that the launch is denied in the room's &launch_denied_reason attribute. This will be @emitted to everyone in the sled if it is unable to launch:

&launch_denied_reason <room> = The sled struggles and whines but fails to pull free of the marshy ground.


Remember to note the room dbref and explain what happens in the &note attribute on your master claim object. Refer to "Registers to Include on your Master Claim Object" in Getting Started.

 

Damaging a Crystal Cutter

One can imagine a number of ways in which a cutter could become damaged in the ranges. What if a careless Singer took it swimming in a lake or river? Or waded through deep mud with it? Or accidently dropped it down the side of a cliff? The same code can be used for each of these occasions.

As with injuries, the code to damage the cutter is stored in the @asucc attribute of the exit. The code following steps are executed each time a character goes through the exit:

  1. Determine whether the character is carrying a crystal cutter. If the character is not carrying a cutter, the rest of the code is ignored.
  2. If the character is carrying a cutter, obtain the dbref of the cutter.
  3. Select a random number between 0 and <#-1> (where <#> is the number out of which there is one chance of the cutter being destroyed).
  4. If the random number is between 1 and <#-1>, the rest of the code is ignored.
  5. If the random number is 0, change the contents of the &cutter_repair_needed attribute on the cutter to "yes", store a description of what the broken cutter looks like in the &cutter_broke_desc attribute of the cutter, store a message about the cutter being broken (which will be @pemitted to the character if they try to use it) in the &cutter_broke_pemit attribute on the cutter, and @pemit/oemit messages to the Singer and anyone in the room he or she is entering or left that the cutter has been damaged.


The actual @asucc code is:

&asucc <exit> = @switch [setq(0),cutter(%#)][r(0)]+[rand(<#>)] = +*, {@@ Do nothing, character is not carrying a carton.}, *+0, {&cutter_repair_needed r(0) = yes; &cutter_broke_desc r(0) = [u(damage_desc)]; &cutter_broke_pemit r(0) = [u(damage_pemit)]; &cutter_broke_oemit r(0) = [u(damage_oemit)]; @pemit %# = [u(dropped_cutter)]; @pemit/contents [where(me)] = [u(oxdropped_cutter)]; @oemit %# = [u(odropped_cutter)]}, {@@ Do nothing, Singer lucked out and got 1..<#-1> on the rand - cutter damange only happens when rand(<#>) returns 0.}


In the interests of keeping the @asucc as uncluttered as possible, the damage states and the @pemit/oemit messages will be stored in separate attributes on the exit. First, set up the damage messages that will be added to the cutter's description (&damage_desc) and @pemitted/oemitted when the Singer tries to use the cutter (&damage_pemit). For example:

&damage_desc <exit> = This cutter looks like it's been thrown from a cliff with all the Singer's might! It's dented and full of dirt and small rocks, and refuses to work anymore.

&damage_pemit <exit> = Sorry, looks like you mangled this cutter far beyond use when you dropped it down that cliff.

&damage_oemit <exit> = %N looks at %p cutter and realizes sadly that it is far too damaged for use.


Finally, set up the messages that will be emitted to the character dropping the cutter (&dropped_cutter), the room that he or she left (&oxdropped_cutter), and the other characters in the room that he or she enters (&odropped_cutter). For example:

&dropped_cutter <exit> = %r%r%rYour grip slips on your cutter, and as you clutch desperately at the precious instrument, it crashes to the ledge below!%r%r%r

&oxdropped_cutter <exit> = %r%r%r%N drops %p cutter, sending it crashing to the ledge below!%r%r%r

&odropped_cutter <exit> = %r%r%r%N's cutter crashes to the ledge at your feet! %S follows quickly, screaming in rage!%r%r%r


In order for the cutter code to function it needs to be wiz-owned, so you won't be able to test it.

Remember to list the dbref of the exit in the &wiz attribute of your master claim object, and explain it in the &note attribute. Refer to "Registers to Include on your Master Claim Object" in Getting Started.

 

Destroying a Carton of Crystal

Like the cutter, there are a number of ways a carton could be damaged or destroyed in the ranges: sinking in mud or water, for example, or the old standby of falling down the side of a cliff. The odds of this happening should be low, since destroying the carton also destroys any crystal inside of it, which will likely make the Singer very, VERY unhappy.

First, set the &master_sled attribute on your exit to "#384", the master sled object:

&master_sled <exit> = #384


The master sled object contains the code to deactivate the carton, which has to be executed before the carton can be destroyed. This will be triggered as part of the code on the @asucc attribute on the exit.

The @asucc code on the exit will do the following each time a character goes through:

  1. Determine whether the character is carrying a carton of crystal. If the character is not carrying a carton, the rest of the code is ignored.
  2. If the character is carrying a carton of crystal, obtain the dbref of the carton.
  3. Select a random number between 0 and <#-1> (where <#> is the number out of which there is one chance of the carton being destroyed).
  4. If the random number is between 1 and <#-1>, the rest of the code is ignored.
  5. If the random number is 0, trigger the code in the &deactivate_carton attribute on the sled master #384, destroy the carton, and @pemit/oemit messages to the character carrying the crystal and anyone in the rooms he or she left and is entering that the carton has been destroyed.


This is the code for the @asucc of the exit:

&asucc <exit> = @switch [setq(0),carton(%#)][r(0)]+[rand(<#>)] = +*, {@@ Do nothing, character is not carrying a carton.}, *+0, {@trigger v(master_sled)/deactivate_carton = [r(0)], get(r(0)/sled); @dest r(0); @pemit %# = [u(splat_carton)]; @pemit/contents [where(me)] = [u(oxsplat_carton)]; @oemit %# = [u(osplat_carton)]}, {@@ Do nothing, Singer lucked out and got 1..<#-1> on the rand - carton destruction only happens when rand(<#>) returns 0.}


In the interests of keeping the @asucc as uncluttered as possible, the @pemit/oemit messages will be stored in separate attributes on the exit. These will be emitted to the character dropping the carton (&splat_carton), the room that he or she left (&oxsplat_carton), and the other characters in the room that he or she enters (&osplat_carton). For example:

&splat_carton <exit> = %r%r%rYour grip slips suddenly, and though you scrabble to regain your hold the carton you carry is caught up in the current and swept from your grasp, down the river!%r%r%r

&oxsplat_carton <exit> = %r%r%r%N shrieks suddenly, and your stomach sinks as you watch the carton %s was holding float away down the river.%r%r%r

&osplat_carton <exit> = %r%r%r%N emerges from the river, a sick expression on %p face. You suddenly realize %s is no longer carrying %p carton of crystal.%r%r%r


In order for the carton code to function it needs to be wiz-owned, so you won't be able to test it.

Remember to list the dbref of the exit in the &wiz attribute of your master claim object, and explain it in the &note attribute. Refer to "Registers to Include on your Master Claim Object" in Getting Started.

 

Introduction | Getting Started | Room Guidelines | Exit Guidelines | Puzzles and Pitfalls | Finishing Up


CrystalMush Homepage


CrystalMUSH: moink.nmsu.edu 6886
This guide by: Inanna@CrystalMush (hales@cadvision.com)
This is Revision 2 of the Claim Building guide, 01 January 1998.