[ LiB ] |
Everything that happens in the physical part of the world is considered an action and this includes characters moving, attributes changing, items moving around, and people speaking.
A naive design would give each entity in the game specific calls for each event to look something like this:
class Character { void SawCharacterLeave( entityid p_char, entityid p_portal ); void SawCharacterEnter( entityid p_char, entityid p_portal ); ... ... ... };
Depending on the number of physical actions, this can end up making your codebase literally explode in size.
Instead, as mentioned previously, I use a special structure to represent actions, called the Action structure. (You can find this in /BetterMUD/Entities/Action.h.)
NOTE
There's a constructor that I didn't show in the previous code segment, but it simply takes parameters matching each one of the fields. It also uses default parameters for each of the arguments, so you don't have to use all the arguments all the time. You'll see this used in a bit.
struct Action { std::string actiontype; entityid data1; entityid data2; entityid data3; entityid data4; std::string stringdata; };
An action contains six fields of data: two strings, and four entityid s. These fields contain enough data to represent the details of every physical action within the game.
For example, if you want to tell the game that character 1 entered the realm, you could create an action like this:
Action a( "enterrealm", 1 );
Or when that character attempts to speak, you could create an action like this:
Action b( "attemptsay", 1, 0, 0, 0, "Hello Game!!!" );
The constructor uses default parameter values, but if you want to use the data string, you need to pass in all parameters, even if they aren't used.
NOTE
I show you the meanings of all of the action parameters in a bit.
There are three major types of actions within the BetterMUD: attempted actions, query actions, and completed actions.
Attempted actions are basically requests to the game. You have a script attached to a character, and the script wants to move the character through a portal. The script then tells the game, "Hey, I want this character to go through a portal!" Some attempted actions such as trying to go through portals may fail; others, such as entering the realm, always work.
Attempted actions are always registered with the game module, which I show you in the next chapter.
Here is a listing of player- related attempted actions:
enterrealm a player is entering the realm
leaverealm a player is leaving the realm
announce a system-wide announcement is being made
chat a player wants to globally chat
attemptsay a player wants to speak in a room
vision a room-wide vision event is occurring
command a player wants to execute a command
Then we have some physical event requests:
attemptportalenter a character wants to enter a portal
attempttransport a character wants to teleport to another room without using a portal
transport a character is forced to teleport to another room, without asking permission
spawncharacter a new character wants to be spawned in a room
spawnitem a new item wants to be spawned at a location
destroycharacter a character is told to die
destroyitem an item is destroyed
attemptdropitem a character tries to drop an item
attemptgetitem a character tries to get an item
attemptgiveitem one character gives an item to another
There are also events that deal with the databases:
cleanup tells the item and character databases to clean up all their deleted instances
savedatabases tells the game to save all databases to disk
saveregion tells the game to save a particular region to disk
saveplayers tells the game to save the players (not all characters) to disk
savetimers tells the game to save all timers to disk
reloaditems tells the game to reload the item template database
reloadcharacters tells the game to reload the character template database
reloadregion tells the game to reload a particular region
reloadcommandscript tells the game to reload a command script by name
reloadlogicscript tells the game to reload a logic script by name
And then there are the attribute modifiers:
modifyattribute modify an attribute of an entity Actions
And finally, here are the other actions that don't fit into the other categories:
messagelogic send a generic text message to any logic module in the game
addlogic add a logic module to an entity
dellogic delete a logic module from an entity
do send a generic action event to an entity
Query actions are often supposed to return Booleans, and they govern things that can happen in the realm. For example, you may want to prohibit players of a specific type from picking up items of a specific type, or you may want items of a specific type to refuse to be picked up at all.
To figure out just what the heck can happen in the game, you need a bunch of query actions , which ask an item if an action is allowed.
Here is a list of query actions:
cansay can a character say something?
canleaveregion can a character leave a region?
canenterregion can a character enter a region?
canleaveroom can a character leave a room?
canenterportal can a character enter a portal?
cangetitem can a character get an item?
candropitem can a character drop an item?
canreceiveitem can a character receive an item given by another character?
query generic query that asks custom questions.
All these actions (except query , which I go over in much more detail in Chapter 15) should return a value of zero if the action is acceptable, or one if unacceptable. I know this sounds strange , since zero usually means "no" or "false," but it involves the workings of the action reporting system.
A collection of logic modules governs the actions of every character. If several scripts are attached to a character, the character asks each script if the action can be accomplished. Whenever an action returns non-zero , it is assumed that it is important to return the information to whomever called the script, so the game engine stops sending the action to each module, and just returns the value. Figure 14.1 shows the chaining system of the BetterMUD logic modules.
So, if a character has a module (for example, a logic module for someone dedicated to a church ) that prevents him from picking up certain items (such as an evil relic), that script returns a value of 1 whenever the script prevents the character from getting an item. The script returns 0 if the action is allowed.
In a similar way, items and rooms are asked if they will allow characters to pick things up; I go over the specifics of all this logic in the next chapter.
Now that you've seen what actions can be requested by scripts, you need to know about the other side of the equation. When you tell the game about an action, it tries to accomplish that action, and if it succeeds, it must tell every actor in the equation about what happened .
For example, if a script requests that a player enter a portal, the game tries to move the player, and a number of things must be done to accomplish that move. First, the player must ask the portal for permission to enter, and if he receives permission, the room and everyone in it is told that the player left the room and moved into a portal, the portal is told that the player entered, and then the new room and everyone in it is told that the player entered.
Here are the completed actions that entities are informed of:
enterrealm A character entered the realm.
leaverealm A character left the realm.
leave The game tells a character to leave the game state.
hangup The game tells a character to hang up.
enterregion A character entered a region.
enterroom A character entered a room.
leaveroom A character left a room.
leaveregion A character left a region.
enterportal A character entered a portal.
getitem A character got an item.
dropitem A character dropped an item.
giveitem A character gave an item to another character.
error An error occurred.
announce A system announcement was made.
say Someone said something.
spawnitem A new item was spawned.
spawncharacter A new character was spawned.
destroyitem An item was destroyed.
destroycharacter A character was destroyed.
messagelogic A message was sent to a logic module.
modifyattribute An attribute was modified.
The preceding lists constitute all of the actions possible within the entire game. Table 15.1 shows which entities are notified about which events.
Event | Items | Characters | Rooms | Regions | Portals |
---|---|---|---|---|---|
enterrealm | no | yes | no | no | no |
leaverealm | no | yes | no | no | no |
leave | no | yes | no | no | no |
hangup | no | yes | no | no | no |
enterregion | no | yes | no | yes | no |
enterroom | yes | yes | yes | no | no |
leaveroom | yes | yes | yes | no | no |
leaveregion | no | yes | no | yes | no |
enterportal | no | yes | no | no | yes |
getitem | yes | yes | yes | no | no |
dropitem | yes | yes | yes | no | no |
giveitem | yes | yes | no | no | no |
error | no | yes | no | no | no |
announce | no | yes | no | no | no |
say | yes | yes | yes | no | no |
spawnitem | yes | yes | yeso | no | no |
spawncharacter | no | yes | yes | no | no |
destroyitem | yes | yes | yes | yes | no |
destroycharacter | no | yes | yes | yes | no |
messagelogic | yes | yes | yes | yes | yes |
modifyattributes | yes | yes | yes | yes | yes |
Tables 15.2, 15.3, and 15.4 list the parameters for each action event type. Most of the time you don't have to pass room numbers as arguments, since the logic modules can assume that the room in question is the room that currently contains the player.
Action | arg1 | arg2 | arg3 | arg4 | data |
---|---|---|---|---|---|
chat | player | - | - | - | text |
announce | - | - | - | - | text |
vision | room | - | - | - | text |
enterrealm | player | - | - | - | - |
leaverealm | player | - | - | - | - |
attemptsay | character | - | - | - | text |
command | character | - | - | - | text |
attemptenterportal | character | portal | - | - | - |
attempttransport | character | room | - | - | - |
transport | character | room | - | - | - |
attemptgetitem | character | item | quantity | - | - |
attemptdropitem | character | item | quantity | - | - |
attemptgiveitem | character | character | item | quantity | - |
spawnitem | template | room/person | isroom/person? | quantity | - |
spawncharacter | template | room | - | - | - |
destroyitem | item | quantity | - | - | - |
destroycharacter | character | - | - | - | - |
cleanup | - | - | - | - | - |
savedatabases | - | - | - | - | - |
saveregion | region | - | - | - | - |
saveplayers | - | - | - | - | - |
savetimers | - | - | - | - | - |
reloaditems | - | - | - | - | file |
reloadcharacters | - | - | - | - | file |
reloadregion | - | - | - | - | name |
reloadcommandscript | - | - | - | - | name |
reloadlogicscript | - | - | - | - | name |
modifyattribute | entity type | entityid | value | - | name |
messagelogic | entity type | entityid | - | - | name |
addlogic | entity type | entityid | - | - | logic |
dellogic | entity type | entityid | - | - | logic |
do | entity type | entityid | - | - | text |
Action | arg1 | arg2 | arg3 | arg4 | data |
---|---|---|---|---|---|
cansay | character | - | - | - | text |
canleaveregion | character | region | - | - | - |
canenterregion | character | region | - | - | - |
canleaveroom | character | room | - | - | - |
canenterroom | character | room | - | - | - |
canenterportal | character | portal | - | - | - |
cangetitem | character | item | quantity | - | - |
candropitem | character | item | quantity | - | - |
canreceiveitem | giver | receiver | item | quantity | |
query | optional | optional | optional | optional | optional |
Action | arg1 | arg2 | arg3 | arg4 | data |
---|---|---|---|---|---|
enterrealm | player | - | - | - | - |
leaverealm | player | - | - | - | |
leave | - | - | - | - | - |
hangup | - | - | - | - | - |
enterregion | character | region | - | - | - |
enterroom | character | portal | - | - | - |
leaveroom | character | portal | - | - | - |
leaveregion | character | region | - | - | - |
enterportal | character | portal | - | - | - |
getitem | character | item | - | - | - |
dropitem | character | item | - | - | - |
giveitem | character | recipient | item | - | |
error | text | ||||
announce | - | - | - | - | text |
say | character | - | - | - | text |
spawnitem | item | - | - | - | - |
spawncharacter | character | - | - | - | - |
destroyitem | item | - | - | - | - |
destroycharacter | character | - | - | - | - |
messagelogic | entity type | entityid | - | - | name |
modifyattribute | entity type | entityid | value | - | name |
A few of the actions are "routable" actions, in which the action is routed to a specific entity in the game. These actions have an entity type and an entity ID that determine where they go. Here is a listing of the entity types:
0character
1item
2room
3portal
4region
So if you wanted to set attribute foo of item number 24 to the value 80, then you would construct an action like this:
Action a( "modifyattribute", 1, 24, 80, 0, "foo" );
[ LiB ] |