www.pudn.com > SimpleMUD.rar > Game.cpp


// MUD Programming 
// Ron Penton 
// (C)2003 
// Game.cpp - This class is the game handler for SimpleMUD. 
//  
//  
 
#include "Logon.h" 
#include "Game.h" 
#include "Train.h" 
#include "ItemDatabase.h" 
#include "PlayerDatabase.h" 
#include "RoomDatabase.h" 
#include "StoreDatabase.h" 
#include "EnemyDatabase.h" 
#include "BasicLib/BasicLib.h" 
 
using namespace SocketLib; 
using namespace BasicLib; 
using std::string; 
 
namespace SimpleMUD 
{ 
 
 
// declare the static instance of the timer 
BasicLib::Timer Game::s_timer; 
bool Game::s_running = false; 
 
// ------------------------------------------------------------------------ 
//  This handles incomming commands. Anything passed into this function 
//  is assumed to be a complete command from a client. 
// ------------------------------------------------------------------------ 
void Game::Handle( string p_data ) 
{ 
    Player& p = *m_player; 
 
    // check if the player wants to repeat a command 
    if( p_data == "/" ) 
    { 
        p_data = m_lastcommand; 
    } 
    else 
    { 
        // if not, record the command. 
        m_lastcommand = p_data; 
    } 
 
    // get the first word and lowercase it. 
    string firstword = BasicLib::LowerCase( ParseWord( p_data, 0 ) ); 
 
 
    // ------------------------------------------------------------------------ 
    //  REGULAR access commands 
    // ------------------------------------------------------------------------ 
    if( firstword == "chat" || firstword == ":" ) 
    { 
        string text = RemoveWord( p_data, 0 ); 
        SendGame( magenta + bold + p.Name() + " chats: " + white + text ); 
        return; 
    } 
 
    if( firstword == "experience" || firstword == "exp" ) 
    { 
        p.SendString( PrintExperience() ); 
        return; 
    } 
 
    if( firstword == "help" || firstword == "commands" ) 
    { 
        p.SendString( PrintHelp( p.Rank() ) ); 
        return; 
    } 
 
    if( firstword == "inventory" || firstword == "inv" ) 
    { 
        p.SendString( PrintInventory() ); 
        return; 
    } 
 
    if( firstword == "quit" ) 
    { 
        m_connection->Close(); 
        LogoutMessage( p.Name() + " has left the realm." ); 
        return; 
    } 
 
    if( firstword == "remove" ) 
    { 
        RemoveItem( ParseWord( p_data, 1 ) ); 
        return; 
    } 
 
    if( firstword == "stats" || firstword == "st" ) 
    { 
        p.SendString( PrintStats() ); 
        return; 
    } 
 
    if( firstword == "time" ) 
    { 
        p.SendString( bold + cyan +  
                      "The current system time is: " + BasicLib::TimeStamp() +  
                      " on " + BasicLib::DateStamp() +  
                      "\r\nThe system has been up for: "  
                      + s_timer.GetString() + "." ); 
        return; 
    } 
 
    if( firstword == "use" ) 
    { 
        UseItem( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
    if( firstword == "whisper" ) 
    { 
        // get the players name 
        string name = ParseWord( p_data, 1 ); 
        string message = RemoveWord( RemoveWord( p_data, 0 ), 0 ); 
 
        Whisper( message, name ); 
        return; 
    } 
 
    if( firstword == "who" ) 
    { 
        p.SendString( WhoList( BasicLib::LowerCase( ParseWord( p_data, 1 ) ) ) ); 
        return; 
    } 
 
 
    if( firstword == "look" || firstword == "l" ) 
    { 
        p.SendString( PrintRoom( p.CurrentRoom() ) ); 
        return; 
    } 
 
    if( firstword == "north" || firstword == "n" ) 
    { 
        Move( NORTH ); 
        return; 
    } 
    if( firstword == "east" || firstword == "e" ) 
    { 
        Move( EAST ); 
        return; 
    } 
    if( firstword == "south" || firstword == "s" ) 
    { 
        Move( SOUTH ); 
        return; 
    } 
    if( firstword == "west" || firstword == "w" ) 
    { 
        Move( WEST ); 
        return; 
    } 
 
    if( firstword == "get" || firstword == "take" ) 
    { 
        GetItem( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
    if( firstword == "drop" ) 
    { 
        DropItem( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
 
    if( firstword == "train" ) 
    { 
        if( p.CurrentRoom()->Type() != TRAININGROOM ) 
        { 
            p.SendString( red + bold + "You cannot train here!" ); 
            return; 
        } 
 
        if( p.Train() ) 
        { 
            p.SendString( green + bold + "You are now level " + tostring( p.Level() ) ); 
        } 
        else 
        { 
            p.SendString( red + bold + "You don't have enough experience to train!" ); 
        } 
 
        return; 
    } 
 
    if( firstword == "editstats" ) 
    { 
        if( p.CurrentRoom()->Type() != TRAININGROOM ) 
        { 
            p.SendString( red + bold + "You cannot edit your stats here!" ); 
            return; 
        } 
 
        GotoTrain(); 
        return; 
    } 
 
    if( firstword == "list" ) 
    { 
        if( p.CurrentRoom()->Type() != STORE ) 
        { 
            p.SendString( red + bold + "You're not in a store!" ); 
            return; 
        } 
 
        p.SendString( StoreList( p.CurrentRoom()->Data() ) ); 
        return; 
    } 
 
    if( firstword == "buy" ) 
    { 
        if( p.CurrentRoom()->Type() != STORE ) 
        { 
            p.SendString( red + bold + "You're not in a store!" ); 
            return; 
        } 
 
        Buy( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
    if( firstword == "sell" ) 
    { 
        if( p.CurrentRoom()->Type() != STORE ) 
        { 
            p.SendString( red + bold + "You're not in a store!" ); 
            return; 
        } 
 
        Sell( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
 
    if( firstword == "attack" || firstword == "a" ) 
    { 
        PlayerAttack( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
    // ------------------------------------------------------------------------ 
    //  GOD access commands 
    // ------------------------------------------------------------------------ 
    if( firstword == "kick" && p.Rank() >= GOD ) 
    { 
        // find a player to kick 
        PlayerDatabase::iterator itr =  
            PlayerDatabase::findloggedin( ParseWord( p_data, 1 ) ); 
 
        if( itr == PlayerDatabase::end() ) 
        { 
            p.SendString( red + bold + "Player could not be found." ); 
            return; 
        } 
 
        if( itr->Rank() > p.Rank() ) 
        { 
            p.SendString( red + bold + "You can't kick that player!" ); 
            return; 
        } 
             
        itr->Conn()->Close(); 
        LogoutMessage( itr->Name() + " has been kicked by " +  
                        p.Name() + "!!!" ); 
 
        return; 
    } 
 
 
    // ------------------------------------------------------------------------ 
    //  ADMIN access commands 
    // ------------------------------------------------------------------------ 
    if( firstword == "announce" && p.Rank() >= ADMIN ) 
    { 
        Announce( RemoveWord( p_data, 0 ) ); 
        return; 
    } 
 
    if( firstword == "changerank" && p.Rank() >= ADMIN ) 
    { 
        string name = ParseWord( p_data, 1 ); 
 
        PlayerDatabase::iterator itr = PlayerDatabase::find( name ); 
 
        if( itr == PlayerDatabase::end() ) 
        { 
            p.SendString( red + bold + "Error: Could not find user " + 
                          name ); 
            return; 
        } 
 
        PlayerRank rank = GetRank( ParseWord( p_data, 2 ) ); 
 
        itr->Rank() = rank; 
        SendGame( green + bold + itr->Name() +  
                  "'s rank has been changed to: " + 
                  GetRankString( rank ) ); 
        return; 
    } 
 
 
    if( firstword == "reload" && p.Rank() >= ADMIN ) 
    { 
        string db = BasicLib::LowerCase( ParseWord( p_data, 1 ) ); 
 
        if( db == "items" ) 
        { 
            ItemDatabase::Load(); 
            p.SendString( bold + cyan + "Item Database Reloaded!" ); 
        } 
        else if( db == "player" ) 
        { 
            string user = ParseWord( p_data, 2 ); 
            PlayerDatabase::iterator itr = PlayerDatabase::findfull( user ); 
 
            if( itr == PlayerDatabase::end() ) 
            { 
                p.SendString( bold + red + "Invalid Player Name" ); 
            } 
            else 
            { 
                bool a = itr->Active(); 
                if( a )     itr->Conn()->Handler()->Leave(); 
                PlayerDatabase::LoadPlayer( itr->Name() ); 
                if( a )     itr->Conn()->Handler()->Enter(); 
 
                p.SendString( bold + cyan + "Player " +  
                              itr->Name() + " Reloaded!" ); 
            } 
        } 
        else if( db == "rooms" ) 
        { 
            RoomDatabase::LoadTemplates(); 
            p.SendString( bold + cyan + "Room Template Database Reloaded!" ); 
        } 
        else if( db == "stores" ) 
        { 
            StoreDatabase::Load(); 
            p.SendString( bold + cyan + "Store Database Reloaded!" ); 
        } 
        else if( db == "enemies" ) 
        { 
            EnemyTemplateDatabase::Load(); 
            p.SendString( bold + cyan + "Enemy Database Reloaded!" ); 
        } 
        else 
        { 
            p.SendString( bold + red + "Invalid Database Name" ); 
        } 
        return; 
    } 
 
    if( firstword == "shutdown" && p.Rank() >= ADMIN ) 
    { 
        Announce( "SYSTEM IS SHUTTING DOWN" ); 
        Game::Running() = false; 
        return; 
    } 
 
 
    // ------------------------------------------------------------------------ 
    //  Command not recognized, send to room 
    // ------------------------------------------------------------------------ 
    SendRoom( bold + p.Name() + " says: " + dim + p_data, p.CurrentRoom() ); 
} 
 
 
// ------------------------------------------------------------------------ 
//  This notifies the handler that there is a new connection 
// ------------------------------------------------------------------------ 
void Game::Enter() 
{ 
    USERLOG.Log( GetIPString( m_connection->GetRemoteAddress() ) +  
                 " - User " + m_player->Name() +  
                 " entering Game state." ); 
 
    m_lastcommand = ""; 
 
    Player& p = *m_player; 
    p.CurrentRoom()->AddPlayer( p.ID() ); 
    p.Active() = true; 
    p.LoggedIn() = true; 
 
    SendGame( bold + green + p.Name() + " has entered the realm." ); 
 
    if( p.Newbie() ) 
        GotoTrain(); 
    else 
        p.SendString( PrintRoom( p.CurrentRoom() ) ); 
} 
 
void Game::Leave() 
{ 
    USERLOG.Log(   
        GetIPString( m_connection->GetRemoteAddress() ) +  
        " - User " + m_player->Name() +  
        " leaving Game state." ); 
 
    // remove the player from his room 
    m_player->CurrentRoom()->RemovePlayer( m_player ); 
    m_player->Active() = false; 
 
    // log out the player from the database if the connection has been closed 
    if( m_connection->Closed() ) 
    { 
        PlayerDatabase::Logout( m_player ); 
    } 
} 
 
 
// ------------------------------------------------------------------------ 
//  This notifies the handler that a connection has unexpectedly hung up. 
// ------------------------------------------------------------------------ 
void Game::Hungup() 
{ 
    USERLOG.Log(   
        GetIPString( m_connection->GetRemoteAddress() ) +  
        " - User " + m_player->Name() +  
        " hung up." ); 
 
    Player& p = *m_player; 
    LogoutMessage( p.Name() + " has suddenly disappeared from the realm." ); 
} 
 
// ------------------------------------------------------------------------ 
//  This notifies the handler that a connection is being kicked due to  
//  flooding the server. 
// ------------------------------------------------------------------------ 
void Game::Flooded() 
{ 
    USERLOG.Log(   
        GetIPString( m_connection->GetRemoteAddress() ) +  
        " - User " + m_player->Name() +  
        " flooded." ); 
 
    Player& p = *m_player; 
    LogoutMessage( p.Name() + " has been kicked for flooding!" ); 
} 
 
// ------------------------------------------------------------------------ 
//  Sends a string to everyone connected. 
// ------------------------------------------------------------------------ 
void Game::SendGlobal( const string& p_str ) 
{ 
    operate_on_if( PlayerDatabase::begin(), 
                   PlayerDatabase::end(), 
                   playersend( p_str ), 
                   playerloggedin() ); 
} 
 
// ------------------------------------------------------------------------ 
//  Sends a string to everyone "within the game" 
// ------------------------------------------------------------------------ 
void Game::SendGame( const std::string& p_str ) 
{ 
    operate_on_if( PlayerDatabase::begin(), 
                   PlayerDatabase::end(), 
                   playersend( p_str ), 
                   playeractive() ); 
} 
 
// ------------------------------------------------------------------------ 
//  Sends a logout message 
// ------------------------------------------------------------------------ 
void Game::LogoutMessage( const string& p_reason ) 
{ 
    SendGame( SocketLib::red + SocketLib::bold + p_reason ); 
} 
 
// ------------------------------------------------------------------------ 
//  Sends a system announcement 
// ------------------------------------------------------------------------ 
void Game::Announce( const string& p_announcement ) 
{ 
    SendGlobal( SocketLib::cyan + SocketLib::bold +  
                "System Announcement: " + p_announcement ); 
} 
 
// ------------------------------------------------------------------------ 
//  Sends a whisper string to the requested player 
// ------------------------------------------------------------------------ 
void Game::Whisper( std::string p_str, std::string p_player ) 
{ 
    // find the player 
    PlayerDatabase::iterator itr = PlayerDatabase::findactive( p_player ); 
     
    // if no match was found 
    if( itr == PlayerDatabase::end() ) 
    { 
        m_player->SendString( red + bold + "Error, cannot find user." ); 
    } 
    else 
    { 
        itr->SendString( yellow + m_player->Name() + " whispers to you: " +  
                         reset + p_str ); 
 
        m_player->SendString( yellow + "You whisper to " + itr->Name() +  
                              ": " + reset + p_str ); 
    } 
} 
 
// ------------------------------------------------------------------------ 
//  Functor that generates a who-listing for a single player 
// ------------------------------------------------------------------------ 
struct wholist 
{ 
    string str; 
 
    void operator() ( Player& p ) 
    { 
        str += " " + tostring( p.Name(), 17 ) + "| "; 
        str += tostring( p.Level(), 10 ) + "| "; 
         
         
        if( p.Active() ) 
            str += green + "Online  " + white; 
        else if( p.LoggedIn() ) 
            str += yellow + "Inactive" + white; 
        else 
            str += red + "Offline " + white; 
 
        str += " | "; 
        switch( p.Rank() ) 
        { 
            case REGULAR:   str += white;   break; 
            case GOD:       str += yellow;  break; 
            case ADMIN:     str += green;   break; 
        } 
 
        str += GetRankString( p.Rank() ); 
 
        str += white + "\r\n"; 
    } 
}; 
 
// ------------------------------------------------------------------------ 
//  This prints up the who-list for the realm. 
// ------------------------------------------------------------------------ 
string Game::WhoList( const string& p_who ) 
{ 
    using namespace BasicLib; 
 
    string str = white + bold + 
        "--------------------------------------------------------------------------------\r\n" +  
        " Name             | Level     | Activity | Rank\r\n" +  
        "--------------------------------------------------------------------------------\r\n"; 
 
    wholist who; 
    if( p_who == "all" ) 
    { 
        who = BasicLib::operate_on_if(  
                        PlayerDatabase::begin(), 
                        PlayerDatabase::end(), 
                        wholist(), 
                        always() ); 
    } 
    else 
    { 
        who = BasicLib::operate_on_if(  
                        PlayerDatabase::begin(), 
                        PlayerDatabase::end(), 
                        wholist(), 
                        playerloggedin() ); 
    } 
 
    str += who.str; 
 
     
    str += 
        "--------------------------------------------------------------------------------"; 
 
    return str; 
} 
 
// ------------------------------------------------------------------------ 
//  Prints out a help listing based on a user's rank. 
// ------------------------------------------------------------------------ 
string Game::PrintHelp( PlayerRank p_rank ) 
{ 
    static string help = white + bold +  
        "--------------------------------- Command List ---------------------------------\r\n" +  
        " /                          - Repeats your last command exactly.\r\n" + 
        " chat                 - Sends message to everyone in the game\r\n" + 
        " experience                 - Shows your experience statistics\r\n" + 
        " help                       - Shows this menu\r\n" + 
        " inventory                  - Shows a list of your items\r\n" +  
        " quit                       - Allows you to leave the realm.\r\n" +  
        " remove <'weapon'/'armor'>  - removes your weapon or armor\r\n" +  
        " stats                      - Shows all of your statistics\r\n" +  
        " time                       - shows the current system time.\r\n" + 
        " use                  - use an item in your inventory\r\n" + 
        " whisper          - Sends message to one person\r\n" + 
        " who                        - Shows a list of everyone online\r\n" + 
        " who all                    - Shows a list of everyone\r\n" + 
        " look                       - Shows you the contents of a room\r\n" + 
        " north/east/south/west      - Moves in a direction\r\n" + 
        " get/drop             - Picks up or drops an item on the ground\r\n" + 
        " train                      - Train to the next level (TR)\r\n" + 
        " editstats                  - Edit your statistics (TR)\r\n" + 
        " list                       - Lists items in a store (ST)\r\n" + 
        " buy/sell             - Buy or Sell an item in a store (ST)\r\n" + 
        " attack              - Attack an enemy\r\n"; 
 
 
    static string god = yellow + bold + 
        "--------------------------------- God Commands ---------------------------------\r\n" +  
        " kick                  - kicks a user from the realm\r\n"; 
 
    static string admin = green + bold + 
        "-------------------------------- Admin Commands --------------------------------\r\n" +  
        " announce              - Makes a global system announcement\r\n" +  
        " changerank      - Changes the rank of a player\r\n" +  
        " reload                 - Reloads the requested database\r\n" +  
        " shutdown                   - Shuts the server down\r\n"; 
 
    static string end = white + bold +  
        "--------------------------------------------------------------------------------"; 
 
 
    if( p_rank == REGULAR ) 
        return help + end; 
    else if( p_rank == GOD ) 
        return help + god + end; 
    else if( p_rank == ADMIN ) 
        return help + god + admin + end; 
    else return "ERROR"; 
 
} 
 
// ------------------------------------------------------------------------ 
//  This prints up the stats of the player 
// ------------------------------------------------------------------------ 
string Game::PrintStats() 
{ 
    using namespace BasicLib; 
    Player& p = *m_player; 
 
    return white + bold + 
        "---------------------------------- Your Stats ----------------------------------\r\n" +  
        " Name:          " + p.Name() + "\r\n" + 
        " Rank:          " + GetRankString( p.Rank() ) + "\r\n" +  
        " HP/Max:        " + tostring( p.HitPoints() ) + "/" + tostring( p.GetAttr( MAXHITPOINTS ) ) + 
        "  (" + tostring( percent( p.HitPoints(), p.GetAttr( MAXHITPOINTS )) ) + "%)\r\n" + 
        PrintExperience() + "\r\n" +  
        " Strength:      " + tostring( p.GetAttr( STRENGTH ), 16 ) +  
        " Accuracy:      " + tostring( p.GetAttr( ACCURACY ) ) + "\r\n" + 
        " Health:        " + tostring( p.GetAttr( HEALTH ), 16 ) +  
        " Dodging:       " + tostring( p.GetAttr( DODGING ) ) + "\r\n" + 
        " Agility:       " + tostring( p.GetAttr( AGILITY ), 16 ) +  
        " Strike Damage: " + tostring( p.GetAttr( STRIKEDAMAGE ) ) + "\r\n" + 
        " StatPoints:    " + tostring( p.StatPoints(), 16 ) +  
        " Damage Absorb: " + tostring( p.GetAttr( DAMAGEABSORB ) ) + "\r\n" + 
        "--------------------------------------------------------------------------------"; 
} 
 
// ------------------------------------------------------------------------ 
//  This prints up the experience of the player 
// ------------------------------------------------------------------------ 
string Game::PrintExperience() 
{ 
    using namespace BasicLib; 
    Player& p = *m_player; 
 
    return white + bold + 
        " Level:         " + tostring( p.Level() ) + "\r\n" +  
        " Experience:    " + tostring( p.Experience() ) + "/" + 
        tostring( p.NeedForLevel( p.Level() + 1 ) ) + " (" +  
        tostring( percent( p.Experience(), p.NeedForLevel( p.Level() + 1 ) ) ) +  
        "%)"; 
} 
 
// ------------------------------------------------------------------------ 
//  This prints up the inventory-list of the player 
// ------------------------------------------------------------------------ 
string Game::PrintInventory() 
{ 
    using namespace BasicLib; 
    Player& p = *m_player; 
 
    // Inventory 
    string itemlist = white + bold + 
        "-------------------------------- Your Inventory --------------------------------\r\n" + 
        " Items:  "; 
 
    for( int i = 0; i < PLAYERITEMS; i++ ) 
    { 
        if( p.GetItem( i ) != 0 ) 
        { 
            itemlist += p.GetItem( i )->Name() + ", "; 
        } 
    } 
 
    // chop off the extraneous comma, and add a newline. 
    itemlist.erase( itemlist.size() - 2, 2 ); 
    itemlist += "\r\n"; 
 
    // Weapon/Armor 
    itemlist += " Weapon: "; 
    if( p.Weapon() == 0 ) 
        itemlist += "NONE!"; 
    else 
        itemlist += p.Weapon()->Name(); 
 
    itemlist += "\r\n Armor:  "; 
    if( p.Armor() == 0 ) 
        itemlist += "NONE!"; 
    else 
        itemlist += p.Armor()->Name(); 
 
    // Money 
    itemlist += "\r\n Money:  $" + tostring( p.Money() ); 
 
    itemlist += 
        "\r\n--------------------------------------------------------------------------------"; 
     
    return itemlist; 
} 
 
// ------------------------------------------------------------------------ 
//  This finds and attempts to "use" an item in your inventory. 
// ------------------------------------------------------------------------ 
bool Game::UseItem( const std::string& p_item ) 
{ 
    Player& p = *m_player; 
 
    int i = p.GetItemIndex( p_item ); 
 
    if( i == -1 ) 
    { 
        p.SendString( red + bold + "Could not find that item!" ); 
        return false; 
    } 
 
    Item& itm = *p.GetItem( i ); 
     
 
    switch( itm.Type() ) 
    { 
    case WEAPON: 
        p.UseWeapon( i ); 
        SendRoom( green + bold + p.Name() + " arms a " + itm.Name(),  
                  p.CurrentRoom() ); 
        return true; 
 
    case ARMOR: 
        p.UseArmor( i ); 
        SendRoom( green + bold + p.Name() + " puts on a " + itm.Name(),  
                  p.CurrentRoom() ); 
        return true; 
 
    case HEALING: 
        p.AddBonuses( itm.ID() ); 
        p.AddHitpoints( BasicLib::RandomInt( itm.Min(), itm.Max() ) ); 
        p.DropItem( i ); 
        SendRoom( green + bold + p.Name() + " uses a " + itm.Name(),  
                  p.CurrentRoom() ); 
 
        return true; 
    } 
    return false; 
} 
 
// ------------------------------------------------------------------------ 
//  This removes your weapon or your armor 
// ------------------------------------------------------------------------ 
bool Game::RemoveItem( std::string p_item ) 
{ 
    Player& p = *m_player; 
 
    p_item = BasicLib::LowerCase( p_item ); 
 
    if( p_item == "weapon" && p.Weapon() != 0 ) 
    { 
        SendRoom( green + bold + p.Name() + " puts away a " +  
                  p.Weapon()->Name(), p.CurrentRoom() ); 
        p.RemoveWeapon(); 
        return true; 
    } 
 
    if( p_item == "armor" && p.Armor() != 0 ) 
    { 
        SendRoom( green + bold + p.Name() + " takes off a " +  
                  p.Armor()->Name(), p.CurrentRoom() ); 
        p.RemoveArmor(); 
        return true; 
    } 
 
    p.SendString( red + bold + "Could not Remove item!" ); 
    return false; 
} 
 
 
string Game::PrintRoom( room p_room ) 
{ 
    string desc = "\r\n" + bold + white + p_room->Name() + "\r\n"; 
    string temp; 
    int count; 
 
    desc += bold + magenta + p_room->Description() + "\r\n"; 
    desc += bold + green + "exits: "; 
 
    for( int d = 0; d < NUMDIRECTIONS; d++ ) 
    { 
        if( p_room->Adjacent( d ) != 0 ) 
            desc += DIRECTIONSTRINGS[d] + "  "; 
    } 
    desc += "\r\n"; 
 
 
    // --------------------------------- 
    // ITEMS 
    // --------------------------------- 
    temp = bold + yellow + "You see: "; 
    count = 0; 
    if( p_room->Money() > 0 ) 
    { 
        count++; 
        temp += "$" + tostring( p_room->Money() ) + ", "; 
    } 
 
    std::list::iterator itemitr = p_room->Items().begin(); 
    while( itemitr != p_room->Items().end() ) 
    { 
        count++; 
        temp += (*itemitr)->Name() + ", "; 
        ++itemitr; 
    } 
 
    if( count > 0 ) 
    { 
        // chop off the trailing ", " 
        temp.erase( temp.size() - 2, 2 ); 
        // add a newline 
        desc += temp + "\r\n"; 
    } 
 
    // --------------------------------- 
    // PEOPLE 
    // --------------------------------- 
    temp = bold + cyan + "People: "; 
    count = 0; 
    std::list::iterator playeritr = p_room->Players().begin(); 
    while( playeritr != p_room->Players().end() ) 
    { 
        temp += (*playeritr)->Name() + ", "; 
        count++; 
        ++playeritr; 
    } 
 
    if( count > 0 ) 
    { 
        temp.erase( temp.size() - 2, 2 ); 
        desc += temp + "\r\n"; 
    } 
 
    // --------------------------------- 
    // ENEMIES 
    // --------------------------------- 
    temp = bold + red + "Enemies: "; 
    count = 0; 
    std::list::iterator enemyitr = p_room->Enemies().begin(); 
    while( enemyitr != p_room->Enemies().end() ) 
    { 
        temp += (*enemyitr)->Name() + ", "; 
        count++; 
        ++enemyitr; 
    } 
 
    if( count > 0 ) 
    { 
        temp.erase( temp.size() - 2, 2 ); 
        desc += temp + "\r\n"; 
    } 
 
 
    return desc; 
} 
 
void Game::SendRoom( string p_text, room p_room ) 
{ 
    std::for_each( p_room->Players().begin(), 
                   p_room->Players().end(), 
                   playersend( p_text ) ); 
} 
 
 
 
void Game::Move( int p_direction ) 
{ 
    Player& p = *m_player; 
    room next = p.CurrentRoom()->Adjacent( p_direction ); 
    room previous = p.CurrentRoom(); 
 
    if( next == 0 ) 
    { 
        SendRoom( red + p.Name() + " bumps into the wall to the " + 
                  DIRECTIONSTRINGS[p_direction] + "!!!", 
                  p.CurrentRoom() ); 
        return; 
    } 
 
    previous->RemovePlayer( p.ID() ); 
 
    SendRoom( green + p.Name() + " leaves to the " +  
              DIRECTIONSTRINGS[p_direction] + ".", 
              previous ); 
    SendRoom( green + p.Name() + " enters from the " +  
              DIRECTIONSTRINGS[OppositeDirection(p_direction)] + ".", 
              next ); 
    p.SendString( green + "You walk " + DIRECTIONSTRINGS[p_direction] + "." ); 
 
    p.CurrentRoom() = next; 
    next->AddPlayer( p.ID() ); 
 
    p.SendString( PrintRoom( next ) ); 
} 
 
 
 
void Game::GetItem( string p_item ) 
{ 
    Player& p = *m_player; 
 
    if( p_item[0] == '$' ) 
    { 
        // clear off the '$', and convert the result into a number. 
        p_item.erase( 0, 1 ); 
        money m = BasicLib::totype( p_item ); 
 
        // make sure there's enough money in the room 
        if( m > p.CurrentRoom()->Money() ) 
        { 
            p.SendString( red + bold + "There isn't that much here!" ); 
        } 
        else 
        { 
            p.Money() += m; 
            p.CurrentRoom()->Money() -= m; 
            SendRoom( cyan + bold + p.Name() + " picks up $" +  
                      tostring( m ) + ".", p.CurrentRoom() ); 
        } 
        return; 
    } 
 
    item i = p.CurrentRoom()->FindItem( p_item ); 
 
    if( i == 0 ) 
    { 
        p.SendString( red + bold + "You don't see that here!" ); 
        return; 
    } 
 
    if( !p.PickUpItem( i ) ) 
    { 
        p.SendString( red + bold + "You can't carry that much!" ); 
        return; 
    } 
 
    p.CurrentRoom()->RemoveItem( i ); 
    SendRoom( cyan + bold + p.Name() + " picks up " + i->Name() + ".",  
              p.CurrentRoom() ); 
} 
 
 
void Game::DropItem( string p_item ) 
{ 
    Player& p = *m_player; 
 
    if( p_item[0] == '$' ) 
    { 
        // clear off the '$', and convert the result into a number. 
        p_item.erase( 0, 1 ); 
        money m = BasicLib::totype( p_item ); 
 
        // make sure there's enough money in the inventory 
        if( m > p.Money() ) 
        { 
            p.SendString( red + bold + "You don't have that much!" ); 
        } 
        else 
        { 
            p.Money() -= m; 
            p.CurrentRoom()->Money() += m; 
            SendRoom( cyan + bold + p.Name() + " drops $" +  
                      tostring( m ) + ".", p.CurrentRoom() ); 
        } 
        return; 
    } 
 
    int i = p.GetItemIndex( p_item ); 
 
    if( i == -1 ) 
    { 
        p.SendString( red + bold + "You don't have that!" ); 
        return; 
    } 
 
    SendRoom( cyan + bold + p.Name() + " drops " + 
                p.GetItem( i )->Name() + ".", p.CurrentRoom() ); 
    p.CurrentRoom()->AddItem( p.GetItem( i ) ); 
    p.DropItem( i ); 
} 
 
 
void Game::GotoTrain() 
{ 
            Player& p = *m_player; 
            p.Active() = false; 
            p.Conn()->AddHandler( new Train( *m_connection, p.ID() ) ); 
            LogoutMessage( p.Name() + " leaves to edit stats" ); 
} 
 
 
string Game::StoreList( entityid p_store ) 
{ 
    Store& s = StoreDatabase::get( p_store ); 
 
    string output = white + bold +  
              "--------------------------------------------------------------------------------\r\n"; 
    output += " Welcome to " + s.Name() + "!\r\n"; 
    output += "--------------------------------------------------------------------------------\r\n"; 
    output += " Item                           | Price\r\n"; 
    output += "--------------------------------------------------------------------------------\r\n"; 
 
    Store::iterator itr = s.begin(); 
    while( itr != s.end() ) 
    { 
        output += " " + tostring( (*itr)->Name(), 31 ) + "| "; 
        output += tostring( (*itr)->Price() ) + "\r\n"; 
        ++itr; 
    } 
    output += bold +  
              "--------------------------------------------------------------------------------\r\n"; 
 
    return output; 
} 
 
void Game::Buy( const string& p_item ) 
{ 
    Player& p = *m_player; 
    Store& s = StoreDatabase::get( p.CurrentRoom()->Data() ); 
 
    item i = s.find( p_item ); 
    if( i == 0 ) 
    { 
        p.SendString( red + bold + "Sorry, we don't have that item!" ); 
        return; 
    } 
 
    if( p.Money() < i->Price() ) 
    { 
        p.SendString( red + bold + "Sorry, but you can't afford that!" ); 
        return; 
    } 
 
    if( !p.PickUpItem( i ) ) 
    { 
        p.SendString( red + bold + "Sorry, but you can't carry that much!" ); 
        return; 
    } 
 
    p.Money() -= i->Price(); 
    SendRoom( cyan + bold + p.Name() + " buys a " + i->Name(),  
              p.CurrentRoom() ); 
} 
 
 
 
 
void Game::Sell( const string& p_item ) 
{ 
    Player& p = *m_player; 
    Store& s = StoreDatabase::get( p.CurrentRoom()->Data() ); 
 
    int index = p.GetItemIndex( p_item ); 
    if( index == -1 ) 
    { 
        p.SendString( red + bold + "Sorry, you don't have that!" ); 
        return; 
    } 
 
    item i = p.GetItem( index ); 
    if( !s.has( i ) ) 
    { 
        p.SendString( red + bold + "Sorry, we don't want that item!" ); 
        return; 
    } 
 
    p.DropItem( index ); 
    p.Money() += i->Price(); 
    SendRoom( cyan + bold + p.Name() + " sells a " + i->Name(),  
              p.CurrentRoom() ); 
} 
 
 
 
void Game::EnemyAttack( enemy p_enemy ) 
{ 
    Enemy& e = *p_enemy; 
    room r = e.CurrentRoom(); 
 
    std::list::iterator itr = r->Players().begin(); 
 
    std::advance( itr, BasicLib::RandomInt( 0, r->Players().size() - 1 ) ); 
  
    Player& p = **itr; 
 
    sint64 now = Game::GetTimer().GetMS(); 
 
    int damage; 
    if( e.Weapon() == 0 ) 
    { 
        damage = BasicLib::RandomInt( 1, 3 ); 
        e.NextAttackTime() = now + seconds( 1 ); 
    } 
    else 
    { 
        damage = BasicLib::RandomInt( e.Weapon()->Min(), e.Weapon()->Max() ); 
        e.NextAttackTime() = now + seconds( e.Weapon()->Speed() ); 
    } 
 
    if( BasicLib::RandomInt( 0, 99 ) >= e.Accuracy() - p.GetAttr( DODGING ) ) 
    { 
        Game::SendRoom( white + e.Name() + " swings at " + p.Name() +  
                        " but misses!", e.CurrentRoom() ); 
        return; 
    } 
 
    damage += e.StrikeDamage(); 
    damage -= p.GetAttr( DAMAGEABSORB ); 
 
    if( damage < 1 ) 
        damage = 1; 
 
    p.AddHitpoints( -damage ); 
 
    Game::SendRoom( red + e.Name() + " hits " + p.Name() + " for " +  
                    tostring( damage ) + " damage!", e.CurrentRoom() ); 
 
 
    if( p.HitPoints() <= 0 ) 
        PlayerKilled( p.ID() ); 
} 
 
void Game::PlayerKilled( player p_player ) 
{ 
    Player& p = *p_player; 
 
    Game::SendRoom( red + bold + p.Name() + " has died!", p.CurrentRoom() ); 
     
    // drop the money 
    money m = p.Money() / 10; 
    if( m > 0 ) 
    { 
        p.CurrentRoom()->Money() += m; 
        p.Money() -= m; 
        Game::SendRoom( cyan + "$" + tostring( m ) +  
                        " drops to the ground.", p.CurrentRoom() ); 
    } 
 
    // drop an item 
    if( p.Items() > 0 ) 
    { 
        int index = -1; 
 
        // loop through random numbers until you hit a valid item. 
        while( p.GetItem( index = RandomInt( 0, PLAYERITEMS - 1 ) ) == 0 ); 
        item i = p.GetItem( index ); 
        p.CurrentRoom()->AddItem( i ); 
        p.DropItem( index ); 
 
        Game::SendRoom( cyan + i->Name() + " drops to the ground.",  
                        p.CurrentRoom() ); 
    } 
 
    // subtract 10% experience 
    int exp = p.Experience() / 10; 
    p.Experience() -= exp; 
     
    // remove the player from the room and transport him to room 1. 
    p.CurrentRoom()->RemovePlayer( p_player ); 
    p.CurrentRoom() = 1; 
    p.CurrentRoom()->AddPlayer( p_player ); 
 
    // set the hitpoints to 70%  
    p.SetHitpoints( (int)(p.GetAttr( MAXHITPOINTS ) * 0.7) ); 
    p.SendString( white + bold + "You have died, but have been ressurected in " + 
                  p.CurrentRoom()->Name() ); 
    p.SendString( red + bold + "You have lost " + tostring( exp ) + " experience!" ); 
    Game::SendRoom( white + bold + p.Name() + " appears out of nowhere!!" , p.CurrentRoom() ); 
} 
 
 
 
void Game::PlayerAttack( const string& p_enemy ) 
{ 
    Player& p = *m_player; 
    sint64 now = Game::GetTimer().GetMS(); 
 
    if( now < p.NextAttackTime() ) 
    { 
        p.SendString( red + bold + "You can't attack yet!" ); 
        return; 
    } 
 
 
    enemy ptr = p.CurrentRoom()->FindEnemy( p_enemy ); 
 
    if( ptr == 0 ) 
    { 
        p.SendString( red + bold + "You don't see that here!" ); 
        return; 
    } 
 
    Enemy& e = *ptr; 
 
    int damage; 
    if( p.Weapon() == 0 ) 
    { 
        damage = BasicLib::RandomInt( 1, 3 ); 
        p.NextAttackTime() = now + seconds( 1 ); 
    } 
    else 
    { 
        damage = BasicLib::RandomInt( p.Weapon()->Min(), p.Weapon()->Max() ); 
        p.NextAttackTime() = now + seconds( p.Weapon()->Speed() ); 
    } 
 
    if( BasicLib::RandomInt( 0, 99 ) >= p.GetAttr( ACCURACY ) - e.Dodging() ) 
    { 
        SendRoom( white + p.Name() + " swings at " + e.Name() +  
                  " but misses!", p.CurrentRoom() ); 
        return; 
    } 
 
    damage += p.GetAttr( STRIKEDAMAGE ); 
    damage -= e.DamageAbsorb(); 
 
    if( damage < 1 ) 
        damage = 1; 
 
    e.HitPoints() -= damage; 
 
    SendRoom( red + p.Name() + " hits " + e.Name() + " for " +  
              tostring( damage ) + " damage!", p.CurrentRoom() ); 
 
 
    if( e.HitPoints() <= 0 ) 
        EnemyKilled( e.ID(), m_player ); 
} 
 
 
void Game::EnemyKilled( enemy p_enemy, player p_player ) 
{ 
    Enemy& e = *p_enemy; 
 
    SendRoom( cyan + bold + e.Name() + " has died!", e.CurrentRoom() ); 
     
 
    // drop the money 
    money m = BasicLib::RandomInt( e.MoneyMin(), e.MoneyMax() ); 
    if( m > 0 ) 
    { 
        e.CurrentRoom()->Money() += m; 
        SendRoom( cyan + "$" + tostring( m ) +  
                " drops to the ground.", e.CurrentRoom() ); 
    } 
 
    // drop all the items 
    std::list::iterator itr = e.LootList().begin(); 
    while( itr != e.LootList().end() ) 
    { 
        if( BasicLib::RandomInt( 0, 99 ) < itr->second ) 
        { 
            e.CurrentRoom()->AddItem( itr->first ); 
            SendRoom( cyan + (itr->first)->Name() +  
                      " drops to the ground.", e.CurrentRoom() ); 
        } 
        ++itr; 
    } 
 
    // add experience to the player who killed it 
    Player& p = *p_player; 
    p.Experience() += e.Experience(); 
    p.SendString( cyan + bold + "You gain " + tostring( e.Experience() ) + 
                    " experience." ); 
     
    // remove the enemy from the game 
    EnemyDatabase::Delete( p_enemy ); 
} 
 
}   // end namespace SimpleMUD