#include "world.h"
#include "room.h"
#include "smysql.h"
#include "stringutil.h"
#include "log.h"
#include "commandTable.h"
#include "split.h"
#include "timestamp.h"
Room::Room(unsigned int rid)
{
id = rid;
Load(id);
}
Room::Room( const string& vnum )
{
LoadVnum(vnum);
}
Room::~Room()
{
RoomMap::iterator end = World::Instance()._room_map.end();
Room *limbo = World::Instance().FindRoom(ROOM_LIMBO);
if ( !limbo )
{
glog( "Room::~Room -> Fatal Error: Limbo not found!" );
abort();
}
while( _charList.size() > 0 )
limbo->InsertAvatar( _charList.front(), true );
RoomMap::iterator j = World::Instance()._room_map.find(Get("vnum"));
if ( j != World::Instance()._room_map.end() )
World::Instance()._room_map.erase(j);
}
bool Room::Set( const string &set, const string &value )
{
info[set] = value;
return true;
}
string Room::Get( const string &get )
{
return info[get];
}
bool Room::Load(unsigned int r)
{
string query;
string exits;
Mysql::LMAP::iterator room_info;
Mysql::RESULT z;
query << "SELECT * FROM room WHERE room_id=" << id;
if ( !Mysql::Instance().Load( query.c_str() ) )
return false;
z = Mysql::Instance()._info;
room_info = z[0].find("version");
Set( "version", room_info->second );
room_info = z[0].find("name");
Set( "name", room_info->second );
room_info = z[0].find("description");
Set( "description", room_info->second );
room_info = z[0].find("exits");
Set( "exit_str", room_info->second );
room_info = z[0].find("vnum");
Set( "vnum", room_info->second );
query = "";
query << room_info->second;
World::Instance()._room_map[query] = this;
return true;
}
bool Room::LoadVnum(const string& vnum)
{
string query;
string exits;
Mysql::LMAP::iterator room_info;
Mysql::RESULT z;
query << "SELECT * FROM room WHERE vnum=" << vnum;
if ( !Mysql::Instance().Load( query.c_str() ) )
return false;
z = Mysql::Instance()._info;
room_info = z[0].find("version");
Set( "version", room_info->second );
room_info = z[0].find("room_id");
id = (unsigned int)atoi((room_info->second).c_str());
room_info = z[0].find("name");
Set( "name", room_info->second );
room_info = z[0].find("description");
Set( "description", room_info->second );
room_info = z[0].find("exits");
Set( "exit_str", room_info->second );
room_info = z[0].find("vnum");
Set( "vnum", room_info->second );
query = "";
query << vnum;
World::Instance()._room_map[query] = this;
return true;
}
void Room::InsertAvatar( Char *a, bool look )
{
if ( a == NULL || a->_room == this)
return;
if ( a->_room != NULL )
a->_room->_charList.remove(a); _charList.push_back(a);
a->_room = this;
if ( look == true )
DoCmd( a, "look" );
}
void Room::Broadcast( const string &message )
{
list< Char * >::iterator avatar;
for ( avatar = _charList.begin(); avatar != _charList.end(); ++avatar )
{
if ( (*avatar)->GetStatus() == CONNECTED )
(*avatar)->Send( message );
}
}
bool Room::Save()
{
string query;
query << "UPDATE room SET name='" << Mysql::Instance().EscapeString( Get( "name" ) ) << "', ";
query << "description='" << Mysql::Instance().EscapeString( Get("description") ) << "', ";
query << "exits='" << GenExitStr() << "', ";
query << "vnum=" << Get("vnum") << " WHERE room_id=" << id;
Mysql::Instance().RealQuery( query.c_str() );
return true;
}
void Room::InterpExitStr(string s)
{
string key;
string vnum;
bool inkey = true;
if ( s.empty() )
{
glog( "InterpExitStr: Room %d(%s) has no exits!", this->id, this->Get("name").c_str() );
return;
}
for ( int j = s.length(), i = 0; i < j; i++ )
{
if ( s[i] == ';' )
{
exits[key] = World::Instance().FindRoom(vnum);
inkey = true;
key = "";
vnum = "";
continue;
}
else if ( s[i] == ' ' )
{
inkey = false; continue;
}
if ( inkey == true )
key += s[i];
else
vnum += s[i];
}
}
string Room::GenExitStr()
{
string str;
for ( RoomMap::iterator j = exits.begin(); j != exits.end(); j++ )
str << j->first << " " << j->second->Get("vnum") << ";";
return str;
}
void Room::AddExit( string s, Room *r )
{
if ( s.empty() )
return;
exits[s] = r;
}
void Room::RemExit( string s )
{
if ( s.empty() )
return;
RoomMap::iterator j = exits.find(s);
if ( j != exits.end() )
exits.erase(j);
}
EditRoomHandler::EditRoomHandler()
{
_edit = NULL;
}
EditRoomHandler::EditRoomHandler( Avatar * avatar, const string &vnum )
{
string buf;
if ( (_edit = World::Instance().FindRoom(vnum)) == NULL && CheckVnumRange( avatar, vnum ) )
{
avatar->Send("\n\rCreating new room...\n\r");
buf << "INSERT INTO room ( version, vnum, name ) VALUES ( "
<< ROOM_VERSION << ", " << vnum << ", 'An Empty Room' )";
if ( !Mysql::Instance().Query( buf.c_str() ) )
glog( "EditRoomHandler::EditRoomHandler -> Failed Query!" );
else
_edit = new Room(vnum);
}
buf = "";
buf << "You are now editing [{b" << vnum << "{x]\n\r";
avatar->Send( buf );
}
void EditRoomHandler::Enter( Avatar * avatar )
{
avatar->Send( "================================\n\r" );
avatar->Send( "=== {WRoom Editor{x ===\n\r" );
avatar->Send( "=== #help - More Information ===\n\r" );
avatar->Send( "=== #quit - Exits Editor ===\n\r" );
avatar->Send( "================================\n\r" );
}
void EditRoomHandler::Exit( Avatar * avatar )
{
delete this;
}
void EditRoomHandler::Handle( Avatar * avatar, const string &input)
{
string checked;
string option;
string change;
string buf;
bool command = false;
if ( input.empty () )
return;
checked = input;
for ( string::const_iterator cChar = input.begin(); cChar != input.end(); ++cChar )
{
if ( (*cChar) == '/' && cChar == input.begin() )
{
option = input.substr( 1, input.length() );
if ( !strstr( input.c_str(), "quit" ) ) CommandTable::Instance().Execute( avatar, option );
return;
}
else if ( (*cChar) == '#' && cChar == input.begin() )
{
command = true;
option = input.substr( 1, input.length() );
checked = option;
option.erase();
break;
}
else if ( ( (*cChar) == '\n' || (*cChar) == '\r' ) && cChar == input.begin() )
{
checked.erase();
break;
}
}
split( checked, option, change );
if ( !strcasecmp( option, "quit" ) && command == true )
{
if ( _edit )
{
_edit->Save();
_edit = NULL;
}
else
avatar->ExitHandler();
return;
}
else if ( !strcasecmp( option, "abort" ) && command == true )
{
if ( _edit )
_edit = NULL;
else
avatar->ExitHandler();
return;
}
else if ( ( !strcasecmp( option, "commands" ) || !strcasecmp( option, "help" ) ) && command == true )
{
string buf;
if ( !_edit )
buf << "Enter the vnum you wish to edit.\n\r";
else
{
buf << "|------------------------------ Redit ---------------------------------|\n\r";
buf << "| #commands This help file. |\n\r";
buf << "| #show Shows what you are editing. |\n\r";
buf << "| #quit Quits the Room Editor and saves the room |\n\r";
buf << "| #abort Quits the Room Editor and -does not- save the room |\n\r";
buf << "| #save Save your current progress. |\n\r";
buf << "| #delete Delete the room you're editing. |\n\r";
buf << "| |\n\r";
buf << "| Editing Commands |\n\r";
buf << "| name <name> Changes the room name. |\n\r";
buf << "| desc <description> Changes the room description. |\n\r";
buf << "| exit <dir> <vnum> Adds or changes an exit. |\n\r";
buf << "| bexit <dir> <vnum> Adds or changes an exit and the opposite exit|\n\r";
buf << "| in vnum's room. |\n\r";
buf << "| vnum <num> Changes the vnum of the room. |\n\r";
buf << "| |\n\r";
buf << "| Note: To remove an exit, set the directions vnum to 0. |\n\r";
buf << "| |\n\r";
buf << "| {R*{x Commands preceded by a {B/{x will be executed as regular commands. |\n\r";
buf << "|----------------------------------------------------------------------|\n\r\n\r";
}
avatar->Send( buf );
return;
}
if ( checked.empty() || ( !strcasecmp( option, "show" ) && command == true ) )
{
if ( _edit )
{
RoomMap x = _edit->GetExits();
buf << "[name: " << _edit->Get( "name" ) << "]\n\r";
buf << "[exits:";
for ( RoomMap::const_iterator i = x.begin(); i != x.end(); i++ )
buf << " " << i->first << "(#" << i->second->Get("vnum") << ")";
buf << " ]\n\r";
buf << "[vnum: " << _edit->Get("vnum") << " ]\n\r";
buf << "[description:\n\r\n\r" << _edit->Get("description") << "\n\r";
}
else
buf << "You are not currently editing a room.\n\r";
avatar->Send( buf );
return;
}
else if ( _edit )
{
if ( !strcasecmp( option, "name" ) )
{
_edit->Set( "name", change );
avatar->Send( "Name updated.\n\r" );
return;
}
else if ( !strcasecmp( option, "desc" ) || !strcasecmp(option, "description") )
{
_edit->Set( "description", change );
avatar->Send( "Description updated.\n\r" );
return;
}
else if ( !strcasecmp( option, "exit" ) )
{
string dir = "";
string vnum = "";
split( change, dir, vnum );
if ( change.empty() || dir.empty() || vnum.empty() )
{
avatar->Send("You must supply adaquete data!\n\r");
return;
}
_edit->AddExit(dir, World::Instance().FindRoom(vnum));
if ( _edit->GetExit(dir) == NULL )
_edit->RemExit( dir );
avatar->Send( "Exits updated.\n\r" );
return;
}
else if ( !strcasecmp( option, "bexit" ) )
{
Room *Old = NULL, *New = NULL;
string dir, oppdir;
string vnum;
split( change, dir, vnum );
oppdir = GenOppDir( dir );
if ( oppdir.empty() )
{
avatar->Send( "Only cardinal directions are valid for bexit's.\n\r" );
return;
}
Old = _edit->GetExit(dir);
_edit->AddExit(dir, (New = World::Instance().FindRoom(vnum)));
if ( New )
{
New->AddExit( oppdir, _edit );
New->Save();
}
if ( _edit->GetExit(dir) == NULL )
{
_edit->RemExit( dir );
Old->RemExit( oppdir );
Old->Save();
}
avatar->Send( "Exits updated.\n\r" );
if ( New )
{
RoomMap rmap = New->GetExits();
string buf;
buf << "Room '" << New->Get("name") << "' (#" << New->Get("vnum") << ")'s exits:";
for ( RoomMap::const_iterator i = rmap.begin(); i != rmap.end(); i++ )
buf << " " << i->first << "(#" << i->second->Get("vnum") << ")";
}
return;
}
else if ( !strcasecmp( option, "vnum" ) )
{
Room *r = NULL;
if ( !CheckVnumRange( avatar, change ) )
{
string buf = "Vnum range: ";
buf << MIN_VNUM << " - " << MAX_VNUM << ". Please enter a valid vnum.\n\r";
avatar->Send(buf);
return;
}
if ( (r = World::Instance().FindRoom(change)) != NULL)
{
avatar->Send( "That vnum is already being used!\n\r" );
return;
}
RoomMap::iterator x = World::Instance()._room_map.find(_edit->Get("vnum"));
if ( x != World::Instance()._room_map.end() )
World::Instance()._room_map.erase(x);
World::Instance()._room_map[change] = _edit;
_edit->Set("vnum", change);
avatar->Send( "Vnum changed.\n\r" );
return;
}
else if ( ( !strcasecmp( option, "save" ) && command == true ) )
{
_edit->Save();
avatar->Send( "Room saved to database.\n\r" );
return;
}
else if ( ( !strcasecmp( option, "delete" ) && command == true ) )
{
string buf;
buf << "DELETE FROM room WHERE room_id=" << _edit->id;
Mysql::Instance().Query( buf.c_str() );
delete _edit;
_edit = NULL;
buf = "";
buf << _edit->Get( "name" ) << "(#" << _edit->Get("vnum") << ") has been deleted.\n\r";
avatar->Send( buf );
return;
}
}
else if ( !_edit )
{
string buf;
if ( (_edit = World::Instance().FindRoom(option)) == NULL && CheckVnumRange( avatar, option ) )
{
avatar->Send("\n\rCreating new room...\n\r");
buf << "INSERT INTO room ( version, vnum, name ) VALUES ( "
<< ROOM_VERSION << ", " << option << ", 'An Empty Room' )";
if ( !Mysql::Instance().Query( buf.c_str() ) )
glog( "EditRoomHandler::EditRoomHandler -> Failed Query!" );
else
_edit = new Room(option);
}
buf = "";
buf << "You are now editing [{b" << option << "{x]\n\r";
avatar->Send( buf );
return;
}
if ( command )
avatar->Send( "That is an invalid # command. Try #help\n\r" );
}
string EditRoomHandler::Prompt( Avatar * avatar )
{
return (_edit == NULL ? "Enter vnum: " : ">> ");
}
bool CheckVnumRange( Avatar *av, const string& str )
{
unsigned int vnum = (unsigned int)atoi(str.c_str());
bool is_imp = false;
if (av->Get("group").find( "imp" ) != string::npos )
is_imp = true;
if ( (vnum < MIN_VNUM && is_imp == false) || vnum < 1 || vnum > MAX_VNUM )
return false;
return true;
}
string GenOppDir( string dir, string* str )
{
string oppdir;
char c = '\0';
if ( dir.length() > 1 )
c = dir[1];
switch ( dir[0] )
{
default:
glog( "GenOppDir: Default case! Ack! Dir = %s.", dir.c_str() );
return "";
case 'n':
if ( c == 'w' )
oppdir = "se";
else if ( c == 'e' )
oppdir = "sw";
else if ( dir == "northwest" )
oppdir = "southeast";
else if ( dir == "northeast" )
oppdir = "southwest";
else
oppdir = "south";
break;
case 's':
if ( c == 'w' )
oppdir = "ne";
else if ( c == 'e' )
oppdir = "nw";
else if ( dir == "southwest" )
oppdir = "northeast";
else if ( dir == "southeast" )
oppdir = "northwest";
else
oppdir = "north";
break;
case 'w':
oppdir = "east";
break;
case 'e':
oppdir = "west";
break;
}
if ( str != NULL )
(*str) = oppdir;
return oppdir;
}