Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #1  
Old 04-17-2010, 10:43 AM
Angelox
AX Classic Developer
 
Join Date: May 2006
Location: filler
Posts: 2,049
Default Dual Login Server Code

Secrets: I cant find your original Dual Login server code, so here's what I wanted to add on to it, as it's a continuation of what you did. This has been working fine and I've had it it on since I saw your post a while back.
In summary, here's what happens; first i wanted to maintain separate ID records of my users, so I added another table to table account and called it lsaccount_id2. This is what I have on my notes so has two alterations;
Code:
ALTER TABLE `account` ADD `lsaccount_id2` int(10) UNSIGNED DEFAULT '0'AFTER `lsaccount_id`;
ALTER TABLE `ax_classic`.`account` MODIFY COLUMN `lsaccount_id2` INT(10) UNSIGNED DEFAULT 0;
Since account already had all the users, and I needed one table to start at a higher increment, I converted the original account table;
Code:
UPDATE ax_classic.account SET lsaccount_id=lsaccount_id +5000000 WHERE lsaccount_id > 0;
And my accounts on my LS to match;
Code:
UPDATE new_login.login_accounts SET id=id +5000000;
so now I have my LS and accounts pointed to anything 5000000 or above, and anything below 5000000, must be from EqEmu- I don't think EqEmu will reach 5000000 during my lifetime, but if it did, then just up the increment to my LS accounts.
I have two sets of code, one that I have in use, but since it is sort of "hackish", i wanted one that was true in all areas, one that would monitor and single out/specify each port. But it is a lot of work that goes into a lot of code (and the work is triple for me, because I never know what I'm doing most the time), I got burnt out an put it on my "ToDo" list.
Here's the code I currently use, changes to LS are quoted with DUAL_SERVER, so you can easily pull them out and add them to your code, I posted the whole pages of script, cause diffs won't work with this code, it has other custom stuff, but you can see where the Dual LS code is placed (#ifdef DUAL_SERVER);

LoginServer.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include <stdlib.h>
#include "../common/version.h"

#ifdef WIN32
	#include <process.h>
	#include <windows.h>
	#include <winsock.h>

	#define snprintf	_snprintf
#if (_MSC_VER < 1500)
	#define vsnprintf	_vsnprintf
#endif
	#define strncasecmp	_strnicmp
	#define strcasecmp	_stricmp
#else // Pyro: fix for linux
	#include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
	#include <sys/types.h>
#endif
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <pthread.h>
	#include <unistd.h>
	#include <errno.h>

	#include "../common/unix.h"

	#define SOCKET_ERROR -1
	#define INVALID_SOCKET -1
	extern int errno;
#endif

#define IGNORE_LS_FATAL_ERROR

#include "../common/servertalk.h"
#include "LoginServer.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "WorldConfig.h"

extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numzones;
extern int32 numplayers;
extern volatile bool	RunLoops;
volatile bool LoginLoopRunning = false;

bool AttemptingConnect = false;

#ifdef DUAL_SERVER
LoginServer::LoginServer(const char* iAddress, const char* iAddress2, int16 iPort, int16 iPort2)
#else
LoginServer::LoginServer(const char* iAddress, int16 iPort)
#endif

: statusupdate_timer(LoginServer_StatusUpdateInterval)
{
	LoginServerIP = ResolveIP(iAddress);
	LoginServerPort = iPort;
	tcpc = new EmuTCPConnection(true);
	tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);

#ifdef DUAL_SERVER  //Angelox
	LoginServerIP = ResolveIP(iAddress2);
	LoginServerPort = iPort2;
	tcpc2 = new EmuTCPConnection(true);
	tcpc2->SetPacketMode(EmuTCPConnection::packetModeLogin);
#endif

}

LoginServer::~LoginServer() {
	delete tcpc;

#ifdef DUAL_SERVER
	delete tcpc2;
#endif

}

bool LoginServer::Process() {
	const WorldConfig *Config=WorldConfig::get();

	if (statusupdate_timer.Check()) {
		this->SendStatus();
	}
    
	/************ Get all packets from packet manager out queue and process them ************/
	ServerPacket *pack = 0;

#ifdef DUAL_SERVER
	ServerPacket *pack2 = 0;
#endif

	while((pack = tcpc->PopPacket()))
	{
		_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
		_hex(WORLD__LS_TRACE,pack->pBuffer,pack->size);

		switch(pack->opcode) {
		case 0:
			break;
		case ServerOP_KeepAlive: {
			// ignore this
			break;
		}
		case ServerOP_UsertoWorldReq: {
			UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;	
			int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
			sint16 status = database.CheckStatus(id);

			ServerPacket* outpack = new ServerPacket;
			outpack->opcode = ServerOP_UsertoWorldResp;
			outpack->size = sizeof(UsertoWorldResponse_Struct);
			outpack->pBuffer = new uchar[outpack->size];
			memset(outpack->pBuffer, 0, outpack->size);
			UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
			utwrs->lsaccountid = utwr->lsaccountid;
			utwrs->ToID = utwr->FromID;

			if(Config->Locked == true)
			{
				if((status == 0 || status < 100) && (status != -2 || status != -1))
					utwrs->response = 0;
				if(status >= 100)
					utwrs->response = 1;
			}
			else {
				utwrs->response = 1;
			}

			sint32 x = Config->MaxClients;
			if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
				utwrs->response = -3;

			if(status == -1)
				utwrs->response = -1;
			if(status == -2)
				utwrs->response = -2;

			utwrs->worldid = utwr->worldid;
			SendPacket(outpack);
			delete outpack;
			break;
		}
		case ServerOP_LSClientAuth: {
			ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack->pBuffer;

			if (RuleI(World, AccountSessionLimit) >= 0) {
				// Enforce the limit on the number of characters on the same account that can be 
				// online at the same time.
				client_list.EnforceSessionLimit(slsca->lsaccount_id); 
			}

			client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
			break;
		}
		case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
			WorldConfig::DisableLoginserver();
			_log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
		_log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
			if (pack->size > 1) {
				_log(WORLD__LS_ERR, "     %s",pack->pBuffer);
			}
			break;
		}
		case ServerOP_SystemwideMessage: {
			ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack->pBuffer;
			zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
			break;
		}
		case ServerOP_LSRemoteAddr: {
			if (!Config->WorldAddress.length()) {
				WorldConfig::SetWorldAddress((char *)pack->pBuffer);
				_log(WORLD__LS, "Loginserver provided %s as world address",pack->pBuffer);
			}
			break;
		}
		default:
		{
			_log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size);
DumpPacket(pack->pBuffer, pack->size);
			break;
		}
		}

		delete pack;
	}

#ifdef DUAL_SERVER
		while((pack2 = tcpc2->PopPacket()))
	{
		_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack2->opcode);
		_hex(WORLD__LS_TRACE,pack2->pBuffer,pack2->size);

		switch(pack2->opcode) {
		case 0:
			break;
		case ServerOP_KeepAlive: {
			// ignore this
			break;
		}
		case ServerOP_UsertoWorldReq: {
			UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack2->pBuffer;	
			int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
			sint16 status = database.CheckStatus(id);

			ServerPacket* outpack = new ServerPacket;
			outpack->opcode = ServerOP_UsertoWorldResp;
			outpack->size = sizeof(UsertoWorldResponse_Struct);
			outpack->pBuffer = new uchar[outpack->size];
			memset(outpack->pBuffer, 0, outpack->size);
			UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
			utwrs->lsaccountid = utwr->lsaccountid;
			utwrs->ToID = utwr->FromID;

			if(Config->Locked == true)
			{
				if((status == 0 || status < 100) && (status != -2 || status != -1))
					utwrs->response = 0;
				if(status >= 100)
					utwrs->response = 1;
			}
			else {
				utwrs->response = 1;
			}

			sint32 x = Config->MaxClients;
			if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
				utwrs->response = -3;

			if(status == -1)
				utwrs->response = -1;
			if(status == -2)
				utwrs->response = -2;

			utwrs->worldid = utwr->worldid;
			SendPacket2(outpack);
			delete outpack;
			break;
		}
		case ServerOP_LSClientAuth: {
			ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack2->pBuffer;

			if (RuleI(World, AccountSessionLimit) >= 0) {
				// Enforce the limit on the number of characters on the same account that can be 
				// online at the same time.
				client_list.EnforceSessionLimit(slsca->lsaccount_id); 
			}

			client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
			break;
		}
		case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
			WorldConfig::DisableLoginserver();
			_log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
		_log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
			if (pack2->size > 1) {
				_log(WORLD__LS_ERR, "     %s",pack2->pBuffer);
			}
			break;
		}
		case ServerOP_SystemwideMessage: {
			ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack2->pBuffer;
			zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
			break;
		}
		case ServerOP_LSRemoteAddr: {
			if (!Config->WorldAddress.length()) {
				WorldConfig::SetWorldAddress((char *)pack2->pBuffer);
				_log(WORLD__LS, "Loginserver provided %s as world address",pack2->pBuffer);
			}
			break;
		}
		default:
		{
			_log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack2->opcode,pack->size);
DumpPacket(pack2->pBuffer, pack2->size);
			break;
		}
		}

		delete pack2;
		}
#endif //END DUAL_SERVER

	return true;
}

// this should always be called in a new thread
#ifdef WIN32
	void AutoInitLoginServer(void *tmp) {
#else
	void *AutoInitLoginServer(void *tmp) {
#endif
	srand(time(NULL));

#ifdef DUAL_SERVER
	if (loginserver.ConnectReady() && loginserver.ConnectReady2()) {
#else
	if (loginserver.ConnectReady()) {
#endif

		InitLoginServer();
	}
#ifndef WIN32
	return 0;
#endif
}
//Start
bool InitLoginServer() {
#ifdef DUAL_SERVER
	_log(WORLD__LS, "Dual Connecting to the login servers...");
#else
	_log(WORLD__LS, "Connecting to login server...");
#endif
	const WorldConfig *Config=WorldConfig::get();

#ifdef DUAL_SERVER
	if ((!loginserver.ConnectReady()) || (!loginserver.ConnectReady2())) {
#else
	if (!loginserver.ConnectReady()) {
#endif

		_log(WORLD__LS_ERR,"InitLoginServer() while already attempting connect");
		return false;
	}
	if (!Config->LoginHost.length()) {
		_log(WORLD__LS_ERR,"Login server info not loaded");
		return false;
	}

	AttemptingConnect = true;

#ifdef DUAL_SERVER
	loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginHost2.c_str(), Config->LoginPort2);
#else
	loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort);
#endif

	return true;
}

#ifdef DUAL_SERVER
bool LoginServer::Connect(const char* iAddress, int16 iPort, const char* iAddress2, int16 iPort2) {
#else
bool LoginServer::Connect(const char* iAddress, int16 iPort) {
#endif

	char tmp[25];
	if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){
		minilogin = true;
		_log(WORLD__LS, "Setting World to MiniLogin Server type");
	}
	else
		minilogin = false;

	if (minilogin && WorldConfig::get()->WorldAddress.length()==0) {
		_log(WORLD__LS_ERR, "**** For minilogin to work, you need to set the <address> element in the <world> section.");
		return false;
	}

	char errbuf[TCPConnection_ErrorBufferSize];

#ifdef DUAL_SERVER
	//char errbuf2[TCPConnection_ErrorBufferSize];
#endif

	if (iAddress == 0) {
		_log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
		return false;
	}
	else {
		if ((LoginServerIP = ResolveIP(iAddress, errbuf)) == 0)  {
			_log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress);
			return false;
		}
	}
	if (iPort != 0)
		LoginServerPort = iPort;

	if (LoginServerIP == 0 || LoginServerPort == 0) {
		_log(WORLD__LS_ERR, "LoginServer::Connect: Connect info incomplete, cannot connect");
		return false;
	}

#ifdef DUAL_SERVER
	if (iAddress2 == 0) {
		_log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
		return false;
	}
	else {
		if ((LoginServerIP2 = ResolveIP(iAddress2, errbuf)) == 0) {
			_log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress2);
			return false;
		}
	}
	if (iPort2 != 0)
		LoginServerPort2 = iPort2;

	if (LoginServerIP2 == 0 || LoginServerPort2 == 0) {
		_log(WORLD__LS_ERR, "LoginServer2::Connect: Connect info incomplete, cannot connect");
		return false;
	}


	if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf) && tcpc2->ConnectIP(LoginServerIP2, LoginServerPort2, errbuf)) {
		_log(WORLD__LS, "Connected to EqEmu Loginserver: %s:%d",iAddress,LoginServerPort);
		_log(WORLD__LS, "Connected to AXClassic Loginserver: %s:%d",iAddress2,LoginServerPort2);
#else
	if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
		_log(WORLD__LS, "Connected to Loginserver: %s:%d",iAddress,LoginServerPort);
#endif

		if (minilogin)
			SendInfo();
		else
			SendNewInfo();
		SendStatus();
		zoneserver_list.SendLSZones();
		return true;
	}
	else {

#ifdef DUAL_SERVER
		_log(WORLD__LS_ERR, "FATAL ERROR! - SERVERS NOT CONNECTED. One or more connections not esablished, so none are connected.",errbuf);
#else
		_log(WORLD__LS_ERR, "Could not connect to login server: %s",errbuf);
#endif

		return false;
	}
}
void LoginServer::SendInfo() {
	const WorldConfig *Config=WorldConfig::get();

	ServerPacket* pack = new ServerPacket;
	pack->opcode = ServerOP_LSInfo;
	pack->size = sizeof(ServerLSInfo_Struct);
	pack->pBuffer = new uchar[pack->size];
	memset(pack->pBuffer, 0, pack->size);
	ServerLSInfo_Struct* lsi = (ServerLSInfo_Struct*) pack->pBuffer;
	strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
	strcpy(lsi->serverversion, CURRENT_VERSION);
	strcpy(lsi->name, Config->LongName.c_str());
	strcpy(lsi->account, Config->LoginAccount.c_str());
	strcpy(lsi->password, Config->LoginPassword.c_str());
	strcpy(lsi->address, Config->WorldAddress.c_str());
	SendPacket(pack);

#ifdef DUAL_SERVER
	ServerPacket* pack2 = new ServerPacket;
	pack2->opcode = ServerOP_LSInfo;
	pack2->size = sizeof(ServerLSInfo_Struct);
	pack2->pBuffer = new uchar[pack2->size];
	memset(pack2->pBuffer, 0, pack2->size);
	ServerLSInfo_Struct* lsi2 = (ServerLSInfo_Struct*) pack2->pBuffer;
	strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
	strcpy(lsi2->serverversion, CURRENT_VERSION);
	strcpy(lsi2->name, Config->LongName.c_str());
	strcpy(lsi2->account, Config->LoginAccount2.c_str());
	strcpy(lsi2->password, Config->LoginPassword2.c_str());
	strcpy(lsi2->address, Config->WorldAddress.c_str());
	SendPacket2(pack2);
#endif

	delete pack;

#ifdef DUAL_SERVER
	delete pack2;
#endif
}

void LoginServer::SendNewInfo() {
	uint16 port;
	const WorldConfig *Config=WorldConfig::get();

	ServerPacket* pack = new ServerPacket;
	pack->opcode = ServerOP_NewLSInfo;
	pack->size = sizeof(ServerNewLSInfo_Struct);
	pack->pBuffer = new uchar[pack->size];
	memset(pack->pBuffer, 0, pack->size);
	ServerNewLSInfo_Struct* lsi = (ServerNewLSInfo_Struct*) pack->pBuffer;
	strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
	strcpy(lsi->serverversion, CURRENT_VERSION);
	strcpy(lsi->name, Config->LongName.c_str());
	strcpy(lsi->shortname, Config->ShortName.c_str());
	strcpy(lsi->account, Config->LoginAccount.c_str());
	strcpy(lsi->password, Config->LoginPassword.c_str());
	if (Config->WorldAddress.length())
		strcpy(lsi->remote_address, Config->WorldAddress.c_str());
	if (Config->LocalAddress.length())
		strcpy(lsi->local_address, Config->LocalAddress.c_str());
	else {
		tcpc->GetSockName(lsi->local_address,&port);
		WorldConfig::SetLocalAddress(lsi->local_address);
	}
	SendPacket(pack);

#ifdef DUAL_SERVER
	ServerPacket* pack2 = new ServerPacket;
	pack2->opcode = ServerOP_NewLSInfo;
	pack2->size = sizeof(ServerNewLSInfo_Struct);
	pack2->pBuffer = new uchar[pack2->size];
	memset(pack2->pBuffer, 0, pack2->size);
	ServerNewLSInfo_Struct* lsi2 = (ServerNewLSInfo_Struct*) pack2->pBuffer;
	strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
	strcpy(lsi2->serverversion, CURRENT_VERSION);
	strcpy(lsi2->name, Config->LongName.c_str());
	strcpy(lsi2->shortname, Config->ShortName.c_str());
	strcpy(lsi2->account, Config->LoginAccount.c_str());
	strcpy(lsi2->password, Config->LoginPassword.c_str());
	if (Config->WorldAddress.length())
		strcpy(lsi2->remote_address, Config->WorldAddress.c_str());
	if (Config->LocalAddress.length())
		strcpy(lsi2->local_address, Config->LocalAddress.c_str());
	else {
		tcpc2->GetSockName(lsi2->local_address,&port);
		WorldConfig::SetLocalAddress(lsi2->local_address);
	}
	//SendPacket(pack); Angelox
	SendPacket2(pack2);
#endif

	delete pack;

#ifdef DUAL_SERVER
	delete pack2;
#endif
}

void LoginServer::SendStatus() {
	statusupdate_timer.Start();
	ServerPacket* pack = new ServerPacket;
	pack->opcode = ServerOP_LSStatus;
	pack->size = sizeof(ServerLSStatus_Struct);
	pack->pBuffer = new uchar[pack->size];
	memset(pack->pBuffer, 0, pack->size);
	ServerLSStatus_Struct* lss = (ServerLSStatus_Struct*) pack->pBuffer;

	if (WorldConfig::get()->Locked)
		lss->status = -2;
	else if (numzones <= 0)
		lss->status = -2;
	else
		lss->status = numplayers;

	lss->num_zones = numzones;
	lss->num_players = numplayers;
	SendPacket(pack);

#ifdef DUAL_SERVER
	SendPacket2(pack);
#endif

	delete pack;
}
client.cpp
Code:
#include "../common/debug.h"
#include "../common/EQPacket.h"
#include "../common/EQStreamIntf.h"
#include "../common/misc.h"
#include <iostream>
using namespace std;
#include <iomanip>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include <limits.h>
//FatherNitwit: uncomment to enable my IP based authentication hack
//#define IPBASED_AUTH_HACK

// Disgrace: for windows compile
#ifdef WIN32
	#include <windows.h>
	#include <winsock.h>
	#define snprintf	_snprintf
#if (_MSC_VER < 1500)
	#define vsnprintf	_vsnprintf
#endif
	#define strncasecmp	_strnicmp
	#define strcasecmp  _stricmp
#else
	#include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
	#include <sys/types.h>
#endif
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <unistd.h>
#endif

#include "client.h"
#include "../common/emu_opcodes.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "../common/EQStreamIntf.h"
#include "worlddb.h"
#include "../common/Item.h"
#include "../common/races.h"
#include "../common/classes.h"
#include "../common/languages.h"
#include "../common/skills.h"
#include "../common/extprofile.h"
#include "WorldConfig.h"
#include "LoginServer.h"
#include "zoneserver.h"
#include "zonelist.h"
#include "clientlist.h"
#include "wguild_mgr.h"
#include "../common/rulesys.h"
#include "SoFCharCreateData.h"

extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numclients;
extern volatile bool RunLoops;

Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
  CLE_keepalive_timer(RuleI(World, ClientKeepaliveTimeoutMS)),
  connect(1000),
  eqs(ieqs)
{
	// Live does not send datarate as of 3/11/2005
	//eqs->SetDataRate(7);
	ip = eqs->GetRemoteIP();
	port = ntohs(eqs->GetRemotePort());

	autobootup_timeout.Disable();
	connect.Disable();
	seencharsel = false;
	cle = 0;
	zoneID = 0;
	char_name[0] = 0;
	charid = 0;
	pwaitingforbootup = 0;
	StartInTutorial = false;
	SoFClient = false;
	numclients++;
}

Client::~Client() {
	if (RunLoops && cle && zoneID == 0)
		cle->SetOnline(CLE_Status_Offline);

	numclients--;

	//let the stream factory know were done with this stream
	eqs->Close();
	eqs->ReleaseFromUse();
}

void Client::SendLogServer()
{
	EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogServer, sizeof(LogServer_Struct));
	LogServer_Struct *l=(LogServer_Struct *)outapp->pBuffer;
	const char *wsn=WorldConfig::get()->ShortName.c_str();
	memcpy(l->worldshortname,wsn,strlen(wsn));

	if(RuleB(Mail, EnableMailSystem))
		l->enablemail = 1;

	if(RuleB(Chat, EnableVoiceMacros))
		l->enablevoicemacros = 1;

	if(database.GetServerType() == 1)
		l->enable_pvp = 1;

	//enable when we are ready to implement this!
	//l->enable_petition_wnd = 1;

	QueuePacket(outapp);
	safe_delete(outapp);
}

void Client::SendEnterWorld(string name)
{
char char_name[32]= { 0 };
	if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) {
		if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
			eqs->Close();
			return;
		} else {
			clog(WORLD__CLIENT,"Telling client to continue session.");
		}
	}

	EQApplicationPacket *outapp = new EQApplicationPacket(OP_EnterWorld, strlen(char_name)+1);
	memcpy(outapp->pBuffer,char_name,strlen(char_name)+1);
	QueuePacket(outapp);
	safe_delete(outapp);
}

void Client::SendExpansionInfo() {
	EQApplicationPacket *outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
	ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
	char val[20] = {0};
	if (database.GetVariable("Expansions", val, 20)) {
		eis->Expansions = atoi(val);
	}
	else {
		eis->Expansions = 0x1FF;
	}
	QueuePacket(outapp);
	safe_delete(outapp);
}

void Client::SendCharInfo() {
	if (cle) {
		cle->SetOnline(CLE_Status_CharSelect);
	}

	seencharsel = true;


	// Send OP_SendCharInfo
	EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
	CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;

	database.GetCharSelectInfo(GetAccountID(), cs);

	QueuePacket(outapp);
	safe_delete(outapp);
}

void Client::SendPostEnterWorld() {
	EQApplicationPacket *outapp = new EQApplicationPacket(OP_PostEnterWorld, 1);
	outapp->size=0;
	QueuePacket(outapp);
	safe_delete(outapp);
}

bool Client::HandlePacket(const EQApplicationPacket *app) {
	const WorldConfig *Config=WorldConfig::get();
	EmuOpcode opcode = app->GetOpcode();

	clog(WORLD__CLIENT_TRACE,"Recevied EQApplicationPacket");
	_pkt(WORLD__CLIENT_TRACE,app);

	bool ret = true;

	if (!eqs->CheckState(ESTABLISHED)) {
		clog(WORLD__CLIENT,"Client disconnected (net inactive on send)");
		return false;
	}

	// Voidd: Anti-GM Account hack, Checks source ip against valid GM Account IP Addresses
	if (RuleB(World, GMAccountIPList) && this->GetAdmin() >= (RuleI(World, MinGMAntiHackStatus))) {
		if(!database.CheckGMIPs(long2ip(this->GetIP()).c_str(), this->GetAccountID())) {
			clog(WORLD__CLIENT,"GM Account not permited from source address %s and accountid %i", long2ip(this->GetIP()).c_str(), this->GetAccountID());
			eqs->Close();
		}
	}

	if (GetAccountID() == 0 && opcode != OP_SendLoginInfo) {
		// Got a packet other than OP_SendLoginInfo when not logged in
		clog(WORLD__CLIENT_ERR,"Expecting OP_SendLoginInfo, got %s", OpcodeNames[opcode]);
		return false;
	}
	else if (opcode == OP_AckPacket) {
		return true;
	}

	switch(opcode)
	{
		case OP_CrashDump:
			break;
		case OP_SendLoginInfo:
		{
			if (app->size != sizeof(LoginInfo_Struct)) {
				ret = false;
				break;
			}

			string StreamDescription = eqs->Describe();

			if(StreamDescription == "Patch SoF")
				SoFClient = true;

			LoginInfo_Struct *li=(LoginInfo_Struct *)app->pBuffer;

			// Quagmire - max len for name is 18, pass 15
			char name[19] = {0};
			char password[16] = {0};
			strncpy(name, (char*)li->login_info,18);
			strncpy(password, (char*)&(li->login_info[strlen(name)+1]), 15);

			if (strlen(password) <= 1) {
				// TODO: Find out how to tell the client wrong username/password
				clog(WORLD__CLIENT_ERR,"Login without a password");
				ret = false;
				break;
			}

			pZoning=(li->zoning==1);

#ifdef IPBASED_AUTH_HACK
			struct in_addr tmpip;
			tmpip.s_addr = ip;
#endif
			int32 id=0;
			bool minilogin = loginserver.MiniLogin();
			if(minilogin){
				struct in_addr miniip;
				miniip.s_addr = ip;
				id = database.GetMiniLoginAccount(inet_ntoa(miniip));
			}
			else if(strncasecmp(name, "LS#", 3) == 0)
				id=atoi(&name[3]);
			else
				id=atoi(name);
#ifdef IPBASED_AUTH_HACK
			if ((cle = zoneserver_list.CheckAuth(inet_ntoa(tmpip), password)))
#else

#ifdef DUAL_SERVER
			if (loginserver.Connected() == false && !pZoning) {
				clog(WORLD__CLIENT_ERR,"Error: You're disconnected from one login server, you need to re-connect.");
			}
#else
			if (loginserver.Connected() == false && !pZoning) {
				clog(WORLD__CLIENT_ERR,"Error: Login server login while not connected to login server.");
				ret = false;
				break;
			}
#endif 
			if ((minilogin && (cle = client_list.CheckAuth(id,password,ip))) || (cle = client_list.CheckAuth(id, password)))
#endif
			{
				if (cle->AccountID() == 0 || (!minilogin && cle->LSID()==0)) {
					clog(WORLD__CLIENT_ERR,"ID is 0.  Is this server connected to minilogin?");
					if(!minilogin)
						clog(WORLD__CLIENT_ERR,"If so you forget the minilogin variable...");
					else
						clog(WORLD__CLIENT_ERR,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table.");
					ret = false;
					break;
				}

				cle->SetOnline();

				clog(WORLD__CLIENT,"Logged in. Mode=%s",pZoning ? "(Zoning)" : "(CharSel)");

				if(minilogin){
					WorldConfig::DisableStats();
					clog(WORLD__CLIENT,"MiniLogin Account #%d",cle->AccountID());
				}
				else {
					clog(WORLD__CLIENT,"LS Account #%d",cle->LSID());
				}
				if(Config->UpdateStats){
					ServerPacket* pack = new ServerPacket;
					pack->opcode = ServerOP_LSPlayerJoinWorld;
					pack->size = sizeof(ServerLSPlayerJoinWorld_Struct);
					pack->pBuffer = new uchar[pack->size];
					memset(pack->pBuffer,0,pack->size);
					ServerLSPlayerJoinWorld_Struct* join =(ServerLSPlayerJoinWorld_Struct*)pack->pBuffer;
					strcpy(join->key,GetLSKey());
					join->lsaccount_id = GetLSID();
					loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
					loginserver.SendPacket2(pack);
#endif 
					safe_delete(pack);
				}

				if (!pZoning)
					SendGuildList();
				SendLogServer();
				SendApproveWorld();
				SendEnterWorld(cle->name());
				SendPostEnterWorld();
				if (!pZoning) {
					SendExpansionInfo();
					SendCharInfo();
					database.LoginIP(cle->AccountID(), long2ip(GetIP()).c_str());
				}
			}
			else {
				// TODO: Find out how to tell the client wrong username/password
				clog(WORLD__CLIENT_ERR,"Bad/Expired session key '%s'",name);
				ret = false;
				break;
			}

			if (!cle)
				break;
			cle->SetIP(GetIP());
			break;
		}
		case OP_ApproveName: //Name approval
		{
			if (GetAccountID() == 0) {
				clog(WORLD__CLIENT_ERR,"Name approval request with no logged in account");
				ret = false;
				break;
			}
			snprintf(char_name, 64, "%s", (char*)app->pBuffer);
			uchar race = app->pBuffer[64];
			uchar clas = app->pBuffer[68];

			clog(WORLD__CLIENT,"Name approval request.  Name=%s, race=%s, class=%s",char_name,GetRaceName(race),GetEQClassName(clas));

			EQApplicationPacket *outapp;
			outapp = new EQApplicationPacket;
			outapp->SetOpcode(OP_ApproveName);
			outapp->pBuffer = new uchar[1];
			outapp->size = 1;
			bool valid;
			if(!database.CheckNameFilter(char_name)) {
				valid = false;
			}
			else if(char_name[0] < 'A' && char_name[0] > 'Z') {
				//name must begin with an upper-case letter.
				valid = false;
			}
			else if (database.ReserveName(GetAccountID(), char_name)) {
				valid = true;
			}
			else {
				valid = false;
			}
			outapp->pBuffer[0] = valid? 1 : 0;
			QueuePacket(outapp);
			safe_delete(outapp);
			break;
		}
		case OP_RandomNameGenerator:
		{
			// creates up to a 10 char name
			char vowels[18]="aeiouyaeiouaeioe";
			char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd";
			char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
			char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr";
			int rndnum=rand()%76,n=1;
			bool dlc=false;
			bool vwl=false;
			bool dbl=false;
			if (rndnum>63)
			{	// rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
				rndnum=(rndnum-61)*2;	// name can't start with "ng" "nd" or "rk"
				rndname[0]=paircons[rndnum];
				rndname[1]=paircons[rndnum+1];
				n=2;
			}
			else if (rndnum>16)
			{
				rndnum-=17;
				rndname[0]=cons[rndnum];
			}
			else
			{
				rndname[0]=vowels[rndnum];
				vwl=true;
			}
			int namlen=(rand()%6)+5;
			for (int i=n;i<namlen;i++)
			{
				dlc=false;
				if (vwl)	//last char was a vowel
				{			// so pick a cons or cons pair
					rndnum=rand()%63;
					if (rndnum>46)
					{	// pick a cons pair
						if (i>namlen-3)	// last 2 chars in name?
						{	// name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
							rndnum=(rand()%8)*2;
						}
						else
						{	// pick any from the set
							rndnum=(rndnum-47)*2;
						}
						rndname[i]=paircons[rndnum];
						rndname[i+1]=paircons[rndnum+1];
						dlc=true;	// flag keeps second letter from being doubled below
						i+=1;
					}
					else
					{	// select a single cons
						rndname[i]=cons[rndnum];
					}
				}
				else
				{		// select a vowel
					rndname[i]=vowels[rand()%17];
				}
				vwl=!vwl;
				if (!dbl && !dlc)
				{	// one chance at double letters in name
					if (!(rand()%(i+10)))	// chances decrease towards end of name
					{
						rndname[i+1]=rndname[i];
						dbl=true;
						i+=1;
					}
				}
			}

			rndname[0]=toupper(rndname[0]);
			NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
			memset(ngs->name,0,64);
			strcpy(ngs->name,rndname);

//			char names[8][64] = { "How", "About", "You", "Think", "Of", "Your", "Own", "Name" };
//			//Could have parts of the random name in this struct and they compile together
//			NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
//			strncpy(ngs->name,"Notcreated",64);

			QueuePacket(app);
			break;

		}
		case OP_CharacterCreateRequest: {
			// New OpCode in SoF
			//
			SoFClient = true;
			EQApplicationPacket *outapp = new EQApplicationPacket(OP_CharacterCreateRequest, sizeof(SoFCharCreateInfo));
			memcpy(outapp->pBuffer, &SoFCharCreateInfo, sizeof(SoFCharCreateInfo));
			QueuePacket(outapp);
			safe_delete(outapp);
			break;
		}

		case OP_CharacterCreate: //Char create
		{
			if (GetAccountID() == 0)
			{
				clog(WORLD__CLIENT_ERR,"Account ID not set; unable to create character.");
				ret = false;
				break;
			}
			else if (app->size != sizeof(CharCreate_Struct))
			{
				clog(WORLD__CLIENT_ERR,"Wrong size on OP_CharacterCreate. Got: %d, Expected: %d",app->size,sizeof(CharCreate_Struct));
				DumpPacket(app);
				break;
			}

			CharCreate_Struct *cc = (CharCreate_Struct*)app->pBuffer;
			if(OPCharCreate(char_name,cc) == false)
			{
				database.DeleteCharacter(char_name);
				EQApplicationPacket *outapp = new EQApplicationPacket(OP_ApproveName, 1);
				outapp->pBuffer[0] = 0;
				QueuePacket(outapp);
				safe_delete(outapp);
			}
                  else
			StartInTutorial = true;
			SendCharInfo();

			break;
		}
		case OP_EnterWorld: // Enter world
		{
			if (GetAccountID() == 0) {
				clog(WORLD__CLIENT_ERR,"Enter world with no logged in account");
				eqs->Close();
				break;
			}
			if(GetAdmin() < 0)
			{
				clog(WORLD__CLIENT,"Account banned or suspended.");
				eqs->Close();
				break;
			}

			if (RuleI(World, MaxClientsPerIP) >= 0) {
	            client_list.GetCLEIP(this->GetIP());  //Lieka Edit Begin:  Check current CLE Entry IPs against incoming connection
            }

			EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer;
			strncpy(char_name, ew->name, 64);

			EQApplicationPacket *outapp;
			int32 tmpaccid = 0;
			charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID);
			if (charid == 0 || tmpaccid != GetAccountID()) {
				clog(WORLD__CLIENT_ERR,"Could not get CharInfo for '%s'",char_name);
				eqs->Close();
				break;
			}

			// Make sure this account owns this character
			if (tmpaccid != GetAccountID()) {
				clog(WORLD__CLIENT_ERR,"This account does not own the character named '%s'",char_name);
				eqs->Close();
				break;
			}

			if(!pZoning && ew->return_home)
			{
				CharacterSelect_Struct* cs = new CharacterSelect_Struct;
				memset(cs, 0, sizeof(CharacterSelect_Struct));
				database.GetCharSelectInfo(GetAccountID(), cs);
				bool home_enabled = false;

				for(int x = 0; x < 10; ++x)
				{
					if(strcasecmp(cs->name[x], char_name) == 0)
					{
						if(cs->gohome[x] == 1)
						{
							home_enabled = true;
							break;
						}
					}
				}
				safe_delete(cs);

				if(home_enabled)
				{
					zoneID = database.MoveCharacterToBind(charid,4);
				}
				else
				{
					clog(WORLD__CLIENT_ERR,"'%s' is trying to go home before they're able...",char_name);
					database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to enter the tutorial without having go home enabled for this character.");
					eqs->Close();
					break;
				}
			}
/*
			if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
				CharacterSelect_Struct* cs = new CharacterSelect_Struct;
				memset(cs, 0, sizeof(CharacterSelect_Struct));
				database.GetCharSelectInfo(GetAccountID(), cs);
				bool tutorial_enabled = false;

				for(int x = 0; x < 10; ++x)
				{
					if(strcasecmp(cs->name[x], char_name) == 0)
					{
						if(cs->tutorial[x] == 1)
						{
							tutorial_enabled = true;
							break;
						}
					}
				}
				safe_delete(cs);

				if(tutorial_enabled)
				{
					zoneID = RuleI(World, TutorialZoneID);
					database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
				}
				else
				{
					clog(WORLD__CLIENT_ERR,"'%s' is trying to go to tutorial but are not allowed...",char_name);
					database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
					eqs->Close();
					break;
				}

				// HACK: Entering the Tutorial directly from Character Creation (without going back to Char Select)
				// does not work correctly yet in SoF, so bounce them back to Character Select first.
				//
				if(SoFClient && StartInTutorial) {
					ZoneUnavail();
					StartInTutorial = false;
					break;
				}
			}
*/
			if (zoneID == 0 || !database.GetZoneName(zoneID)) {
				// This is to save people in an invalid zone, once it's removed from the DB
				database.MoveCharacterToZone(charid, "arena");
				clog(WORLD__CLIENT_ERR, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name);
			}

			if(instanceID > 0)
			{
				if(!database.VerifyInstanceAlive(instanceID, GetCharID()))
				{
					zoneID = database.MoveCharacterToBind(charid);
					instanceID = 0;
				}
				else
				{
					if(!database.VerifyZoneInstance(zoneID, instanceID))
					{
						zoneID = database.MoveCharacterToBind(charid);
						instanceID = 0;
					}
				}
			}

			if(!pZoning) {
				database.SetGroupID(char_name, 0, charid);
				database.SetLFP(charid, false);
				database.SetLFG(charid, false);
			}
			else{
				int32 groupid=database.GetGroupID(char_name);
				if(groupid>0){
					char* leader=0;
					char leaderbuf[64]={0};
					if((leader=database.GetGroupLeaderForLogin(char_name,leaderbuf)) && strlen(leader)>1){
						EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct));
						GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer;
						gj->action=8;
						strcpy(gj->yourname,char_name);
						strcpy(gj->membername,leader);
						QueuePacket(outapp3);
						safe_delete(outapp3);
					}
				}
			}
//Angelox
			outapp = new EQApplicationPacket(OP_MOTD);

#ifdef DUAL_SERVER
			char tmp[500] = {0};
			if ((database.GetVariable("MOTD", tmp, 500)) && (GetLSID() > 4999999)) {
				outapp->size = strlen(tmp)+1;
				outapp->pBuffer = new uchar[outapp->size];
				memset(outapp->pBuffer,0,outapp->size);
				strcpy((char*)outapp->pBuffer, tmp);
			}
			else if ((database.GetVariable("MOTDEqEmu", tmp, 500)) && (GetLSID() < 5000000)) {
				outapp->size = strlen(tmp)+1;
				outapp->pBuffer = new uchar[outapp->size];
				memset(outapp->pBuffer,0,outapp->size);
				strcpy((char*)outapp->pBuffer, tmp);
			}
#else
			char tmp[500] = {0};
			if (database.GetVariable("MOTD", tmp, 500)) {
				outapp->size = strlen(tmp)+1;
				outapp->pBuffer = new uchar[outapp->size];
				memset(outapp->pBuffer,0,outapp->size);
				strcpy((char*)outapp->pBuffer, tmp);
			}
#endif

			else {
				// Null Message of the Day. :)
				outapp->size = 1;
				outapp->pBuffer = new uchar[outapp->size];
				outapp->pBuffer[0] = 0;
			}
			QueuePacket(outapp);
			safe_delete(outapp);

			int MailKey = MakeRandomInt(1, INT_MAX);

			database.SetMailKey(charid, GetIP(), MailKey);

			char ConnectionType = (SoFClient ? 'S' : 'C');

			EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_SetChatServer);
			char buffer[112];
			sprintf(buffer,"%s,%i,%s.%s,%c%08X",
				Config->ChatHost.c_str(),
				Config->ChatPort,
				Config->ShortName.c_str(),
				this->GetCharName(), ConnectionType, MailKey
			);
			outapp2->size=strlen(buffer)+1;
			outapp2->pBuffer = new uchar[outapp2->size];
			memcpy(outapp2->pBuffer,buffer,outapp2->size);
			QueuePacket(outapp2);
			safe_delete(outapp2);

			outapp2 = new EQApplicationPacket(OP_SetChatServer2);

			if(!SoFClient)
				ConnectionType = 'M';

			sprintf(buffer,"%s,%i,%s.%s,%c%08X",
				Config->MailHost.c_str(),
				Config->MailPort,
				Config->ShortName.c_str(),
				this->GetCharName(), ConnectionType, MailKey
			);
			outapp2->size=strlen(buffer)+1;
			outapp2->pBuffer = new uchar[outapp2->size];
			memcpy(outapp2->pBuffer,buffer,outapp2->size);
			QueuePacket(outapp2);
			safe_delete(outapp2);

			EnterWorld();
			break;
		}
		case OP_LoginComplete:{
			break;
		}
		case OP_DeleteCharacter: {
			int32 char_acct_id = database.GetAccountIDByChar((char*)app->pBuffer);
			if(char_acct_id == GetAccountID())
			{
			clog(WORLD__CLIENT,"Delete character: %s",app->pBuffer);
			database.DeleteCharacter((char *)app->pBuffer);
			SendCharInfo();
			}
			break;
		}
		case OP_ApproveWorld:
		{
			break;
		}
		case OP_WorldClientReady:{
			break;
		}
		case OP_World_Client_CRC1:
		case OP_World_Client_CRC2: {
			// Derision: There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
			// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
			// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
			// then 'Start Tutorial' was not chosen.
			StartInTutorial = false;
			break;
		}
		case OP_WearChange: { // User has selected a different character
			break;
		}
		case OP_WorldComplete: {
			eqs->Close();
			break;
		}
		case OP_LoginUnknown1:
		case OP_LoginUnknown2:
			break;

		default: {
			clog(WORLD__CLIENT_ERR,"Received unknown EQApplicationPacket");
			_pkt(WORLD__CLIENT_ERR,app);
			break;
		}
	}
	return ret;
}

bool Client::Process() {
	bool ret = true;
	//bool sendguilds = true;
    sockaddr_in to;

	memset((char *) &to, 0, sizeof(to));
    to.sin_family = AF_INET;
    to.sin_port = port;
    to.sin_addr.s_addr = ip;

	if (autobootup_timeout.Check()) {
		clog(WORLD__CLIENT_ERR, "Zone bootup timer expired, bootup failed or too slow.");
		ZoneUnavail();
	}
	if(connect.Check()){
		SendGuildList();// Send OPCode: OP_GuildsList
		SendApproveWorld();
		connect.Disable();
	}
	if (CLE_keepalive_timer.Check()) {
		if (cle)
			cle->KeepAlive();
	}

	/************ Get all packets from packet manager out queue and process them ************/
	EQApplicationPacket *app = 0;
	while(ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
		ret = HandlePacket(app);

		delete app;
	}

	if (!eqs->CheckState(ESTABLISHED)) {
		if(WorldConfig::get()->UpdateStats){
			ServerPacket* pack = new ServerPacket;
			pack->opcode = ServerOP_LSPlayerLeftWorld;
			pack->size = sizeof(ServerLSPlayerLeftWorld_Struct);
			pack->pBuffer = new uchar[pack->size];
			memset(pack->pBuffer,0,pack->size);
			ServerLSPlayerLeftWorld_Struct* logout =(ServerLSPlayerLeftWorld_Struct*)pack->pBuffer;
			strcpy(logout->key,GetLSKey());
			logout->lsaccount_id = GetLSID();
			loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
			loginserver.SendPacket2(pack);
#endif
			safe_delete(pack);
		}
		clog(WORLD__CLIENT,"Client disconnected (not active in process)");
		return false;
	}

	return ret;
}

void Client::EnterWorld(bool TryBootup) {
	if (zoneID == 0)
		return;

	ZoneServer* zs = NULL;
	if(instanceID > 0)
	{
		if(database.VerifyInstanceAlive(instanceID, GetCharID()))
		{
			if(database.VerifyZoneInstance(zoneID, instanceID))
			{
				zs = zoneserver_list.FindByInstanceID(instanceID);
			}
			else
			{
				instanceID = 0;
				zs = NULL;
				database.MoveCharacterToBind(GetCharID());
				ZoneUnavail();
				return;
			}
		}
		else
		{
			instanceID = 0;
			zs = NULL;
			database.MoveCharacterToBind(GetCharID());
			ZoneUnavail();
			return;
		}
	}
	else
		zs = zoneserver_list.FindByZoneID(zoneID);


	const char *zone_name=database.GetZoneName(zoneID, true);
	if (zs) {
		// warn the world we're comming, so it knows not to shutdown
		zs->IncommingClient(this);
	}
	else {
		if (TryBootup) {
			clog(WORLD__CLIENT,"Attempting autobootup of %s (%d:%d)",zone_name,zoneID,instanceID);
			autobootup_timeout.Start();
			pwaitingforbootup = zoneserver_list.TriggerBootup(zoneID, instanceID);
			if (pwaitingforbootup == 0) {
				clog(WORLD__CLIENT_ERR,"No zoneserver available to boot up.");
				ZoneUnavail();
			}
			return;
		}
		else {
			clog(WORLD__CLIENT_ERR,"Requested zone %s is no running.",zone_name);
			ZoneUnavail();
			return;
		}
	}
	pwaitingforbootup = 0;

	cle->SetChar(charid, char_name);
	database.UpdateLiveChar(char_name, GetAccountID());
	clog(WORLD__CLIENT,"%s %s (%d:%d)",seencharsel ? "Entering zone" : "Zoning to",zone_name,zoneID,instanceID);
//	database.SetAuthentication(account_id, char_name, zone_name, ip);

	if (seencharsel) {
		if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zoneID)) {
			clog(WORLD__CLIENT_ERR,"Enter world failed.  Zone is locked.");
			ZoneUnavail();
			return;
		}

		ServerPacket* pack = new ServerPacket;
		pack->opcode = ServerOP_AcceptWorldEntrance;
		pack->size = sizeof(WorldToZone_Struct);
		pack->pBuffer = new uchar[pack->size];
		memset(pack->pBuffer, 0, pack->size);
		WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
		wtz->account_id = GetAccountID();
		wtz->response = 0;
		zs->SendPacket(pack);
		delete pack;
	}
	else {	// if they havent seen character select screen, we can assume this is a zone
			// to zone movement, which should be preauthorized before they leave the previous zone
		Clearance(1);
	}
}

void Client::Clearance(sint8 response)
{
	ZoneServer* zs = NULL;
	if(instanceID > 0)
	{
		zs = zoneserver_list.FindByInstanceID(instanceID);
	}
	else
	{
		zs = zoneserver_list.FindByZoneID(zoneID);
	}

    if(zs == 0 || response == -1 || response == 0)
    {
        if (zs == 0)
        {
            clog(WORLD__CLIENT_ERR,"Unable to find zoneserver in Client::Clearance!!");
        } else {
        	clog(WORLD__CLIENT_ERR, "Invalid response %d in Client::Clearance", response);
        }

        ZoneUnavail();
        return;
    }

	EQApplicationPacket* outapp;

    if (zs->GetCAddress() == NULL) {
        clog(WORLD__CLIENT_ERR, "Unable to do zs->GetCAddress() in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

    if (zoneID == 0) {
        clog(WORLD__CLIENT_ERR, "zoneID is NULL in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

	const char* zonename = database.GetZoneName(zoneID);
    if (zonename == 0) {
        clog(WORLD__CLIENT_ERR, "zonename is NULL in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

	// @bp This is the chat server
	/*
	char packetData[] = "64.37.148.34.9876,MyServer,Testchar,23cd2c95";
	outapp = new EQApplicationPacket(OP_0x0282, sizeof(packetData));
	strcpy((char*)outapp->pBuffer, packetData);
	QueuePacket(outapp);
	delete outapp;
	*/

	// Send zone server IP data
	outapp = new EQApplicationPacket(OP_ZoneServerInfo, sizeof(ZoneServerInfo_Struct));
	ZoneServerInfo_Struct* zsi = (ZoneServerInfo_Struct*)outapp->pBuffer;
	const char *zs_addr=zs->GetCAddress();
	if (!zs_addr[0]) {
		if (cle->IsLocalClient()) {
			struct in_addr  in;
			in.s_addr = zs->GetIP();
			zs_addr=inet_ntoa(in);
			if (!strcmp(zs_addr,"127.0.0.1"))
				zs_addr=WorldConfig::get()->LocalAddress.c_str();
		} else {
			zs_addr=WorldConfig::get()->WorldAddress.c_str();
		}
	}
	strcpy(zsi->ip, zs_addr);
	zsi->port =zs->GetCPort();
	clog(WORLD__CLIENT,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zoneID,instanceID,zsi->ip,zsi->port);
	QueuePacket(outapp);
	safe_delete(outapp);

	if (cle)
		cle->SetOnline(CLE_Status_Zoning);
}

void Client::ZoneUnavail() {
	EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneUnavail, sizeof(ZoneUnavail_Struct));
	ZoneUnavail_Struct* ua = (ZoneUnavail_Struct*)outapp->pBuffer;
	const char* zonename = database.GetZoneName(zoneID);
	if (zonename)
		strcpy(ua->zonename, zonename);
	QueuePacket(outapp);
	delete outapp;

	zoneID = 0;
	pwaitingforbootup = 0;
	autobootup_timeout.Disable();
}

bool Client::GenPassKey(char* key) {
	char* passKey=NULL;
	*passKey += ((char)('A'+((int)(rand()%26))));
	*passKey += ((char)('A'+((int)(rand()%26))));
	memcpy(key, passKey, strlen(passKey));
	return true;
}

void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req) {
	clog(WORLD__CLIENT_TRACE, "Sending EQApplicationPacket OpCode 0x%04x",app->GetOpcode());
	_pkt(WORLD__CLIENT_TRACE, app);

	ack_req = true;	// It's broke right now, dont delete this line till fix it. =P
	eqs->QueuePacket(app, ack_req);
}

void Client::SendGuildList() {
	EQApplicationPacket *outapp;
	outapp = new EQApplicationPacket(OP_GuildsList);

	//ask the guild manager to build us a nice guild list packet
	outapp->pBuffer = guild_mgr.MakeGuildList("", outapp->size);
	if(outapp->pBuffer == NULL) {
		clog(GUILDS__ERROR, "Unable to make guild list!");
		return;
	}

	clog(GUILDS__OUT_PACKETS, "Sending OP_GuildsList of length %d", outapp->size);
//	_pkt(GUILDS__OUT_PACKET_TRACE, outapp);

	eqs->FastQueuePacket((EQApplicationPacket **)&outapp);
}

// @merth: I have no idea what this struct is for, so it's hardcoded for now
void Client::SendApproveWorld()
{
	EQApplicationPacket* outapp;

	// Send OPCode: OP_ApproveWorld, size: 544
	outapp = new EQApplicationPacket(OP_ApproveWorld, sizeof(ApproveWorld_Struct));
	ApproveWorld_Struct* aw = (ApproveWorld_Struct*)outapp->pBuffer;
	uchar foo[] = {
//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x5E,0x30,0xA5,0xCA,0xD4,0xEA,0xF5,
//0xCB,0x14,0xFC,0xF7,0x78,0xE2,0x73,0x15,0x90,0x17,0xCE,0x7A,0xEB,0xEC,0x3C,0x34,
//0x5C,0x6D,0x10,0x05,0xFC,0xEA,0xED,0x19,0xC5,0x0D,0x7A,0x82,0x17,0xCC,0xCC,0x71,
//0x56,0x38,0xDF,0x78,0x8D,0xE6,0x44,0xD3,0x6F,0xDB,0xE3,0xCF,0x21,0x30,0x75,0x2F,
//0xCD,0xDC,0xE9,0xB4,0xA4,0x4E,0x58,0xDE,0xEE,0x54,0xDD,0x87,0xDA,0xE9,0xC6,0xC8,
//0x02,0xDD,0xC4,0xFD,0x94,0x36,0x32,0xAD,0x1B,0x39,0x0F,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x87,0x13,0xbe,0xc8,0xa7,0x77,0xcb,
0x27,0xed,0xe1,0xe6,0x5d,0x1c,0xaa,0xd3,0x3c,0x26,0x3b,0x6d,0x8c,0xdb,0x36,0x8d,
0x91,0x72,0xf5,0xbb,0xe0,0x5c,0x50,0x6f,0x09,0x6d,0xc9,0x1e,0xe7,0x2e,0xf4,0x38,
0x1b,0x5e,0xa8,0xc2,0xfe,0xb4,0x18,0x4a,0xf7,0x72,0x85,0x13,0xf5,0x63,0x6c,0x16,
0x69,0xf4,0xe0,0x17,0xff,0x87,0x11,0xf3,0x2b,0xb7,0x73,0x04,0x37,0xca,0xd5,0x77,
0xf8,0x03,0x20,0x0a,0x56,0x8b,0xfb,0x35,0xff,0x59,0x00,0x00,0x00,0x00,0x00,0x00,

//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x42,0x69,0x2a,0x87,0xdd,0x04,0x3d,
//0x7f,0xb1,0xb3,0xbb,0xde,0xd5,0x5f,0xfc,0x1f,0xb3,0x25,0x94,0x16,0xd5,0xf3,0x97,
//0x43,0xdf,0xb9,0x69,0x68,0xdf,0x2b,0x64,0x98,0xf5,0x44,0xbe,0x38,0x65,0xef,0xff,
//0x36,0x89,0x90,0xcf,0x26,0xbb,0x9f,0x76,0xd5,0xaf,0x6d,0xf2,0x08,0xbe,0xce,0xd8,
//0x3e,0x4b,0x53,0x8a,0xf3,0x44,0x7c,0x19,0x49,0x5d,0x97,0x99,0xd8,0x8b,0xee,0x10,
//0x1a,0x7d,0xb7,0x8b,0x49,0x9b,0x40,0x8c,0xea,0x49,0x09,0x00,0x00,0x00,0x00,0x00,
//
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00
};
	memcpy(aw->unknown544, foo, sizeof(foo));
	QueuePacket(outapp);
	safe_delete(outapp);
}

bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
{
	PlayerProfile_Struct pp;
	ExtendedProfile_Struct ext;
	Inventory inv;
	time_t bday = time(NULL);
	char startzone[50]={0};
	uint32 i;
	struct in_addr	in;


	int stats_sum = cc->STR + cc->STA + cc->AGI + cc->DEX +
		cc->WIS + cc->INT + cc->CHA;

	in.s_addr = GetIP();
	clog(WORLD__CLIENT,"Character creation request from %s LS#%d (%s:%d) : ", GetCLE()->LSName(), GetCLE()->LSID(), inet_ntoa(in), GetPort());
	clog(WORLD__CLIENT,"Name: %s", name);
	clog(WORLD__CLIENT,"Race: %d  Class: %d  Gender: %d  Deity: %d  Start zone: %d",
		cc->race, cc->class_, cc->gender, cc->deity, cc->start_zone);
	clog(WORLD__CLIENT,"STR  STA  AGI  DEX  WIS  INT  CHA    Total");
	clog(WORLD__CLIENT,"%3d  %3d  %3d  %3d  %3d  %3d  %3d     %3d",
		cc->STR, cc->STA, cc->AGI, cc->DEX, cc->WIS, cc->INT, cc->CHA,
		stats_sum);
	clog(WORLD__CLIENT,"Face: %d  Eye colors: %d %d", cc->face, cc->eyecolor1, cc->eyecolor2);
	clog(WORLD__CLIENT,"Hairstyle: %d  Haircolor: %d", cc->hairstyle, cc->haircolor);
	clog(WORLD__CLIENT,"Beard: %d  Beardcolor: %d", cc->beard, cc->beardcolor);

	// validate the char creation struct
	if(!CheckCharCreateInfo(cc))
	{
		clog(WORLD__CLIENT_ERR,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
		return false;
	}

	// Convert incoming cc_s to the new PlayerProfile_Struct
	memset(&pp, 0, sizeof(PlayerProfile_Struct));	// start building the profile

	InitExtendedProfile(&ext);

	strncpy(pp.name, name, 63);
	// clean the capitalization of the name
#if 0	// on second thought, don't - this will just make the creation fail
// because the name won't match what was already reserved earlier
	for (i = 0; pp.name[i] && i < 63; i++)
	{
		if(!isalpha(pp.name[i]))
			return false;
		pp.name[i] = tolower(pp.name[i]);
	}
	pp.name[0] = toupper(pp.name[0]);
#endif

	pp.race				= cc->race;
	pp.class_			= cc->class_;
	pp.gender			= cc->gender;
	pp.deity			= cc->deity;
	pp.STR				= cc->STR;
	pp.STA				= cc->STA;
	pp.AGI				= cc->AGI;
	pp.DEX				= cc->DEX;
	pp.WIS				= cc->WIS;
	pp.INT				= cc->INT;
	pp.CHA				= cc->CHA;
	pp.face				= cc->face;
	pp.eyecolor1		= cc->eyecolor1;
	pp.eyecolor2		= cc->eyecolor2;
	pp.hairstyle		= cc->hairstyle;
	pp.haircolor		= cc->haircolor;
	pp.beard		 	= cc->beard;
	pp.beardcolor		= cc->beardcolor;
	pp.drakkin_heritage		= cc->drakkin_heritage;
	pp.drakkin_tattoo		= cc->drakkin_tattoo;
	pp.drakkin_details		= cc->drakkin_details;
	pp.birthday		= bday;
	pp.lastlogin	= bday;
	pp.level			= 1;
	pp.points			= 5;
	pp.cur_hp			= 1000; // 1k hp during dev only
	//what was the point of this? zone dosent handle this:
	//pp.expAA			= 0xFFFFFFFF;

	pp.hunger_level = 6000;
	pp.thirst_level = 6000;


	// FIXME: FV roleplay, database goodness...

	// Racial Languages
	SetRacialLanguages( &pp ); // bUsh
	SetRaceStartingSkills( &pp ); // bUsh
	SetClassStartingSkills( &pp ); // bUsh
	pp.skills[SENSE_HEADING] = 200;
	// Some one fucking fix this to use a field name. -Doodman
	//pp.unknown3596[28] = 15; // @bp: This is to enable disc usage
//	strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());


	for(i = 0; i < MAX_PP_SPELLBOOK; i++)
		pp.spell_book[i] = 0xFFFFFFFF;

	for(i = 0; i < MAX_PP_MEMSPELL; i++)
		pp.mem_spells[i] = 0xFFFFFFFF;

	for(i = 0; i < BUFF_COUNT; i++)
		pp.buffs[i].spellid = 0xFFFF;


	//was memset(pp.unknown3704, 0xffffffff, 8);
	//but I dont think thats what you really wanted to do...
	//memset is byte based

	//If server is PVP by default, make all character set to it.
	pp.pvp = database.GetServerType() == 1 ? 1 : 0;

	//If it is an SoF Client and the SoF Start Zone rule is set, send new chars there
	if(SoFClient && (RuleI(World, SoFStartZoneID) > 0)) {
		clog(WORLD__CLIENT,"Found 'SoFStartZoneID' rule setting: %i", (RuleI(World, SoFStartZoneID)));
		pp.zone_id = (RuleI(World, SoFStartZoneID));
		if(pp.zone_id)
			database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
		else
			clog(WORLD__CLIENT_ERR,"Error getting zone id for Zone ID %i", (RuleI(World, SoFStartZoneID)));
	}
	else
	{
		// if there's a startzone variable put them in there
		if(database.GetVariable("startzone", startzone, 50))
		{
			clog(WORLD__CLIENT,"Found 'startzone' variable setting: %s", startzone);
			pp.zone_id = database.GetZoneID(startzone);
			if(pp.zone_id)
				database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
			else
				clog(WORLD__CLIENT_ERR,"Error getting zone id for '%s'", startzone);
		}
		else   // otherwise use normal starting zone logic
		{
			if(!SoFClient)
				database.GetStartZone(&pp, cc);
			else
				database.GetStartZoneSoF(&pp, cc);
		}
	}

	if(!pp.zone_id)
	{
		pp.zone_id = 1;		// qeynos
		pp.x = pp.y = pp.z = -1;
	}

	if(!pp.binds[0].zoneId)
	{
		pp.binds[0].zoneId = pp.zone_id;
		pp.binds[0].x = pp.x;
		pp.binds[0].y = pp.y;
		pp.binds[0].z = pp.z;
		pp.binds[0].heading = pp.heading;
 	}

	// set starting city location to the initial bind point
	pp.binds[4] = pp.binds[0];


	clog(WORLD__CLIENT,"Current location: %s  %0.2f, %0.2f, %0.2f",
		database.GetZoneName(pp.zone_id), pp.x, pp.y, pp.z);
	clog(WORLD__CLIENT,"Bind location: %s  %0.2f, %0.2f, %0.2f",
		database.GetZoneName(pp.binds[0].zoneId), pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);


	// Starting Items inventory
	database.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());


	// now we give the pp and the inv we made to StoreCharacter
	// to see if we can store it
	if (!database.StoreCharacter(GetAccountID(), &pp, &inv, &ext))
	{
		clog(WORLD__CLIENT_ERR,"Character creation failed: %s", pp.name);
		return false;
	}
	else
	{
		clog(WORLD__CLIENT,"Character creation successful: %s", pp.name);
		return true;
	}
}

// returns true if the request is ok, false if there's an error
bool CheckCharCreateInfo(CharCreate_Struct *cc)
{
	int32 bSTR, bSTA, bAGI, bDEX, bWIS, bINT, bCHA, bTOTAL, cTOTAL, stat_points;	//these are all int32 in CharCreate_Struct, so we'll make them int32 here to make the compiler shut up
	int classtemp, racetemp;
	int Charerrors = 0;


// solar: if this is increased you'll have to add a column to the classrace
// table below
#define _TABLE_RACES	16

	static const int BaseRace[_TABLE_RACES][7] =
	{            /* STR  STA  AGI  DEX  WIS  INT  CHR */
	{ /*Human*/      75,  75,  75,  75,  75,  75,  75},
	{ /*Barbarian*/ 103,  95,  82,  70,  70,  60,  55},
	{ /*Erudite*/    60,  70,  70,  70,  83, 107,  70},
	{ /*Wood Elf*/   65,  65,  95,  80,  80,  75,  75},
	{ /*High Elf*/   55,  65,  85,  70,  95,  92,  80},
	{ /*Dark Elf*/   60,  65,  90,  75,  83,  99,  60},
	{ /*Half Elf*/   70,  70,  90,  85,  60,  75,  75},
	{ /*Dwarf*/      90,  90,  70,  90,  83,  60,  45},
	{ /*Troll*/     108, 109,  83,  75,  60,  52,  40},
	{ /*Ogre*/      130, 122,  70,  70,  67,  60,  37},
	{ /*Halfling*/   70,  75,  95,  90,  80,  67,  50},
	{ /*Gnome*/      60,  70,  85,  85,  67,  98,  60},
	{ /*Iksar*/      70,  70,  90,  85,  80,  75,  55},
	{ /*Vah Shir*/   90,  75,  90,  70,  70,  65,  65},
	{ /*Froglok*/    70,  80, 100, 100,  75,  75,  50},
	{ /*Drakkin*/    70,  80,  85,  75,  80,  85,  75}
	};

	static const int BaseClass[PLAYER_CLASS_COUNT][8] =
	{              /* STR  STA  AGI  DEX  WIS  INT  CHR  ADD*/
	{ /*Warrior*/      10,  10,   5,   0,   0,   0,   0,  25},
	{ /*Cleric*/        5,   5,   0,   0,  10,   0,   0,  30},
	{ /*Paladin*/      10,   5,   0,   0,   5,   0,  10,  20},
	{ /*Ranger*/        5,  10,  10,   0,   5,   0,   0,  20},
	{ /*ShadowKnight*/ 10,   5,   0,   0,   0,   10,  5,  20},
	{ /*Druid*/         0,  10,   0,   0,  10,   0,   0,  30},
	{ /*Monk*/          5,   5,  10,  10,   0,   0,   0,  20},
	{ /*Bard*/          5,   0,   0,  10,   0,   0,  10,  25},
	{ /*Rouge*/         0,   0,  10,  10,   0,   0,   0,  30},
	{ /*Shaman*/        0,   5,   0,   0,  10,   0,   5,  30},
	{ /*Necromancer*/   0,   0,   0,  10,   0,  10,   0,  30},
	{ /*Wizard*/        0,  10,   0,   0,   0,  10,   0,  30},
	{ /*Magician*/      0,  10,   0,   0,   0,  10,   0,  30},
	{ /*Enchanter*/     0,   0,   0,   0,   0,  10,  10,  30},
	{ /*Beastlord*/     0,  10,   5,   0,  10,   0,   5,  20},
	{ /*Berserker*/    10,   5,   0,  10,   0,   0,   0,  25}
	};

	static const bool ClassRaceLookupTable[PLAYER_CLASS_COUNT][_TABLE_RACES]=
	{                   /*Human  Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf  Troll  Ogre   Halfling Gnome  Iksar  Vahshir Froglok Drakkin*/
	{ /*Warrior*/         true,  true,     false,  true,   false,  true,   true,   true,  true,  true,  true,    true,  true,  true,   true,   true},
	{ /*Cleric*/          true,  false,    true,   false,  true,   true,   true,   true,  false, false, true,    true,  false, false,  true,   true},
	{ /*Paladin*/         true,  false,    true,   false,  true,   false,  true,   true,  false, false, true,    true,  false, false,  true,   true},
	{ /*Ranger*/          true,  false,    false,  true,   false,  false,  true,   false, false, false, true,    false, false, false,  false,  true},
	{ /*ShadowKnight*/    true,  false,    true,   false,  false,  true,   false,  false, true,  true,  false,   true,  true,  false,  true,   true},
	{ /*Druid*/           true,  false,    false,  true,   false,  false,  true,   false, false, false, true,    false, false, false,  false,  true},
	{ /*Monk*/            true,  false,    false,  false,  false,  false,  false,  false, false, false, false,   false, true,  false,  false,  true},
	{ /*Bard*/            true,  false,    false,  true,   false,  false,  true,   false, false, false, false,   false, false, true,   false,  true},
	{ /*Rogue*/           true,  true,     false,  true,   false,  true,   true,   true,  false, false, true,    true,  false, true,   true,   true},
	{ /*Shaman*/          false, true,     false,  false,  false,  false,  false,  false, true,  true,  false,   false, true,  true,   true,   false},
	{ /*Necromancer*/     true,  false,    true,   false,  false,  true,   false,  false, false, false, false,   true,  true,  false,  true,   true},
	{ /*Wizard*/          true,  false,    true,   false,  true,   true,   false,  false, false, false, false,   true,  false, false,  true,   true},
	{ /*Magician*/        true,  false,    true,   false,  true,   true,   false,  false, false, false, false,   true,  false, false,  false,  true},
	{ /*Enchanter*/       true,  false,    true,   false,  true,   true,   false,  false, false, false, false,   true,  false, false,  false,  true},
	{ /*Beastlord*/       false, true,     false,  false,  false,  false,  false,  false, true,  true,  false,   false, true,  true,   false,  false},
	{ /*Berserker*/       false, true,     false,  false,  false,  false,  false,  true,  true,  true,  false,   false, false, true,   false,  false}
	};//Initial table by kathgar, editted by Wiz for accuracy, solar too

	if(!cc) return false;

	_log(WORLD__CLIENT,"Validating char creation info...");

	classtemp = cc->class_ - 1;
	racetemp = cc->race - 1;
	// these have non sequential race numbers so they need to be mapped
	if (cc->race == FROGLOK) racetemp = 14;
	if (cc->race == VAHSHIR) racetemp = 13;
	if (cc->race == IKSAR) racetemp = 12;
	if (cc->race == DRAKKIN) racetemp = 15;

	// if out of range looking it up in the table would crash stuff
	// so we return from these
	if(classtemp >= PLAYER_CLASS_COUNT)
	{
		_log(WORLD__CLIENT_ERR,"  class is out of range");
		return false;
	}
	if(racetemp >= _TABLE_RACES)
	{
		_log(WORLD__CLIENT_ERR,"  race is out of range");
		return false;
	}

	if(!ClassRaceLookupTable[classtemp][racetemp]) //Lookup table better than a bunch of ifs?
	{
		_log(WORLD__CLIENT_ERR,"  invalid race/class combination");
		// we return from this one, since if it's an invalid combination our table
		// doesn't have meaningful values for the stats
		return false;
	}

	// solar: add up the base values for this class/race
	// this is what they start with, and they have stat_points more
	// that can distributed
	bSTR = BaseClass[classtemp][0] + BaseRace[racetemp][0];
	bSTA = BaseClass[classtemp][1] + BaseRace[racetemp][1];
	bAGI = BaseClass[classtemp][2] + BaseRace[racetemp][2];
	bDEX = BaseClass[classtemp][3] + BaseRace[racetemp][3];
	bWIS = BaseClass[classtemp][4] + BaseRace[racetemp][4];
	bINT = BaseClass[classtemp][5] + BaseRace[racetemp][5];
	bCHA = BaseClass[classtemp][6] + BaseRace[racetemp][6];
	stat_points = BaseClass[classtemp][7];
	bTOTAL = bSTR + bSTA + bAGI + bDEX + bWIS + bINT + bCHA;
	cTOTAL = cc->STR + cc->STA + cc->AGI + cc->DEX + cc->WIS + cc->INT + cc->CHA;

	// solar: the first check makes sure the total is exactly what was expected.
	// this will catch all the stat cheating, but there's still the issue
	// of reducing CHA or INT or something, to use for STR, so we check
	// that none are lower than the base or higher than base + stat_points
	// NOTE: these could just be else if, but i want to see all the stats
	// that are messed up not just the first hit

	if(bTOTAL + stat_points != cTOTAL)
	{
		_log(WORLD__CLIENT_ERR,"  stat points total doesn't match expected value: expecting %d got %d", bTOTAL + stat_points, cTOTAL);
		Charerrors++;
	}

	if(cc->STR > bSTR + stat_points || cc->STR < bSTR)
	{
		_log(WORLD__CLIENT_ERR,"  stat STR is out of range");
		Charerrors++;
	}
	if(cc->STA > bSTA + stat_points || cc->STA < bSTA)
	{
		_log(WORLD__CLIENT_ERR,"  stat STA is out of range");
		Charerrors++;
	}
	if(cc->AGI > bAGI + stat_points || cc->AGI < bAGI)
	{
		_log(WORLD__CLIENT_ERR,"  stat AGI is out of range");
		Charerrors++;
	}
	if(cc->DEX > bDEX + stat_points || cc->DEX < bDEX)
	{
		_log(WORLD__CLIENT_ERR,"  stat DEX is out of range");
		Charerrors++;
	}
	if(cc->WIS > bWIS + stat_points || cc->WIS < bWIS)
	{
		_log(WORLD__CLIENT_ERR,"  stat WIS is out of range");
		Charerrors++;
	}
	if(cc->INT > bINT + stat_points || cc->INT < bINT)
	{
		_log(WORLD__CLIENT_ERR,"  stat INT is out of range");
		Charerrors++;
	}
	if(cc->CHA > bCHA + stat_points || cc->CHA < bCHA)
	{
		_log(WORLD__CLIENT_ERR,"  stat CHA is out of range");
		Charerrors++;
	}

	/*TODO: Check for deity/class/race.. it'd be nice, but probably of any real use to hack(faction, deity based items are all I can think of)
	I am NOT writing those tables - kathgar*/

	_log(WORLD__CLIENT,"Found %d errors in character creation request", Charerrors);

	return Charerrors == 0;
}

void Client::SetClassStartingSkills( PlayerProfile_Struct *pp )
{
   switch( pp->class_ )
   {
   case BARD:
      {
         pp->skills[_1H_SLASHING] = 5;
         pp->skills[SINGING] = 5;
         break;
      }
   case BEASTLORD:
      {
         pp->skills[HAND_TO_HAND] = 5;
         break;
      }
   case BERSERKER: // A Guess
      {
         pp->skills[_2H_SLASHING] = 5;
         break;
      }
   case CLERIC:
      {
         pp->skills[_1H_BLUNT] = 5;
         break;
      }
   case DRUID:
      {
         pp->skills[_1H_BLUNT] = 5;
         break;
      }
   case ENCHANTER:
      {
         pp->skills[PIERCING] = 5;
         break;
      }
   case MAGICIAN:
      {
         pp->skills[PIERCING] = 5;
         break;
      }
   case MONK:
      {
         pp->skills[DODGE] = 5;
         pp->skills[DUAL_WIELD] = 5;
         pp->skills[HAND_TO_HAND] = 5;
         break;
      }
   case NECROMANCER:
      {
         pp->skills[PIERCING] = 5;
         break;
      }
   case PALADIN:
      {
         pp->skills[_1H_SLASHING] = 5;
         break;
      }
   case RANGER:
      {
         pp->skills[_1H_SLASHING] = 5;
         break;
      }
   case ROGUE:
      {
         pp->skills[PIERCING] = 5;
         pp->languages[LANG_THIEVES_CANT] = 100; // Thieves Cant
         break;
      }
   case SHADOWKNIGHT:
      {
         pp->skills[_1H_SLASHING] = 5;
         break;
      }
   case SHAMAN:
      {
         pp->skills[_1H_BLUNT] = 5;
         break;
      }
   case WARRIOR:
      {
         pp->skills[_1H_SLASHING] = 5;
         break;
      }
   case WIZARD:
      {
         pp->skills[PIERCING] = 5;
         break;
      }
   }
}

void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
{
   switch( pp->race )
   {
   case BARBARIAN:
   case DWARF:
   case ERUDITE:
   case HALF_ELF:
   case HIGH_ELF:
   case HUMAN:
   case OGRE:
   case TROLL:
   case DRAKKIN:	//Drakkin are supposed to get a starting AA Skill
      {
         // No Race Specific Skills
         break;
      }
   case DARK_ELF:
      {
         pp->skills[HIDE] = 50;
         break;
      }
   case FROGLOK:
      {
         pp->skills[SWIMMING] = 125;
         break;
      }
   case GNOME:
      {
         pp->skills[TINKERING] = 50;
         break;
      }
   case HALFLING:
      {
         pp->skills[HIDE] = 50;
         pp->skills[SNEAK] = 50;
         break;
      }
   case IKSAR:
      {
         pp->skills[FORAGE] = 50;
         pp->skills[SWIMMING] = 100;
         break;
      }
   case WOOD_ELF:
      {
         pp->skills[FORAGE] = 50;
         pp->skills[HIDE] = 50;
         break;
      }
   case VAHSHIR:
      {
         pp->skills[SAFE_FALL] = 50;
         pp->skills[SNEAK] = 50;
         break;
      }
   }
}

void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
{
   switch( pp->race )
   {
   case BARBARIAN:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_BARBARIAN] = 100;
         break;
      }
   case DARK_ELF:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_DARK_ELVISH] = 100;
         pp->languages[LANG_DARK_SPEECH] = 100;
         pp->languages[LANG_ELDER_ELVISH] = 100;
         pp->languages[LANG_ELVISH] = 25;
         break;
      }
   case DWARF:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_DWARVISH] = 100;
         pp->languages[LANG_GNOMISH] = 25;
         break;
      }
   case ERUDITE:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_ERUDIAN] = 100;
         break;
      }
   case FROGLOK:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_FROGLOK] = 100;
         pp->languages[LANG_TROLL] = 25;
         break;
      }
   case GNOME:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_DWARVISH] = 25;
         pp->languages[LANG_GNOMISH] = 100;
         break;
      }
   case HALF_ELF:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_ELVISH] = 100;
         break;
      }
   case HALFLING:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_HALFLING] = 100;
         break;
      }
   case HIGH_ELF:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_DARK_ELVISH] = 25;
         pp->languages[LANG_ELDER_ELVISH] = 25;
         pp->languages[LANG_ELVISH] = 100;
         break;
      }
   case HUMAN:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         break;
      }
   case IKSAR:
      {
         pp->languages[LANG_COMMON_TONGUE] = 95;
         pp->languages[LANG_DARK_SPEECH] = 100;
         pp->languages[LANG_LIZARDMAN] = 100;
         break;
      }
   case OGRE:
      {
         pp->languages[LANG_COMMON_TONGUE] = 95;
         pp->languages[LANG_DARK_SPEECH] = 100;
         pp->languages[LANG_OGRE] = 100;
         break;
      }
   case TROLL:
      {
         pp->languages[LANG_COMMON_TONGUE] = 95;
         pp->languages[LANG_DARK_SPEECH] = 100;
         pp->languages[LANG_TROLL] = 100;
         break;
      }
   case WOOD_ELF:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_ELVISH] = 100;
         break;
      }
   case VAHSHIR:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_COMBINE_TONGUE] = 100;
         pp->languages[LANG_ERUDIAN] = 25;
         pp->languages[LANG_VAH_SHIR] = 100;
         break;
      }
   case DRAKKIN:
      {
         pp->languages[LANG_COMMON_TONGUE] = 100;
         pp->languages[LANG_ELDER_DRAGON] = 100;
         pp->languages[LANG_DRAGON] = 100;
         break;
      }
   }
}
Note: client.cpp also includes a fix for dual MOTD, so you need to add the variable;
Code:
INSERT INTO `variables` VALUES ('MOTDEqEmu','Welcome to AXCLASSIC!','Server Message of the Day','2010-01-08 13:19:53');
So you can specify different MOTDs on different LS.

cliententry.cpp
Code:
#include "../common/debug.h"
#include "cliententry.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "worlddb.h"
#include "zoneserver.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
extern int32 numplayers;
extern LoginServer loginserver;
extern ClientList		client_list;
extern volatile bool RunLoops;

ClientListEntry::ClientListEntry(int32 in_id, int32 iLSID, const char* iLoginName, const char* iLoginKey, sint16 iWorldAdmin, int32 ip, uint8 local)
: id(in_id)
{
	ClearVars(true);
	
	pIP = ip;
	pLSID = iLSID;
	if(iLSID > 0)
		paccountid = database.GetAccountIDFromLSID(iLSID, paccountname, &padmin);
	strn0cpy(plsname, iLoginName, sizeof(plsname));
	strn0cpy(plskey, iLoginKey, sizeof(plskey));
	pworldadmin = iWorldAdmin;
	plocal=(local==1);

	pinstance = 0;
}

ClientListEntry::ClientListEntry(int32 in_id, int32 iAccID, const char* iAccName, MD5& iMD5Pass, sint16 iAdmin)
: id(in_id)
{
	ClearVars(true);
	
	pIP = 0;
	pLSID = 0;
	pworldadmin = 0;

	paccountid = iAccID;
	strn0cpy(paccountname, iAccName, sizeof(paccountname));
	pMD5Pass = iMD5Pass;
	padmin = iAdmin;

	pinstance = 0;
}

ClientListEntry::ClientListEntry(int32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline)
: id(in_id)
{
	ClearVars(true);
	
	pIP = 0;
	pLSID = scl->LSAccountID;
	strn0cpy(plsname, scl->name, sizeof(plsname));
	strn0cpy(plskey, scl->lskey, sizeof(plskey));
	pworldadmin = 0;

	paccountid = scl->AccountID;
	strn0cpy(paccountname, scl->AccountName, sizeof(paccountname));
	padmin = scl->Admin;

	pinstance = 0;

	if (iOnline >= CLE_Status_Zoning)
		Update(iZS, scl, iOnline);
	else
		SetOnline(iOnline);
}

ClientListEntry::~ClientListEntry() {
	if (RunLoops) {
		Camp(); // updates zoneserver's numplayers
		client_list.RemoveCLEReferances(this);
	}
}

void ClientListEntry::SetChar(int32 iCharID, const char* iCharName) {
	pcharid = iCharID;
	strn0cpy(pname, iCharName, sizeof(pname));
}

void ClientListEntry::SetOnline(ZoneServer* iZS, sint8 iOnline) {
	if (iZS == this->Server())
		SetOnline(iOnline);
}

void ClientListEntry::SetOnline(sint8 iOnline) {
	if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online)
		numplayers++;
	else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) {
		numplayers--;
	}
	if (iOnline != CLE_Status_Online || pOnline < CLE_Status_Online)
		pOnline = iOnline;
	if (iOnline < CLE_Status_Zoning)
		Camp();
	if (pOnline >= CLE_Status_Online)
		stale = 0;
}
void ClientListEntry::LSUpdate(ZoneServer* iZS){
	if(WorldConfig::get()->UpdateStats){
		ServerPacket* pack = new ServerPacket;
		pack->opcode = ServerOP_LSZoneInfo;
		pack->size = sizeof(ZoneInfo_Struct);
		pack->pBuffer = new uchar[pack->size];
		ZoneInfo_Struct* zone =(ZoneInfo_Struct*)pack->pBuffer;
		zone->count=iZS->NumPlayers();
		zone->zone = iZS->GetZoneID();
		zone->zone_wid = iZS->GetID();

#ifdef DUAL_SERVER
		loginserver.SendPacket2(pack);
#else
		loginserver.SendPacket(pack);
#endif

		safe_delete(pack);
	}
}
void ClientListEntry::LSZoneChange(ZoneToZone_Struct* ztz){
	if(WorldConfig::get()->UpdateStats){
		ServerPacket* pack = new ServerPacket;
		pack->opcode = ServerOP_LSPlayerZoneChange;
		pack->size = sizeof(ServerLSPlayerZoneChange_Struct);
		pack->pBuffer = new uchar[pack->size];
		ServerLSPlayerZoneChange_Struct* zonechange =(ServerLSPlayerZoneChange_Struct*)pack->pBuffer;
		zonechange->lsaccount_id = LSID();
		zonechange->from = ztz->current_zone_id;
		zonechange->to = ztz->requested_zone_id;
		loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
		loginserver.SendPacket2(pack);
#endif

		safe_delete(pack);
	}
}
void ClientListEntry::Update(ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline) {
	if (pzoneserver != iZS) {
		if (pzoneserver){
			pzoneserver->RemovePlayer();
			LSUpdate(pzoneserver);
		}
		if (iZS){
			iZS->AddPlayer();
			LSUpdate(iZS);
		}
	}
	pzoneserver = iZS;
	pzone = scl->zone;
	pinstance = scl->instance_id;
	pcharid = scl->charid;

	strcpy(pname, scl->name);
	if (paccountid == 0) {
		paccountid = scl->AccountID;
		strcpy(paccountname, scl->AccountName);
		strcpy(plsname, scl->AccountName);
		pIP = scl->IP;
		pLSID = scl->LSAccountID;
		strn0cpy(plskey, scl->lskey, sizeof(plskey));
	}
	padmin = scl->Admin;
	plevel = scl->level;
	pclass_ = scl->class_;
	prace = scl->race;
	panon = scl->anon;
	ptellsoff = scl->tellsoff;
	pguild_id = scl->guild_id;
	pLFG = scl->LFG;
	gm = scl->gm;
	// Fields from the LFG Window
	if((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
		pLFGFromLevel = scl->LFGFromLevel;
		pLFGToLevel = scl->LFGToLevel;
		pLFGMatchFilter = scl->LFGMatchFilter;
		memcpy(pLFGComments, scl->LFGComments, sizeof(pLFGComments));
	}

	SetOnline(iOnline);
}

void ClientListEntry::LeavingZone(ZoneServer* iZS, sint8 iOnline) {
	if (iZS != 0 && iZS != pzoneserver)
		return;
	SetOnline(iOnline);

	if (pzoneserver){
		pzoneserver->RemovePlayer();
		LSUpdate(pzoneserver);
	}
	pzoneserver = 0;
	pzone = 0;
}

void ClientListEntry::ClearVars(bool iAll) {
	if (iAll) {
		pOnline = CLE_Status_Never;
		stale = 0;

		pLSID = 0;
		memset(plsname, 0, sizeof(plsname));
		memset(plskey, 0, sizeof(plskey));
		pworldadmin = 0;

		paccountid = 0;
		memset(paccountname, 0, sizeof(paccountname));
		padmin = 0;
	}
	pzoneserver = 0;
	pzone = 0;
	pcharid = 0;
	memset(pname, 0, sizeof(pname));
	plevel = 0;
	pclass_ = 0;
	prace = 0;
	panon = 0;
	ptellsoff = 0;
	pguild_id = GUILD_NONE;
	pLFG = 0;
	gm = 0;
}

void ClientListEntry::Camp(ZoneServer* iZS) {
	if (iZS != 0 && iZS != pzoneserver)
		return;
	if (pzoneserver){
		pzoneserver->RemovePlayer();
		LSUpdate(pzoneserver);
	}

	ClearVars();

	stale = 0;
}

bool ClientListEntry::CheckStale() {
	stale++;
	if (stale >= 3) {
		if (pOnline > CLE_Status_Offline)
			SetOnline(CLE_Status_Offline);
		else
			return true;
	}
	return false;
}

bool ClientListEntry::CheckAuth(int32 iLSID, const char* iKey) {
//	if (LSID() == iLSID && strncmp(plskey, iKey,10) == 0) {
	if (strncmp(plskey, iKey,10) == 0) {
		if (paccountid == 0 && LSID()>0) {
			sint16 tmpStatus = WorldConfig::get()->DefaultStatus;
			paccountid = database.CreateAccount(plsname, 0, tmpStatus, LSID());
			if (!paccountid) {
				_log(WORLD__CLIENTLIST_ERR,"Error adding local account for LS login: '%s', either duplicate name or adding a second LS account will do this, if latter, try again." ,plsname);
				return false;
			}
			strn0cpy(paccountname, plsname, sizeof(paccountname));
			padmin = tmpStatus;
		}
		char lsworldadmin[15] = "0";
		database.GetVariable("honorlsworldadmin", lsworldadmin, sizeof(lsworldadmin));
		if (atoi(lsworldadmin) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0))
			padmin = pworldadmin;
		return true;
	}
	return false;
}

bool ClientListEntry::CheckAuth(const char* iName, MD5& iMD5Password) {
	if (LSAccountID() == 0 && strcmp(paccountname, iName) == 0 && pMD5Pass == iMD5Password)
		return true;
	return false;
}

bool ClientListEntry::CheckAuth(int32 id, const char* iKey, int32 ip) {
	if (pIP==ip && strncmp(plskey, iKey,10) == 0){
		paccountid = id;
		database.GetAccountFromID(id,paccountname,&padmin);
		return true;
	}
	return false;
}
zoneserver.cpp
Code:
#include "../common/debug.h"
#include "zoneserver.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "zonelist.h"
#include "worlddb.h"
#include "console.h"
#include "client.h"
#include "../common/md5.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
#include "../common/packet_dump.h"
#include "../common/misc.h"
#include "cliententry.h"
#include "wguild_mgr.h"
#include "lfplist.h"
extern ClientList	client_list;
extern GroupLFPList LFPGroupList;
extern ZSList		zoneserver_list;
extern ConsoleList		console_list;
extern LoginServer loginserver;
extern volatile bool RunLoops;

ZoneServer::ZoneServer(EmuTCPConnection* itcpc) 
: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) {
	ID = zoneserver_list.GetNextID();
	memset(zone_name, 0, sizeof(zone_name));
	memset(compiled, 0, sizeof(compiled));
	zoneID = 0;
	instanceID = 0;

	memset(clientaddress, 0, sizeof(clientaddress));
	clientport = 0;
	BootingUp = false;
	authenticated = false;
	staticzone = false;
	pNumPlayers = 0;
}

ZoneServer::~ZoneServer() {
	if (RunLoops)
		client_list.CLERemoveZSRef(this);
	tcpc->Free();
}

bool ZoneServer::SetZone(int32 iZoneID, int32 iInstanceID, bool iStaticZone) {
	BootingUp = false;
	
	const char* zn = MakeLowerString(database.GetZoneName(iZoneID));
	char*	longname;

	if (iZoneID)
		zlog(WORLD__ZONE,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID, 
			iStaticZone ? " (Static)" : "");

	zoneID = iZoneID;
	instanceID = iInstanceID;
	if(iZoneID!=0)
		oldZoneID = iZoneID;
	if (zoneID == 0) {
		client_list.CLERemoveZSRef(this);
		pNumPlayers = 0;
		LSSleepUpdate(GetPrevZoneID());
	}

	staticzone = iStaticZone;

	if (zn)
	{
		strcpy(zone_name, zn);
		if( database.GetZoneLongName( (char*)zone_name, &longname, NULL, NULL, NULL, NULL, NULL, NULL ) )
		{
			strcpy(long_name, longname);
			safe_delete( longname );
		}
		else
			strcpy(long_name, "");
	}
	else
	{
		strcpy(zone_name, "");
		strcpy(long_name, "");
	}	

	client_list.ZoneBootup(this);
	ls_zboot.Start();

	return true;
}

void ZoneServer::LSShutDownUpdate(int32 zoneid){
	if(WorldConfig::get()->UpdateStats){
		ServerPacket* pack = new ServerPacket;
		pack->opcode = ServerOP_LSZoneShutdown;
		pack->size = sizeof(ZoneShutdown_Struct);
		pack->pBuffer = new uchar[pack->size];
		memset(pack->pBuffer,0,pack->size);
		ZoneShutdown_Struct* zsd =(ZoneShutdown_Struct*)pack->pBuffer;
		if(zoneid==0)
			zsd->zone = GetPrevZoneID();
		else
			zsd->zone = zoneid;
		zsd->zone_wid = GetID();
		loginserver.SendPacket(pack);
		
#ifdef DUAL_SERVER
		loginserver.SendPacket2(pack);
#endif

		safe_delete(pack);
	}
}
void ZoneServer::LSBootUpdate(int32 zoneid, int32 instanceid, bool startup){
	if(WorldConfig::get()->UpdateStats){
		ServerPacket* pack = new ServerPacket;
		if(startup)
			pack->opcode = ServerOP_LSZoneStart;
		else
			pack->opcode = ServerOP_LSZoneBoot;
		pack->size = sizeof(ZoneBoot_Struct);
		pack->pBuffer = new uchar[pack->size];
		memset(pack->pBuffer,0,pack->size);
		ZoneBoot_Struct* bootup =(ZoneBoot_Struct*)pack->pBuffer;
		if(startup)
			strcpy(bootup->compile_time,GetCompileTime());
		bootup->zone = zoneid;
		bootup->zone_wid = GetID();
		bootup->instance = instanceid;
		loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
		loginserver.SendPacket2(pack);
#endif
		safe_delete(pack);
	}
}

void ZoneServer::LSSleepUpdate(int32 zoneid){
	if(WorldConfig::get()->UpdateStats){
		ServerPacket* pack = new ServerPacket;
		pack->opcode = ServerOP_LSZoneSleep;
		pack->size = sizeof(ServerLSZoneSleep_Struct);
		pack->pBuffer = new uchar[pack->size];
		memset(pack->pBuffer,0,pack->size);
		ServerLSZoneSleep_Struct* sleep =(ServerLSZoneSleep_Struct*)pack->pBuffer;
		sleep->zone = zoneid;
		sleep->zone_wid = GetID();
		loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
		loginserver.SendPacket2(pack);
#endif

		safe_delete(pack);
	}
}

bool ZoneServer::Process() {
	if (!tcpc->Connected())
		return false;
	if(ls_zboot.Check()){
		LSBootUpdate(GetZoneID(), true);
		ls_zboot.Disable();
	}
	ServerPacket *pack = 0;
	while((pack = tcpc->PopPacket())) {
		_hex(WORLD__ZONE_TRACE,pack->pBuffer,pack->size);
		if (!authenticated) {
			if (WorldConfig::get()->SharedKey.length() > 0) {
				if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) {
					int8 tmppass[16];
					MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass);
					if (memcmp(pack->pBuffer, tmppass, 16) == 0)
						authenticated = true;
					else {
						struct in_addr  in;
						in.s_addr = GetIP();
						zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
						ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
						SendPacket(pack);
						delete pack;
						Disconnect();
						return false;
					}
				}
				else {
					struct in_addr  in;
					in.s_addr = GetIP();
					zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
					ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
					SendPacket(pack);
					delete pack;
					Disconnect();
					return false;
				}
			}
			else
			{
				_log(WORLD__ZONE,"**WARNING** You have not configured a world shared key in your config file. You should add a <key>STRING</key> element to your <world> element to prevent unauthroized zone access.");
				authenticated = true;
			}
		}
		switch(pack->opcode) {
		case 0:
			break;
		case ServerOP_KeepAlive: {
			// ignore this
			break;
		}
		case ServerOP_ZAAuth: {
			break;
		}
		case ServerOP_LSZoneBoot:{
			if(pack->size==sizeof(ZoneBoot_Struct)){
				ZoneBoot_Struct* zbs= (ZoneBoot_Struct*)pack->pBuffer;
				SetCompile(zbs->compile_time);
			}
			break;
		}
		/*
		case ServerOP_SendGroup: {
			SendGroup_Struct* sgs=(SendGroup_Struct*)pack->pBuffer;
			ZoneServer* zs=zoneserver_list.FindByZoneID(sgs->zoneid);
			if(!zs)
				zlog(WORLD__ZONE,"Could not find zone id: %i running to transfer group to!",sgs->zoneid);
			else{
				zs->SendPacket(pack);
			}
			break;
		}*/
		case ServerOP_GroupIDReq: {
			SendGroupIDs();
			break;
		}
		case ServerOP_GroupLeave: {
			if(pack->size != sizeof(ServerGroupLeave_Struct))
				break;
			zoneserver_list.SendPacket(pack); //bounce it to all zones
			break;
		}

		case ServerOP_GroupJoin: {
			if(pack->size != sizeof(ServerGroupJoin_Struct))
				break;
			zoneserver_list.SendPacket(pack); //bounce it to all zones
			break;
		}

		case ServerOP_ForceGroupUpdate: {
			if(pack->size != sizeof(ServerForceGroupUpdate_Struct))
				break;
			zoneserver_list.SendPacket(pack); //bounce it to all zones
			break;
		}

		case ServerOP_OOZGroupMessage: {
			zoneserver_list.SendPacket(pack); //bounce it to all zones
			break;
		}

		case ServerOP_DisbandGroup: {
			if(pack->size != sizeof(ServerDisbandGroup_Struct))
				break;
			zoneserver_list.SendPacket(pack); //bounce it to all zones
			break;
		}

		case ServerOP_RaidAdd:{
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidRemove: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidDisband: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidLockFlag: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidChangeGroup: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_UpdateGroup: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidGroupDisband: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidGroupAdd: {
			if(pack->size != sizeof(ServerRaidGroupAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidGroupRemove: {
			if(pack->size != sizeof(ServerRaidGroupAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidGroupSay: {
			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidSay: {
			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidGroupLeader: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_RaidLeader: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_DetailsChange: {
			if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
				break;

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_SpawnCondition: {
			if(pack->size != sizeof(ServerSpawnCondition_Struct))
				break;
			//bounce the packet to the correct zone server, if its up
			ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer;
			zoneserver_list.SendPacket(ssc->zoneID, 0, pack);
			break;
		}
		case ServerOP_SpawnEvent: {
			if(pack->size != sizeof(ServerSpawnEvent_Struct))
				break;
			//bounce the packet to the correct zone server, if its up
			ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer;
			zoneserver_list.SendPacket(sse->zoneID, 0, pack);
			break;
		}
		case ServerOP_ChannelMessage: {
			ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer;
			if (scm->chan_num == 7 || scm->chan_num == 14) {
				if (scm->deliverto[0] == '*') {
					Console* con = 0;
					con = console_list.FindByAccountName(&scm->deliverto[1]);
					if (((!con) || (!con->SendChannelMessage(scm))) && (!scm->noreply))
						zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
					break;
				}
				ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
				if (cle == 0 || cle->Online() < CLE_Status_Zoning || (cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
					if (!scm->noreply)
						zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
				}
				else if (cle->Online() == CLE_Status_Zoning) {
					if (!scm->noreply) {
						char errbuf[MYSQL_ERRMSG_SIZE];
						char *query = 0;
						MYSQL_RES *result;
						//MYSQL_ROW row;   Trumpcard - commenting.  Currently unused.
						time_t rawtime;
						struct tm * timeinfo;
						time ( &rawtime );
						timeinfo = localtime ( &rawtime );
						char *telldate=asctime(timeinfo);
						if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT name from character_ where name='%s'",scm->deliverto), errbuf, &result)) {
							safe_delete(query);
							if (result!=0) {
								if (database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO tellque (Date,Receiver,Sender,Message) values('%s','%s','%s','%s')",telldate,scm->deliverto,scm->from,scm->message), errbuf, &result))
									zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "Your message has been added to the %s's que.", scm->to);
								else
									zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
								safe_delete(query);
							}
							else
								zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
							mysql_free_result(result);
						}
						else
							safe_delete(query);
					}
				//		zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
				}
				else if (cle->Server() == 0) {
					if (!scm->noreply)
						zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not contactable at this time'", scm->to, scm->to);
				}
				else
					cle->Server()->SendPacket(pack);
			}
			else {
				if (scm->chan_num == 5 || scm->chan_num == 6 || scm->chan_num == 11) {
					console_list.SendChannelMessage(scm);
				}
				zoneserver_list.SendPacket(pack);
			}
			break;
		}
		case ServerOP_EmoteMessage: {
			ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
			zoneserver_list.SendEmoteMessageRaw(sem->to, sem->guilddbid, sem->minstatus, sem->type, sem->message);
			break;
		}
		case ServerOP_VoiceMacro: {

			ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer;
			
			if(svm->Type == VoiceMacroTell) {

				ClientListEntry* cle = client_list.FindCharacter(svm->To);

				if (!cle || (cle->Online() < CLE_Status_Zoning) || !cle->Server())  {

					zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);

					break;
				}

				cle->Server()->SendPacket(pack);
			}
			else
				zoneserver_list.SendPacket(pack);

			break;
		}

		case ServerOP_RezzPlayerAccept: {
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_RezzPlayer: {

			RezzPlayer_Struct* sRezz = (RezzPlayer_Struct*) pack->pBuffer;
			if (zoneserver_list.SendPacket(pack)){
				zlog(WORLD__ZONE,"Sent Rez packet for %s",sRezz->rez.your_name);
			}
			else {
				zlog(WORLD__ZONE,"Could not send Rez packet for %s",sRezz->rez.your_name);
			}
			break;
		}
		case ServerOP_MultiLineMsg: {
			ServerMultiLineMsg_Struct* mlm = (ServerMultiLineMsg_Struct*) pack->pBuffer;
			client_list.SendPacket(mlm->to, pack);
			break;
		}
		case ServerOP_SetZone: {
			if(pack->size != sizeof(SetZone_Struct))
				break;

			SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer;	
			if (szs->zoneid != 0) {
				if(database.GetZoneName(szs->zoneid))
					SetZone(szs->zoneid, szs->instanceid, szs->staticzone);
				else
					SetZone(0);
			}
			else
				SetZone(0);

			break;
		}
		case ServerOP_SetConnectInfo: {
			if (pack->size != sizeof(ServerConnectInfo))
					break;
			ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer;

			if (!sci->port) {
				clientport=zoneserver_list.GetAvailableZonePort();

				ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo));
				memset(p.pBuffer,0,sizeof(ServerConnectInfo));
				ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer;
				sci->port = clientport;
				SendPacket(&p);
				zlog(WORLD__ZONE,"Auto zone port configuration.  Telling zone to use port %d",clientport);
			} else {
				clientport=sci->port;
				zlog(WORLD__ZONE,"Zone specified port %d, must be a previously allocated zone reconnecting.",clientport);
			}

		}
		case ServerOP_SetLaunchName: {
			if(pack->size != sizeof(LaunchName_Struct))
				break;
			const LaunchName_Struct* ln = (const LaunchName_Struct*)pack->pBuffer;
			launcher_name = ln->launcher_name;
			launched_name = ln->zone_name;
			zlog(WORLD__ZONE, "Zone started with name %s by launcher %s", launched_name.c_str(), launcher_name.c_str());
			break;
		}
		case ServerOP_ShutdownAll: {
			if(pack->size==0){
				zoneserver_list.SendPacket(pack);
				zoneserver_list.Process();
				CatchSignal(2);
			}
			else{
				WorldShutDown_Struct* wsd=(WorldShutDown_Struct*)pack->pBuffer;
				if(wsd->time==0 && wsd->interval==0 && zoneserver_list.shutdowntimer->Enabled()){
					zoneserver_list.shutdowntimer->Disable();
					zoneserver_list.reminder->Disable();
				}
				else{
					zoneserver_list.shutdowntimer->SetTimer(wsd->time);
					zoneserver_list.reminder->SetTimer(wsd->interval-1000);
					zoneserver_list.reminder->SetAtTrigger(wsd->interval);
					zoneserver_list.shutdowntimer->Start();
					zoneserver_list.reminder->Start();
				}
			}
			break;
		}
		case ServerOP_ZoneShutdown: {
			ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
			ZoneServer* zs = 0;
			if (s->ZoneServerID != 0)
				zs = zoneserver_list.FindByID(s->ZoneServerID);
			else if (s->zoneid != 0)
				zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
			else
				zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: neither ID nor name specified");

			if (zs == 0)
				zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: zoneserver not found");
			else
				zs->SendPacket(pack);
			break;
		}
		case ServerOP_ZoneBootup: {
			ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
			zoneserver_list.SOPZoneBootup(s->adminname, s->ZoneServerID, database.GetZoneName(s->zoneid), s->makestatic);
			break;
		}
		case ServerOP_ZoneStatus: {
			if (pack->size >= 1)
				zoneserver_list.SendZoneStatus((char *) &pack->pBuffer[1], (int8) pack->pBuffer[0], this);
			break;

		}
		case ServerOP_AcceptWorldEntrance: {
			if(pack->size != sizeof(WorldToZone_Struct))
				break;

			WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
			Client* client = 0;
			client = client_list.FindByAccountID(wtz->account_id);
			if(client != 0)
				client->Clearance(wtz->response);
		}
		case ServerOP_ZoneToZoneRequest: {
		//
		// solar: ZoneChange is received by the zone the player is in, then the
		// zone sends a ZTZ which ends up here.  This code then find the target
		// (ingress point) and boots it if needed, then sends the ZTZ to it.
		// The ingress server will decide wether the player can enter, then will
		// send back the ZTZ to here.  This packet is passed back to the egress
		// server, which will send a ZoneChange response back to the client
		// which can be an error, or a success, in which case the client will
		// disconnect, and their zone location will be saved when ~Client is
		// called, so it will be available when they ask to zone.
		//

			
			if(pack->size != sizeof(ZoneToZone_Struct))
				break;
			ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer;
			ClientListEntry* client = NULL;
			if(WorldConfig::get()->UpdateStats)
				client = client_list.FindCharacter(ztz->name);

			zlog(WORLD__ZONE,"ZoneToZone request for %s current zone %d req zone %d\n",
				ztz->name, ztz->current_zone_id, ztz->requested_zone_id);

			if(GetZoneID() == ztz->current_zone_id && GetInstanceID() == ztz->current_instance_id)	// this is a request from the egress zone
			{
				zlog(WORLD__ZONE,"Processing ZTZ for egress from zone for client %s\n", ztz->name);

				if
				(
					ztz->admin < 80 &&
					ztz->ignorerestrictions < 2 &&
					zoneserver_list.IsZoneLocked(ztz->requested_zone_id)
				)
				{
					ztz->response = 0;
					SendPacket(pack);
					break;
				}

				ZoneServer *ingress_server = NULL;
				if(ztz->requested_instance_id > 0)
				{
					ingress_server = zoneserver_list.FindByInstanceID(ztz->requested_instance_id);
				}
				else
				{
					ingress_server = zoneserver_list.FindByZoneID(ztz->requested_zone_id);

				}

				if(ingress_server)	// found a zone already running
				{
					_log(WORLD__ZONE,"Found a zone already booted for %s\n", ztz->name);
					ztz->response = 1;
				}
				else	// need to boot one
				{
					int server_id;
					if ((server_id = zoneserver_list.TriggerBootup(ztz->requested_zone_id, ztz->requested_instance_id))){
						_log(WORLD__ZONE,"Successfully booted a zone for %s\n", ztz->name);
						// bootup successful, ready to rock
						ztz->response = 1;
						ingress_server = zoneserver_list.FindByID(server_id);
					}
					else
					{
						_log(WORLD__ZONE_ERR,"FAILED to boot a zone for %s\n", ztz->name);
						// bootup failed, send back error code 0
						ztz->response = 0;
					}
				}
				if(ztz->response!=0 && client)
					client->LSZoneChange(ztz);
				SendPacket(pack);	// send back to egress server
				if(ingress_server)	// if we couldn't boot one, this is 0
				{
					ingress_server->SendPacket(pack);	// inform target server
				}
			}
			else	// this is response from the ingress server, route it back to the egress server
			{
				zlog(WORLD__ZONE,"Processing ZTZ for ingress to zone for client %s\n", ztz->name);
				ZoneServer *egress_server = NULL;
				if(ztz->current_instance_id > 0)
				{
					egress_server = zoneserver_list.FindByInstanceID(ztz->current_instance_id);
				}
				else
				{
					egress_server = zoneserver_list.FindByZoneID(ztz->current_zone_id);
				}

				if(egress_server)
				{
					egress_server->SendPacket(pack);
				}
			}

			break;
		}
		case ServerOP_ClientList: {
			if (pack->size != sizeof(ServerClientList_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientList. Got: %d, Expected: %d",pack->size,sizeof(ServerClientList_Struct));
				break;
			}
			client_list.ClientUpdate(this, (ServerClientList_Struct*) pack->pBuffer);
			break;
		}
		case ServerOP_ClientListKA: {
			ServerClientListKeepAlive_Struct* sclka = (ServerClientListKeepAlive_Struct*) pack->pBuffer;
			if (pack->size < 4 || pack->size != 4 + (4 * sclka->numupdates)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientListKA. Got: %d, Expected: %d",pack->size, (4 + (4 * sclka->numupdates)));
				break;
			}
			client_list.CLEKeepAlive(sclka->numupdates, sclka->wid);
			break;
		}
		case ServerOP_Who: {
			ServerWhoAll_Struct* whoall = (ServerWhoAll_Struct*) pack->pBuffer;
			Who_All_Struct* whom = new Who_All_Struct;
			memset(whom,0,sizeof(Who_All_Struct));
			whom->gmlookup = whoall->gmlookup;
			whom->lvllow = whoall->lvllow;
			whom->lvlhigh = whoall->lvlhigh;
			whom->wclass = whoall->wclass;
			whom->wrace = whoall->wrace;
			strcpy(whom->whom,whoall->whom);
			client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this);
			delete whom;
			break;
		}
		case ServerOP_FriendsWho: {
			ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer;
			client_list.SendFriendsWho(FriendsWho, this);
			break;
		}
		case ServerOP_LFGMatches: {
			ServerLFGMatchesRequest_Struct* smrs = (ServerLFGMatchesRequest_Struct*) pack->pBuffer;
			client_list.SendLFGMatches(smrs);
			break;
		}
		case ServerOP_LFPMatches: {
			ServerLFPMatchesRequest_Struct* smrs = (ServerLFPMatchesRequest_Struct*) pack->pBuffer;
			LFPGroupList.SendLFPMatches(smrs);
			break;
		}
		case ServerOP_LFPUpdate: {
			ServerLFPUpdate_Struct* sus = (ServerLFPUpdate_Struct*) pack->pBuffer;	
			if(sus->Action) 
				LFPGroupList.UpdateGroup(sus);
			else
				LFPGroupList.RemoveGroup(sus);
			break;
		}
		case ServerOP_ZonePlayer: {
			//ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer;
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_KickPlayer: {
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_KillPlayer: {
			zoneserver_list.SendPacket(pack);
			break;
		}
		
		//these opcodes get processed by the guild manager.
		case ServerOP_RefreshGuild:
		case ServerOP_DeleteGuild:
		case ServerOP_GuildCharRefresh:
		case ServerOP_GuildMemberUpdate: {
			guild_mgr.ProcessZonePacket(pack);
			break;
		}
		
		case ServerOP_FlagUpdate: {
			ClientListEntry* cle = client_list.FindCLEByAccountID(*((int32*) pack->pBuffer));
			if (cle)
				cle->SetAdmin(*((sint16*) &pack->pBuffer[4]));
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_GMGoto: {
			if (pack->size != sizeof(ServerGMGoto_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_GMGoto. Got: %d, Expected: %d",pack->size,sizeof(ServerGMGoto_Struct));
				break;
			}
			ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer;
			ClientListEntry* cle = client_list.FindCharacter(gmg->gotoname);
			if (cle != 0) {
				if (cle->Server() == 0)
					this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: Cannot identify %s's zoneserver.", gmg->gotoname);
				else if (cle->Anon() == 1 && cle->Admin() > gmg->admin) // no snooping for anon GMs
					this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
				else
					cle->Server()->SendPacket(pack);
			}
			else {
				this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
			}
			break;
		}
		case ServerOP_Lock: {
			if (pack->size != sizeof(ServerLock_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Lock. Got: %d, Expected: %d",pack->size,sizeof(ServerLock_Struct));
				break;
			}
			ServerLock_Struct* slock = (ServerLock_Struct*) pack->pBuffer;
  			if (slock->mode >= 1) 
				WorldConfig::LockWorld();
			else
				WorldConfig::UnlockWorld();
			if (loginserver.Connected()) {
				loginserver.SendStatus();
				if (slock->mode >= 1)
					this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked");
				else
					this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked");
			}
			else {
				if (slock->mode >= 1)
					this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked, but login server not connected.");
				else 
					this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked, but login server not conencted.");
			}
			break;
							}
		case ServerOP_Motd: {
			if (pack->size != sizeof(ServerMotd_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Motd. Got: %d, Expected: %d",pack->size,sizeof(ServerMotd_Struct));
				break;
			}
			ServerMotd_Struct* smotd = (ServerMotd_Struct*) pack->pBuffer;
			database.SetVariable("MOTD",smotd->motd);
			//this->SendEmoteMessage(smotd->myname, 0, 0, 13, "Updated Motd.");
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_Uptime: {
			if (pack->size != sizeof(ServerUptime_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Uptime. Got: %d, Expected: %d",pack->size,sizeof(ServerUptime_Struct));
				break;
			}
			ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
			if (sus->zoneserverid == 0) {
				ZSList::ShowUpTime(this, sus->adminname);
			}
			else {
				ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
				if (zs)
					zs->SendPacket(pack);
			}
			break;
							  }
		case ServerOP_Petition: {
			zoneserver_list.SendPacket(pack);
			break;
								}
		case ServerOP_GetWorldTime: {
			zlog(WORLD__ZONE,"Broadcasting a world time update");
			ServerPacket* pack = new ServerPacket;
			
			pack->opcode = ServerOP_SyncWorldTime;
			pack->size = sizeof(eqTimeOfDay);
			pack->pBuffer = new uchar[pack->size];
			memset(pack->pBuffer, 0, pack->size);
			eqTimeOfDay* tod = (eqTimeOfDay*) pack->pBuffer;
			tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime();
			tod->start_realtime=zoneserver_list.worldclock.getStartRealTime();
			SendPacket(pack);
			delete pack;
			break;
									}
		case ServerOP_SetWorldTime: {
			zlog(WORLD__ZONE,"Received SetWorldTime");
			eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
			zoneserver_list.worldclock.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
			zlog(WORLD__ZONE,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime);
			zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str());
			zoneserver_list.SendTimeSync();
			break;
		}
		case ServerOP_IPLookup: {
			if (pack->size < sizeof(ServerGenericWorldQuery_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_IPLookup. Got: %d, Expected (at least): %d",pack->size,sizeof(ServerGenericWorldQuery_Struct));
				break;
			}
			ServerGenericWorldQuery_Struct* sgwq = (ServerGenericWorldQuery_Struct*) pack->pBuffer;
			if (pack->size == sizeof(ServerGenericWorldQuery_Struct))
				client_list.SendCLEList(sgwq->admin, sgwq->from, this);
			else
				client_list.SendCLEList(sgwq->admin, sgwq->from, this, sgwq->query);
			break;
		}
		case ServerOP_LockZone: {
			if (pack->size < sizeof(ServerLockZone_Struct)) {
				zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_LockZone. Got: %d, Expected: %d",pack->size,sizeof(ServerLockZone_Struct));
				break;
			}
			ServerLockZone_Struct* s = (ServerLockZone_Struct*) pack->pBuffer;
			switch (s->op) {
				case 0:
					zoneserver_list.ListLockedZones(s->adminname, this);
					break;
				case 1:
					if (zoneserver_list.SetLockedZone(s->zoneID, true))
						zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(s->zoneID));
					else
						this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
					break;
				case 2:
					if (zoneserver_list.SetLockedZone(s->zoneID, false))
						zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(s->zoneID));
					else
						this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
					break;
			}
			break;
		}
		case ServerOP_ItemStatus: {
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_OOCMute: {
			zoneserver_list.SendPacket(pack);
			break;
		}
		case ServerOP_Revoke: {
			RevokeStruct* rev = (RevokeStruct*)pack->pBuffer;
			ClientListEntry* cle = client_list.FindCharacter(rev->name);
			if (cle != 0 && cle->Server() != 0)
			{
				cle->Server()->SendPacket(pack);
			}
			break;
		}
		case ServerOP_SpawnPlayerCorpse: {
			SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
			ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
			if(zs) {
				if (zs->SendPacket(pack)) {
					zlog(WORLD__ZONE,"Sent request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
				}
				else {
					zlog(WORLD__ZONE_ERR,"Could not send request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
				}
			}
			break;
		}
	    case ServerOP_Consent: {
			// Message string id's likely to be used here are:
			// CONSENT_YOURSELF = 399
			// CONSENT_INVALID_NAME = 397
			// TARGET_NOT_FOUND = 101
			ZoneServer* zs;
			ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
			ClientListEntry* cle = client_list.FindCharacter(s->grantname);
			if(cle) {
				if(cle->instance() != 0)
				{
					zs = zoneserver_list.FindByInstanceID(cle->instance());
					if(zs) {
						if(zs->SendPacket(pack)) {
							zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->instance());
						}
						else {
							zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent operation.", s->instance_id);
						}
					}
					else
					{
						delete pack;
						pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
						ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
						strcpy(scs->grantname, s->grantname);
						strcpy(scs->ownername, s->ownername);
						scs->permission = s->permission;
						scs->zone_id = s->zone_id;
						scs->instance_id = s->instance_id;
						scs->message_string_id = 101;
						zs = zoneserver_list.FindByInstanceID(s->instance_id);
						if(zs) {
							if(!zs->SendPacket(pack))
								zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
						}
						else {
							zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
						}
					}
				}
				else
				{
					zs = zoneserver_list.FindByZoneID(cle->zone());
					if(zs) {
						if(zs->SendPacket(pack)) {
							zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->zone());
						}
						else {
							zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent operation.", s->zone_id);
						}
					}
					else {
						// send target not found back to requester
						delete pack;
						pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
						ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
						strcpy(scs->grantname, s->grantname);
						strcpy(scs->ownername, s->ownername);
						scs->permission = s->permission;
						scs->zone_id = s->zone_id;
						scs->message_string_id = 101;
						zs = zoneserver_list.FindByZoneID(s->zone_id);
						if(zs) {
							if(!zs->SendPacket(pack))
								zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
						}
						else {
							zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
						}
					}
				}
			}
			else {
				// send target not found back to requester
				delete pack;
				pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
				ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
				strcpy(scs->grantname, s->grantname);
				strcpy(scs->ownername, s->ownername);
				scs->permission = s->permission;
				scs->zone_id = s->zone_id;
				scs->message_string_id = 397;
				zs = zoneserver_list.FindByZoneID(s->zone_id);
				if(zs) {
					if(!zs->SendPacket(pack))
						zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
				}
				else {
					zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
				}
			}
			break;
		}
		case ServerOP_Consent_Response: {
			// Message string id's likely to be used here are:
			// CONSENT_YOURSELF = 399
			// CONSENT_INVALID_NAME = 397
			// TARGET_NOT_FOUND = 101
			ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
			if(s->instance_id != 0)
			{
				ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id);
				if(zs) {
					if(!zs->SendPacket(pack))
						zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
				}
				else {
					zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
				}
			}
			else
			{
				ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
				if(zs) {
					if(!zs->SendPacket(pack))
						zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
				}
				else {
					zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
				}
			}
			break;
		}

		case ServerOP_InstanceUpdateTime :
		{
			ServerInstanceUpdateTime_Struct *iut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer;
			ZoneServer *zm = zoneserver_list.FindByInstanceID(iut->instance_id);
			if(zm)
			{
				zm->SendPacket(pack);
			}
			break;
		}
		case ServerOP_QGlobalUpdate:
		{
			if(pack->size != sizeof(ServerQGlobalUpdate_Struct))
		{
			break;
		}

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_QGlobalDelete:
		{
			if(pack->size != sizeof(ServerQGlobalDelete_Struct))
			{
				break;
			}

			zoneserver_list.SendPacket(pack);
			break;
		}

		case ServerOP_AdventureCreate:
		case ServerOP_AdventureAddPlayer:
		case ServerOP_AdventureDestroy: 
		case ServerOP_AdventureUpdate:
		case ServerOP_AdventureCount:
		case ServerOP_AdventureFinish:
		case ServerOP_AdventureMessage:
		case ServerOP_DepopAllPlayersCorpses:
		case ServerOP_ReloadTitles:
		case ServerOP_SpawnStatusChange:
		case ServerOP_ReloadTasks:
		case ServerOP_UpdateSpawn:
		{
			zoneserver_list.SendPacket(pack);
			break;
		}
		default:
		{
			zlog(WORLD__ZONE_ERR,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size);
			DumpPacket(pack->pBuffer, pack->size);
			break;
		}
		}

		delete pack;
	} 
	return true;
}

void ZoneServer::SendEmoteMessage(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message, ...) {
	if (!message)
		return;
	va_list argptr;
	char buffer[1024];

	va_start(argptr, message);
	vsnprintf(buffer, sizeof(buffer), message, argptr);
	va_end(argptr);
	SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
}

void ZoneServer::SendEmoteMessageRaw(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message) {
	if (!message)
		return;
	ServerPacket* pack = new ServerPacket;

	pack->opcode = ServerOP_EmoteMessage;
	pack->size = sizeof(ServerEmoteMessage_Struct)+strlen(message)+1;
	pack->pBuffer = new uchar[pack->size];
	memset(pack->pBuffer, 0, pack->size);
	ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
	
	if (to != 0) {
		strcpy((char *) sem->to, to);
	}
	else {
		sem->to[0] = 0;
	}

	sem->guilddbid = to_guilddbid;
	sem->minstatus = to_minstatus;
	sem->type = type;
	strcpy(&sem->message[0], message);
	
	pack->Deflate();
	SendPacket(pack);
	delete pack;
}

void ZoneServer::SendGroupIDs() {
	ServerPacket* pack = new ServerPacket(ServerOP_GroupIDReply, sizeof(ServerGroupIDReply_Struct));
	ServerGroupIDReply_Struct* sgi = (ServerGroupIDReply_Struct*)pack->pBuffer;
	zoneserver_list.NextGroupIDs(sgi->start, sgi->end);
	SendPacket(pack);
	delete pack;
}

void ZoneServer::ChangeWID(int32 iCharID, int32 iWID) {
	ServerPacket* pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
	ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*) pack->pBuffer;
	scw->charid = iCharID;
	scw->newwid = iWID;
	zoneserver_list.SendPacket(pack);
	delete pack;
}


void ZoneServer::TriggerBootup(int32 iZoneID, int32 iInstanceID, const char* adminname, bool iMakeStatic) {
	BootingUp = true;
	zoneID = iZoneID;
	instanceID = iInstanceID;

	ServerPacket* pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct));
	ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
	s->ZoneServerID = ID;
	if (adminname != 0)
		strcpy(s->adminname, adminname);
	
	if (iZoneID == 0)
		s->zoneid = this->GetZoneID();
	else
		s->zoneid = iZoneID;

	s->instanceid = iInstanceID;
	s->makestatic = iMakeStatic;
	SendPacket(pack);
	delete pack;
	LSBootUpdate(iZoneID, iInstanceID);
}

void ZoneServer::IncommingClient(Client* client) {
	BootingUp = true;
	ServerPacket* pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncommingClient_Struct));
	ServerZoneIncommingClient_Struct* s = (ServerZoneIncommingClient_Struct*) pack->pBuffer;
	s->zoneid = GetZoneID();
	s->instanceid = GetInstanceID();
	s->wid = client->GetWID();
	s->ip = client->GetIP();
	s->accid = client->GetAccountID();
	s->admin = client->GetAdmin();
	s->charid = client->GetCharID();
	if (client->GetCLE())
		s->tellsoff = client->GetCLE()->TellsOff();
	strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));
	strn0cpy(s->lskey, client->GetLSKey(), sizeof(s->lskey));
	SendPacket(pack);
	delete pack;
}
This was WORLD, COMMON will be on next post

Last edited by Angelox; 04-17-2010 at 08:51 PM..
Reply With Quote
  #2  
Old 04-17-2010, 11:12 AM
Angelox
AX Classic Developer
 
Join Date: May 2006
Location: filler
Posts: 2,049
Default

Note; if you have an account on your server on one lsaccount table, but the second lsaccount table is still empty, when you access the empty one for the first time, you will get bumped back to LS while it makes the account ID. after that, it works fine.
EqEmuConfig.cpp
Code:
#include "../common/debug.h"
#include "EQEmuConfig.h"
#include "MiscFunctions.h"
#include <iostream>
string EQEmuConfig::ConfigFile = "eqemu_config.xml";
EQEmuConfig *EQEmuConfig::_config = NULL;

void EQEmuConfig::do_world(TiXmlElement *ele) {
	const char *text;
	TiXmlElement * sub_ele;;

	text= ParseTextBlock(ele,"shortname");
	if (text)
		ShortName=text;

	text = ParseTextBlock(ele,"longname");
	if (text)
		LongName=text;

	text = ParseTextBlock(ele,"address",true);
	if (text)
		WorldAddress=text;

	text = ParseTextBlock(ele,"localaddress",true);
	if (text)
		LocalAddress=text;

	text = ParseTextBlock(ele,"maxclients",true);
	if (text)
		MaxClients=atoi(text);

	// Get the <key> element
	text = ParseTextBlock(ele,"key",true);
	if (text)
		SharedKey=text;

	// Get the <loginserver> element
	sub_ele = ele->FirstChildElement("loginserver");
	if (sub_ele) {
		text=ParseTextBlock(sub_ele,"host",true);
		if (text)
			LoginHost=text;

		text=ParseTextBlock(sub_ele,"port",true);
		if (text)
			LoginPort=atoi(text);
		
		text=ParseTextBlock(sub_ele,"account",true);
		if (text)
			LoginAccount=text;

		text=ParseTextBlock(sub_ele,"password",true);
		if (text)
			LoginPassword=text;

#ifdef DUAL_SERVER
		text=ParseTextBlock(sub_ele,"host2",true);
		if (text)
			LoginHost2=text;

		text=ParseTextBlock(sub_ele,"port2",true);
		if (text)
			LoginPort2=atoi(text);
		
		text=ParseTextBlock(sub_ele,"account2",true);
		if (text)
			LoginAccount2=text;

		text=ParseTextBlock(sub_ele,"password2",true);
		if (text)
			LoginPassword2=text;
#endif

	}
	
	// Check for locked
	sub_ele = ele->FirstChildElement("locked");
	if (sub_ele != NULL)
		Locked=true;

	// Get the <tcp> element
	sub_ele = ele->FirstChildElement("tcp");
	if(sub_ele != NULL) {

		text = sub_ele->Attribute("ip");
		if (text)
			WorldIP=text;

		text = sub_ele->Attribute("port");
		if (text)
			WorldTCPPort=atoi(text);

		text = sub_ele->Attribute("telnet");
		if (text && !strcasecmp(text,"enabled"))
			TelnetEnabled=true;

	}

	// Get the <http> element
	sub_ele = ele->FirstChildElement("http");
	if(sub_ele != NULL) {

//		text = sub_ele->Attribute("ip");
//		if (text)
//			WorldIP=text;

		text = sub_ele->Attribute("mimefile");
		if (text)
			WorldHTTPMimeFile=text;

		text = sub_ele->Attribute("port");
		if (text)
			WorldHTTPPort=atoi(text);

		text = sub_ele->Attribute("enabled");
		if (text && !strcasecmp(text,"true"))
			WorldHTTPEnabled=true;
		
	}
}

void EQEmuConfig::do_chatserver(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		ChatHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		ChatPort=atoi(text);
}
		
void EQEmuConfig::do_mailserver(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		MailHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		MailPort=atoi(text);
}
		
void EQEmuConfig::do_database(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		DatabaseHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		DatabasePort=atoi(text);

	text=ParseTextBlock(ele,"username",true);
	if (text)
		DatabaseUsername=text;

	text=ParseTextBlock(ele,"password",true);
	if (text)
		DatabasePassword=text;

	text=ParseTextBlock(ele,"db",true);
	if (text)
		DatabaseDB=text;
}
		
void EQEmuConfig::do_zones(TiXmlElement *ele) {
	const char *text;
	TiXmlElement *sub_ele;
//	TiXmlNode *node,*sub_node;

	text=ParseTextBlock(ele,"defaultstatus",true);
	if (text)
		DefaultStatus=atoi(text);

	// Get the <ports> element
	sub_ele = ele->FirstChildElement("ports");
	if(sub_ele != NULL) {

		text = sub_ele->Attribute("low");
		if (text)
			ZonePortLow=atoi(text);;

		text = sub_ele->Attribute("high");
		if (text)
			ZonePortHigh=atoi(text);
	}

/*	node = ele->FirstChild("start");
	if (node) {
		string s_static="static";
		string s_dynamic="dynamic";
		sub_node=NULL;
		while( (sub_node = node->IterateChildren( sub_node )) ) {
			if(sub_node->Type() != TiXmlNode::ELEMENT)
				continue;	//skip crap we dont care about

			TiXmlElement *sub_ele = (TiXmlElement *) sub_node;

			if (s_static == sub_ele->Value()) {
				const char *zone = MakeLowerString(sub_ele->Attribute("zone"));
				const char *port = sub_ele->Attribute("port");
				if (zone) {
					StaticZones[zone] = (port) ? atoi(port) : 0;
				}
			} else if (s_dynamic == sub_ele->Value()) {
				const char *count = sub_ele->Attribute("count");
				if (count) {
					DynamicCount=atoi(count);
				}
			}
		}
	}*/
}

void EQEmuConfig::do_files(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"spells",true);
	if (text)
		SpellsFile=text;

	text=ParseTextBlock(ele,"opcodes",true);
	if (text)
		OpCodesFile=text;

	text=ParseTextBlock(ele,"logsettings",true);
	if (text)
		LogSettingsFile=text;

	text=ParseTextBlock(ele,"eqtime",true);
	if (text)
		EQTimeFile=text;
}

void EQEmuConfig::do_directories(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"maps",true);
	if (text)
		MapDir=text;

	text=ParseTextBlock(ele,"quests",true);
	if (text)
		QuestDir=text;

	text=ParseTextBlock(ele,"plugins",true);
	if (text)
		PluginDir=text;

}

void EQEmuConfig::do_launcher(TiXmlElement *ele) {
	const char *text;
	TiXmlElement *sub_ele;

	text=ParseTextBlock(ele,"logprefix",true);
	if (text)
		LogPrefix = text;

	text=ParseTextBlock(ele,"logsuffix",true);
	if (text)
		LogSuffix = text;

	// Get the <exe> element
	text = ParseTextBlock(ele,"exe",true);
	if (text)
		ZoneExe = text;

	// Get the <timers> element
	sub_ele = ele->FirstChildElement("timers");
	if(sub_ele != NULL) {
		text = sub_ele->Attribute("restart");
		if (text)
			RestartWait = atoi(text);

		text = sub_ele->Attribute("reterminate");
		if (text)
			TerminateWait = atoi(text);

		text = sub_ele->Attribute("initial");
		if (text)
			InitialBootWait = atoi(text);

		text = sub_ele->Attribute("interval");
		if (text)
			ZoneBootInterval = atoi(text);
	}
}

string EQEmuConfig::GetByName(const string &var_name) const {
	if(var_name == "ShortName")
		return(ShortName);
	if(var_name == "LongName")
		return(LongName);
	if(var_name == "WorldAddress")
		return(WorldAddress);
	if(var_name == "LoginHost")
		return(LoginHost);
	if(var_name == "LoginAccount")
		return(LoginAccount);
	if(var_name == "LoginPassword")
		return(LoginPassword);
	if(var_name == "LoginPort")
		return(itoa(LoginPort));

#ifdef DUAL_SERVER
	if(var_name == "LoginHost2")
		return(LoginHost2);
	if(var_name == "LoginAccount2")
		return(LoginAccount2);
	if(var_name == "LoginPassword2")
		return(LoginPassword2);
	if(var_name == "LoginPort2")
		return(itoa(LoginPort2));
#endif

	if(var_name == "Locked")
		return(Locked?"true":"false");
	if(var_name == "WorldTCPPort")
		return(itoa(WorldTCPPort));
	if(var_name == "WorldIP")
		return(WorldIP);
	if(var_name == "TelnetEnabled")
		return(TelnetEnabled?"true":"false");
	if(var_name == "WorldHTTPPort")
		return(itoa(WorldHTTPPort));
	if(var_name == "WorldHTTPMimeFile")
		return(WorldHTTPMimeFile);
	if(var_name == "WorldHTTPEnabled")
		return(WorldHTTPEnabled?"true":"false");
	if(var_name == "ChatHost")
		return(ChatHost);
	if(var_name == "ChatPort")
		return(itoa(ChatPort));
	if(var_name == "MailHost")
		return(MailHost);
	if(var_name == "MailPort")
		return(itoa(MailPort));
	if(var_name == "DatabaseHost")
		return(DatabaseHost);
	if(var_name == "DatabaseUsername")
		return(DatabaseUsername);
	if(var_name == "DatabasePassword")
		return(DatabasePassword);
	if(var_name == "DatabaseDB")
		return(DatabaseDB);
	if(var_name == "DatabasePort")
		return(itoa(DatabasePort));
	if(var_name == "SpellsFile")
		return(SpellsFile);
	if(var_name == "OpCodesFile")
		return(OpCodesFile);
	if(var_name == "EQTimeFile")
		return(EQTimeFile);
	if(var_name == "LogSettingsFile")
		return(LogSettingsFile);
	if(var_name == "MapDir")
		return(MapDir);
	if(var_name == "QuestDir")
		return(QuestDir);
	if(var_name == "PluginDir")
		return(PluginDir);
	if(var_name == "LogPrefix")
		return(LogPrefix);
	if(var_name == "LogSuffix")
		return(LogSuffix);
	if(var_name == "ZoneExe")
		return(ZoneExe);
	if(var_name == "ZonePortLow")
		return(itoa(ZonePortLow));
	if(var_name == "ZonePortHigh")
		return(itoa(ZonePortHigh));
	if(var_name == "DefaultStatus")
		return(itoa(DefaultStatus));
//	if(var_name == "DynamicCount")
//		return(itoa(DynamicCount));
	return("");
}

void EQEmuConfig::Dump() const
{
	cout << "ShortName = " << ShortName << endl;
	cout << "LongName = " << LongName << endl;
	cout << "WorldAddress = " << WorldAddress << endl;
	cout << "LoginHost = " << LoginHost << endl;
	cout << "LoginAccount = " << LoginAccount << endl;
	cout << "LoginPassword = " << LoginPassword << endl;
	cout << "LoginPort = " << LoginPort << endl;

#ifdef DUAL_SERVER
	cout << "LoginHost2 = " << LoginHost2 << endl;
	cout << "LoginAccount2 = " << LoginAccount2 << endl;
	cout << "LoginPassword2 = " << LoginPassword2 << endl;
	cout << "LoginPort2 = " << LoginPort2 << endl;
#endif

	cout << "Locked = " << Locked << endl;
	cout << "WorldTCPPort = " << WorldTCPPort << endl;
	cout << "WorldIP = " << WorldIP << endl;
	cout << "TelnetEnabled = " << TelnetEnabled << endl;
	cout << "WorldHTTPPort = " << WorldHTTPPort << endl;
	cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << endl;
	cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << endl;
	cout << "ChatHost = " << ChatHost << endl;
	cout << "ChatPort = " << ChatPort << endl;
	cout << "MailHost = " << MailHost << endl;
	cout << "MailPort = " << MailPort << endl;
	cout << "DatabaseHost = " << DatabaseHost << endl;
	cout << "DatabaseUsername = " << DatabaseUsername << endl;
	cout << "DatabasePassword = " << DatabasePassword << endl;
	cout << "DatabaseDB = " << DatabaseDB << endl;
	cout << "DatabasePort = " << DatabasePort << endl;
	cout << "SpellsFile = " << SpellsFile << endl;
	cout << "OpCodesFile = " << OpCodesFile << endl;
	cout << "EQTimeFile = " << EQTimeFile << endl;
	cout << "LogSettingsFile = " << LogSettingsFile << endl;
	cout << "MapDir = " << MapDir << endl;
	cout << "QuestDir = " << QuestDir << endl;
	cout << "PluginDir = " << PluginDir << endl;
	cout << "ZonePortLow = " << ZonePortLow << endl;
	cout << "ZonePortHigh = " << ZonePortHigh << endl;
	cout << "DefaultStatus = " << (int)DefaultStatus << endl;
//	cout << "DynamicCount = " << DynamicCount << endl;
}
EqEmuConfig.h
Code:
#ifndef __EQEmuConfig_H
#define __EQEmuConfig_H

#include "XMLParser.h"

class EQEmuConfig : public XMLParser {
public:
	virtual string GetByName(const string &var_name) const;

	// From <world/>
	string ShortName;
	string LongName;
	string WorldAddress;
	string LocalAddress;
	string LoginHost;
	string LoginAccount;
	string LoginPassword;
	uint16 LoginPort;

#ifdef DUAL_SERVER
	string LoginHost2;
	string LoginAccount2;
	string LoginPassword2;
	uint16 LoginPort2;
#endif

	bool Locked;
	uint16 WorldTCPPort;
	string WorldIP;
	bool TelnetEnabled;
	sint32 MaxClients;
	bool WorldHTTPEnabled;
	uint16 WorldHTTPPort;
	string WorldHTTPMimeFile;
	string SharedKey;
	
	// From <chatserver/>
	string ChatHost;
	uint16 ChatPort;
	
	// From <mailserver/>
	string MailHost;
	uint16 MailPort;

	// From <database/>
	string DatabaseHost;
	string DatabaseUsername;
	string DatabasePassword;
	string DatabaseDB;
	uint16 DatabasePort;

	// From <files/>
	string SpellsFile;
	string OpCodesFile;
	string EQTimeFile;
	string LogSettingsFile;

	// From <directories/>
	string MapDir;
	string QuestDir;
	string PluginDir;
	
	// From <launcher/>
	string LogPrefix;
	string LogSuffix;
	string ZoneExe;
	uint32 RestartWait;
	uint32 TerminateWait;
	uint32 InitialBootWait;
	uint32 ZoneBootInterval;

	// From <zones/>
	uint16 ZonePortLow;
	uint16 ZonePortHigh;
	uint8 DefaultStatus;

//	uint16 DynamicCount;

//	map<string,uint16> StaticZones;
	
protected:

	static EQEmuConfig *_config;

	static string ConfigFile;

#define ELEMENT(name) \
	void do_##name(TiXmlElement *ele);
	#include "EQEmuConfig_elements.h"


	EQEmuConfig() {
		// import the needed handler prototypes
#define ELEMENT(name) \
		Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
	#include "EQEmuConfig_elements.h"

		// Set sane defaults

		// Login server
		LoginHost="eqemulator.net";
		LoginPort=5998;

#ifdef DUAL_SERVER
		LoginHost2="eqemulator.net2";
		LoginPort2=5999;
#endif

		// World
		Locked=false;
		WorldTCPPort=9000;
		TelnetEnabled=false;
		WorldHTTPEnabled=false;
		WorldHTTPPort=9080;
		WorldHTTPMimeFile="mime.types";
		SharedKey = "";	//blank disables authentication

		// Mail
		ChatHost="eqchat.eqemulator.net";
		ChatPort=7778;

		// Mail
		MailHost="eqmail.eqemulator.net";
		MailPort=7779;

		// Mysql
		DatabaseHost="localhost";
		DatabasePort=3306;
		DatabaseUsername="eq";
		DatabasePassword="eq";
		DatabaseDB="eq";

		// Files
		SpellsFile="spells_us.txt";
		OpCodesFile="opcodes.conf";
		EQTimeFile="eqtime.cfg";
		LogSettingsFile="log.ini";

		// Dirs
		MapDir="Maps";
		QuestDir="quests";
		PluginDir="plugins";
		
		// Launcher
		LogPrefix = "logs/zone-";
		LogSuffix = ".log";
		RestartWait = 10000;		//milliseconds
		TerminateWait = 10000;		//milliseconds
		InitialBootWait = 20000;	//milliseconds
		ZoneBootInterval = 2000;	//milliseconds
#ifdef WIN32
		ZoneExe = "zone.exe";
#else
		ZoneExe = "./zone";
#endif
		
		// Zones
		ZonePortLow=7000;
		ZonePortHigh=7999;
		DefaultStatus=0;
		
		// For where zones need to connect to.
		WorldIP="127.0.0.1";
		
		// Dynamics to start
		//DynamicCount=5;
		
		MaxClients=-1;
		
	}
	virtual ~EQEmuConfig() {}

public:

	// Produce a const singleton
	static const EQEmuConfig *get() {
		if (_config == NULL) 
			LoadConfig();
		return(_config);
	}

	// Allow the use to set the conf file to be used.
	static void SetConfigFile(string file) { EQEmuConfig::ConfigFile = file; }

	// Load the config
	static bool LoadConfig() {
		if (_config != NULL)
			delete _config;
		_config=new EQEmuConfig;

		return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
	}

	void Dump() const;
};

#endif
TCPConnection.cpp
Code:
#include "../common/debug.h"

#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;

#include "TCPConnection.h"
#include "../common/servertalk.h"
#include "../common/timer.h"
#include "../common/packet_dump.h"

#ifdef FREEBSD //Timothy Whitman - January 7, 2003
	#define MSG_NOSIGNAL 0
#endif

#ifdef WIN32
InitWinsock winsock;
#endif

#define LOOP_GRANULARITY 3	//# of ms between checking our socket/queues

#define TCPN_DEBUG				0
#define TCPN_DEBUG_Console		0
#define TCPN_DEBUG_Memory		0
#define TCPN_LOG_RAW_DATA_OUT	0		//1 = info, 2 = length limited dump, 3 = full dump
#define TCPN_LOG_RAW_DATA_IN	0		//1 = info, 2 = length limited dump, 3 = full dump

#ifdef DUAL_SERVER
#include "../world/LoginServer.h"
#endif

//client version
TCPConnection::TCPConnection()
: ConnectionType(Outgoing),
  connection_socket(0),
  id(0),
  rIP(0),
  rPort(0)
{
	pState = TCPS_Ready;
	pFree = false;
	pEcho = false;
	recvbuf = NULL;
	sendbuf = NULL;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #2 on outgoing TCP# " << GetID() << endl;
#endif
}

//server version
TCPConnection::TCPConnection(int32 ID, SOCKET in_socket, int32 irIP, int16 irPort)
: ConnectionType(Incomming),
  connection_socket(in_socket),
  id(ID),
  rIP(irIP),
  rPort(irPort)
{
	pState = TCPS_Connected;
	pFree = false;
	pEcho = false;
	recvbuf = NULL;
	sendbuf = NULL;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #2 on incoming TCP# " << GetID() << endl;
#endif
}

TCPConnection::~TCPConnection() {
	FinishDisconnect();
	ClearBuffers();
	if (ConnectionType == Outgoing) {
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		MLoopRunning.lock();
		MLoopRunning.unlock();
#if TCPN_DEBUG_Memory >= 6
		cout << "Deconstructor on outgoing TCP# " << GetID() << endl;
#endif
	}
#if TCPN_DEBUG_Memory >= 5
	else {
		cout << "Deconstructor on incomming TCP# " << GetID() << endl;
	}
#endif
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	safe_delete_array(charAsyncConnect);
}

void TCPConnection::SetState(State_t in_state) {
	MState.lock();
	pState = in_state;
	MState.unlock();
}

TCPConnection::State_t TCPConnection::GetState() const {
	State_t ret;
	MState.lock();
	ret = pState;
	MState.unlock();
	return ret;
}

bool TCPConnection::GetSockName(char *host, uint16 *port)
{
	bool result=false;
	LockMutex lock(&MState);
	if (!Connected())
		return false;

	struct sockaddr_in local;

#ifdef WIN32
	int addrlen;
#else
#ifdef FREEBSD
	socklen_t addrlen;
#else
	size_t addrlen;
#endif
#endif
	addrlen=sizeof(struct sockaddr_in);
#ifdef WIN32
	if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
#else
	if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
#endif
		unsigned long ip=local.sin_addr.s_addr;
		sprintf(host,"%d.%d.%d.%d",
			*(unsigned char *)&ip,
				*((unsigned char *)&ip+1),
				*((unsigned char *)&ip+2),
				*((unsigned char *)&ip+3));
		*port=ntohs(local.sin_port);

		result=true;
	}

	return result;
}

void TCPConnection::Free() {
	if (ConnectionType == Outgoing) {
		ThrowError("TCPConnection::Free() called on an Outgoing connection");
	}
#if TCPN_DEBUG_Memory >= 5
	cout << "Free on TCP# " << GetID() << endl;
#endif
	Disconnect();
	pFree = true;
}

bool TCPConnection::Send(const uchar* data, sint32 size) {
	if (!Connected())
		return false;
	if (!size)
		return true;
	ServerSendQueuePushEnd(data, size);
	return true;
}

void TCPConnection::ServerSendQueuePushEnd(const uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == NULL) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size + 1024;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

void TCPConnection::ServerSendQueuePushEnd(uchar** data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = *data;
		sendbuf_size = size;
		sendbuf_used = size;
		MSendQueue.unlock();
		*data = 0;
		return;
	}
	if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], *data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
	safe_delete_array(*data);
}

void TCPConnection::ServerSendQueuePushFront(uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(&tmp[size], sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(sendbuf, data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

bool TCPConnection::ServerSendQueuePop(uchar** data, sint32* size) {
	bool ret;
	if (!MSendQueue.trylock())
		return false;
	if (sendbuf) {
		*data = sendbuf;
		*size = sendbuf_used;
		sendbuf = 0;
		ret = true;
	}
	else {
		ret = false;
	}
	MSendQueue.unlock();
	return ret;
}

bool TCPConnection::ServerSendQueuePopForce(uchar** data, sint32* size) {
	bool ret;
	MSendQueue.lock();
	if (sendbuf) {
		*data = sendbuf;
		*size = sendbuf_used;
		sendbuf = 0;
		ret = true;
	}
	else {
		ret = false;
	}
	MSendQueue.unlock();
	return ret;
}

char* TCPConnection::PopLine() {
	char* ret;
	if (!MLineOutQueue.trylock())
		return 0;
	ret = (char*) LineOutQueue.pop();
	MLineOutQueue.unlock();
	return ret;
}

bool TCPConnection::LineOutQueuePush(char* line) {
	MLineOutQueue.lock();
	LineOutQueue.push(line);
	MLineOutQueue.unlock();
	return(false);
}


void TCPConnection::FinishDisconnect() {
	MState.lock();
	if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
		if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
			bool sent_something = false;
			SendData(sent_something);
		}
		pState = TCPS_Closing;
		shutdown(connection_socket, 0x01);
		shutdown(connection_socket, 0x00);
#ifdef WIN32
		closesocket(connection_socket);
#else
		close(connection_socket);
#endif
		connection_socket = 0;
		rIP = 0;
		rPort = 0;
		ClearBuffers();
	}
	pState = TCPS_Disconnected;
	MState.unlock();
}

void TCPConnection::Disconnect() {
	MState.lock();
	if(pState == TCPS_Connected || pState == TCPS_Connecting) {
		pState = TCPS_Disconnecting;
	}
	MState.unlock();
}

bool TCPConnection::GetAsyncConnect() {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	MAsyncConnect.unlock();
	return ret;
}

bool TCPConnection::SetAsyncConnect(bool iValue) {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	pAsyncConnect = iValue;
	MAsyncConnect.unlock();
	return ret;
}

bool TCPConnection::ConnectReady() const {
	State_t s = GetState();
	if (s != TCPS_Ready && s != TCPS_Disconnected)
		return(false);
	return(ConnectionType == Outgoing);
}

void TCPConnection::AsyncConnect(const char* irAddress, int16 irPort) {
	safe_delete_array(charAsyncConnect);
	charAsyncConnect = new char[strlen(irAddress) + 1];
	strcpy(charAsyncConnect, irAddress);
	AsyncConnect((int32) 0, irPort);
}

void TCPConnection::AsyncConnect(int32 irIP, int16 irPort) {
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!");
		return;
	}
	if(!ConnectReady()) {
#if TCPN_DEBUG > 0
		printf("Trying to do async connect in invalid state %s\n", GetState());
#endif
		return;
	}
	MAsyncConnect.lock();
	if (pAsyncConnect) {
		MAsyncConnect.unlock();
#if TCPN_DEBUG > 0
		printf("Trying to do async connect when already doing one.\n");
#endif
		return;
	}
#if TCPN_DEBUG > 0
		printf("Start async connect.\n");
#endif
	pAsyncConnect = true;
	if(irIP != 0)
		safe_delete_array(charAsyncConnect);
	rIP = irIP;
	rPort = irPort;
	MAsyncConnect.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
	}
	return;
}

bool TCPConnection::Connect(const char* irAddress, int16 irPort, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	int32 tmpIP = ResolveIP(irAddress);
	if (!tmpIP) {
		if (errbuf) {
#ifdef WIN32
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
#else
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
#endif
		}
		return false;
	}
	return ConnectIP(tmpIP, irPort, errbuf);
}

bool TCPConnection::ConnectIP(int32 in_ip, int16 in_port, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::Connect() call on a Incomming connection object!");
		return false;
	}
	MState.lock();
	if (ConnectReady()) {
		pState = TCPS_Connecting;
	} else {
		MState.unlock();
		SetAsyncConnect(false);
		return false;
	}
	MState.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
	}

	connection_socket = INVALID_SOCKET;
    struct sockaddr_in	server_sin;
//    struct in_addr	in;

	if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
#ifdef WIN32
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
#else
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
#endif
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
	server_sin.sin_family = AF_INET;
	server_sin.sin_addr.s_addr = in_ip;
	server_sin.sin_port = htons(in_port);

	// Establish a connection to the server socket.
#ifdef WIN32
	if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
		closesocket(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#else
	if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
		close(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#endif
	int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
	setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef WIN32
	unsigned long nonblocking = 1;
	ioctlsocket(connection_socket, FIONBIO, &nonblocking);
#else
	fcntl(connection_socket, F_SETFL, O_NONBLOCK);
#endif

	SetEcho(false);
	ClearBuffers();
	
	rIP = in_ip;
	rPort = in_port;
	SetState(TCPS_Connected);
	SetAsyncConnect(false);
	return true;
}

void TCPConnection::ClearBuffers() {
	LockMutex lock1(&MSendQueue);
	LockMutex lock3(&MRunLoop);
	LockMutex lock4(&MState);
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	
	char* line = 0;
	while ((line = LineOutQueue.pop()))
		safe_delete_array(line);
}

bool TCPConnection::CheckNetActive() {
	MState.lock();
	if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
		MState.unlock();
		return true;
	}
	MState.unlock();
	return false;
}

/* This is always called from an IO thread. Either the server socket's thread, or a 
 * special thread we create when we make an outbound connection. */
bool TCPConnection::Process() {
	char errbuf[TCPConnection_ErrorBufferSize];
	switch(GetState()) {
	case TCPS_Ready:
	case TCPS_Connecting:
		if (ConnectionType == Outgoing) {
			if (GetAsyncConnect()) {
				if (charAsyncConnect)
					rIP = ResolveIP(charAsyncConnect);
				ConnectIP(rIP, rPort);
			}
		}
		return(true);
	
	case TCPS_Connected:
		// only receive data in the connected state, no others...
		if (!RecvData(errbuf)) {
		    struct in_addr	in;
			in.s_addr = GetrIP();
			//cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
			return false;
		}
		/* we break to do the send */
		break;
	
	case TCPS_Disconnecting: {
		//waiting for any sending data to go out...
		MSendQueue.lock();
		if(sendbuf) {
			if(sendbuf_used > 0) {
				//something left to send, keep processing...
				MSendQueue.unlock();
				break;
			}
			//else, send buffer is empty.
			safe_delete_array(sendbuf);
		} //else, no send buffer, we are done.
		MSendQueue.unlock();
	}
		/* Fallthrough */
	
	case TCPS_Disconnected:
		FinishDisconnect();
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
//		SetState(TCPS_Ready);	//reset the state in case they want to use it again...
		return(false);
	
	case TCPS_Closing:
		//I dont understand this state...
	
	case TCPS_Error:
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		return(false);
	}
	
	/* we get here in connected or disconnecting with more data to send */
	
	bool sent_something = false;
	if (!SendData(sent_something, errbuf)) {
	    struct in_addr	in;
		in.s_addr = GetrIP();
		cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
		return false;
	}
	
	return true;
}

bool TCPConnection::RecvData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (!Connected()) {
		return false;
	}

	int	status = 0;
	if (recvbuf == 0) {
		recvbuf = new uchar[5120];
		recvbuf_size = 5120;
		recvbuf_used = 0;
		recvbuf_echo = 0;
	}
	else if ((recvbuf_size - recvbuf_used) < 2048) {
		uchar* tmpbuf = new uchar[recvbuf_size + 5120];
		memcpy(tmpbuf, recvbuf, recvbuf_used);
		recvbuf_size += 5120;
		safe_delete_array(recvbuf);
		recvbuf = tmpbuf;
		if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
			return false;
		}
	}

    status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);

    if (status >= 1) {
#if TCPN_LOG_RAW_DATA_IN >= 1
		struct in_addr	in;
		in.s_addr = GetrIP();
		CoutTimestamp(true);
		cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
		cout << endl;
	#if TCPN_LOG_RAW_DATA_IN == 2
		sint32 tmp = status;
		if (tmp > 32)
			tmp = 32;
		DumpPacket(&recvbuf[recvbuf_used], status);
	#elif TCPN_LOG_RAW_DATA_IN >= 3
		DumpPacket(&recvbuf[recvbuf_used], status);
	#endif
#endif
		recvbuf_used += status;
		if (!ProcessReceivedData(errbuf))
			return false;
    }
	else if (status == SOCKET_ERROR) {
#ifdef WIN32
		if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
			return false;
		}
#else
		if (!(errno == EWOULDBLOCK)) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
			return false;
		}
#endif
	} else if (status == 0) {
		snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
		return false;
	}

	return true;
}


bool TCPConnection::GetEcho() {
	bool ret;
	ret = pEcho;
	return ret;
}

void TCPConnection::SetEcho(bool iValue) {
	pEcho = iValue;
}

bool TCPConnection::ProcessReceivedData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (!recvbuf)
		return true;
#if TCPN_DEBUG_Console >= 4
	if (recvbuf_used) {
		cout << "Starting Processing: recvbuf=" << recvbuf_used << endl;
		DumpPacket(recvbuf, recvbuf_used);
	}
#endif
	for (int i=0; i < recvbuf_used; i++) {
		if (GetEcho() && i >= recvbuf_echo) {
			Send(&recvbuf[i], 1);
			recvbuf_echo = i + 1;
		}
		switch(recvbuf[i]) {
		case 0: { // 0 is the code for clear buffer
				if (i==0) {
					recvbuf_used--;
					recvbuf_echo--;
					memmove(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					if (i == recvbuf_used) {
						safe_delete_array(recvbuf);
						i = -1;
					}
					else {
						uchar* tmpdel = recvbuf;
						recvbuf = new uchar[recvbuf_size];
						memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
						recvbuf_used -= i + 1;
						recvbuf_echo -= i + 1;
						safe_delete_array(tmpdel);
						i = -1;
					}
				}
#if TCPN_DEBUG_Console >= 5
				cout << "Removed 0x00" << endl;
				if (recvbuf_used) {
					cout << "recvbuf left: " << recvbuf_used << endl;
					DumpPacket(recvbuf, recvbuf_used);
				}
				else
					cout << "recbuf left: None" << endl;
#endif
				m_previousLineEnd = false;
				break;
			}
			case 10:
			case 13: // newline marker
			{
				char *line = NULL;
				if (i==0) { // empty line
					if(!m_previousLineEnd) {
						//char right before this was NOT a CR, report the empty line.
						line = new char[1];
						line[0] = '\0';
						m_previousLineEnd = true;
					} else {
						m_previousLineEnd = false;
					}
					recvbuf_used--;
					recvbuf_echo--;
					memcpy(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					line = new char[i+1];
					memset(line, 0, i+1);
					memcpy(line, recvbuf, i);
#if TCPN_DEBUG_Console >= 3
					cout << "Line Out: " << endl;
					DumpPacket((uchar*) line, i);
#endif
					//line[i] = 0;
					uchar* tmpdel = recvbuf;
					recvbuf = new uchar[recvbuf_size];
					recvbuf_used -= i+1;
					recvbuf_echo -= i+1;
					memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
#if TCPN_DEBUG_Console >= 5
					cout << "i+1=" << i+1 << endl;
					if (recvbuf_used) {
						cout << "recvbuf left: " << recvbuf_used << endl;
						DumpPacket(recvbuf, recvbuf_used);
					}
					else
						cout << "recbuf left: None" << endl;
#endif
					safe_delete_array(tmpdel);
					i = -1;
					m_previousLineEnd = true;
				}
				
				
				if(line != NULL) {
					bool finish_proc = false;
					finish_proc = LineOutQueuePush(line);
					if(finish_proc)
						return(true);	//break early as requested by LineOutQueuePush
				}
				
				break;
			}
			case 8: // backspace
			{
				if (i==0) { // nothin to backspace
					recvbuf_used--;
					recvbuf_echo--;
					memmove(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					uchar* tmpdel = recvbuf;
					recvbuf = new uchar[recvbuf_size];
					memcpy(recvbuf, tmpdel, i-1);
					memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
					recvbuf_used -= 2;
					recvbuf_echo -= 2;
					safe_delete_array(tmpdel);
					i -= 2;
				}
				break;
				m_previousLineEnd = false;
			}
			default:
				m_previousLineEnd = false;
		}
	}
	if (recvbuf_used < 0)
		safe_delete_array(recvbuf);
	return true;
}

bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	/************ Get first send packet on queue and send it! ************/
	uchar* data = 0;
	sint32 size = 0;
	int status = 0;
	if (ServerSendQueuePop(&data, &size)) {
#ifdef WIN32
		status = send(connection_socket, (const char *) data, size, 0);
#else
		status = send(connection_socket, data, size, MSG_NOSIGNAL);
		if(errno==EPIPE) status = SOCKET_ERROR;
#endif
		if (status >= 1) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
			struct in_addr	in;
			in.s_addr = GetrIP();
			CoutTimestamp(true);
			cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
			cout << endl;
	#if TCPN_LOG_RAW_DATA_OUT == 2
			sint32 tmp = status;
			if (tmp > 32)
				tmp = 32;
			DumpPacket(data, status);
	#elif TCPN_LOG_RAW_DATA_OUT >= 3
			DumpPacket(data, status);
	#endif
#endif
			sent_something = true;
			if (status < (signed)size) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
				struct in_addr	in;
				in.s_addr = GetrIP();
				CoutTimestamp(true);
				cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
				cout << endl;
#endif
				// If there's network congestion, the number of bytes sent can be less than
				// what we tried to give it... Push the extra back on the queue for later
				ServerSendQueuePushFront(&data[status], size - status);
			}
			else if (status > (signed)size) {
				ThrowError("TCPConnection::SendData(): WTF! status > size");
				return false;
			}
			// else if (status == size) {}
		}
		else {
			ServerSendQueuePushFront(data, size);
		}

		safe_delete_array(data);
		if (status == SOCKET_ERROR) {
#ifdef WIN32
			if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
			if (errno != EWOULDBLOCK)
#endif
			{
				if (errbuf) {
#ifdef WIN32
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
#else
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
#endif
				}
				
				//if we get an error while disconnecting, just jump to disconnected
				MState.lock();
				if(pState == TCPS_Disconnecting)
					pState = TCPS_Disconnected;
				MState.unlock();
				
				return false;
			}
		}
	}
	return true;
}

ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
#ifdef WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
	if (tmp == 0) {
		ThrowError("TCPConnectionLoop(): tmp = 0!");
		THREAD_RETURN(NULL);
	}
	TCPConnection* tcpc = (TCPConnection*) tmp;
#ifndef WIN32
	_log(COMMON__THREADS, "Starting TCPConnectionLoop with thread ID %d", pthread_self());
#endif
	tcpc->MLoopRunning.lock();
	while (tcpc->RunLoop()) {
		Sleep(LOOP_GRANULARITY);
		if (!tcpc->ConnectReady()) {
			_CP(TCPConnectionLoop);
			if (!tcpc->Process()) {
				//the processing loop has detecting an error.. 
				//we want to drop the link immediately, so we clear buffers too.
				tcpc->ClearBuffers();
				tcpc->Disconnect();
			}
#ifdef DUAL_SERVER
			Sleep(100);
#else
			Sleep(1);
#endif
		}
		else if (tcpc->GetAsyncConnect()) {
			_CP(TCPConnectionLoop);
			if (tcpc->charAsyncConnect)
				tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
			else
				tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
			tcpc->SetAsyncConnect(false);
		}
		else
			Sleep(10);	//nothing to do.
	}
	tcpc->MLoopRunning.unlock();
	
#ifndef WIN32
#ifdef DUAL_SERVER
	_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d, Did you loose a server connection?", pthread_self()); //Angelox
#else
	_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d", pthread_self());
#endif
#endif
	
	THREAD_RETURN(NULL);

#ifdef DUAL_SERVER
	_log(WORLD__CONSOLE,"Login Server Reconnect Attempt...");
	InitLoginServer();
/*	#ifdef WIN32
		_beginthread(AutoInitLoginServer, 0, NULL);
	#else
		pthread_t thread;
		pthread_create(&thread, NULL, &AutoInitLoginServer, NULL);
	#endif
	RunLoops = true;
	_log(WORLD__CONSOLE,"Login Server Reconnect Attempt..."); */
#endif
}

bool TCPConnection::RunLoop() {
	bool ret;
	MRunLoop.lock();
	ret = pRunLoop;
	MRunLoop.unlock();
	return ret;
}
database.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include <map>

// Disgrace: for windows compile
#ifdef WIN32
#include <windows.h>
#define snprintf	_snprintf
#define strncasecmp	_strnicmp
#define strcasecmp	_stricmp
#else
#include "unix.h"
#include <netinet/in.h>
#include <sys/time.h>
#endif

#ifdef EQBOTS
#include "../zone/botDatabase.h"
#endif //EQBOTS

#include "database.h"
#include "eq_packet_structs.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "extprofile.h"
/*#include "../common/classes.h"
#include "../common/races.h"
#include "../common/files.h"
#include "../common/EQEMuError.h"
#include "../common/packet_dump.h"
*/
extern Client client;

/*
This is the amount of time in seconds the client has to enter the zone
server after the world server, or inbetween zones when that is finished
*/

/*
Establish a connection to a mysql database with the supplied parameters

  Added a very simple .ini file parser - Bounce

	Modify to use for win32 & linux - misanthropicfiend
*/
Database::Database ()
{
	DBInitVars();
}

/*
Establish a connection to a mysql database with the supplied parameters
*/

Database::Database(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
	DBInitVars();
	Connect(host, user, passwd, database, port);
}

bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
	int32 errnum= 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	if (!Open(host, user, passwd, database, port, &errnum, errbuf))
	{
		LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
		HandleMysqlError(errnum);

		return false;
	}
	else
	{
		LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
		return true;
	}
}

void Database::DBInitVars() {

	max_zonename = 0;
	zonename_array = 0;
	varcache_array = 0;
	varcache_max = 0;
	varcache_lastupdate = 0;
}



void Database::HandleMysqlError(int32 errnum) {
/*	switch(errnum) {
		case 0:
			break;
		case 1045: // Access Denied
		case 2001: {
			AddEQEMuError(EQEMuError_Mysql_1405, true);
			break;
		}
		case 2003: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2003, true);
			break;
		}
		case 2005: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2005, true);
			break;
		}
		case 2007: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2007, true);
			break;
		}
	}*/
}

/*

Close the connection to the database
*/
Database::~Database()
{
	unsigned int x;
	if (zonename_array) {
		for (x=0; x<=max_zonename; x++) {
			if (zonename_array[x])
				safe_delete_array(zonename_array[x]);
		}
		safe_delete_array(zonename_array);
	}
	if (varcache_array) {
		for (x=0; x<varcache_max; x++) {
			safe_delete_array(varcache_array[x]);
		}
		safe_delete_array(varcache_array);
	}
}


/*
Check if there is an account with name "name" and password "password"
Return the account id or zero if no account matches.
Zero will also be returned if there is a database error.
*/
int32 Database::CheckLogin(const char* name, const char* password, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if(strlen(name) >= 50 || strlen(password) >= 50)
		return(0);

	char tmpUN[100];
	char tmpPW[100];
	DoEscapeString(tmpUN, name, strlen(name));
	DoEscapeString(tmpPW, password, strlen(password));

	if (RunQuery(query, MakeAnyLenString(&query,
		"SELECT id, status FROM account WHERE name='%s' AND password is not null "
		"and length(password) > 0 and (password='%s' or password=MD5('%s'))",
		tmpUN, tmpPW, tmpPW), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int32 id = atoi(row[0]);
			if (oStatus)
				*oStatus = atoi(row[1]);
			mysql_free_result(result);
			return id;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in CheckLogin query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;
}


//Lieka:  Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
bool Database::CheckBannedIPs(const char* loginIP)
{
 	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
 	//cout << "Checking against Banned IPs table."<< endl; //Lieka:  Debugging
 	if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%s'", loginIP), errbuf, &result)) {
 		safe_delete_array(query);
 		if (mysql_num_rows(result) != 0)
 		{
 			//cout << loginIP << " was present in the banned IPs table" << endl; //Lieka:  Debugging
 			mysql_free_result(result);
 			return true;
 		}
 		else
 		{
 			//cout << loginIP << " was not present in the banned IPs table." << endl; //Lieka:  Debugging
 			mysql_free_result(result);
 			return false;
 		}
 		mysql_free_result(result);
 	}
 	else
 	{
 		cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
 		safe_delete_array(query);
 		return true;
 	}
 	return true;
}

bool Database::AddBannedIP(char* bannedIP, const char* notes)
{
 	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

 	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes), errbuf)) {
 		cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
 		safe_delete_array(query);
 		return false;
 	}
 	safe_delete_array(query);
 	return true;
}
 //End Lieka Edit
 
 bool Database::CheckGMIPs(const char* ip_address, int32 account_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM `gm_ips` WHERE `ip_address` = '%s' AND `account_id` = %i", ip_address, account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			mysql_free_result(result);
			return true;
		} else {
			mysql_free_result(result);
			return false;
		}
		mysql_free_result(result);

	} else {
		safe_delete_array(query);
		return false;
	}
	
	return false;
}

bool Database::AddGMIP(char* ip_address, char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into `gm_ips` SET `ip_address` = '%s', `name` = '%s'", ip_address, name), errbuf)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);
	return true;
}

void Database::LoginIP(int32 AccountID, const char* LoginIP)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO account_ip SET accid=%i, ip='%s' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()", AccountID, LoginIP), errbuf)) {
 		cerr << "Error in Log IP query '" << query << "' " << errbuf << endl;
 	}
 	safe_delete_array(query);
}

sint16 Database::CheckStatus(int32 account_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT status FROM account WHERE id='%i'", account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			sint16 status = atoi(row[0]);

			mysql_free_result(result);
			return status;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in CheckStatus query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;
}

#ifdef DUAL_SERVER
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id, int32 lsaccount_id2) {
#else
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id) {
#endif
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 querylen;
	int32 last_insert_id;
	MYSQL_RES *result;
// if (paccountid == 0 && LSID()>0) {

#ifdef DUAL_SERVER
    RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", name), errbuf, &result);
    if (mysql_num_rows(result) == 1) {
      lsaccount_id2 = lsaccount_id;
      safe_delete_array(query); 
      if (lsaccount_id > 4999999){
	(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id=%i WHERE name='%s'AND lsaccount_id IS NULL;", lsaccount_id, name), errbuf, 0));
	safe_delete_array(query);
      }
      else if (lsaccount_id < 5000000){
	(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id2=%i WHERE name='%s'AND lsaccount_id2='0';", lsaccount_id2, name), errbuf, 0));
	safe_delete_array(query);
      }
      safe_delete_array(query);
    }
   safe_delete_array(query);

	    if ((password) && (lsaccount_id > 4999999))
#else
	    if (password)
#endif

		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id=%i;",name,password,status, lsaccount_id);
	
#ifdef DUAL_SERVER	
	    else if (lsaccount_id > 4999999)
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#else
	    else
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#endif

#ifdef DUAL_SERVER
  lsaccount_id2 = lsaccount_id;
  if ((password) && (lsaccount_id < 5000000))
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id2=%i;",name,password,status, lsaccount_id2);
	else if (lsaccount_id < 5000000)
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id2=%i;",name, status, lsaccount_id2);
#endif //Dual Server

	cerr << "Account Attempting to be created:" << name << " " << (sint16) status << endl;
	if (!RunQuery(query, querylen, errbuf, 0, 0, &last_insert_id)) {
		cerr << "Error in CreateAccount query, possible second account added,try again- '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}
	safe_delete_array(query);

	if (last_insert_id == 0) {
		cerr << "Error in CreateAccount query '" << query << "' " << errbuf << endl;
		return 0;
	}
	return last_insert_id;
}

bool Database::DeleteAccount(const char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected_rows = 0;

	cerr << "Account Attempting to be deleted:" << name << endl;
	if (RunQuery(query, MakeAnyLenString(&query, "DELETE FROM account WHERE name='%s';",name), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		if (affected_rows == 1) {
			return true;
		}
	}
	else {

		cerr << "Error in DeleteAccount query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return false;
}

bool Database::SetLocalPassword(int32 accid, const char* password) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET password=MD5('%s') where id=%i;", password, accid), errbuf)) {
		cerr << "Error in SetLocalPassword query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);
	return true;
}

bool Database::SetAccountStatus(const char* name, sint16 status) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	cout << "Account being GM Flagged:" << name << ", Level: " << (sint16) status << endl;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET status=%i WHERE name='%s';", status, name), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0) {
		cout << "Account: " << name << " does not exist, therefore it cannot be flagged\n";
		return false;
	}

	return true;
}


//---------------------------------
//End of adventure database code.--
//---------------------------------


bool Database::ReserveName(int32 account_id, char* name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into character_ SET account_id=%i, name='%s', profile=NULL", account_id, name), errbuf)) {
		cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);
	return true;
}

/*
Delete the character with the name "name"
returns false on failure, true otherwise
*/
bool Database::DeleteCharacter(char *name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query=0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int charid, matches;
	int32 affected_rows;

	if(!name ||	!strlen(name))
	{
		printf("DeleteCharacter: request to delete without a name (empty char slot)\n");
		return false;
	}

// SCORPIOUS2K - get id from character_ before deleting record so we can clean up inventory and qglobal

#if DEBUG >= 5
	printf("DeleteCharacter: Attempting to delete '%s'\n", name);
#endif
	RunQuery(query, MakeAnyLenString(&query, "SELECT id from character_ WHERE name='%s'", name), errbuf, &result);
	if (query)
	{
		safe_delete_array(query);
		query = NULL;
	}
	matches = mysql_num_rows(result);
	if(matches == 1)
	{
		row = mysql_fetch_row(result);
		charid = atoi(row[0]);
#if DEBUG >= 5
		printf("DeleteCharacter: found '%s' with char id: %d\n", name, charid);
#endif
	}
	else
	{
		printf("DeleteCharacter: error: got %d rows matching '%s'\n", matches, name);
		if(result)
		{
			mysql_free_result(result);
			result = NULL;
		}
		return false;
	}

	if(result)
	{
		mysql_free_result(result);
		result = NULL;
	}



#if DEBUG >= 5
	printf("DeleteCharacter: deleting '%s' (id %d): ", name, charid);
	printf(" quest_globals");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from quest_globals WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_tasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_activities");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_activities WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_enabledtasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_enabledtasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" completed_tasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from completed_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" friends");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from friends WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" ptimers");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from timers WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" inventory");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from inventory WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" guild_members");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE FROM guild_members WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" _character");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_ WHERE id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}
	if(affected_rows != 1)	// here we have to have a match or it's an error
	{
		LogFile->write(EQEMuLog::Error, "DeleteCharacter: error: delete operation affected %d rows\n", affected_rows);
		return false;
	}
#if DEBUG >= 5
    printf(" keyring");
#endif
    RunQuery(query, MakeAnyLenString(&query, "DELETE FROM keyring WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
    if(query)
    {
        safe_delete_array(query);
        query = NULL;
    }
#if DEBUG >= 5
	printf("\n");
#endif
	printf("DeleteCharacter: successfully deleted '%s' (id %d)\n", name, charid);

	return true;
}
// Store new character information into the character_ and inventory tables
bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext)
{
	_CP(Database_StoreCharacter);
	char errbuf[MYSQL_ERRMSG_SIZE];
	char query[256+sizeof(PlayerProfile_Struct)*2+sizeof(ExtendedProfile_Struct)*2+5];
	char* end = query;
	int32 affected_rows = 0;
	int i;
	int32 charid = 0;
	char* charidquery = 0;
	char* invquery = 0;
	MYSQL_RES *result;
	MYSQL_ROW row = 0;
	char zone[50];
	float x, y, z;

//	memset(&playeraa, 0, sizeof(playeraa));

	// get the char id (used in inventory inserts below)
	if(!RunQuery
	(
		charidquery,
		MakeAnyLenString
		(
			&charidquery,
			"SELECT id FROM character_ where name='%s'",
			pp->name
		),
		errbuf,
		&result
	)) {
		LogFile->write(EQEMuLog::Error, "Error in char store id query: %s: %s", charidquery, errbuf);
		return(false);
	}
	safe_delete_array(charidquery);

	if(mysql_num_rows(result) == 1)
	{
		row = mysql_fetch_row(result);
		if(row[0])
			charid = atoi(row[0]);
	}

	if(!charid)
	{
		LogFile->write(EQEMuLog::Error, "StoreCharacter: no character id");
		return false;
	}

	const char *zname = GetZoneName(pp->zone_id);
	if(zname == NULL) {
		//zone not in the DB, something to prevent crash...
		strncpy(zone, "qeynos", 49);
		pp->zone_id = 1;
	} else
		strncpy(zone, zname, 49);
	x=pp->x;
	y=pp->y;
	z=pp->z;

	// construct the character_ query
	end += sprintf(end,
		"UPDATE character_ SET timelaston=0, "
		"zonename=\'%s\', x=%f, y=%f, z=%f, profile=\'",
		zone, x, y, z
	);
	end += DoEscapeString(end, (char*)pp, sizeof(PlayerProfile_Struct));
	end += sprintf(end, "\', extprofile=\'");
	end += DoEscapeString(end, (char*)ext, sizeof(ExtendedProfile_Struct));
	end += sprintf(end, "\' WHERE account_id=%d AND name='%s'",account_id, pp->name);

	RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows);

	if(!affected_rows)
	{
		LogFile->write(EQEMuLog::Error, "StoreCharacter query '%s' %s", query, errbuf);
		return false;
	}

	affected_rows = 0;


	// Doodman: Is this even used?
	// now the inventory

	for (i=0; i<=2270;)
	{
		const ItemInst* newinv = inv->GetItem((sint16)i);
		if (newinv)
		{
			MakeAnyLenString
			(
				&invquery,
				"INSERT INTO inventory SET "
				"charid=%0u, slotid=%0d, itemid=%0u, charges=%0d, color=%0u",
				charid, i, newinv->GetItem()->ID,
				newinv->GetCharges(), newinv->GetColor()
			);

			RunQuery(invquery, strlen(invquery), errbuf, 0, &affected_rows);
			if(!affected_rows)
			{
				LogFile->write(EQEMuLog::Error, "StoreCharacter inventory failed.  Query '%s' %s", invquery, errbuf);
			}
			safe_delete_array(invquery);
#if EQDEBUG >= 9
			else
			{
				LogFile->write(EQEMuLog::Debug, "StoreCharacter inventory succeeded.  Query '%s' %s", invquery, errbuf);
			}
#endif
		}

		if(i==30){ //end of standard inventory/cursor, jump to internals of bags/cursor
			i = 251;
			continue;
		} else if(i==340){ //end of internals of bags/cursor, jump to bank slots
			i = 2000;
			continue;
		} else if(i==2023){ //end of bank slots, jump to internals of bank bags
			i = 2031;
			continue;
		}

		i++;
	}

	return true;
}

//0=failure, otherwise returns the char ID for the given char name.
int32 Database::GetCharacterID(const char *name) {
	int32 cid = 0;
	if(GetAccountIDByChar(name, &cid) == 0)
		return(0);
	return(cid);
}

/*
This function returns the account_id that owns the character with
the name "name" or zero if no character with that name was found
Zero will also be returned if there is a database error.
*/
int32 Database::GetAccountIDByChar(const char* charname, int32* oCharID) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id, id FROM character_ WHERE name='%s'", charname), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
			if (oCharID)
				*oCharID = atoi(row[1]);
			mysql_free_result(result);
			return tmp;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDByChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return 0;
}

// Retrieve account_id for a given char_id
uint32 Database::GetAccountIDByChar(uint32 char_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char* query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	uint32 ret = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id FROM character_ WHERE id=%i", char_id), errbuf, &result)) {
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			ret = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
		}
		mysql_free_result(result);
	}
	else {
		LogFile->write(EQEMuLog::Error, "Error in GetAccountIDByChar query '%s': %s", query, errbuf);
	}

	safe_delete_array(query);
	return ret;
}

int32 Database::GetAccountIDByName(const char* accname, sint16* status, int32* lsid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;


	for (unsigned int i=0; i<strlen(accname); i++) {
		if ((accname[i] < 'a' || accname[i] > 'z') &&
			(accname[i] < 'A' || accname[i] > 'Z') &&
			(accname[i] < '0' || accname[i] > '9'))
			return 0;
	}

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", accname), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
			if (status)
				*status = atoi(row[1]);
			if (lsid) {
				if (row[2])
					*lsid = atoi(row[2]);
				else
					*lsid = 0;
			}
			mysql_free_result(result);
			return tmp;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDByAcc query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return 0;
}

void Database::GetAccountName(int32 accountid, char* name, int32* oLSAccountID) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, lsaccount_id FROM account WHERE id='%i'", accountid), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);

			strcpy(name, row[0]);
			if (row[1] && oLSAccountID) {
				*oLSAccountID = atoi(row[1]);
			}
		}

		mysql_free_result(result);
	}
	else {
		safe_delete_array(query);
		cerr << "Error in GetAccountName query '" << query << "' " << errbuf << endl;
	}
}

void Database::GetCharName(int32 char_id, char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM character_ WHERE id='%i'", char_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);

			strcpy(name, row[0]);
		}

		mysql_free_result(result);
	}
	else {
		safe_delete_array(query);
		cerr << "Error in GetCharName query '" << query << "' " << errbuf << endl;
	}

}

bool Database::LoadVariables() {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;

	if (RunQuery(query, LoadVariables_MQ(&query), errbuf, &result)) {
		safe_delete_array(query);
		bool ret = LoadVariables_result(result);
		mysql_free_result(result);
		return ret;
	}
	else {
		cerr << "Error in LoadVariables query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return false;
}

int32 Database::LoadVariables_MQ(char** query) {
// the read of this single variable should be atomic... this was causing strange problems
//	LockMutex lock(&Mvarcache);
	return MakeAnyLenString(query, "SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache_lastupdate);
}

bool Database::LoadVariables_result(MYSQL_RES* result) {
	int32 i;
    MYSQL_ROW row;
	LockMutex lock(&Mvarcache);
	if (mysql_num_rows(result) > 0) {
		if (!varcache_array) {
			varcache_max = mysql_num_rows(result);
			varcache_array = new VarCache_Struct*[varcache_max];
			for (i=0; i<varcache_max; i++)
				varcache_array[i] = 0;
		}
		else {
			int32 tmpnewmax = varcache_max + mysql_num_rows(result);
			VarCache_Struct** tmp = new VarCache_Struct*[tmpnewmax];
			for (i=0; i<tmpnewmax; i++)
				tmp[i] = 0;
			for (i=0; i<varcache_max; i++)
				tmp[i] = varcache_array[i];
			VarCache_Struct** tmpdel = varcache_array;
			varcache_array = tmp;
			varcache_max = tmpnewmax;
			delete tmpdel;
		}
		while ((row = mysql_fetch_row(result))) {
			varcache_lastupdate = atoi(row[2]);
			for (i=0; i<varcache_max; i++) {
				if (varcache_array[i]) {
					if (strcasecmp(varcache_array[i]->varname, row[0]) == 0) {
						delete varcache_array[i];
						varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
						strn0cpy(varcache_array[i]->varname, row[0], sizeof(varcache_array[i]->varname));
						strcpy(varcache_array[i]->value, row[1]);
						break;
					}
				}
				else {
					varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
					strcpy(varcache_array[i]->varname, row[0]);
					strcpy(varcache_array[i]->value, row[1]);
					break;
				}
			}
		}
		int32 max_used = 0;
		for (i=0; i<varcache_max; i++) {
			if (varcache_array[i]) {
				if (i > max_used)
					max_used = i;
			}
		}
		max_used++;
		varcache_max = max_used;
	}
	return true;
}

// Gets variable from 'variables' table
bool Database::GetVariable(const char* varname, char* varvalue, int16 varvalue_len) {
	varvalue[0] = '\0';

	LockMutex lock(&Mvarcache);
	if (strlen(varname) <= 1)
		return false;
	for (int32 i=0; i<varcache_max; i++) {

		if (varcache_array[i]) {
			if (strcasecmp(varcache_array[i]->varname, varname) == 0) {
				snprintf(varvalue, varvalue_len, "%s", varcache_array[i]->value);
				varvalue[varvalue_len-1] = 0;
				return true;
			}
		}
		else
			return false;
	}
	return false;
}

bool Database::SetVariable(const char* varname_in, const char* varvalue_in) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32 affected_rows = 0;

	char *varname,*varvalue;

	varname=(char *)malloc(strlen(varname_in)*2+1);
	varvalue=(char *)malloc(strlen(varvalue_in)*2+1);
	DoEscapeString(varname, varname_in, strlen(varname_in));
	DoEscapeString(varvalue, varvalue_in, strlen(varvalue_in));

	if (RunQuery(query, MakeAnyLenString(&query, "Update variables set value='%s' WHERE varname like '%s'", varvalue, varname), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		if (affected_rows == 1) {
			LoadVariables(); // refresh cache
			free(varname);
			free(varvalue);
			return true;
		}
		else {
			if (RunQuery(query, MakeAnyLenString(&query, "Insert Into variables (varname, value) values ('%s', '%s')", varname, varvalue), errbuf, 0, &affected_rows)) {
				safe_delete_array(query);
				if (affected_rows == 1) {
					LoadVariables(); // refresh cache
					free(varname);
					free(varvalue);
					return true;
				}
			}
		}
	}
	else {
		cerr << "Error in SetVariable query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	free(varname);
	free(varvalue);
	return false;
}

int32 Database::GetMiniLoginAccount(char* ip){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 retid = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM account WHERE minilogin_ip='%s'", ip), errbuf, &result)) {
		safe_delete_array(query);
		if ((row = mysql_fetch_row(result)))
			retid = atoi(row[0]);
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetMiniLoginAccount query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return retid;
}

// Pyro: Get zone starting points from DB
bool Database::GetSafePoints(const char* short_name, float* safe_x, float* safe_y, float* safe_z, sint16* minstatus, int8* minlevel, char *flag_needed, int8* canzone) { //Angelox4
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	//	int buf_len = 256;
	//    int chars = -1;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query,
		"SELECT safe_x, safe_y, safe_z, min_status, min_level, "
		" flag_needed, canzone FROM zone " //Angelox4
		" WHERE short_name='%s'", short_name), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (safe_x != 0)
				*safe_x = atof(row[0]);
			if (safe_y != 0)
				*safe_y = atof(row[1]);
			if (safe_z != 0)
				*safe_z = atof(row[2]);
			if (minstatus != 0)
				*minstatus = atoi(row[3]);
			if (minlevel != 0)
				*minlevel = atoi(row[4]);
			if (flag_needed != NULL)
				strcpy(flag_needed, row[5]);
			if (canzone != 0) //Angelox4
				*canzone = atoi(row[6]); //Angelox4
			mysql_free_result(result);
			return true;
		}

		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetSafePoint query '" << query << "' " << errbuf << endl;
		cerr << "If it errors, run the following querys:\n";
		cerr << "ALTER TABLE `zone` CHANGE `minium_level` `min_level` TINYINT(3)  UNSIGNED DEFAULT \"0\" NOT NULL;\n";
		cerr << "ALTER TABLE `zone` CHANGE `minium_status` `min_status` TINYINT(3)  UNSIGNED DEFAULT \"0\" NOT NULL;\n";
		cerr << "ALTER TABLE `zone` ADD flag_needed VARCHAR(128) NOT NULL DEFAULT '';\n";

		safe_delete_array(query);
	}
	return false;
}


bool Database::GetZoneLongName(const char* short_name, char** long_name, char* file_name, float* safe_x, float* safe_y, float* safe_z, int32* graveyard_id, int32* maxclients) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s'", short_name), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (long_name != 0) {
				*long_name = strcpy(new char[strlen(row[0])+1], row[0]);
			}
			if (file_name != 0) {
				if (row[1] == 0)
					strcpy(file_name, short_name);
				else
					strcpy(file_name, row[1]);
			}
			if (safe_x != 0)
				*safe_x = atof(row[2]);
			if (safe_y != 0)
				*safe_y = atof(row[3]);
			if (safe_z != 0)
				*safe_z = atof(row[4]);
			if (graveyard_id != 0)
				*graveyard_id = atoi(row[5]);
			if (maxclients)
				*maxclients = atoi(row[6]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneLongName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return false;
}
int32 Database::GetZoneGraveyardID(int32 zone_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
    int32 GraveyardID = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT graveyard_id FROM zone WHERE zoneidnumber='%u'", zone_id), errbuf, &result))
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			GraveyardID = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneGraveyardID query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
	return GraveyardID;
}
bool Database::GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid, float* graveyard_x, float* graveyard_y, float* graveyard_z, float* graveyard_heading) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone_id, x, y, z, heading FROM graveyard WHERE id=%i", graveyard_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if(graveyard_zoneid != 0)
				*graveyard_zoneid = atoi(row[0]);
			if(graveyard_x != 0)
				*graveyard_x = atof(row[1]);
			if(graveyard_y != 0)
				*graveyard_y = atof(row[2]);
			if(graveyard_z != 0)
				*graveyard_z = atof(row[3]);
			if(graveyard_heading != 0)
				*graveyard_heading = atof(row[4]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneGraveyard query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return false;
}

bool Database::LoadZoneNames() {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	query = new char[256];
	strcpy(query, "SELECT MAX(zoneidnumber) FROM zone");

	if (RunQuery(query, strlen(query), errbuf, &result)) {
		safe_delete_array(query);
		row = mysql_fetch_row(result);
		if (row && row[0])
		{
			max_zonename = atoi(row[0]);
			zonename_array = new char*[max_zonename+1];
			for(unsigned int i=0; i<max_zonename; i++) {
				zonename_array[i] = 0;
			}
			mysql_free_result(result);

			MakeAnyLenString(&query, "SELECT zoneidnumber, short_name FROM zone");
			if (RunQuery(query, strlen(query), errbuf, &result)) {
				safe_delete_array(query);
				while((row = mysql_fetch_row(result))) {
					zonename_array[atoi(row[0])] = new char[strlen(row[1]) + 1];
					strcpy(zonename_array[atoi(row[0])], row[1]);
					Sleep(0);
				}
				mysql_free_result(result);
			}
			else {
				cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
				safe_delete_array(query);
				return false;
			}
		}
		else {
			mysql_free_result(result);
		}
	}
	else {
		cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	return true;
}

int32 Database::GetZoneID(const char* zonename) {
	if (zonename_array == 0)
		return 0;
	if (zonename == 0)
		return 0;
	for (unsigned int i=0; i<=max_zonename; i++) {
		if (zonename_array[i] != 0 && strcasecmp(zonename_array[i], zonename) == 0) {
			return i;
		}
	}
	return 0;
}

const char* Database::GetZoneName(int32 zoneID, bool ErrorUnknown) {
	if (zonename_array == 0) {
		if (ErrorUnknown)
			return "UNKNOWN";
		else
			return 0;
	}
	
	if (zoneID <= max_zonename) {
  		if (zonename_array[zoneID])
  			return zonename_array[zoneID];
  		else {
  			if (ErrorUnknown)
  				return "UNKNOWN";
  			else
  				return 0;
  		}
  	}
	else {
		if (ErrorUnknown)
			return "UNKNOWN";
		else
			return 0;
	}
	return 0;
}

int8 Database::GetPEQZone(int32 zoneID){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int peqzone=0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT peqzone from zone where zoneidnumber='%i'", zoneID), errbuf, &result)) 
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			peqzone = atoi(row[0]);
		}
			mysql_free_result(result);
		}
		else
		{
			cerr << "Error in GetPEQZone query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
	return peqzone;
}

bool Database::CheckNameFilter(const char* name, bool surname) 
{
	std::string str_name = name;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if(surname)
	{
		// the minimum 4 is enforced by the client too
		if(!name || strlen(name) < 3)
		{
			return false;
		}
	}
	else
	{
		// the minimum 4 is enforced by the client too
		if(!name || strlen(name) < 4 || strlen(name) > 64)
		{
			return false;
		}
	}

	for (int i = 0; i < str_name.size(); i++)
	{
		if(!isalpha(str_name[i]))
		{
			return false;
		}
	}

	for(int x = 0; x < str_name.size(); ++x)
	{
		str_name[x] = tolower(str_name[x]);
	}

	char c = '\0';
	int8 num_c = 0;
	for(int x = 0; x < str_name.size(); ++x)
	{
		if(str_name[x] == c)
		{
			num_c++;
		}
		else
		{
			num_c = 1;
			c = str_name[x];
		}
		if(num_c > 2)
		{
			return false;
		}
	}

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM name_filter"), errbuf, &result)) {
		safe_delete_array(query);
		while(row = mysql_fetch_row(result))
		{
			std::string current_row = row[0];
			for(int x = 0; x < current_row.size(); ++x)
			{
				current_row[x] = tolower(current_row[x]);
			}

			if(str_name.find(current_row) != std::string::npos)
			{
				return false;
			}
		}

		mysql_free_result(result);
		return true;
	}
	else
	{
		cerr << "Error in CheckNameFilter query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return true;
}

bool Database::AddToNameFilter(const char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32 affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO name_filter (name) values ('%s')", name), errbuf, 0, &affected_rows)) {
		cerr << "Error in AddToNameFilter query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);

	if (affected_rows == 0) {
		return false;
	}

	return true;
}

int32 Database::GetAccountIDFromLSID(int32 iLSID, char* oAccountName, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
    
#ifdef DUAL_SERVER
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id2=%i OR lsaccount_id=%i", iLSID, iLSID), errbuf, &result))
#else
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id=%i", iLSID), errbuf, &result))
#endif

	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 account_id = atoi(row[0]);
			if (oAccountName)
				strcpy(oAccountName, row[1]);
			if (oStatus)
				*oStatus = atoi(row[2]);
			mysql_free_result(result);
			return account_id;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDFromLSID query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}

	return 0;
}

void Database::GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, status FROM account WHERE id=%i", id), errbuf, &result))
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (oAccountName)
				strcpy(oAccountName, row[0]);
			if (oStatus)
				*oStatus = atoi(row[1]);
		}
		mysql_free_result(result);
	}
	else
		cerr << "Error in GetAccountFromID query '" << query << "' " << errbuf << endl;
	safe_delete_array(query);
}

void Database::ClearMerchantTemp(){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "delete from merchantlist_temp"), errbuf)) {
		cerr << "Error in ClearMerchantTemp query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
}

bool Database::UpdateName(const char* oldname, const char* newname) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32	affected_rows = 0;

	cout << "Renaming " << oldname << " to " << newname << "..." << endl;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET name='%s' WHERE name='%s';", newname, oldname), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

// If the name is used or an error occurs, it returns false, otherwise it returns true
bool Database::CheckUsedName(const char* name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
    MYSQL_RES *result;
	//if (strlen(name) > 15)
	//	return false;
	if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM character_ where name='%s'", name), errbuf, &result)) {
		cerr << "Error in CheckUsedName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	else { // It was a valid Query, so lets do our counts!
		safe_delete_array(query);
		int32 tmp = mysql_num_rows(result);
		mysql_free_result(result);
		if (tmp > 0) // There is a Name!  No change (Return False)
			return false;
		else // Everything is okay, so we go and do this.
			return true;
	}
}

int8 Database::GetServerType()
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT value FROM variables WHERE varname='ServerType'"), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int8 ServerType = atoi(row[0]);
			mysql_free_result(result);
			return ServerType;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else

	{


		cerr << "Error in GetServerType query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;

}

bool Database::MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if(zonename == NULL || strlen(zonename) == 0)
		return(false);

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s',zoneid=%i,x=-1, y=-1, z=-1 WHERE name='%s'", zonename,zoneid, charname), errbuf, 0,&affected_rows)) {
		cerr << "Error in MoveCharacterToZone(name) query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
		return false;

	return true;
}

bool Database::MoveCharacterToZone(const char* charname, const char* zonename) {
	return MoveCharacterToZone(charname, zonename, GetZoneID(zonename));
}

bool Database::MoveCharacterToZone(int32 iCharID, const char* iZonename) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s', zoneid=%i, x=-1, y=-1, z=-1 WHERE id=%i", iZonename, GetZoneID(iZonename), iCharID), errbuf, 0,&affected_rows)) {
		cerr << "Error in MoveCharacterToZone(id) query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
		return false;

	return true;
}

int8 Database::CopyCharacter(const char* oldname, const char* newname, int32 acctid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	PlayerProfile_Struct* pp;
	ExtendedProfile_Struct* ext;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile, guild, guildrank, extprofile FROM character_ WHERE name='%s'", oldname), errbuf, &result)) {
		safe_delete_array(query);

		row = mysql_fetch_row(result);

		pp = (PlayerProfile_Struct*)row[0];
		strcpy(pp->name, newname);

		ext = (ExtendedProfile_Struct*)row[3];

		mysql_free_result(result);
	}

	else {
		cerr << "Error in CopyCharacter read query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}

	int32 affected_rows = 0;
	char query2[276 + sizeof(PlayerProfile_Struct)*2 + sizeof(ExtendedProfile_Struct)*2 + 1];
	char* end=query2;

	end += sprintf(end, "INSERT INTO character_ SET zonename=\'%s\', x = %f, y = %f, z = %f, profile=\'", GetZoneName(pp->zone_id), pp->x, pp->y, pp->z);
    end += DoEscapeString(end, (char*) pp, sizeof(PlayerProfile_Struct));
	end += sprintf(end,"\', extprofile=\'");
	end += DoEscapeString(end, (char*) ext, sizeof(ExtendedProfile_Struct));
    end += sprintf(end, "\', account_id=%d, name='%s'", acctid, newname);

	if (!RunQuery(query2, (int32) (end - query2), errbuf, 0, &affected_rows)) {
        cerr << "Error in CopyCharacter query '" << query << "' " << errbuf << endl;
		return 0;
    }

	// @merth: Need to copy inventory as well (and shared bank?)
	if (affected_rows == 0) {
		return 0;
	}

	return 1;
}

bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked) values('%s','%s','%s')", accountname, charactername, hacked), errbuf, 0,&affected_rows)) {
		cerr << "Error in SetHackerFlag query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka:  Utilize the "hacker" table, but also give zone information.

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {
		cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;
		return false;
	}

	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

int8 Database::GetRaceSkill(int8 skillid, int8 in_race)
{
	int16 race_cap = 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	//Check for a racial cap!
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT skillcap from race_skillcaps where skill = %i && race = %i", skillid, in_race), errbuf, &result, &affected_rows))
	{
		if (affected_rows != 0)
		{
			row = mysql_fetch_row(result);
			race_cap = atoi(row[0]);
		}
		delete[] query;
		mysql_free_result(result);
	}

	return race_cap;
}

int8 Database::GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level)
{
	int8 skill_level = 0, skill_formula = 0;
	int16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	//Fetch the data from DB.
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class), errbuf, &result, &affected_rows))
	{
		if (affected_rows != 0)
		{
			row = mysql_fetch_row(result);
			skill_level = atoi(row[0]);
			skill_formula = atoi(row[1]);
			skill_cap = atoi(row[2]);
			if (atoi(row[3]) > skill_cap)
				skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
			skill_cap3 = atoi(row[4]);
		}
		delete[] query;
		mysql_free_result(result);
	}

	int race_skill = GetRaceSkill(skillid,in_race);

	if (race_skill > 0 && (race_skill > skill_cap || skill_cap == 0 || in_level < skill_level))
		return race_skill;

	if (skill_cap == 0) //Can't train this skill at all.
		return 255; //Untrainable

	if (in_level < skill_level)
		return 254; //Untrained

	//Determine pre-51 level-based cap
	if (skill_formula > 0)
		base_cap = in_level*skill_formula+skill_formula;
	if (base_cap > skill_cap || skill_formula == 0)
		base_cap = skill_cap;
	//If post 50, add post 50 cap to base cap.
	if (in_level > 50 && skill_cap2 > 0)
		base_cap += skill_cap2*(in_level-50);
	//No cap should ever go above its post50cap
	if (skill_cap3 > 0 && base_cap > skill_cap3)
		base_cap = skill_cap3;
	//Base cap is now the max value at the person's level, return it!
	return base_cap;
}

int32 Database::GetCharacterInfo(const char* iName, int32* oAccID, int32* oZoneID, int32* oInstanceID, float* oX, float* oY, float* oZ) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, account_id, zonename, instanceid, x, y, z FROM character_ WHERE name='%s'", iName), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 charid = atoi(row[0]);
			if (oAccID)
				*oAccID = atoi(row[1]);
			if (oZoneID)
				*oZoneID = GetZoneID(row[2]);
			if(oInstanceID)
				*oInstanceID = atoi(row[3]);
			if (oX)
				*oX = atof(row[4]);
			if (oY)
				*oY = atof(row[5]);
			if (oZ)
				*oZ = atof(row[6]);
			mysql_free_result(result);
			return charid;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetCharacterInfo query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return 0;
}

bool Database::UpdateLiveChar(char* charname,int32 lsaccount_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET charname='%s' WHERE id=%i;",charname, lsaccount_id), errbuf)) {
		cerr << "Error in UpdateLiveChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);
	return true;
}

bool Database::GetLiveChar(int32 account_id, char* cname) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charname FROM account WHERE id=%i", account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			strcpy(cname,row[0]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetLiveChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return false;
}

void Database::SetLFP(int32 CharID, bool LFP) {

	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;

	if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfp=%i where id=%i",LFP, CharID), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);

	safe_delete_array(Query);

}

void Database::SetLFG(int32 CharID, bool LFG) {

	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;

	if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfg=%i where id=%i",LFG, CharID), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);

	safe_delete_array(Query);

}

void Database::AddReport(std::string who, std::string against, std::string lines)
{
	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;
	char *escape_str = new char[lines.size()*2+1];
	DoEscapeString(escape_str, lines.c_str(), lines.size());

	if (!RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error adding a report for %s: %s", who.c_str(), ErrBuf);

	safe_delete_array(Query);
	safe_delete_array(escape_str);
}

void  Database::SetGroupID(const char* name,int32 id, int32 charid){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(id == 0){ //removing you from table
	if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where charid=%i and name='%s'",charid, name), errbuf))
		printf("Unable to get group id: %s\n",errbuf);
	}
	else{
	if (!RunQuery(query, MakeAnyLenString(&query, "replace into group_id set charid=%i, groupid=%i, name='%s'",charid, id, name), errbuf))
		printf("Unable to get group id: %s\n",errbuf);
	}
#ifdef _EQDEBUG
	printf("Set group id on '%s' to %d\n", name, id);
#endif
	safe_delete_array(query);
}

void Database::ClearGroup(int32 gid) {
	ClearGroupLeader(gid);
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(gid == 0) {  //clear all groups
		//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid!=0"), errbuf))
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id"), errbuf))
			printf("Unable to clear groups: %s\n",errbuf);
	} else {	//clear a specific group
		//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid = %lu", gid), errbuf))
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where groupid = %lu", (unsigned long)gid), errbuf))
			printf("Unable to clear groups: %s\n",errbuf);
	}
	safe_delete_array(query);
}

int32 Database::GetGroupID(const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 groupid=0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT groupid from group_id where name='%s'", name), errbuf, &result)) {
		if((row = mysql_fetch_row(result)))
		{
			if(row[0])
				groupid=atoi(row[0]);
		}
		else
			printf("Unable to get group id, char not found!\n");
		mysql_free_result(result);
	}
	else
			printf("Unable to get group id: %s\n",errbuf);
	safe_delete_array(query);
	return groupid;
}

char* Database::GetGroupLeaderForLogin(const char* name,char* leaderbuf){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	PlayerProfile_Struct pp;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile from character_ where name='%s'", name), errbuf, &result)) {
		row = mysql_fetch_row(result);
		unsigned long* lengths = mysql_fetch_lengths(result);
		if (lengths[0] == sizeof(PlayerProfile_Struct)) {
			memcpy(&pp, row[0], sizeof(PlayerProfile_Struct));
			strcpy(leaderbuf,pp.groupMembers[0]);
		}
		mysql_free_result(result);
	}
	else{
			printf("Unable to get leader name: %s\n",errbuf);
	}
	safe_delete_array(query);
	return leaderbuf;
}

void Database::SetGroupLeaderName(int32 gid, const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "Replace into group_leaders set gid=%lu, leadername='%s'",(unsigned long)gid,name), errbuf))
		printf("Unable to set group leader: %s\n",errbuf);

	safe_delete_array(query);
}

char *Database::GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist, char *marknpc, GroupLeadershipAA_Struct* GLAA){
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES* result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT leadername, assist, marknpc, leadershipaa FROM group_leaders WHERE gid=%lu",(unsigned long)gid),
		     errbuf, &result)) {

		safe_delete_array(query);

		row = mysql_fetch_row(result);
		unsigned long* Lengths = mysql_fetch_lengths(result);

		if(row != NULL){

			if(leaderbuf)
				strcpy(leaderbuf, row[0]);

			if(assist)
				strcpy(assist, row[1]);

			if(marknpc)
				strcpy(marknpc, row[2]);

			if(GLAA && (Lengths[3] == sizeof(GroupLeadershipAA_Struct)))
				memcpy(GLAA, row[3], sizeof(GroupLeadershipAA_Struct));

			mysql_free_result(result);
			return leaderbuf;
		}
	}
	else
		safe_delete_array(query);

	if(leaderbuf)
		strcpy(leaderbuf, "UNKNOWN");

	if(assist)
		assist[0] = 0;

	if(marknpc)
		marknpc[0] = 0;

	return leaderbuf;
}

void Database::ClearGroupLeader(int32 gid){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(gid == 0) {  //clear all group leaders
		if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders"), errbuf))
			printf("Unable to clear group leaders: %s\n",errbuf);
	} else {	//clear a specific group leader
		if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders where gid = %lu", (unsigned long)gid), errbuf))
			printf("Unable to clear group leader: %s\n",errbuf);
	}
	safe_delete_array(query);
}

bool FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap)
{
MYSQL_FIELD *fields;
MYSQL_ROW row;
unsigned long num_fields,i;
bool  retval=false;
	rowmap.clear();
	if (result && (num_fields=mysql_num_fields(result)) && (row = mysql_fetch_row(result))!=NULL && (fields = mysql_fetch_fields(result))!=NULL) {
		retval=true;
		for(i=0;i<num_fields;i++) {
			rowmap[fields[i].name]=(row[i] ? row[i] : "");
		}
	}

	return retval;
}

int8 Database::GetAgreementFlag(int32 acctid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES* result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT rulesflag FROM account WHERE id=%i",acctid), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int8 flag = atoi(row[0]);
			mysql_free_result(result);
			return flag;
		}
	}
	else
	{
		safe_delete_array(query);
	}
	return 0;
}

void Database::SetAgreementFlag(int32 acctid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET rulesflag=1 where id=%i",acctid), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
	}
	else
	safe_delete_array(query);
}

void Database::ClearRaid(int32 rid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(rid == 0) {  //clear all raids
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members"), errbuf))
			printf("Unable to clear raids: %s\n",errbuf);
	} else {	//clear a specific group
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members where raidid = %lu", (unsigned long)rid), errbuf))
			printf("Unable to clear raids: %s\n",errbuf);
	}
	safe_delete_array(query);
}

void Database::ClearRaidDetails(int32 rid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(rid == 0) {  //clear all raids
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details"), errbuf))
			printf("Unable to clear raid details: %s\n",errbuf);
	} else {	//clear a specific group
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details where raidid = %lu", (unsigned long)rid), errbuf))
			printf("Unable to clear raid details: %s\n",errbuf);
	}
	safe_delete_array(query);
}

int32 Database::GetRaidID(const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 raidid=0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT raidid from raid_members where name='%s'", name), 
		errbuf, &result)) {
		if((row = mysql_fetch_row(result)))
		{
			if(row[0])
				raidid=atoi(row[0]);
		}
		else
			printf("Unable to get raid id, char not found!\n");
		mysql_free_result(result);
	}
	else
			printf("Unable to get raid id: %s\n",errbuf);
	safe_delete_array(query);
	return raidid;
}

const char *Database::GetRaidLeaderName(int32 rid)
{
	static char name[128];

	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM raid_members WHERE raidid=%u AND israidleader=1", 
		rid), errbuf, &result)) {
		if((row = mysql_fetch_row(result)) != NULL)
		{
			memset(name, 0, 128);
			strcpy(name, row[0]);
			mysql_free_result(result);
			safe_delete_array(query);
			return name;
		}
		else
			printf("Unable to get raid id, char not found!\n");
		mysql_free_result(result);
	}
	else
		printf("Unable to get raid id: %s\n",errbuf);
	safe_delete_array(query);
	return "UNKNOWN";
}

bool Database::VerifyInstanceAlive(int16 instance_id, int32 char_id)
{

	//we are not saved to this instance so set our instance to 0
	if(!CharacterInInstanceGroup(instance_id, char_id))
	{
		SetCharacterInstance(0, char_id);
		return false;
	}

	if(CheckInstanceExpired(instance_id))
	{
		DeleteInstance(instance_id);
		SetCharacterInstance(0, char_id);
		return false;
	}
	return true;
}

bool Database::VerifyZoneInstance(int32 zone_id, int16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id=%u AND zone=%u", 
		instance_id, zone_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			mysql_free_result(result);
			return true;
		}
		else
		{
			mysql_free_result(result);
			return false;
		}
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

bool Database::CharacterInInstanceGroup(int16 instance_id, int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	bool lockout_instance_player = false;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player where id=%u AND charid=%u", 
		instance_id, char_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) 
		{
			lockout_instance_player = true;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return lockout_instance_player;
}

void Database::SetCharacterInstance(int16 instance_id, int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET instanceid=%u WHERE id=%u", instance_id, 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::DeleteInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout WHERE id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE instance_id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}
	BuryCorpsesInInstance(instance_id);
}

bool Database::CheckInstanceExpired(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int32 start_time = 0;
	int32 duration = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u", 
		instance_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			start_time = atoi(row[0]);
			duration = atoi(row[1]);
		}
		else
		{
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return true;
	}

	timeval tv;
	gettimeofday(&tv, NULL);
	if((start_time + duration) <= tv.tv_sec)
	{
		return true;
	}
	return false;
}

int32 Database::ZoneIDFromInstanceID(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int32 Database::VersionFromInstanceID(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int32 Database::GetTimeRemainingInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 start_time = 0;
	int32 duration = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u", 
		instance_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			start_time = atoi(row[0]);
			duration = atoi(row[1]);
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}

	timeval tv;
	gettimeofday(&tv, NULL);
	return ((start_time + duration) - tv.tv_sec);
}

bool Database::GetUnusedInstanceID(uint16 &instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT COUNT(*) FROM instance_lockout"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			int count = atoi(row[0]);
			if(count == 0)
			{
				mysql_free_result(result);
				instance_id = 1;
				return true;
			}
		}
		else
		{
			mysql_free_result(result);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		instance_id = 0;
		return false;
	}

	int32 count = 1;
	int32 max = 65535;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout ORDER BY id"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			while(row = mysql_fetch_row(result))
			{
				if(count < atoi(row[0]))
				{
					instance_id = count;
					mysql_free_result(result);
					return true;
				}
				else if(count > max)
				{
					instance_id = 0;
					mysql_free_result(result);
					return false;
				}
				else
				{
					count++;
				}
			}
		}
		else
		{
			mysql_free_result(result);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	instance_id = count;
	return true;
}

//perhaps purge any expireds too
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout (id, zone, version, start_time, duration)" 
		" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

void Database::PurgeExpiredInstances()
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int16 id = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where "
			"(start_time+duration)<=UNIX_TIMESTAMP()"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) > 0) 
		{
			row = mysql_fetch_row(result);
			while(row != NULL)
			{
				id = atoi(row[0]);
				DeleteInstance(id);
				row = mysql_fetch_row(result);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout_player(id, charid) "
			"values(%lu, %lu)", (unsigned long)instance_id, (unsigned long)char_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu AND charid=%lu", 
		(unsigned long)instance_id, (unsigned long)char_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::RemoveClientsFromInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu", 
		(unsigned long)instance_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::CheckInstanceExists(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
		return false;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

void Database::BuryCorpsesInInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET IsBurried=1, instanceid=0 WHERE instanceid=%u", 
		instance_id), errbuf, &result))
	{
		mysql_free_result(result);
	}
	safe_delete_array(query);
}

int16 Database::GetInstanceVersion(uint16 instance_id)
{
	if(instance_id < 1)
		return 0;

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int16 Database::GetInstanceID(const char* zone, int32 charid, int16 version)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
		"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
		"instance_lockout_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;		
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int16 Database::GetInstanceID(int32 zone, int32 charid, int16 version)
{
	if(!zone)
		return 0;

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
		"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
		"instance_lockout_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;		
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

void Database::AssignGroupToInstance(int32 gid, int32 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 zone_id = ZoneIDFromInstanceID(instance_id);
	int16 version = VersionFromInstanceID(instance_id);

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id WHERE groupid=%u", gid), 
		errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			if(GetInstanceID(zone_id, charid, version) == 0)
			{
				AddClientToInstance(instance_id, charid);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::AssignRaidToInstance(int32 rid, int32 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 zone_id = ZoneIDFromInstanceID(instance_id);
	int16 version = VersionFromInstanceID(instance_id);

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members WHERE raidid=%u", rid), 
		errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			if(GetInstanceID(zone_id, charid, version) == 0)
			{
				AddClientToInstance(instance_id, charid);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid)
{
	int16 id = GetInstanceID(zone, charid, version);
	if(id != 0)
		return;

	char ln[128];
	memset(ln, 0, 128);
	strcpy(ln, GetGroupLeadershipInfo(gid, ln));
	int32 l_charid = GetCharacterID((const char*)ln);
	int16 l_id = GetInstanceID(zone, l_charid, version);

	if(l_id == 0)
		return;

	AddClientToInstance(l_id, charid);
}

void Database::FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid)
{
	int16 id = GetInstanceID(zone, charid, version);
	if(id != 0)
		return;

	int32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
	int16 l_id = GetInstanceID(zone, l_charid, version);

	if(l_id == 0)
		return;

	AddClientToInstance(l_id, charid);
}

void Database::SetInstanceDuration(int16 instance_id, int32 new_duration)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_lockout` SET start_time=UNIX_TIMESTAMP(), "
		"duration=%u WHERE id=%u", new_duration, instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 m_avg_level = 0;
	int8 num_in_group = 0;
	int16 min_level = 2000;
	int16 max_level = 0;

#ifndef GROUP_ADV_USE_VIEW
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT character_.level FROM character_, group_id"
		" WHERE character_.id=group_id.charid AND group_id.groupid=%u", gid), errbuf, &result))
#else
	if (RunQuery(query, MakeAnyLenString(&query, "select level from vwGroups where groupid = %u", gid), errbuf, &result))
#endif
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int16 m_lvl = atoi(row[0]);
			m_avg_level += m_lvl;
			if(m_lvl < min_level)
				min_level = m_lvl;

			if(m_lvl > max_level)
				max_level = m_lvl;
			num_in_group++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	avg_level = (m_avg_level / num_in_group);
	range = max_level-min_level;
}

void Database::RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 m_avg_level = 0;
	int8 num_in_group = 0;
	int16 min_level = 2000;
	int16 max_level = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT raid_members.level FROM raid_members "
		"WHERE raid_members.raidid=%u", rid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int16 m_lvl = atoi(row[0]);
			m_avg_level += m_lvl;
			if(m_lvl < min_level)
				min_level = m_lvl;

			if(m_lvl > max_level)
				max_level = m_lvl;
			num_in_group++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	avg_level = (m_avg_level / num_in_group);
	range = max_level-min_level;
}

int32 Database::CreateAdventure(int32 adventure_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected_rows = 0;
	int32 last_insert_id = 0;

    if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_details` SET adventure_id=%u,"
		" time_created=UNIX_TIMESTAMP()", adventure_id), errbuf, 0, &affected_rows, &last_insert_id)) {
		safe_delete_array(query);
		return 0;
    }
	safe_delete_array(query);
	
	if (affected_rows == 0) 
	{
		return 0;
	}

	if (last_insert_id == 0) 
	{
		return 0;
	}
	return last_insert_id;
}

void Database::AddPlayerToAdventure(int32 id, int32 charid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_members` SET"
		" id=%u, charid=%u", id, charid), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::RemovePlayerFromAdventure(int32 id, int32 charid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
		" id=%u AND charid=%u", id, charid), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::RemovePlayersFromAdventure(int32 id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
		" id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::AddGroupToAdventure(int32 id, int32 gid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id "
		"WHERE groupid=%u", gid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			AddPlayerToAdventure(id, charid);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::AddRaidToAdventure(int32 id, int32 rid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members "
		"WHERE raidid=%u", rid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			AddPlayerToAdventure(id, charid);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::DestroyAdventure(int32 id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details` WHERE id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

bool Database::GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count, 
								   int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 adv_id = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1", 
		charid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adv_id = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(adv_id == 0)
		return false;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `adventure_id`, `instance_id`, `count`, `assassinate_count`, `status`, "
		"`time_created`, `time_zoned`, `time_completed` FROM `adventure_details` WHERE id=%u LIMIT 1", adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adventure_id = atoi(row[0]);
			instance_id = atoi(row[1]);
			count = atoi(row[2]);
			ass_count = atoi(row[3]);
			status = atoi(row[4]);
			time_c = atoi(row[5]);
			time_z = atoi(row[6]);
			time_comp = atoi(row[7]);
			id = adv_id;
		}
		mysql_free_result(result);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

int32 Database::GetAdventureID(int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 adv_id = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1", 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adv_id = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return adv_id;
}

int32 Database::CountPlayersInAdventure(int32 id) 
{ 
	//SELECT `charid` FROM `adventure_members` WHERE id=%u
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int count = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE "
		"id=%u", id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			count++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return count;
}

void Database::PurgeAdventures() 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details`"), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members`"), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::AddAdventureToInstance(int32 adv_id, int32 inst_id) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 id = atoi(row[0]);
			AddClientToInstance(inst_id, id);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureStatus(int32 adv_id, int32 status) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET status=%u WHERE id=%u", 
		status, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET instance_id=%d, "
		"time_zoned=%u WHERE id=%u", inst_id, time, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureCompleted(int32 adv_id, int32 time)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET time_completed=%u "
		"WHERE id=%u", time, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureCount(int32 adv_id, int32 new_count)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=%u "
		"WHERE id=%u", new_count, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::IncrementAdventureCount(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=count+1 "
		"WHERE id=%u", adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

int32 Database::GetAdventureCount(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `count` FROM `adventure_details` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 count = atoi(row[0]);
			return count;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;	
}

bool Database::AdventureExists(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_details` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

void Database::UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected = 0;

	std::string field;

	if(win)
	{
		switch(theme)
		{
			case 1:
			{
				field = "guk_wins";
				break;
			}
			case 2:
			{
				field = "mir_wins";
				break;
			}
			case 3:
			{
				field = "mmc_wins";
				break;
			}
			case 4:
			{
				field = "ruj_wins";
				break;
			}
			case 5:
			{
				field = "tak_wins";
				break;
			}
			default:
			{
				return;
			}
		}
	}
	else
	{
		switch(theme)
		{
			case 1:
			{
				field = "guk_losses";
				break;
			}
			case 2:
			{
				field = "mir_losses";
				break;
			}
			case 3:
			{
				field = "mmc_losses";
				break;
			}
			case 4:
			{
				field = "ruj_losses";
				break;
			}
			case 5:
			{
				field = "tak_losses";
				break;
			}
			default:
			{
				return;
			}
		}
	}

		if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_stats` SET %s=%s+1 WHERE player_id=%u",
		field.c_str(), field.c_str(), char_id), errbuf, NULL, &affected))
		{
			safe_delete_array(query);
		}
		else
		{
			//error
			safe_delete_array(query);
		}

	if(affected == 0)
	{
		if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_stats` SET %s=1, player_id=%u",
			field.c_str(), char_id), errbuf))
		{
			safe_delete_array(query);
		}
		else
		{
			//error
			safe_delete_array(query);
		}
	}
}

void Database::UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if(!AdventureExists(adv_id))
		return;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			UpdateAdventureStatsEntry(charid, theme, win);
		}
		mysql_free_result(result);
	}
	else
	{
		safe_delete_array(query);
	}
}

bool Database::GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w, 
								 int32 &tak_w, int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `guk_wins`, `mir_wins`, `mmc_wins`, `ruj_wins`, `tak_wins`, "
		"`guk_losses`, `mir_losses`, `mmc_losses`, `ruj_losses`, `tak_losses` FROM `adventure_stats` WHERE player_id=%u", 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			guk_w = atoi(row[0]);
			mir_w = atoi(row[1]);
			mmc_w = atoi(row[2]);
			ruj_w = atoi(row[3]);
			tak_w = atoi(row[4]);
			guk_l = atoi(row[5]);
			mir_l = atoi(row[6]);
			mmc_l = atoi(row[7]);
			ruj_l = atoi(row[8]);
			tak_l = atoi(row[9]);
		}
		mysql_free_result(result);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

int32 Database::AdventureGetAssassinateKills(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret_val = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `assassinate_count` FROM"
		" `adventure_details` WHERE id=%u", adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			ret_val = atoi(row[0]);
		}
		mysql_free_result(result);
		return ret_val;
	}
	else 
	{
		safe_delete_array(query);
		return ret_val;
	}
}

void Database::AdventureSetAssassinateKills(int32 adv_id, int32 kills)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET assassinate_count=%u "
		"WHERE id=%u", kills, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}
database.h
Code:
#ifndef EQEMU_DATABASE_H
#define EQEMU_DATABASE_H

#define AUTHENTICATION_TIMEOUT	60
#define INVALID_ID				0xFFFFFFFF

#include "debug.h"
#include "types.h"
#include "dbcore.h"
#include "linked_list.h"
#include "eq_packet_structs.h"
/*#include "EQStream.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "Mutex.h"
#include "Item.h"
#include "extprofile.h"*/
#include <string>
#include <vector>
#include <map>
using namespace std;

//atoi is not int32 or uint32 safe!!!!
#define atoul(str) strtoul(str, NULL, 10)

//class Spawn;
class Corpse;
class Spawn2;
class NPC;
class SpawnGroupList;
class Petition;
class Client;
struct Combine_Struct;
//struct Faction;
//struct FactionMods;
//struct FactionValue;
struct ZonePoint;
struct NPCType;
class Inventory;
class ItemInst;

struct EventLogDetails_Struct {
	int32	id;
	char	accountname[64];
	int32	account_id;
	sint16	status;
	char	charactername[64];
	char	targetname[64];
	char	timestamp[64];
	char	descriptiontype[64];
	char	details[128];
};

struct CharacterEventLog_Struct {
int32	count;
int8	eventid;
EventLogDetails_Struct eld[255];
};


// Added By Hogie 
// INSERT into variables (varname,value) values('decaytime [minlevel] [maxlevel]','[number of seconds]');
// IE: decaytime 1 54 = Levels 1 through 54
//     decaytime 55 100 = Levels 55 through 100
// It will always put the LAST time for the level (I think) from the Database
struct npcDecayTimes_Struct {
	int16 minlvl;
	int16 maxlvl;
	int32 seconds;
};
// Added By Hogie -- End

struct VarCache_Struct {
	char varname[26];	// varname is char(25) in database
	char value[0];
};

struct PlayerProfile_Struct;
struct GuildRankLevel_Struct;
struct GuildRanks_Struct;
struct ExtendedProfile_Struct;
struct GuildMember_Struct;
class PTimerList;

class Database : public DBcore {
public:
	Database();
	Database(const char* host, const char* user, const char* passwd, const char* database,int32 port);
	bool Connect(const char* host, const char* user, const char* passwd, const char* database,int32 port);
	~Database();
	
	
//	void	ExtraOptions();
	

	/*
	 * General Character Related Stuff
	 */
	bool	MoveCharacterToZone(const char* charname, const char* zonename);
	bool	MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid);
	bool	MoveCharacterToZone(int32 iCharID, const char* iZonename);
	bool	UpdateName(const char* oldname, const char* newname);
	bool	SetHackerFlag(const char* accountname, const char* charactername, const char* hacked);
	bool	SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
	bool	AddToNameFilter(const char* name);
	bool	ReserveName(int32 account_id, char* name);
	bool	CreateCharacter(uint32 account_id, char* name, int16 gender, int16 race, int16 class_, int8 str, int8 sta, int8 cha, int8 dex, int8 int_, int8 agi, int8 wis, int8 face);
	bool	StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext);
	bool	DeleteCharacter(char* name);
	int8	CopyCharacter(const char* oldname, const char* newname, int32 acctid);

	/*
	 * General Information Getting Queries
	 */
	bool	CheckNameFilter(const char* name, bool surname = false);
	bool	CheckUsedName(const char* name);
	int32	GetAccountIDByChar(const char* charname, int32* oCharID = 0);
	uint32	GetAccountIDByChar(uint32 char_id);
	int32	GetAccountIDByName(const char* accname, sint16* status = 0, int32* lsid = 0);
	void	GetAccountName(int32 accountid, char* name, int32* oLSAccountID = 0);
	void	GetCharName(int32 char_id, char* name);
	int32	GetCharacterInfo(const char* iName, int32* oAccID = 0, int32* oZoneID = 0, int32* oInstanceID = 0,float* oX = 0, float* oY = 0, float* oZ = 0);
	int32	GetCharacterID(const char *name);
	bool	CheckBannedIPs(const char* loginIP); //Lieka Edit:  Check incomming connection against banned IP table.
 	bool	AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit:  Add IP address to the Banned_IPs table.
	bool	CheckGMIPs(const char* loginIP, int32 account_id);
	bool	AddGMIP(char* ip_address, char* name);
	void	LoginIP(int32 AccountID, const char* LoginIP);

	/*
	 * Instancing Stuff
	 */
	bool VerifyZoneInstance(int32 zone_id, int16 instance_id);
	bool VerifyInstanceAlive(int16 instance_id, int32 char_id);
	bool CharacterInInstanceGroup(int16 instance_id, int32 char_id);
	void SetCharacterInstance(int16 instance_id, int32 char_id);
	void DeleteInstance(uint16 instance_id);
	bool CheckInstanceExpired(uint16 instance_id);
	int32 ZoneIDFromInstanceID(uint16 instance_id);
	int32 VersionFromInstanceID(uint16 instance_id);
	int32 GetTimeRemainingInstance(uint16 instance_id);
	bool GetUnusedInstanceID(uint16 &instance_id);
	bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
	void PurgeExpiredInstances();
	bool AddClientToInstance(uint16 instance_id, uint32 char_id);
	bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
	bool RemoveClientsFromInstance(uint16 instance_id);
	bool CheckInstanceExists(uint16 instance_id);
	void BuryCorpsesInInstance(uint16 instance_id);
	int16 GetInstanceVersion(uint16 instance_id);
	int16 GetInstanceID(const char* zone, int32 charid, int16 version);
	int16 GetInstanceID(int32 zone, int32 charid, int16 version);
	void AssignGroupToInstance(int32 gid, int32 instance_id);
	void AssignRaidToInstance(int32 rid, int32 instance_id);
	void FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid);
	void FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid);
	void SetInstanceDuration(int16 instance_id, int32 new_duration);

	/*
	 * Adventure
	 */
	void GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range);
	void RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range);
	int32 CreateAdventure(int32 adventure_id);
	void AddPlayerToAdventure(int32 id, int32 charid);
	void RemovePlayerFromAdventure(int32 id, int32 charid);
	void RemovePlayersFromAdventure(int32 id);
	void AddGroupToAdventure(int32 id, int32 gid);
	void AddRaidToAdventure(int32 id, int32 rid);
	void DestroyAdventure(int32 id);
	bool GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count, 
		int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp);
	int32 GetAdventureID(int32 char_id);
	int32 CountPlayersInAdventure(int32 id);
	void PurgeAdventures();
	void AddAdventureToInstance(int32 adv_id, int32 inst_id);
	void UpdateAdventureStatus(int32 adv_id, int32 status);
	void UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time);
	void UpdateAdventureCompleted(int32 adv_id, int32 time);
	void UpdateAdventureCount(int32 adv_id, int32 new_count);
	void IncrementAdventureCount(int32 adv_id);
	int32 GetAdventureCount(int32 adv_id);
	bool AdventureExists(int32 adv_id);
	void UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win);
	void UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win);
	bool GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w, int32 &tak_w, 
		int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l);
	int32 AdventureGetAssassinateKills(int32 adv_id);
	void AdventureSetAssassinateKills(int32 adv_id, int32 kills);

	/*
	 * Account Related
	 */
	int32	GetMiniLoginAccount(char* ip);
	void	GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus);
	int32	CheckLogin(const char* name, const char* password, sint16* oStatus = 0);
	sint16	CheckStatus(int32 account_id);
#ifdef DUAL_SERVER
	int32	CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0, int32 lsaccount_id2 = 0);
	int32	pLSID;
	inline int32		LSID()	const		{ return pLSID; }
#else
	int32	CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0);
#endif

	bool	DeleteAccount(const char* name);
 	bool	SetAccountStatus(const char* name, sint16 status);
	bool	SetLocalPassword(uint32 accid, const char* password);
	int32	GetAccountIDFromLSID(int32 iLSID, char* oAccountName = 0, sint16* oStatus = 0);
	bool	UpdateLiveChar(char* charname,int32 lsaccount_id);
	bool	GetLiveChar(int32 account_id, char* cname);
	int8	GetAgreementFlag(int32 acctid);
	void	SetAgreementFlag(int32 acctid);
	
	/*
	 * Groups
	 */
	int32	GetGroupID(const char* name);
	void	SetGroupID(const char* name, int32 id, int32 charid);
	void	ClearGroup(int32 gid = 0);
	char*	GetGroupLeaderForLogin(const char* name,char* leaderbuf);
	
	void	SetGroupLeaderName(int32 gid, const char* name);
	char*	GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist = NULL, char *marknpc = NULL,
				       GroupLeadershipAA_Struct* GLAA = NULL);
	void	ClearGroupLeader(int32 gid = 0);

	/*
	 * Raids
	 */
	void	ClearRaid(int32 rid = 0);
	void	ClearRaidDetails(int32 rid = 0);
	int32	GetRaidID(const char* name);
	const char *GetRaidLeaderName(int32 rid);

	/*
	 * Database Varaibles
	 */
	bool	GetVariable(const char* varname, char* varvalue, int16 varvalue_len);
	bool	SetVariable(const char* varname, const char* varvalue);
	bool	LoadVariables();
	int32	LoadVariables_MQ(char** query);
	bool	LoadVariables_result(MYSQL_RES* result);
	
	/*
	 * General Queries
	 */
	bool	LoadZoneNames();
	bool	GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int32* graveyard_id = 0, int32* maxclients = 0);
	bool	GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
	int32	GetZoneGraveyardID(int32 zone_id);
	int32	GetZoneID(const char* zonename);
	int8    GetPEQZone(int32 zoneID);
	const char*	GetZoneName(int32 zoneID, bool ErrorUnknown = false);
	int8	GetServerType();
	bool	GetSafePoints(const char* short_name, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0); //Angelox4
	bool	GetSafePoints(int32 zoneID, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0) { return GetSafePoints(GetZoneName(zoneID), safe_x, safe_y, safe_z, minstatus, minlevel, flag_needed, canzone); } //Angelox4
	int8	GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level);
	int8	GetRaceSkill(int8 skillid, int8 in_race);
	
	bool	LoadPTimers(uint32 charid, PTimerList &into);
	void	ClearPTimers(uint32 charid);
	void	ClearMerchantTemp();
	void	SetLFP(int32 CharID, bool LFP); 
	void	SetLFG(int32 CharID, bool LFG); 
	void	AddReport(std::string who, std::string against, std::string lines);
	

protected:
	void	HandleMysqlError(int32 errnum);
	//bool	RunQuery(const char* query, int32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, int32* affected_rows = 0, int32* errnum = 0, bool retry = true);
	
private:
	void DBInitVars();
	
	int32				max_zonename;
	char**				zonename_array;
	
	Mutex				Mvarcache;
	uint32				varcache_max;
	VarCache_Struct**	varcache_array;
	uint32				varcache_lastupdate;
};

bool	FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap);
#endif
Reply With Quote
  #3  
Old 04-17-2010, 08:35 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

For the record, the dual LS code was originally from Secrets. I haven't done anything at all with the LS code yet :P
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #4  
Old 04-17-2010, 08:52 PM
Angelox
AX Classic Developer
 
Join Date: May 2006
Location: filler
Posts: 2,049
Default

Thanks - now I know why I couldn't find the post!
Reply With Quote
  #5  
Old 04-17-2010, 10:29 PM
gaeorn
Developer
 
Join Date: Apr 2009
Location: USA
Posts: 478
Default

It's the first portion of the muiltiple login server thread. I renamed it since it no longer was limited to dual login servers.
Reply With Quote
  #6  
Old 02-28-2014, 04:10 AM
rabbired1
Fire Beetle
 
Join Date: Feb 2007
Posts: 6
Default

makering..............
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 03:39 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3