Handler Design

[ LiB ]

The BetterMUD's account logon process is almost identical to the SimpleMUD's character logon process (the BetterMUD::TelnetLogon and SimpleMUD::Logon classes are almost the same). But once a character is logged on, the similarities end.

Logging On

Logging into the game is a simple task, so I'm not going to spend much time on it. There is one important point to remember, however. In the SimpleMUD, all the text strings printed to the user were hard coded into the executable. The BetterMUD is little more flexible. For example, when you first log into the game, the logon handler consults a text file named /data/logon/logon.data and prints the contents of that file to the connection. For example, my BetterMUD has this logon file:

 <#FF0000>             ######  ####### ####### ####### ####### ######             #     # #          #       #    #       #     #             #     # #          #       #    #       #     #             ######  #####      #       #    #####   ######             #     # #          #       #    #       #   #             #     # #          #       #    #       #    #             ######  #######    #       #    ####### #     #                         #     # #     # ######                         ##   ## #     # #     #                         # # # # #     # #     #                         #  #  # #     # #     #                         #     # #     # #     #                         #     # #     # #     #                         #     #  #####  ###### <#FFFFFF> Welcome to BetterMUD v1.0! If you are a new user, type "new" at the prompt to create a new account. If not, just enter your user name and password to log in. <#7F7F7F> If you have any problems or questions, please email the administrator at Ron@Ronpenton.net Please prefix your email titles with <#FF0000>MUD BOOK <#00FF00>Your Name: <#FFFFFF> 

The handler prints out a very basic ASCII text logo (note the usage of the BetterMUD color codes), and short instructions for logging on. It also prints out my contact information, so that people who can't log in can contact me.

You can replace the contents of the file with whatever you want when you run the MUD. I'm going to show you the Enter function of the TelnetLogon class, to show you how this is done:

 void TelnetLogon::Enter() {     std::ifstream f( "data/logon/logon.data", std::ios::binary );     std::string str;     std::getline( f, str, ' 
 void TelnetLogon::Enter() { std:: ifstream f( "data/logon/logon.data", std::ios::binary ); std::string str; std::getline( f, str, '\0' ); // read everything from the file m_connection->Protocol().SendString( *m_connection, str ); } 
' ); // read everything from the file m_connection->Protocol().SendString( *m_connection, str ); }

It's not that difficult. I used the std::getline function to read the entire contents of the file into a single string, and then I print the string out to the player's connection.

Table 16.2 lists the data text files used in the BetterMUD. Because the data is stored in the files, you can update the news, your logo, or anything else without stopping the MUD and recompiling.

Table 16.2. BetterMUD Text Datafiles

File

Contents

data/logon/help.data

A description of the MUD, who runs it, and how to contact him.

data/logon/logon.data

The MUD logo and basic logon information.

data/logon/newaccount.data

Information for people signing up for a new account.

data/logon/news.data

The latest game news.


There is one difference in the logon process from the SimpleMUD: accounts can be banned. Whenever an account is banned, the logon process prevents the user from completing a logon, and tells him who to contact about the issue before hanging up on him. This allows you to enforce rules in the game and remove trouble makers .

NOTE

Whenever you have data like this in a text file, which is meant to be streamed directly out to a connection, you should be cautious. Telnet requires that every line sent terminate in a CRLF pair. ASCII text files on different operating systems use different line endings, however. Windows is okay, because Windows ASCII text files by default end with CRLF on each line. UNIX/Linux is a different beast , however. Those ASCII files have lines that typically end in an LF, which looks messed up when streamed to Telnet. You could easily make a conversion routine that automatically adds CRs before LFs, if you are so inclined. I didn't bother since I do my file editing in the UltraEdit text editor, which has functions to automatically convert LF to CRLF, and vice versa.

Menu Process

Figure 16.5 illustrates the entire logon process.

Figure 16.5. All the handlers involved in logging a character onto the game.

graphic/16fig05.gif


If you recall from Chapter 8, for the SimpleMUD, the player simply entered the player game after logging on. The BetterMUD adds an intermediate stepa game menu. The five game menu handlers can be found in the menu marked with dashed lines. They're all simple little classes, derived from BetterTelnet::handler , which is just another name for the SocketLib::ConnectionHandler<BetterTelnet, std::string> class. (See Chapters 6 and 8 if you've forgetten what a ConnectionHandler is.)

Basically, you manage characters through a game menu. Here's a listing of what the Telnet version of the menu looks like:

 -----------------------------------------------------------  BetterMUD v1.0 Main Menu -----------------------------------------------------------  0 - Quit  1 - Enter the Game  2 - Create a new Character  3 - Delete an existing Character  4 - View Help -----------------------------------------------------------  Enter Choice: 

Option 0 obviously just hangs up your connection, and the other options correspond to the four boxes that "Menu Handler" pointed to from Figure 13.4. Each of these options has its own state class, which can all be found in the TelnetMenu.h and .cpp files.

The simplest of these is the TelnetMenuHelp handler. Its only purpose is to load the help.data file and print it out to the user. Then it waits for user input and goes back to the main menu when it has received input.

The other handlers are a bit more complex, as you can see from Figure 16.6.

Figure 16.6. The state diagrams of the four menu handlers.

graphic/16fig06.gif


It's not really a difficult process to understand. Most of the code deals with interfacing with the various databases to print your available characters, or the available character prototypes to choose from when you enter the game.

Adding Characters

When a player enters the game, he is given a list of prototype characters to choose from. In the SimpleMUD, everyone started out as the same boring character with no individual characteristics.

In most popular game systems, you're allowed to choose a species such as a human, elf, or goblin. In most games , each species has different physical attributes. Elves are usually quicker but weaker than humans , ogres are slower and stronger, and so forth.

Instead of using species, I use prototypes . In Chapter 13, I showed you a dual-database that holds templates and instances. A player's "species" is whatever template character his instance character derives from. In the character template database, I have included characters named "Human", "Elf", and "Dwarf", starting at ID 1. So when a player creates a new character, and chooses an ID of 1 as his template, that template also designates his species in the game. The template copies information that makes him unique from other species in the game.

So when a player enters the "new character" state, the game prints out a list of all the characters he can choose to be. The game gets this list by consulting a script, named /data/logon/ logon.py. I'll go over the script in more detail in Chapter 18, but for now all you need to know is that it is asked for a string of the character templates that the character can become:

 void TelnetMenuNew::PrintRaces() {     std::string str =  StringFromPy( m_creationmod.Call( "listchars" ) );  m_connection->Protocol().SendString( *m_connection, str ); } 

Don't worry about not knowing exactly what the code in bold does yet; all you need to know is that it returns a string.

Finally, the handler checks to see if the requested name is taken, and if it isn't, the new-character handler tries to figure out if you've entered a valid character type. Here's a little snippet from that section of code:

 m_char = EntityFromPy( m_creationmod.Call( "gettemplateid",                                            EntityToPy( option ) ) ); // check if it was valid if( m_char == 0 ) {     m_connection->Protocol().SendString( *m_connection,         "<#FF0000>Invalid option, please try again: <#FFFFFF>" );     return; } // create character, set its account, and add char to account. m_char = CharacterDB.generate( m_char ); character( m_char ).SetAccount( m_account.ID() ); m_account.AddCharacter( m_char ); // now perform the inital setup: m_creationmod.Call( "setup", EntityToPy( m_char ) ); 

This code again heavily relies on the logon.py script. The first thing it does is ask the script to get a character template ID based on the option that the user selected. This should return a number other than 0 if the user entered a valid option, or return 0 if the option was invalid (which can happen; users like to try to break your programs).

Otherwise, the function continues and generates the character. The last line of the function again calls the logon.py script, and this time the script is supposed to set up the new player, by putting him in an appropriate room, giving him commands, and special logic modules or whatever else you want to do.

Deleting Characters

Whenever a character is deleted, the actual character isn't immediately deleted. This is actually a very important security issue. Imagine if someone discovered your password and deleted your character that you spent months creating argh! To be on the safe side, the character deletion handler removes only the character from the player's account. The administrator can delete the character manually at a later date.

Game Handler

In the SimpleMUD, the Game handler was a very complex piece of code, which managed the game's reaction to every input of the players. I'm not saying it was a great design, emm it wasn't. But it was okay, simply because it got the job done, and it wasn't designed to handle anything other than Telnet.

For the BetterMUD, however, things are different. In the BetterMUD, the game handler is much simpler; its purpose and flexibility are shown in Figure 16.7.

Figure 16.7. The game handler translates commands from the native network format into data the game understands.

graphic/16fig07.gif


The game handlers for the BetterMUD are just simple classes. Their only function is to translate data from the client into data that the game understands. Take a look at the TelnetGame::Handle function, for example:

 void TelnetGame::Handle( string p_data ) {     g_game.DoCommand( m_character.ID(), p_data.c_str() ); } 

The function simply passes the command to the game. You should note that the game handler tracks which character it is currently attached to, much as the SimpleMUD's Game class did. I'll show you how the Game class works in Chapter 15.

[ LiB ]


MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net