/*
* This file is part of UAS2.
*
* UAS2 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* UAS2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with UASv1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/**
 *	@file WorldManager.cpp
 *	Encapsulates basic world functionality.  Maintains client and object lists.
 *	Loads world objects and populates/depopulates landblock object lists.
 *	Also controls when and which objects' Create Packets are sent to the client.
 *		@see ReceiveAllObjectsInLandBlock() - encapsulates the functionality to create the objects within a given avatar's landblock.
 *		@see ReceiveAllObjectsInFocus() - encapsulates funtionality to create tthe objects with the area of a given avatar's landblock.
 *		@see LandBlocksWithin() - determines which landblocks are in the area of a given avatar's landblock. 
 */

//TODO: When a landblock is disabled, the important information should be saved to disk. Important
//		information being things like corpses.

//Your location is Landblock: a5b4002b, X: 133.4, Y: 51.5, Z: 52.0, H: 184.8  
//Your location is Landblock: a5b30030, X: 127.6, Y: 169.9, Z: 55.9, H: 184.8

#define RADAR_RADIUS	120

#include "MasterServer.h"
#include "WorldManager.h"
#include "Client.h"
#include "cModels.h"
#include "cMagicModels.h"

//Initialize static members
//=============================================================
DWORD	cWorldManager::m_dwGUIDCycle_Avatar;
DWORD	cWorldManager::m_dwGUIDCycle_Object;
std::list< DWORD >		cWorldManager::m_lstUnusedAvatarGUIDs;
std::list< DWORD >		cWorldManager::m_lstUnusedObjectGUIDs;

std::vector<ConfirmPanel>	cWorldManager::m_lstConfirmsPending;
DWORD	cWorldManager::m_dwConfirmSequence;

char	cWorldManager::g_szAccessFile[MAX_PATH+20];
cLandBlock *cLandBlock::m_lpcHashTable[510];
WORD	wTmpMoveCounter;
//=============================================================

/**
 *	Loads the initial world objects
 *
 *	This function is called when the server is started.
 */
void cWorldManager::Load( )
{
	cDatabase::InitializeAvatarGUIDs( m_dwGUIDCycle_Avatar );
	cDatabase::InitializeObjectGUIDs( m_dwGUIDCycle_Object );
	cLandBlock::Hash_Load( );
	cWorldManager::m_dwConfirmSequence	= 0x00000000;
	
//	UpdateConsole( " --------------------------------------------------------------------------\r\n\r\n" );
	UpdateConsole( " Starting to load the world:\r\n\r\n" );

	cDatabase::LoadModelList( );
//		UpdateConsole( "\r\n Model list has been loaded.\r\n\r\n");

	cMasterServer::LoadItemModels( );
		UpdateConsole( "\r\n Item model loading complete.\r\n\r\n" );

	cMasterServer::LoadWorldModels( );
		UpdateConsole( "\r\n World model loading complete.\r\n\r\n" );

	cMasterServer::LoadSpellModels( );
		UpdateConsole( "\r\n Spell model loading complete.\r\n\r\n" );

	cMasterServer::LoadSpells( );
		UpdateConsole( "\r\n Spell loading complete.\r\n\r\n" );
	
	cMasterServer::LoadSpellComps( );
		UpdateConsole( "\r\n Spell component loading complete.\r\n\r\n" );

	cMasterServer::LoadWorldObjects( );
		UpdateConsole( "\r\n World objects loading complete.\r\n\r\n" );

	cMasterServer::LoadWorldObjects2( );
		UpdateConsole( "\r\n Merchant sign loading complete.\r\n\r\n" );

	cMasterServer::LoadHousing( );
		UpdateConsole( "\r\n Housing object loading complete.\r\n\r\n" );

	cMasterServer::LoadCovenants( );
		UpdateConsole( "\r\n Covenant crystal loading complete.\r\n\r\n" );
				
	cMasterServer::LoadHooks( );
		UpdateConsole( "\r\n Housing hooks loading complete.\r\n\r\n" );

	cMasterServer::LoadStorage( );
		UpdateConsole( "\r\n Housing storage loading complete.\r\n\r\n" );

	cMasterServer::LoadDoors( );
		UpdateConsole( "\r\n Door loading completed.\r\n\r\n" );

	cMasterServer::LoadChests( );
		UpdateConsole( "\r\n Chest loading complete.\r\n\r\n" );

	cMasterServer::LoadLifestones( );
		UpdateConsole( "\r\n Lifestone loading complete.\r\n\r\n" );

	cMasterServer::LoadPortals( );
		UpdateConsole( "\r\n Portal loading complete.\r\n\r\n" );

	cMasterServer::LoadAltars( );
		UpdateConsole( "\r\n Altar loading complete.\r\n\r\n" );

	cMasterServer::LoadNPCModels( );
		UpdateConsole( "\r\n NPC model loading complete.\r\n\r\n" );

  	cMasterServer::LoadMonsterModels( );
		UpdateConsole( "\r\n Monster model loading complete.\r\n\r\n" );

	cMasterServer::LoadNPCs( );
		UpdateConsole( "\r\n NPC loading complete.\r\n\r\n" );

	cMasterServer::LoadGroundSpawns( );
		UpdateConsole( "\r\n Ground spawn loading complete.\r\n\r\n" );

	cMasterServer::LoadMonsters( );
		UpdateConsole( "\r\n Monster loading complete.\r\n\r\n" );

	UpdateConsole( " World loading complete!\r\n\r\n" );
}

void cWorldManager::Unload( )
{
	cLandBlock::Hash_Unload( );
}

/**
 *	Handles the processing for when an avatar moves.
 *
 *	This function is called whenever an avatar moves.  The function checks whether the avatar
 *	has moved into a new landblock and populates/depopulates landblocks appropriately.
 *	The function also sends the movement animation to all clients within focus.
 *
 *	@param *pcClient - A pointer to the client whose avatar is being teleported.
 *	@param &NewLoc - The address of the cLocation struct value that represents the location to which the avatar is being teleported.
 *	@param wAnim - The numeric value of the animation to play.
 *	@param flPlay - The speed at which to play the gievn animation.
 *
 *	@return BOOL - A boolean value representing whether the avatar's landblock has not changed.
 */
BOOL cWorldManager::MoveAvatar( cClient *pcClient, cLocation& NewLoc, WORD wAnim, float flPlaySpeed )
{
	WORD wOldLB			= HIWORD( pcClient->m_pcAvatar->m_Location.m_dwLandBlock );
	WORD wNewLB			= HIWORD( NewLoc.m_dwLandBlock );
  	WORD wO_LB			= LOWORD( pcClient->m_pcAvatar->m_Location.m_dwLandBlock );
	WORD wN_LB			= LOWORD( NewLoc.m_dwLandBlock );
	cLandBlock *pcNewLB = cLandBlock::Hash_New( wNewLB );
	SimpleAI::ExecuteActions( );
	
	/*
	#ifdef _DEBUG
		char szPacketA[120];
		sprintf( szPacketA, "Move: LB: %08x X: %f Y: %f Z: %f H1: %f U1: %f U2: %f H2: %f",NewLoc.m_dwLandBlock,NewLoc.m_flX, NewLoc.m_flY,NewLoc.m_flZ,NewLoc.m_flA,NewLoc.m_flB, NewLoc.m_flC,NewLoc.m_flW);
		cMasterServer::ServerMessage( ColorBlue,pcClient,(char *)szPacketA);
	 #endif
	*/
	cLocation OldLoc = pcClient->m_pcAvatar->m_Location;
	pcClient->m_pcAvatar->SetLocation( NewLoc );

 	if ( wOldLB != wNewLB )
	{
		cLandBlock *pcOldLB = cLandBlock::Hash_Find( wOldLB );
		if ( !pcOldLB )
			return FALSE;

		WORD wLBUnFocus[9];
		WORD wLBFocus[9];
		cMessage cmLogin;
		// Must be signed to allow for negatives.
		short sDiffX		= HIBYTE( wNewLB ) - HIBYTE( wOldLB );
		short sDiffY		= LOBYTE( wNewLB ) - LOBYTE( wOldLB );
		cMessage cmCreate	= pcClient->m_pcAvatar->CreatePacket( );
		BYTE bChangeSize	= 0;
		
		*((DWORD *)&MSG_00000002[4]) = pcClient->m_pcAvatar->GetGUID( );
		cmLogin.CannedData( MSG_00000002, sizeof( MSG_00000002 ) );

		if ( sDiffY )
		{
			wLBFocus[0] = wNewLB + sDiffY * 2;
			wLBFocus[1] = wLBFocus[0] - 0x0100;
			wLBFocus[2] = wLBFocus[0] + 0x0100;
			wLBFocus[3] = wLBFocus[0] - 0x0200;
			wLBFocus[4] = wLBFocus[0] + 0x0200;

			wLBUnFocus[0] = wOldLB - sDiffY * 2;
			wLBUnFocus[1] = wLBUnFocus[0] - 0x0100;
			wLBUnFocus[2] = wLBUnFocus[0] + 0x0100;
			wLBUnFocus[3] = wLBUnFocus[0] - 0x0200;
			wLBUnFocus[4] = wLBUnFocus[0] + 0x0200;

			bChangeSize = 5;
		}

		if ( sDiffX )
		{
			if ( !bChangeSize )
			{
				wLBFocus[0] = wNewLB + sDiffX * 0x0200;
				wLBFocus[1] = wLBFocus[0] - 1;
				wLBFocus[2] = wLBFocus[0] + 1;
				wLBFocus[3] = wLBFocus[0] - 2;
				wLBFocus[4] = wLBFocus[0] + 2; 

				wLBUnFocus[0] = wOldLB - sDiffX * 0x0200;
				wLBUnFocus[1] = wLBUnFocus[0] - 1;
				wLBUnFocus[2] = wLBUnFocus[0] + 1;
				wLBUnFocus[3] = wLBUnFocus[0] - 2;
				wLBUnFocus[4] = wLBUnFocus[0] + 2;

				bChangeSize	= 5;
			}
			else
			{
				wLBFocus[5] = wNewLB + sDiffX * 0x0200;
				wLBFocus[6] = wLBFocus[5] - 1;
				wLBFocus[7] = wLBFocus[5] + 1;

				wLBUnFocus[5] = wOldLB - sDiffX * 0x0200;
				wLBUnFocus[6] = wLBUnFocus[5] - 1;
				wLBUnFocus[7] = wLBUnFocus[5] + 1;

				if ( sDiffY > 0 )
				{
					wLBFocus[8]		= wLBFocus[5] - 2;
					wLBUnFocus[8]	= wLBUnFocus[5] + 2;
				}
				else
				{
					wLBFocus[8]		= wLBFocus[5] + 2;
					wLBUnFocus[8]	= wLBUnFocus[5] - 2;
				}

				bChangeSize	= 9;
			}
		}

		cLandBlock *pcRemFocus; 
		cLandBlock *pcAddFocus;
		for ( int i = 0; i < bChangeSize; ++i )
		{
			pcRemFocus = cLandBlock::Hash_Find( wLBUnFocus[i] );
			pcAddFocus = cLandBlock::Hash_New( wLBFocus[i] );

			AddFocus( pcAddFocus, pcClient );

			if ( pcRemFocus )
				RemFocus( pcRemFocus, pcClient );

			//ReceiveAllObjectsInLandBlock( pcClient, pcAddFocus );

			ReceiveAllObjectsInFocus( pcClient, pcAddFocus );
			SendToAllInLandBlock( pcAddFocus, cmCreate, 3 );
			SendToAllInLandBlock( pcAddFocus, cmLogin, 3 );
		}

		// Guaranteed to happen for any kind of movement.
		
		AddClient( pcNewLB, pcClient );
		AddFocus( pcOldLB, pcClient );
		RemFocus( pcNewLB, pcClient );
		RemClient( pcOldLB, pcClient );
	}
//	 	if (( wOldLB == wNewLB ) && (HIBYTE(wO_LB) != HIBYTE( wN_LB)))
	 	if (( wOldLB == wNewLB ) && (wTmpMoveCounter > 60))
		{
 			ReceiveAllObjectsInFocus( pcClient, pcNewLB );

			wTmpMoveCounter = 0;
		}

	if ( wAnim )
	SendToOthersInFocus( pcNewLB, pcClient, pcClient->m_pcAvatar->Animation( wAnim, flPlaySpeed ), 3 );
	
	SendToAllInFocus( pcNewLB, pcClient->m_pcAvatar->LocationPacket( ), 3 );

	wTmpMoveCounter = wTmpMoveCounter + 1 ;

	if ( cObject *CollisionPortal = GetCollisionPortal( OldLoc, NewLoc ) )
		CollisionPortal->Action( pcClient );

	return TRUE;
}

/**
 *	Handles the processing for when an avatar is teleported
 *
 *	This function is called whenever an avatar is teleported.
 *
 *	@param *pcClient - A pointer to the client whose avatar is being teleported.
 *	@param &NewLoc - The address of the cLocation struct value that represents the location to which the avatar is being teleported.
 *
 *	@return BOOL - A boolean value representing whether the avatar's landblock has not changed.
 */
BOOL cWorldManager::TeleportAvatar( cClient *pcClient, cLocation& NewLoc )
{
	WORD wOldLB			= HIWORD( pcClient->m_pcAvatar->m_Location.m_dwLandBlock );
	cLandBlock *pcOldLB	= cLandBlock::Hash_Find( wOldLB );
	cLocation OldLoc	= pcClient->m_pcAvatar->m_Location;

	if ( !pcOldLB )
		return FALSE;

	pcClient->m_pcAvatar->m_wPortalCount += 2;
	pcClient->m_pcAvatar->SetLocation( NewLoc );

	SendToAllInFocus( pcOldLB, pcClient->m_pcAvatar->LocationPacket( ), 3 );

	pcClient->m_pcAvatar->SetLocation( OldLoc );

	if ( !RemoveClient( pcClient, FALSE, FALSE ) )
		return FALSE;

	pcClient->m_pcAvatar->SetLocation( NewLoc );

	return TRUE;
}

/**
 *	Handles the processing for when a client is removed from the server.
 *
 *	This function is called whenever an avatar removed from the server
 *
 *	@param *pcClient - A pointer to the client whose avatar is being removed.
 *	@param fRemoveAvatar - A value representing whether the avatar should be removed.
 *	@param fDeleteavatar - A value representing whether the avatar object should be deleted from working memory.
 *
 *	@return BOOL - A boolean value representing whether the avatar is located in a known landblock.
 */
BOOL cWorldManager::RemoveClient( cClient *pcClient, BOOL fRemoveAvatar, BOOL fDeleteAvatar )
{
	WORD wLBs[25];
	WORD wLandBlock		= HIWORD( pcClient->m_pcAvatar->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_Find( wLandBlock );

	if ( !pcLB )
		return FALSE;
	
	if ( pcClient->m_pcAvatar )
	{
		if ( fRemoveAvatar )
		{
			char szIP[32];
			cMasterServer::FormatIP_Port( pcClient->m_saSockAddr, szIP );
			UpdateConsole(	" World Server disconnection:\r\n"
							"      User: %s\r\n"
							"      Avatar: %s\r\n"
							"      IP: %s\r\n", pcClient->m_szAccountName, pcClient->m_pcAvatar->m_strName.c_str(), szIP);
			
			RemoveAvatar( pcClient, pcLB, 0x011B );
			//Karki
			cMasterServer::m_UserCount--;
			cMasterServer::ServerMessage( ColorMagenta, NULL, "%s has left %s. %d client(s) connected.", pcClient->m_pcAvatar->Name( ), cMasterServer::m_szServerName, cMasterServer::m_UserCount);
			//EndKarki
		}
		if ( fDeleteAvatar )
			SAFEDELETE( pcClient->m_pcAvatar )
	}

	RemClient( pcLB, pcClient );

	LandBlocksWithin( 2, wLandBlock, wLBs );
	for ( int i = 0; i < 24; ++i )
	{
		pcLB = cLandBlock::Hash_Find( wLBs[i] );
		if ( pcLB )
			RemFocus( pcLB, pcClient );
	}

	return TRUE;
}

/**
 *	Handles the processing for when a client is added to the server.
 *
 *	This function is called whenever an avatar is added to the server.
 *
 *	@param *pcClient - A pointer to the client whose avatar is being added.
 *	@param fSpawnAvatar - A value representing whether the avatar should be spawned.
 */
BOOL cWorldManager::AddClient( cClient *pcClient, BOOL fSpawnAvatar )
{
	WORD wLBs[25];
	WORD wLandBlock		= HIWORD( pcClient->m_pcAvatar->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_New( wLandBlock );

	AddClient( pcLB, pcClient );

	LandBlocksWithin( 2, wLandBlock, wLBs );
	cLandBlock *pcFLB;
	for ( int i = 0; i < 24; ++i )
	{
		pcFLB = cLandBlock::Hash_New( wLBs[i] );
		AddFocus( pcFLB, pcClient );
	}

	if ( fSpawnAvatar )
		SpawnAvatar( pcClient, pcLB );

	return TRUE;
}

/**
 *	Handles the processing of objects within an avatar's landblock.
 *
 *	Sends the client the create messages of all objects within the specified landblock.
 *	This is accomplished by iterating through all the clients within the landblock and sending
 *	their Create Packets (excluding that packet for the client receiving them) and then 
 *	iterating through all the other objects and sending their Create Packets.
 *
 *	@param *pcClient - A pointer to the client whose avatar should receive the packets.
 *	@param *pcLB - The landblock in which the given avatar resides.
 */
void cWorldManager::ReceiveAllObjectsInLandBlock( cClient *pcClient, cLandBlock *pcLB )
{
	//Iterate through all the clients within the landblock
	for ( iterClient_lst itClient = pcLB->m_lstClients.begin( ); itClient != pcLB->m_lstClients.end( ); ++itClient )
	{
		//Exclude the pcClient
		if ( pcClient != *itClient )
		{
			cMessage cmLogin;

			*((DWORD *)&MSG_00000002[4]) = (*itClient)->m_pcAvatar->GetGUID( );
			cmLogin.CannedData( MSG_00000002, sizeof( MSG_00000002 ) );
		
			/*BOOL fContinue;
			do
			{
				cMessage cmChildren = ( *itClient )->m_pcAvatar->CreateChildren( fContinue );
				if( fContinue )
					pcClient->AddPacket( WORLD_SERVER, cmChildren, 3 );
			} while ( fContinue );*/

			( *itClient )->m_pcAvatar->CreateChildren( pcClient );

			pcClient->AddPacket( WORLD_SERVER, (*itClient)->m_pcAvatar->CreatePacket( ), 3 );
			pcClient->AddPacket( WORLD_SERVER, cmLogin, 3 );
		}
	}

	//Iterate through all the objects within the landblock
	for ( iterObject_lst itObject = pcLB->m_lstObjects.begin( ); itObject != pcLB->m_lstObjects.end( ); ++itObject )
	{
		pcClient->AddPacket( WORLD_SERVER, (*itObject)->CreatePacket( ), 3 );
	}
	
}

/**
 *	Sends the client the Create Messages for all of the objects within the focus range of the specified landblock.
 *
 *	Iterates through the landblocks within a specified range of the avatar's current landblock.
 *	A call is made to LandBlocksWithin() to determine which landblocks lie within the specified range.
 *	For each landblock with the range, a call to ReceiveAllObjectsInLandBlock() is made.
 *
 *	@param *pcClient - A pointer to the client whose avatar should referenced.
 *	@param *pcLB - The landblock in which the given avatar resides.
 */
void cWorldManager::ReceiveAllObjectsInFocus( cClient *pcClient, cLandBlock *pcLB )
{
	WORD wLBs[25];

	LandBlocksWithin( 2, pcLB->m_wLandBlock, wLBs );

	// Receive all the objects in the landblock itself first.
	ReceiveAllObjectsInLandBlock( pcClient, pcLB );
	for ( int i = 0; i < 24; ++i )
	{
		pcLB = cLandBlock::Hash_Find( wLBs[i] );

		if ( pcLB )
		{
			//cMasterServer::LoadSpawns(pcLB->m_wLandBlock);
			ReceiveAllObjectsInLandBlock( pcClient, pcLB );
		}
		
	}
}

/**
 *	Adds an object to object list of the landblock in which it is located.
 *
 *	@param *pcObject - A pointer to the object to add.
 *	@param fSpawnObject - A value representing whether the object should be spawned.
 */
BOOL cWorldManager::AddObject( cObject *pcObject, BOOL fSpawnObject )
{
	//Find the object's landblock
	WORD wLandBlock		= HIWORD( pcObject->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_Find( wLandBlock );

	if ( !pcLB )
		pcLB = cLandBlock::Hash_New( wLandBlock );

	AddObject( pcLB, pcObject );

	if ( fSpawnObject )
		SpawnObject( pcObject, pcLB );

	return TRUE;
}
/**
 *	Removes an object to object list of the landblock in which it is located.
 *
 *	@param *pcObject - A pointer to the object to remove.
 *	@param fRemoveObject - A value representing whether the object should be removed.
 *	@param fDeleteObject - A value representing whether the object should be deleted from working memory.
 */
BOOL cWorldManager::RemoveObject( cObject *pcObject, BOOL fRemoveObject, BOOL fDeleteObject )
{
	WORD wLandBlock		= HIWORD( pcObject->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_Find( wLandBlock );

	if ( !pcLB )
		return FALSE;

	RemObject( pcLB, pcObject );

	if ( fRemoveObject )
		RemoveObject( pcObject, pcLB );
	if ( fDeleteObject )
		SAFEDELETE( pcObject )

	return TRUE;
}

//// Object changes Landblock location
/**
 *	Adds an object to object list of the landblock in which it is located.
 *
 *	Used for when an object changes landblock location.
 *
 *	@param *pcObject - A pointer to the object to add.
 */
BOOL cWorldManager::MoveAddObject( cObject *pcObject )
{
	WORD wLandBlock		= HIWORD( pcObject->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_Find( wLandBlock );

	if ( !pcLB )
		pcLB = cLandBlock::Hash_New( wLandBlock );

	AddObject( pcLB, pcObject );

	return TRUE;
}
/**
 *	Removes an object from the object list of the landblock in which it is located.
 *
 *	Used for when an object changes landblock location.
 *
 *	@param *pcObject - A pointer to the object to remove.
 *
 *	@return BOOL - A boolean value representing whether the object is located in a known landblock.
 */
BOOL cWorldManager::MoveRemObject( cObject *pcObject )
{
	WORD wLandBlock		= HIWORD( pcObject->m_Location.m_dwLandBlock );
	cLandBlock *pcLB	= cLandBlock::Hash_Find( wLandBlock );

	if ( !pcLB )
		return FALSE;

	RemObject( pcLB, pcObject );

	return TRUE;
}
//////////////////////////////////////////////////////

/**
 *	Removes all object from the object list of all the landblocks.
 *
 *	This is accomplished by iterating through each landblock, for each landblock iterating through each object, 
 *	and deleting the objects as they are iterated through.
 */
void cWorldManager::RemoveAllObjects()
{
	for ( int i = 0; i < 510; ++i )
	{
		cLandBlock *pcLB = cLandBlock::m_lpcHashTable[i];
		while ( pcLB )
		{
			 for ( iterObject_lst itObject = pcLB->m_lstObjects.begin( ); itObject != pcLB->m_lstObjects.end( ); )
			 {
				 if( !(*itObject)->IsStatic( ) )
				 {
					RemoveObject( (*itObject), pcLB );
					SAFEDELETE( *itObject );
					itObject = pcLB->m_lstObjects.erase( itObject );
				 }
				 else
					++itObject;
			 }
			pcLB = pcLB->m_pcNext;
		}
	}
}

/**
 *	Takes a center landblock and returns the landblocks around it.
 */
void cWorldManager::LandBlocksWithin( BYTE bDistance, WORD wCenterLB, WORD *pwStore )
{
	static WORD i = 0;
	WORD wDiameter = 2 * bDistance + 1;

	pwStore[i++] = wCenterLB + bDistance + (0x0100 * bDistance);

	int j = 1, k = -1;
	while ( 1 )
	{
		if ( j++ >= wDiameter )
		{
			if ( k == -1 )
			{
				k = -0x0100;
				j = 1;
				continue;
			}
			else if ( k == -0x0100 )
			{
				k = 1;
				j = 1;
				continue;
			}
			else if ( k == 1 )
			{
				k = 0x0100;
				j = 2;
				continue;
			}
			else
				break;
		}

		pwStore[i++] = pwStore[i-1] + k;
	}

	if ( bDistance > 1 )
		LandBlocksWithin( --bDistance, wCenterLB, pwStore );
	else
	{
		pwStore[i] = wCenterLB;
		i = 0;
	}
}

void cWorldManager::AddPendingConfirm(DWORD sequence, DWORD type, std::string szText, DWORD senderGUID, DWORD receiptGUID)
{
	ConfirmPanel aConfirmPanel;

	aConfirmPanel.m_dwSequence = sequence;
	aConfirmPanel.m_dwType = type;
	aConfirmPanel.m_szText = szText;

	aConfirmPanel.m_dwSenderGUID = senderGUID;
	aConfirmPanel.m_dwReceiptGUID = receiptGUID;

	m_lstConfirmsPending.push_back(aConfirmPanel);
}

void cWorldManager::FindPendingConfirm( DWORD dwSeq, DWORD dwReply )
{
	for( cWorldManager::iterConfirmPanel_lst itConfirmPanel = m_lstConfirmsPending.begin(); itConfirmPanel != m_lstConfirmsPending.end(); ++itConfirmPanel )
	{
		if ( itConfirmPanel->m_dwSequence == dwSeq )
		{
			cClient *pcSendClient = cClient::FindClient( itConfirmPanel->m_dwSenderGUID );
			cClient *pcRecvClient = cClient::FindClient( itConfirmPanel->m_dwReceiptGUID );			
				
			switch (itConfirmPanel->m_dwType)
			{
				case 1:
					{
						pcRecvClient->m_pcAvatar->SwearAllegiance(itConfirmPanel->m_szText, dwReply, itConfirmPanel->m_dwSenderGUID);
						break;
					}
				case 2:
					{
						break;
					}
				case 3:
					{
						break;
					}					
				case 4:
					{
						pcRecvClient->m_pcAvatar->FellowshipRecruitRecv(itConfirmPanel->m_szText, dwReply, itConfirmPanel->m_dwReceiptGUID);
						pcSendClient->m_pcAvatar->FellowshipRecruitSend(itConfirmPanel->m_szText, dwReply, itConfirmPanel->m_dwSenderGUID);
						break;
					}
				case 5:
					{
						break;
					}
			}

			m_lstConfirmsPending.erase(itConfirmPanel);
			break;	// the "itConfirmPanel" iterator is now invalid; must break
		}
	}
}