Step’s JediMUD Zone File
Tutorial
Version 0.0
Begun August, 2002
Completed January, 2003
In early August, 2002, after
reading Mandragora’s discussion of the math involved in bulk-loading
mob-packages based on interdependent percentage-loads, I began to consider the
possibility that I had never used the zone file commands to their full
potential.
This is particularly true of
the “if-state” options: most authors use only Option
0 and Option 1 (“do always” and “do
if the previous command succeeded”). Only
rarely had I ever considered using Option 2
(“do if the previous command failed”), and I had quite deliberately ignored the
remaining four options (see below, Section 1),
believing them useless. After a series
of brainstorms for my pending “Scipio Dreaming” area, I realized that those
four options in fact opened up previously unexplored vistas in area writing.
When I sat down to explore
some of these possibilities, I quickly realized that much could be done with
the additional concept of “control rooms”
used as loading sites for “control objects”
and “control mobs” (see below, Section 2).
Late in August, I had a series of extensive chats with ProtoClown about
the implications of some of these techniques.
He was quick to see the point, and took nearly all of my suggestions several
steps further.
I quickly realized that my
own difficulty grasping some of the concepts in question – and indeed, the fact
that it had taken me nearly a decade to have this conceptual breakthrough –
meant that I ought to write my ideas in the form of a zone file tutorial, with
the aim of making sure these techniques can be available to everyone who might
find them useful.
N.B.: I have no familiarity with Unicorn’s World
Builder. This tutorial therefore assumes
on the part of the area writer the ability to edit his or her zone files
manually. Throughout this document, I
use the phrases “at a crash” or “after a crash” to refer to the start of any
given uptime, whether that uptime was caused by a bug-induced crash or an
administrative reboot. From the point of
view of the zone-file code, the two types of events are identical.
1: The Under-Used If-States
I quote the following table
directly from the JediMUD area-building documentation:
Conditions for the Load
Command to Execute |
If Flag |
Execute no matter what. |
0 |
Execute only if the last
command was successful. |
1 |
Execute only if the last
command was not successful. |
2 |
Execute if the last monster
load command was successful. |
3 |
Execute if the last monster
load command failed because of a probability test. |
4 |
Execute if the last monster
load command was successful. |
5 |
Execute if the last monster
load command did not succeed for any reason. |
6 |
Option 0 is easy, and requires no explanation.
Option 1 is also easy to understand, but offers one or two
nuances. This option is usually used for
giving equipment to mobs, but can just as easily be used to make the existence
of one mob (or one group of mobs) dependent upon the existence of another mob
(or group of mobs). For example, a unit
of guards might be set to load only if the captain of the guard loads first. Most area writers have always known this.
Option 2 has generally seen little use. I think most authors cannot see what good it
might do. But consider two objects,
Matter and Anti-Matter. Matter loads
into the room on a 50% chance. We
obviously do not want our Anti-Matter to load if Matter is already there, so we
use Option 2, to make Anti-Matter’s load
dependent specifically on Matter’s failed load.
I have only been able to document this option’s use in JediMUD area
files in a very small number of places.
Option 3 at first glance seems to be nothing more than a
redundant Option 1. Understanding why this is false is the first
step towards revolutionizing your zone files.
The phrase “last monster load” does not necessarily apply to the command
which immediately precedes. Any number
of object, equipment, or door loads, dependent or otherwise, may
intervene. In other words, Option 3 gives you a way to make a load dependent
on something that happened two, ten, even twenty zone commands prior to the
load in question. Valhalla makes
extensive use of this option,
and it appears twice in
Arachnos as well. There, the authors
employ it simply to keep the second of two probability-based object loads from
being dependent on the first. (In other
words, if you want Steppin’s Bardic Decapitator and Steppin’s Bardic
Circumcisor to both have 25% load
probabilities, you want to use Option 3 on
the second object, so as to avoid subordinating it to the first object’s
success or failure.)
Option 4 lets you refine your approach considerably. With the “failure option” of Option 2, we do not know why the previous command
failed, only that it did. It may have
failed a probability test, or it may have failed because a maximum number had
been exceeded. And remember, Option 4 has the same power as Option 3: it allows us to refer back to the last
monster load, while overlooking non-monster commands which have taken place in
the meantime. I do not know whether any
JediMUD area writer has ever used this option.
Option 5 is indeed nothing more than a redundant Option 3, and in fact, in earlier versions of
JediMUD documentation, this option was simply given the cryptic label, “For
parsimony.” The only examples of this
option being used in JediMUD’s world-files – three which I can document – are,
as far as I can tell, employed unnecessarily.
Option 6 has powers similar to Option
4. Far from being simply a
redundant Option 2, it is more powerful in
its ability to skip intervening commands.
It also provides an option which triggers based not simply on
probability, but also on the exceeding of a maximum number. In other words, we can use Option 6 to implement Matter and Anti-Matter (the
example used above) as mobs with subordinate object loads separating them in
the zone file. Use of this option has
been exceedingly rare; I have been able to verify only one known example.
2: Control Rooms, Mobs, and Objects
The discussion in this
section centers around the following proposal: that zone writers can use rooms
off-limits to player interference in order to more carefully control what
happens in the rest of their zone.
Zone-file load commands depend on the concept of the “max exist” – the
idea that the load of an object or mobile can depend on how many other versions
of that object or mobile already exist in the game at the current time. While the zone author can set the max exist
for an object or a mobile, to a very large degree, the central variable (how
many other versions of it already exist) is completely beyond author control. The zone author can never know how many given
versions of a mob have been killed or an object loaded at any given reset.
This problem will never completely go away until JediMUD
implements zone commands designed to purge
specific mobs and objects.
However, the problem can be
mitigated somewhat by the use of control rooms and control objects. Consider for instance a room without any
entrances to it from the outside world, a room not accessible via teleportation
or the Shadow Storm, and (to prevent immortal interference) a room that is
NO_VIOLENCE, GOD_ONLY, etc. That room
essentially represents a controlled environment, in which the zone author has
complete control over which and how many mobs and objects load. Thus, while the success of normal zone
commands is to some extent dependent on what players have already done within
the zone, and what objects they wield elsewhere in the game, control rooms, and
the mobs and objects within them, can allow the zone author considerably more
certainty as to what actually loads in the main zone.
I will forsake in-depth
analysis of this technique here, and instead divide it into several examples
included in the answers to the questions in the sections that follow.
3: Objects
A. Ignoring the role of the “max exist,”
valuable objects usually load at random, or only at the start of an
uptime. How can I ensure that an object
will never load at the start of an uptime?
Crashing-running as we once
knew it has gradually died out with the incredible increase in uptimes, and
with the growing focus on resetting (or “popping”) a zone through brute force. Use of this following technique can help
ensure that the valuable items in your zone can never be crash-run. Consider
the following example, where room 75000 is a “control
room” (see Section 2 above) which is
inaccessible to player tampering, and room 75001 is a normal room in your zone:
O 0 5001 1 75000 Load a control object to
the control room
O 2 5031 1 75001 If that load fails, load a
normal object in the main zone
In this example, the valuable
object, 5031, will load only if object 5001 fails to load in the previous
command. This failure can only happen if object 5001 already exists
somewhere in the game. In other words,
since object 5001 will always load on
a crash, object 5031 will never load
on a crash. Placing object 5001 in a
control room ensures that it cannot be taken, junked, rented, etc., thus ensuring that the first command
in this example will always fail for
the rest of the uptime.
Consider a permutations of
this example:
O 0 5001 1 75000 Load a control object to
the control room
O 2 5031 10 75001 If that load fails, load
another object of max-exist 10
In this previous version,
object 5031 will not load at the crash, but will
load during the next ten zone resets.
And:
O 0 5001 1 75000 Load a control object to
the control room
X 2 5031 10 75001 50 If that load fails, load an
object of max-exist 10 half the time
In this version, object 5031
will not load at the crash, but has a 50% chance of loading during subsequent
resets, until the max exist of 10 is reached. This may theoretically take only
ten resets, but could conceivably take 15, 20, etc.
B. How can I load an object only
if a specific number of that same object already exist?
Area writers have, I believe,
a tendency to think about “max exists” in static terms. In other words, they imagine that if an
object has a max exist in one location in a zone file, it must always have that
max exist. That is not necessarily the
case. Consider the following example,
designed to load object 3001 to room 27001:
O 0 3001 12 27001 Load up to 12 of that object
into that room
O 2 3001 13 27001 If that load fails, load a
13th into that room
If less than a dozen items of
vnum 3001 currently exist in the world, the first command will always succeed,
and the second command will never get called.
If a dozen items of vnum 3001 exist, the first command will always fail,
as the max exist has been reached. But
if the first command fails, the second command gets called (by virtue of using Option 2).
The second command, however, uses a different max exist, one higher,
which – if there are only a dozen of the objects in existence – in this case
permits the command to succeed.
In other words, this pair of
example commands will load the object if
and only if the item in question is already at its max exist. A higher max exist in the second command (14,
15, etc.) can give you flexibility to
determine how many times this might happen.
Use of probability loading can help you determine what percentage of the time it will happen.
Nor does it have to be the
same object in both cases:
O 0 3001 12 27001 Load up to 12 of that object
into that room
O 2 3002 1 27001 If those 12 already exist,
load another object
This pair of commands will
load object 3002 if and only if
object 3001 is already at its max exist, but object 3002 does not yet exist.
4: Mobiles
A. How can I make a unique mobile load
in one place one time, and another at another?
There tends to be very little
middle ground for placing non-wandering mobs within a zone. A king either stays in his throne room (e.g. Honorius Augustus) or a complex
procedure is required to guide him on one fixed route from Point A to Point B (e.g. King Welmar). But what if you want your mob (call him
President Clinton) to be in the bedroom for one reset and the kitchen in the
next? Consider the following example:
W 0 6605 1 6630 50 Mob loads to room 6630 50% of
the time
M 2 6605 1 6640 If mob fails to do so, it
loads instead in 6640
This is a fairly clear-cut
example, but suffers from two limitations: 1) for any location switch to take
place, the mob must be dead, or not otherwise loaded into the game; and 2)
because of the probability load in the first command, the author cannot
guarantee which room the mob will load in.
B. How can I make two unique mobiles
swap locations with one another?
If the cityguard is in the
town square one minute and the temple the next, the plague-ridden leper running
from him might be in the temple one minute and the town square the next. (Paying attention?!) Here, the technique suffers from limitations
similar to those in the previous example:
W 0 9930 1 9905 85 A mob usually in 9905, 85% of
the time
M 4 9930 1 9910 Except when it’s in 9910
*
W 6 9940 1 9910 85 Another mob, usually in 9910,
85% of the time
M 6 9940 1 9905 Except when it’s in 9905
Let’s walk through this. The first command loads the guard to the town
square 85% of the time. The second
command uses Option 4 to load him to the
temple if and only if he failed to
load to the town square because of the probability test. (In other words, we do not load him in the
temple if he exceeded his max-exist in the town square.) The third command uses Option 6 to load the leper in the temple if the
guard failed to load there for any reason at all. But the third command will never load the
leper in the temple if the guard has already loaded there. Thus, the fourth command succeeds in loading
the leper to the town square, if and only
if the guard has loaded in the temple.
Got it?
5: Dependency on Player Actions
A. How can I make object and mob loads
dependent on player actions?
We generally imagine each
zone to exist independently of our own actions.
For instance, the citizens of Ravenna either riot or do not, but their
decision to do so has nothing to do with us.
This is not particularly realistic.
It is true that object devices allow a certain amount of player
interactivity, but expanding this interactivity will depend on future additions
to the device code. In the meantime,
consider the technique outlined here. If
the Elvish Princess cannot understand the scripture she is studying because
someone has killed her tutor, she will instead go wandering in the garden. Room 4570 is a control
room in this example:
O 0 4550 1 4525 The book is always there
waiting for the Princess
M 0 4502 1 4570 Put one version of the
tutor in the control room
M 0 4502 2 4525 And try putting another
one in the bedchamber
* Which would succeed
only if the bedchamber’s tutor had been
* Killed before this
previous reset
M 1 4501 1 4530 Which means the Princess
went wandering in the garden
M 2 4501 1 4525 Or stayed in the
bedchamber if the tutor had not been killed
Take a minute to walk through
it and convince yourself. The book is
merely for show. Start from the
crash. The first mob load puts a tutor
in the control room. The second mob load puts the real tutor into the main zone, in the
bedchamber. The Princess herself starts
the game in the garden. But what happens
if someone kills her? On the next reset,
the tutor will catch her, and she will have to stay in the bedchamber, hitting
the books.
This is an extremely crude
technique, one which could benefit greatly from the implementation of purge commands as mentioned in Section 2 above.
(Specifically, it works only if someone kills the Princess, and not the
tutor, not the Princess and the
tutor, and so on.)
I will outline alternatives
to this method in Section 6 below.
B. How can I make the state of a door
dependent on player actions?
Most area writers have not, I
think, noticed the fact that door-loads use the same “if-states” as every other
zone command. Thus most authors use Option 0 exclusively when writing door-loads. But consider the following example, where
room 63030 is a normal, accessible room in your zone:
M 0 63230 1 63030 Loads a mob into room 63030
D 2 63030 0 2 If fails, load a
locked door north in the same room
In this case, the door will
load only if the mob fails to
load. Since the mob has a max exist of
one, the mob itself will fail to load only if it already exists. Thus, this door will load on the subsequent
reset of the zone, but if and only if
the mob has not been killed.
In this previous case, the
loading of a door is dependent on player inaction. Can we create a situation in which the
loading of a door is dependent on positive player action? At first glance, we might be temped to use
the following more simple example:
O 0 63020 1 63030 Loads a unique object into
the same room
D 1 63030 2 2 If succeeds, load a
locked south door in the same room
In this case, the door will
load only if object 63020 loads as well.
Since it is a unique object, and would load on a crash, someone would
have to come along later and junk it, rent it, etc. Then, the door command
will succeed. But this is pointless, as
the door command will already have
succeeded, at the crash. So, clearly we
need something more complex. Room 63099
is a control room in this example, and 63069
a control object:
O 0 63069 1 63099 Loads a control object to a
control room, crash-only
O 1 63020 1 63030 Loads a unique object into
the main room, crash-only
O 2 63020 1 63030 Load a unique object into
that room, never on a crash
D 1 63030 1 2 If succeeds, loads a
locked east door in the same room
This is a confusing example,
and needs some clarification. The first
command simply puts a random object in the control
room, creating a unique event to serve as an anchor for the commands
that follow. The second command loads an
object into the zone if that unique event just took place, i.e. right at the crash, but never on any of the subsequent resets. The third command only takes place if the
second command fails. Since the second
command can only fail on subsequent
resets, the third command will only
succeed on subsequent resets, and then if
and only if there is no other object 63020 in the game. Since the second command loads that very
object, the third command will succeed if
and only if someone takes and junks or rents the version of object 63020
loaded in the second command. The fourth
and final command is the door-load, which takes place only when the third
command succeeds. Thus, the door-load
takes place if and only if someone
takes and junks or rents the version of object 63020 loaded right at the crash.
Phew!
6: Coordination with Mob Procs
The more observant among you
will by now have noticed that in some of my previous examples, I have used
unnecessarily complex methods to achieve my stated aims. To some extent, this was merely to prove a
point, that we have not sufficiently explored the potential complexities of our
zone files. But if more simple tools are
available to us, we should make use of them.
In recent years, JediMUD has added an impressive system of special
procedures for mobiles that can be customized in the mob file itself, without compile-access
to the game’s C files. These procs can
be used in coordination with zone-file commands to achieve a wide variety of
interesting effects.
Consider the following three
procs now available to any new mob on JediMUD:
GATE_IN_MOB
LOAD_ITEM_ON_DEATH
LOAD_MOB_ON_DEATH
Area writers not already
familiar with these procedures should consult the JediMUD Builder’s Guide
before trying to use them.
These are extremely powerful
special procedures, essentially allowing the area writer to place zone-file
commands outside of the zone file. With these
three examples, the area writer can load mobs and objects based solely on
whether a mob is attacked or killed, without reference to any load- or
probability-event in the zone file.
How can I use this technique in place of
some of the methods you’ve outlined above?
If you found some of the
zone-file methods I’ve outlined too confusing, you and I have something in
common. So, these new mob procs may be
the first step towards simplifying your life.
No mob or item will load on a crash if you omit it from the zone file
completely. Thus, any mob or object that
is load on
death will load only in response
to a player action (namely, the killing of some other mob), and thus can never take
place at a crash, only after it. Logically, then, these mob procs can be used
as potential substitutes for the methods outlined above in Sections 3A and 5A.
How can I use this technique to hard-wire
an event-driven “clock” into my zone?
My use of the term “clock”
may be somewhat misleading. After all,
the game already uses a clock to time each zone, resetting it, and thus
executing new load commands, based on how much time has passed. But what if we want to execute new zone
commands based not on real-time, but on event-time? For instance, it may be that the Negus of Showa
wants to summon increasingly more powerful bodyguards to the scene of the crime
each time someone commits a violent act.
Only after all these guards have been defeated in sequence does the
Negus admit defeat and give the player a chance to compete for the final prize,
a manuscript of the Kibre Negast. Using these new mob-procs in coordination
with zone-file commands can create this sort of event-driven clock. Consider the following, in which 13099 is a control room:
In the mob file under mob 13000:
LOAD_MOB_ON_DEATH 100 0 13005
In the mob file under mob 13005:
LOAD_MOB_ON_DEATH 100 0 13015
In the mob file under mob 13015:
LOAD_MOB_ON_DEATH 100 0 13025
In the zone file:
M 0 13000 1 13030 Put the first mob into a
random room in the zone
M 0 13025 1 13099 Try putting the final load on death mob in the control
room
* Failure to load 13025
guarantees that someone killed 13000,
* 13005, and 13015 all in
sequence
O 2 13063 1 13030 Which means we can load the Kibre Negast at the next reset,
Note that this particular
example will work if and only if a
player kills mobs 13000, 13005, and 13015 before the zone resets (at which time
the second command would be successful), and if and only if the player does not
kill mob 13025 before that same reset.
Infinite variety is possible here.
I have not thoroughly
explored some of the implications of event-driven zone-clocks. There is no particular reason why a dozen
events like the one outlined here could not be stacked one atop the other. But I suspect that they will only work
through one iteration. In other words,
without purge commands, I see
no obvious way to set the clock back to zero, and start the event-cycle over
again.
Appendix: Example Zone File
Extensive employment of the
techniques I outline in this file can lead to rolling waves of loads, or stages
of resets, in which zone files do not simply issue the same set of commands
during each reset, but instead issue one of a dozen or more sets depending on
what stage in the “control” process the zone has reached. These techniques can be used to march armed
regiments across a battle-field (e.g. the
Goths in Ravenna), enact scenes in an ongoing plot (e.g. the guard chasing the leper, discussed above), and so on. Here we will consider only one short
possibility, the Chessboard. The
following example is a hypothetical excerpt from a revision to that zone, in
which each reset of the zone marks a move in an ongoing chess game. In this particular sequence, the black knight
takes the white queen. (Quick, someone
call D.W. Griffith!) In this case, the control room is 6399, where we put all the pieces
once they’ve “been captured.”
* After loading the other
chess pieces
* In one stage of the
event-clock
M 0 6307 1 6360 The white queen is still
on her starting square
M 0 6304 2 6343 But
one of the black knights has moved to a position
* From which he can take
the queen
* In a later stage of the
event-clock
M 0 6307 1 6399 A player provides the
trigger, killing the two pieces
M 1 6304 2 6399 Permitting these two
commands to work
* The game then places
them in the control room
* Success of these
commands cues the black response
M 1 6304 2 6360 Black knight seizes white
queen’s square
Right.
by Giovanni Ruffini
Copied Right, Month of the Dragon, Year 365