|[ LiB ]|
As well as having a completely flexible logical design, the BetterMUD has a flexible network layer, because it is more abstracted from the game than the SimpleMUD's network layer.
Like the SimpleMUD, the BetterMUD focuses on the idea of entities , so I won't need to spend much time going over entity concepts. In the BetterMUD, however, there are different kinds of entities.
The first major change from the SimpleMUD to the BetterMUD is the addition of regions . Most MUDs have regional systems, which allow you to organize your game more easily. Figure 11.3 shows a simple three-region layout. Regions also make it easy to group logic, and they ease the strain on your auto-saving system.
To understand regions, imagine a collection of rooms in the magical forest of the realm. Whenever evil monsters such as orcs and goblins enter the forest, they receive a curse that slightly lowers their stats. Without regions, there's really no easy way to do this. To make this work, you give a region the logical actions "character entered" and "character left," which are executed whenever characters enter or leave. So when an evil monster enters a magical forest, the magical forest's logic module curses the character, and when the character leaves the forest, the curse is removed. This is a nice, elegant system of implementing a large collection of scripts in just one area, instead of putting them in every room that is in the forest area.
Regions make things easier for the database, too. Imagine a large game, with thousands, or even tens of thousands of rooms. Whenever your game tries to do a complete database dump, it takes a long time, and the game is going to lag up for a second at least, or maybe much longer.
To prevent the lag, you may want your game to save one region at a time, splitting up the job over a long period of time, so that the game doesn't lag.
Regions are simple entities. They need to know only the basics: their name , ID, and description, as well as a logic module, and lists of all entities contained within the region.
In the BetterMUD, rooms are similar to and simpler than SimpleMUD rooms. In the BetterMUD, rooms are no longer involved with money on the ground, simply because money isn't a special case object. Neither do they deal with tracking who respawns in the room, because this functionality is provided in the logic modules you implement instead.
The physical aspect of a room in the BetterMUD deals only with a few things: room name, description, ID, associated region, exits from the room, characters in the room, and the items on the floor.
Portals are a new concept in the BetterMUD. In the SimpleMUD, each room simply had four exit IDsthose are the IDs of the rooms attached to that room. In the BetterMUD, it's not that simpleevery room has a list of portals , which are basically structures that describe a path from one point to another. Every portal has one or more entries into it, as shown in Figure 11.4. Rooms are never explicitly linked; instead, they point to a portal, and the portal manages the entry of a player to different rooms depending on which room they entered the portal from.
Portals are complex, and I evaluated many designs before selecting one. You could easily go with simple one-way portals, but there are problems with that kind of a design.
For example, it would make sense that if a portal door is closed, both one-way portals would need to know that it is closed, which would mean that the portals need a communication system between their logic modules. Overall, that's a bad design because it can blow up in your face rather quickly.
Other designs had me thinking about a segmented approach, in which there were two types of portals: inter-regional (portals that connect rooms in two different regions), and intra-regional (portals that connect two rooms in the same region). This design is complicated as well, because each room must track whether its portals are inter- or intra-regional, which violently explodes the amount of code needed. (Trust meI tried implementing it as a test to see how much code would actually be needed.) The best rule you can use is the KISS rule; keep it simple, stupid.
The current portal design is nice and robust and is not limited to one- or two-way designs, since it uses a list of variable entries. When a player enters a portal, the list of variable entries searches for the player's starting point, and then spits the player out at the ending point. If there is a logic module attached to a portal, it tells the module that someone is trying to enter the portal.
This is where portals are coolportal logic modules have the option of rejecting an entrance . Let's say you create a magical portal that only admins can enter, and if a nonadmin tries entering, it says, "Nope, you're not getting in here, buddy!" Or even better, you could have magic force field logic scripts that not only reject entering, but also damage the players who try to enter. (That'll teach them!) The possibilities are endless, and I could go on for days listing what logic modules can accomplish.
Accounts are another new concept in the BetterMUD. There are times when you're going to want to have more than one player in the gamemaybe an extra player to hold your loot and booty, or someone to help you along in battles . Whatever the case, the ability exists. Therefore, your players can create new characters without changing usernames or passwords.
An account is simply an entity and needs only the following:
Number of characters allowed
Indication of whether or not characters are banned
List of all the players it owns
You'll see how this works in Chapter 16, when I go over the networking system.
In SimpleMUD, there were players and enemies; therefore. it was awkward for players to fight each other without copying large amounts of code, which is always a sign of a weak design. In the BetterMUD, I've unified the concepts of players and enemies into one entity type: characters .
Basically, a character is any living being in the game. Characters can hold stuff, move around, see things, and die.
Characters have attributes, much like the attributes in the SimpleMUD, but instead of hard-coding these attributes, you're going to be able to access them via strings. This is because characters in the BetterMUD are somewhat flexible. You load the attributes from a text file on disk whenever the MUD starts, and the scripts and everything else have access to those variables .
Absolutely none of the attributes are hard-coded in the BetterMUD. This was designed to give you complete flexibility over what you want to do with the engine. I'm not going to say "players must have health and hitpoints!", because quite frankly, you may decide not to have those kinds of things in your MUD. When I get to Chapter 18, you'll see how this whole thing works out; believe me, it's cool.
Characters need containers for various things, such as for a list of items that the character is currently carrying.
Characters also have a collection of logic modules (in fact, all entites have these), and a special collection of logic modules named command modules . Command modules allow characters to interface with the game. Every character can have a personalized collection of commands, so you can do things like giving blacksmiths a "repair" command to repair broken itemsan ability other characters won't have.
Characters will have all sorts of logic modules, and you can use them for varying purposes. You could make logic modules represent conditions stuff like "on fire" or "poisoned." With this kind of system, you can say, "If a character has the logic module on fire , that character is actually on fire!"
Conditions are usually time based, which means that they last for a certain duration, or that they have an event that repeats. (For example, the "on fire" condition logic would take off X hitpoints every second until it burned out.)
I go over the timer registry and action events in detail in Chapters 14 and 15 .
When a condition is activated, it should typically perform some operation on a player (usually just modifying an attribute). During the activation sequence, the module has several options. For example, it can set itself up to terminate after a minute or so, by adding an entry to the global timer registry. Or the module can remain resident in a player and wait for another logic module in the game to remove it. (For example, a player could pay a witchdoctor to remove a curse.) The other option would be to set up an event in the global timer registry that would message the condition at a later time, telling it to perform its "repeating" action (that is, the burning of the fire). Every time the fire module receives a "burn" command, it will immediately add another "burn" command to the global timer registry.
Figure 11.5 shows three methods for using condition modules. The first method sets a condition and then waits for another module to deactivate the condition. The second method shows the activation telling the timer registry to remove the condition at a specific time. The final example shows a condition that has also registered a repeating condition, which repeats until the condition is deactivated.
Characters are by no means forced to use only those three methods with conditions. For example, a character could be poisoned with a special venom that doesn't leave his blood-stream, and the venom continues to call the repeating action of the condition until the character finds a cure. Due to the highly flexible nature of these script objects, anything can happen. Maybe you can implement a linked set of conditions, such as a cold. First, you can activate a symptomatic condition, which only slightly modifies the character. After a certain amount of time when that condition is deactivated, it automatically activates another condition, which makes the character even sicker. The chain can continue until the character is eventually incapacitated or finds help. The possibilities are endless.
You can also use logic modules to represent quests , which constitute a large part of expanding the gameplay in the BetterMUD. In the game, characters obviously want to do more than run around killing everything in their paths, as they do in so many hack-and-slash games . The BetterMUD is flexible, so why not put that flexibility to good use?
For example, let me use a common occurrence in RPG-type games: the Kill All Rats quest.
Newly arrived in the city, a player goes to the town employment office to get a job. The clerk examines his papers and says, "Hey, we've got a rat problem in the sewers. Why don't you go down there, kill 40 rats, and then come back for your pay?" The game then assigns the rat-quest to the character, and he starts killing rats.
Whenever an action involves a character, all of his logic modules are notified. For example, whenever a character kills a rat, the game checks all the character's logics and tells each one of them that he killed something. The rat-quest module then says something like, "Oh! He killed a rat! I'll add one to the tally now!"
Logic modules also have attributes, which allow other scripts to determine the state of a module, if it knows what kind of module it is. For example, the "kill all rats" quest would allow you to retrieve a variable named ratskilled , which would allow other logic modules in the game to figure out if you've killed the requisite 40 or not.
It's advisable to keep the number of logic modules active in a current player to a minimum, but that's up to you. Just keep in mind that the more script objects, the slower the game, since every logic module must be notified about everything that happens to a character.
Items are the final entity type in the game, and they are basically anything inanimate. Items are always owned by a room or a character, and the items know who owns them.
Items have a listing of attributes, which corresponds to the attributes the players have. As with characters, there are no default item attributes; you customize everything. I show you some recommended values in Chapter 18.
There are two main types of items in the game; single items and collections of items. Single items are always single items; they typically represent large items such as weapons and armor , or even smaller stuff such as potions and scrolls .
Collections of items, on the other hand, are single items that have a count value, and thus act like many of the same item. Only certain types of items can be combined into collec-tionsmostly things such as coins , jewels , diamonds, and maybe even weapon-type stuff such as stars that can be thrown, or arrows for a bow.
Collection objects can be split, but only by dropping them, giving them to other characters, or picking them up. Whenever a collection object enters a new domain (either a room or an inventory of a character), the object automatically merges with other collection objects of the same type. Strictly speaking, splitting doesn't have to work this way, but it's easier on the interfaces if it does.
For example, you enter a room with a pile of 23 gold coins. There is an enemy in the room, and when you kill him, he drops a pile of 10 gold coins. Instead of creating two pilesa pile of 23 gold coins and a pile of 10 gold coinsthe game merges them to create one pile of 33 gold coins. It's not too realistic, but it really cuts down on the clutter. It would be really annoying to enter a room that has 20 piles of the same kind of object, because everyone is too lazy to pick them up.
Items also have logic modules, which are told about actions such as being dropped and picked up.
|[ LiB ]|