Step’s JediMUD Zone File Tutorial
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
Execute no matter what.
Execute only if the last command was successful.
Execute only if the last command was not successful.
Execute if the last monster load command was successful.
Execute if the last monster load command failed because of a probability test.
Execute if the last monster load command was successful.
Execute if the last monster load command did not succeed for any reason.
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.
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.
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.
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.
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.
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:
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
by Giovanni Ruffini
Copied Right, Month of the Dragon, Year 365