// World.cpp : Implementation of cWorld
//  Prepping for latest modifications

#include "stdafx.h"
#include "DecalFilters.h"

#include "World.h"
#include "WorldObject.h"
#include "WorldIterator.h"

#include <time.h>
#include <stdio.h>
#include <math.h>


const IID EVTID_AcHooks = { 
			0xEB282FE5, 0x7170, 0x4a37, {0xA2, 0x6E, 0x92, 0xAF, 0x36, 0x38, 0x5D, 0x2C}} ;

const IID LIBID_Decal = {
			0xFF7F5F6D, 0x34E0, 0x4B6F, {0xB3, 0xBB, 0x81, 0x41, 0xDE, 0x2E, 0xF7, 0x32}} ;

const IID IID_Plugins = {
			0x702D3901, 0xC13A, 0x448e, {0x88, 0x71, 0xEC, 0xDC, 0x8B, 0xC8, 0xD0, 0x79}} ;


/////////////////////////////////////////////////////////////////////////////
// cWorld

// static bstring stable of doom :(
BSTR strContainer;
BSTR strcontainer;
BSTR strSlot;
BSTR strslot;
BSTR strwielder;
BSTR strkey ;
BSTR strdwords ;
BSTR strstring ;
BSTR strdoubles ;
BSTR strstrings ;
BSTR strspellCount ;
BSTR strspells ;
BSTR strspellID ;
BSTR strspellFlag ;
BSTR strdamageType ;
BSTR strspeed ;
BSTR strskill ;
BSTR strdamage ;
BSTR strdamageRange ;
BSTR strdamageBonus ;
BSTR strrange ;
BSTR strdefenseBonus ;
BSTR strattackBonus ;
BSTR strslashProt ;
BSTR strpierceProt ;
BSTR strbludgeonProt ;
BSTR strcoldProt ;
BSTR strfireProt ;
BSTR stracidProt ;
BSTR strelectricalProt ;
BSTR strlandblock;
BSTR strOffset;
BSTR strStackCount;
BSTR strstackCount;
BSTR strvalue;

BSTR strxOffset;
BSTR stryOffset;
BSTR strzOffset;
BSTR strxHeading;
BSTR strdestroyed;
BSTR stritem;
BSTR strcount;
BSTR strobject;
BSTR strowner;
BSTR strsequence;
BSTR strequipType;
BSTR strsequence2;
BSTR strcoverage;
BSTR strflags1;
BSTR strflags;
BSTR strlocation;
BSTR strwieldingSlot;
BSTR strflags2;
BSTR strobjectName;
BSTR strsecondaryName;
BSTR strmodel;
BSTR strrealmodel;
BSTR strunkgreen;
BSTR stricon;
BSTR strunknown_v0_2;
BSTR strunknown_v0_3;
BSTR strunknown_v2;
BSTR strunknown_v4;
BSTR strunknown_v5;
BSTR strunknown_w1;
BSTR strunknown10;
BSTR strunknown11b;
BSTR stritemSlots;
BSTR strpackSlots;	
BSTR strusesLeft;	
BSTR strtotalUses;	
BSTR strstackMax;	
BSTR strapproachDistance;	
BSTR strequipmentType;
BSTR strtradenoteVendor;
BSTR strcoverage1;
BSTR strcoverage2;
BSTR strcoverage3;
BSTR strmonarch;
BSTR strmaterial;
BSTR strassociatedSpell;
BSTR strtext;
BSTR strsenderName;
BSTR strtype;
BSTR strcharacter;
BSTR strevent;
BSTR strpack;
BSTR stritemCount;	
BSTR stritems;
BSTR strdestination;
BSTR strinventoryCount;
BSTR strinventory;
BSTR strisContainer;
BSTR strOwner;
BSTR strposition;
BSTR strburden;
BSTR strworkmanship;
BSTR strhouseOwnerID;
BSTR strSizeChange;
BSTR strStorageChange;
BSTR strLocationChange;
BSTR strIdentReceived;
BSTR strReleasePending;
BSTR strExpirationCancel;

enum AcMessages
{
	msgDestroyObj			= 0x0024,
	msgLocalChat			= 0x0037,
	msgAdjustStackSize		= 0x0197,
	msgSetCoverage			= 0x0229,
	msgSetContainer			= 0x022D,
	msgEnd3dMode			= 0xF653,
	msgFailToLogin			= 0xF659,
	msgCreateObject			= 0xF745,
	msgRemoveItem			= 0xF747,
	msgSetObjectPosition	= 0xF748,
	msgWieldItem			= 0xF749,
	msgMoveToInventory		= 0xF74A,
	msgGameEvent			= 0xF7B0,
	msgUpdateObject			= 0xF7DB,
	msgUnknown				= 0
};

enum AcGameEvents
{
	gevLogin				= 0x0013,
	gevInsertIntoInventory	= 0x0022,
	gevIdentifyObject		= 0x00C9,
	gevSetPackContents		= 0x0196,
	gevDropItem				= 0x019A,
	gevWearItem				= 0x0023,
	gevUnknown				= 0
};


cWorld::cWorld()
{
 	m_nNextTime = 0;
	m_HookIsSet = false ;
};

HRESULT cWorld::onInitialize()
{
	_DebugLog("OnInitialize") ;

	_DebugLog("\n\nLogin") ;

	SysReAllocString( &strContainer, L"Container" );
	SysReAllocString( &strContainer, L"Container" );
	SysReAllocString( &strcontainer, L"container" );
	SysReAllocString( &strSlot, L"Slot" );
	SysReAllocString( &strslot, L"slot" );
	SysReAllocString( &strwielder, L"wielder" );
	SysReAllocString( &strkey, L"key" );
	SysReAllocString( &strdwords, L"dwords" );
	SysReAllocString( &strstring, L"string" );
	SysReAllocString( &strdoubles, L"doubles") ;
	SysReAllocString( &strstrings, L"strings") ;
	SysReAllocString( &strspellCount, L"spellCount") ;
	SysReAllocString( &strspells, L"spells") ;
	SysReAllocString( &strspellID, L"spellID") ;
	SysReAllocString( &strspellFlag, L"spellFlag") ;
	SysReAllocString( &strdamageType, L"damageType") ;
	SysReAllocString( &strspeed, L"speed") ;
	SysReAllocString( &strskill, L"skill") ;
	SysReAllocString( &strdamage, L"damage") ;
	SysReAllocString( &strdamageRange, L"damageRange") ;
	SysReAllocString( &strdamageBonus, L"damageBonus") ;
	SysReAllocString( &strrange, L"range") ;
	SysReAllocString( &strdefenseBonus, L"defenseBonus") ;
	SysReAllocString( &strattackBonus, L"attackBonus") ;
	SysReAllocString( &strslashProt, L"slashProt") ;
	SysReAllocString( &strpierceProt, L"pierceProt") ;
	SysReAllocString( &strbludgeonProt, L"bludgeonProt") ;
	SysReAllocString( &strcoldProt, L"coldProt") ;
	SysReAllocString( &strfireProt, L"fireProt") ;
	SysReAllocString( &stracidProt, L"acidProt") ;
	SysReAllocString( &strelectricalProt, L"electricalProt") ;
	SysReAllocString( &strlandblock, L"landblock" );
	SysReAllocString( &strOffset, L"Offset" );
	SysReAllocString( &strStackCount, L"StackCount" );
	SysReAllocString( &strstackCount, L"stackCount" );
	SysReAllocString( &strvalue, L"value" );

	SysReAllocString( &strxOffset, L"xOffset" );
	SysReAllocString( &stryOffset, L"yOffset" );
	SysReAllocString( &strzOffset, L"zOffset" );
	SysReAllocString( &strxHeading, L"xHeading" );
	SysReAllocString( &strdestroyed, L"destroyed" );
	SysReAllocString( &stritem, L"item" );
	SysReAllocString( &strcount, L"count" );
	SysReAllocString( &strobject, L"object" );
	SysReAllocString( &strowner, L"owner" );
	SysReAllocString( &strsequence, L"sequence" );
	SysReAllocString( &strequipType, L"equipType" );
	SysReAllocString( &strsequence2, L"sequence2" );
	SysReAllocString( &strcoverage, L"coverage" );
	SysReAllocString( &strflags1, L"flags1" );
	SysReAllocString( &strflags, L"flags" );
	SysReAllocString( &strlocation, L"location" );
	SysReAllocString( &strwieldingSlot, L"wieldingSlot" );
	SysReAllocString( &strflags2, L"flags2" );
	SysReAllocString( &strobjectName, L"objectName" );
	SysReAllocString( &strsecondaryName, L"secondaryName" );
	SysReAllocString( &strmodel, L"model" );
	SysReAllocString( &strrealmodel, L"modelNumber" );
	SysReAllocString( &strunkgreen, L"unknown_green" );
	SysReAllocString( &stricon, L"icon" );
	SysReAllocString( &strunknown_v0_2, L"unknown_v0_2" );
	SysReAllocString( &strunknown_v0_3, L"unknown_v0_3" );
	SysReAllocString( &strunknown_v2, L"unknown_v2" );
	SysReAllocString( &strunknown_v4, L"unknown_v4" );
	SysReAllocString( &strunknown_v5, L"unknown_v5" );
	SysReAllocString( &strunknown_w1, L"unknown_w1" );
	SysReAllocString( &strunknown10, L"unknown10" );
	SysReAllocString( &strunknown11b, L"unknown11b" );
	SysReAllocString( &stritemSlots, L"itemSlots" );
	SysReAllocString( &strpackSlots, L"packSlots" );
	SysReAllocString( &strusesLeft, L"usesLeft" );
	SysReAllocString( &strtotalUses, L"totalUses" );
	SysReAllocString( &strstackMax, L"stackMax" );
	SysReAllocString( &strapproachDistance, L"approachDistance" );
	SysReAllocString( &strequipmentType, L"equipmentType" );
	SysReAllocString( &strtradenoteVendor, L"tradenoteVendor" );
	SysReAllocString( &strcoverage1, L"coverage1" );
	SysReAllocString( &strcoverage2, L"coverage2" );
	SysReAllocString( &strcoverage3, L"coverage3" );
	SysReAllocString( &strmonarch, L"monarch" );
	SysReAllocString( &strmaterial, L"material" );
	SysReAllocString( &strassociatedSpell, L"associatedSpell" );
	SysReAllocString( &strtext, L"text" );
	SysReAllocString( &strsenderName, L"senderName" );
	SysReAllocString( &strtype, L"type" );
	SysReAllocString( &strcharacter, L"character" );
	SysReAllocString( &strevent, L"event" );
	SysReAllocString( &strpack, L"pack" );
	SysReAllocString( &stritemCount, L"itemCount" );
	SysReAllocString( &stritems, L"items" );
	SysReAllocString( &strdestination, L"destination" );
	SysReAllocString( &strinventoryCount, L"inventoryCount" );
	SysReAllocString( &strinventory, L"inventory" );
	SysReAllocString( &strisContainer, L"isContainer" );
	SysReAllocString( &strOwner, L"Owner" );
	SysReAllocString( &strposition, L"position" );
	SysReAllocString( &strburden, L"burden" );
	SysReAllocString( &strworkmanship, L"workmanship" );
	SysReAllocString( &strhouseOwnerID, L"houseOwnerID" );
	SysReAllocString( &strSizeChange, L"EvtSizeChange" );
	SysReAllocString( &strStorageChange, L"EvtStorageChange" );
	SysReAllocString( &strLocationChange, L"EvtLocationChange" );
	SysReAllocString( &strIdentReceived, L"EvtIdentReceived" );
	SysReAllocString( &strReleasePending, L"EvtReleasePending"  );
	SysReAllocString( &strExpirationCancel, L"EvtExpirationCancel" );

	if( !m_HookIsSet )
		SetHook() ;

	return S_OK;
}


void cWorld::SetHook()
{
	HRESULT hr = m_pService->get_Decal( &m_pDecal );

	if( SUCCEEDED( hr ) )
	{
		_DebugLog("\nGotDecal") ;

		hr = m_pDecal->get_Hooks(&m_pHooks) ;

		if( SUCCEEDED( hr ) )
		{
			_DebugLog("\nGot Hooks") ;
			IACHooksEventsImpl<HookDestroyObj, cWorld>::advise(m_pHooks) ;
			m_HookIsSet = true ;
		}

		else
			_DebugLog("\nFailed Get Hooks %x", hr) ;
	}

	else
		_DebugLog("\nFailed to get Decal %x", hr) ;
}


HRESULT cWorld::onTerminate()
{
	_DebugLog("OnTerminate") ;
	_DebugLog("CLOSEFILE") ;
	if( m_HookIsSet )
	{
		IACHooksEventsImpl<HookDestroyObj, cWorld>::unadvise(m_pHooks) ;

		if( m_pHooks.p != NULL )
		{
			m_pHooks.Release() ;
			//m_pHooks = NULL ;
		}

		m_HookIsSet = false ;
	}

	if( m_pDecal.p != NULL )
	{
		m_pDecal.Release() ;
		//m_pDecal = NULL ;
	}

	// cleanup our bstr mess...
	SysFreeString( strContainer );
	SysFreeString( strcontainer );
	SysFreeString( strSlot );
	SysFreeString( strslot );
	SysFreeString( strwielder );
	SysFreeString( strkey );
	SysFreeString( strdwords );
	SysFreeString( strstring );
	SysFreeString(strdoubles) ;
	SysFreeString(strstrings) ;
	SysFreeString(strspellCount) ;
	SysFreeString(strspells) ;
	SysFreeString(strspellID) ;
	SysFreeString(strspellFlag) ;
	SysFreeString(strdamageType) ;
	SysFreeString(strspeed) ;
	SysFreeString(strskill) ;
	SysFreeString(strdamage) ;
	SysFreeString(strdamageRange) ;
	SysFreeString(strdamageBonus) ;
	SysFreeString(strrange) ;
	SysFreeString(strdefenseBonus) ;
	SysFreeString(strattackBonus) ;
	SysFreeString(strslashProt) ;
	SysFreeString(strpierceProt) ;
	SysFreeString(strbludgeonProt) ;
	SysFreeString(strcoldProt) ;
	SysFreeString(strfireProt) ;
	SysFreeString(stracidProt) ;
	SysFreeString(strelectricalProt) ;

	SysFreeString( strlandblock );
	SysFreeString( strOffset );
	SysFreeString( strStackCount );
	SysFreeString( strstackCount );
	SysFreeString( strvalue );
	SysFreeString( strxOffset );
	SysFreeString( stryOffset );
	SysFreeString( strzOffset );
	SysFreeString( strxHeading );
	SysFreeString( strdestroyed );
	SysFreeString( stritem );
	SysFreeString( strcount );
	SysFreeString( strobject );
	SysFreeString( strowner );
	SysFreeString( strsequence );
	SysFreeString( strequipType );
	SysFreeString( strsequence2 );
	SysFreeString( strcoverage );
	SysFreeString( strflags1 );
	SysFreeString( strflags );
	SysFreeString( strlocation );
	SysFreeString( strwieldingSlot );
	SysFreeString( strflags2 );
	SysFreeString( strobjectName );
	SysFreeString( strsecondaryName );
	SysFreeString( strmodel );
	SysFreeString( strrealmodel );
	SysFreeString( strunkgreen );
	SysFreeString( stricon );
	SysFreeString( strunknown_v0_2 );
	SysFreeString( strunknown_v0_3 );
	SysFreeString( strunknown_v2 );
	SysFreeString( strunknown_v4 );
	SysFreeString( strunknown_v5 );
	SysFreeString( strunknown_w1 );
	SysFreeString( strunknown10 );
	SysFreeString( stritemSlots );	
	SysFreeString( strpackSlots );	
	SysFreeString( strusesLeft );	
	SysFreeString( strtotalUses );	
	SysFreeString( strstackMax );	
	SysFreeString( strapproachDistance );	
	SysFreeString( strequipmentType );
	SysFreeString( strtradenoteVendor );
	SysFreeString( strcoverage1 );
	SysFreeString( strcoverage2 );
	SysFreeString( strcoverage3 );
	SysFreeString( strmonarch );
	SysFreeString( strmaterial );
	SysFreeString( strassociatedSpell );
	SysFreeString( strtext );
	SysFreeString( strsenderName );
	SysFreeString( strtype );
	SysFreeString( strcharacter );
	SysFreeString( strevent );
	SysFreeString( strpack );
	SysFreeString( stritemCount );	
	SysFreeString( stritems );
	SysFreeString( strdestination );
	SysFreeString( strinventoryCount );
	SysFreeString( strinventory );
	SysFreeString( strisContainer );
	SysFreeString( strOwner );
	SysFreeString( strposition );
	SysFreeString( strburden );
	SysFreeString( strworkmanship );
	SysFreeString( strhouseOwnerID );
	SysFreeString( strSizeChange );
	SysFreeString( strStorageChange );
	SysFreeString( strLocationChange );
	SysFreeString( strIdentReceived );
	SysFreeString( strReleasePending ); 
	SysFreeString( strExpirationCancel );

	return S_OK;
}

void cWorld::FreeData()
{
	_DebugLog("\nFreeData") ;
	for (cWorldDataMap::iterator iData = m_objects.begin(); iData != m_objects.end(); iData++)
	{
		if (iData->second) {
			delete iData->second;
			//_DebugLog("\ndeleted %x", iData->first) ;
		}
	}

	m_objects.clear();
	// Gouru: reset the player so next login the player gets updated...
	m_objects.player(0) ;
}


STDMETHODIMP cWorld::DispatchServer(IMessage2 *pMsg)
{
	USES_CONVERSION;
	long nType;
	pMsg->get_Type(&nType);

	CComPtr< IMessageIterator > pMembers;
	pMsg->get_Begin(&pMembers);

	switch (nType)
	{
	case msgFailToLogin:		FreeData();							break ;
	case msgEnd3dMode:			FreeData();							break ;
	case msgDestroyObj:			DoDestroyObj(pMembers) ;			break ;
	case msgSetCoverage:		DoSetCoverage(pMembers) ;			break ;
	case msgSetContainer:		DoSetContainer(pMembers) ;			break ;
	case msgAdjustStackSize:	DoAdjustStackSize(pMembers) ;		break ;
	case msgGameEvent:			DoGameEvent(pMembers) ;				break ;
	case msgSetObjectPosition:	DoSetObjectPosition(pMembers) ;		break ;
	case msgWieldItem:			DoWieldItem(pMembers) ;				break ;
	case msgRemoveItem:			DoRemoveItem(pMembers) ;			break ;
	case msgCreateObject:		DoCreateObject(pMembers) ;			break ;
	case msgUpdateObject:		DoCreateObject(pMembers) ;			break ;
	case msgMoveToInventory:	DoMoveToInventory(pMembers) ;		break ;
#ifdef Logging
	case msgLocalChat:			DoLocalChat(pMembers) ;				break ;
#endif
	}
	
//	ReleaseAllPendingObjects() ;
	
	return S_OK;
}

#ifdef Logging
// Gouru: used in logging to allow log to have chat events to determine when a test action
//	begins and ends.
void cWorld::DoLocalChat(CComPtr<IMessageIterator> pMembers)
{
	BSTR Text ;
	BSTR Sender ;
	long nType ;

	pMembers->get_NextString(strtext, &Text) ;
	pMembers->get_NextString(strsenderName, &Sender) ;
	pMembers->get_NextInt(strtype, &nType) ;
	if (nType==2) {
		USES_CONVERSION;
		_DebugLog("\n\n%s: %s", OLE2A(Sender), OLE2A(Text)) ;
	}
}
#endif

void cWorld::DoGameEvent(CComPtr<IMessageIterator> pMembers) 
{
	long nCharacter, nEvent;

	pMembers->get_NextInt(strcharacter, &nCharacter);
	pMembers->get_NextInt(strevent, &nEvent);

	if (!m_objects.player()) {
		_DebugLog("\nPlayer: %x", nCharacter) ;
		m_objects.player(nCharacter);
	}
	
	switch (nEvent) 
	{
	case gevLogin:					DoLogin(pMembers) ;					break ;
	case gevInsertIntoInventory:	DoInsertIntoInventory(pMembers) ;	break ; 
	case gevSetPackContents:		DoSetPackContents(pMembers) ;		break ;
	case gevIdentifyObject:			DoIdentifyObject(pMembers) ;		break ;
	case gevDropItem:				DoDropItem(pMembers) ;				break ;
	case gevWearItem:				DoWearItem(pMembers) ;				break ;
	}
}


void cWorld::ReleaseAllPendingObjects()
{
//	if (m_nNextTime <= time(NULL)) 
//	{
//		cWorldData *pData = NULL;
//		
//		for (cWorldDataMap::iterator iData = m_objects.begin(); iData != m_objects.end();) 
//		{
//			pData = iData->second;
//			
//			if (pData && pData->m_tExpires && pData->m_tExpires <= time(NULL)) 
//			{
//				_DebugLog("\nReleased object %x", pData->m_dwGUID) ;
//				cWorldDataMap::iterator iSkip = iData;
//				iSkip++;
//
//				DestroyObject(pData) ;
//
//				iData = iSkip;
//			}
//			else
//				++iData;
//		}
//		m_nNextTime = time(NULL) + 5; // 5 seconds until next check
//	}
}

void cWorld::DestroyObject(cWorldData* pData)
{
	_DebugLog("\nDestroyObject: %x", pData->m_dwGUID) ;
	
	if (pData->m_dwGUID != m_objects.player()) {
		_DebugLog(" : ReleaseObject") ;
		Fire_ReleaseObject(pData->m_p);

		_DebugLog(" : MoveSlotBack") ;
		MoveSlotBack(pData);

		_DebugLog(" : erase") ;
		m_objects.erase(pData->m_dwGUID);

		_DebugLog(" : delete") ;
		delete pData;

		_DebugLog(" : ReleaseDone" );
		Fire_ReleaseDone();
	}
}


STDMETHODIMP cWorld::get_Object(long GUID, IWorldObject **pVal)
{
	*pVal = NULL ;
	if (cWorldData *pData = Data(GUID)) {
		pData->m_p->QueryInterface(pVal);
		return S_OK;
	}

	return S_FALSE;
}


STDMETHODIMP cWorld::get_ByName(BSTR Name, IWorldIterator **pVal)
{
	USES_CONVERSION;
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByName(Name);
	pList->QueryInterface(pVal);

	return S_OK;
}

STDMETHODIMP cWorld::get_All(IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByAll();
	pList->QueryInterface(pVal);

	return S_OK;
}

STDMETHODIMP cWorld::get_ByType(eObjectType Type, IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByType(Type);
	pList->QueryInterface(pVal);

	return S_OK;
}

STDMETHODIMP cWorld::get_ByNameSubstring(BSTR Substring, IWorldIterator **pVal)
{
	USES_CONVERSION;
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByNameSubstring(Substring);
	pList->QueryInterface(pVal);

	return S_OK;
}

STDMETHODIMP cWorld::get_ByContainer(long GUID, IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);
	
	pList->Initialize(&m_objects);
	pList->ByContainer(GUID);
	pList->QueryInterface(pVal);
	
	return S_OK;
}

STDMETHODIMP cWorld::get_ByOwner(long GUID, IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);
	
	pList->Initialize(&m_objects);
	pList->ByOwner(GUID) ;
	pList->QueryInterface(pVal);
	
	return S_OK;
}

STDMETHODIMP cWorld::Distance2D(
	long GUID1, 
	long GUID2,
	float* pVal)
{
	*pVal = 0.0 ;
	_DebugLog("\nDistance2D %x %x", GUID1, GUID2) ;
	if (cWorldData* pData1 = Data(GUID1)) {
		_DebugLog(" from %s", pData1->m_strName.c_str()) ;
		if (cWorldData* pData2 = Data(GUID2)) {
			_DebugLog(" to %s", pData2->m_strName.c_str()) ;
			float ew1 = EastWest(pData1->m_dwLandblock, pData1->m_fxOffset) ;
			float ns1 = NorthSouth(pData1->m_dwLandblock, pData1->m_fyOffset) ;
			float ew2 = EastWest(pData2->m_dwLandblock, pData2->m_fxOffset) ;
			float ns2 = NorthSouth(pData2->m_dwLandblock, pData2->m_fyOffset) ;
			_DebugLog(" %3.2f %3.2f %3.2f %3.2f", ew1, ns1, ew2, ns2) ;
			ew1 -= ew2 ;		// get eastwest difference
			ns1 -= ns2 ;		// get northsouth difference
			// ask pythagorous how far...
			ns1 = (ns1*ns1) + (ew1*ew1) ;
			*pVal = sqrtf(ns1) ;
		}
	}
	return S_OK ;
}



// Returns a pointer to the data object for the specified GUID, if the guid
//	is zero, or item not found, returns NULL.
cWorldData *cWorld::Data(DWORD nGuid)
{
	// don't bother searching if guid is null, object doesnt exist
	if (nGuid==0) return NULL ;
	cWorldDataMap::iterator iData = m_objects.find(nGuid);
	if (iData != m_objects.end()) {
		//_DebugLog("\nFound %x", nGuid) ;
		return iData->second;
	} else {
		//_DebugLog("\nFailed find of %x", nGuid) ;
		return NULL;
	}
}


void cWorld::DoDestroyObj(CComPtr< IMessageIterator > pMembers)
{
	long nDestroyed;
	pMembers->get_NextInt(strdestroyed, &nDestroyed);
	_DebugLog("\n\nDestroyObj %x", nDestroyed) ;
	
	// if we know about this object
	if (cWorldData *pData = Data(nDestroyed)) {
		// remove it
		DestroyObject(pData) ;
	}
}


// Gouru: we only use this command to update what areas are being covered by an item, the
//	coverage is not updated to reflect what is actually covered at any given time. To determine
//	if an area of the body is covered, first the item must be in slot -1 (equipped) then the
//	coverage information is the actual current coverage.
void cWorld::DoSetCoverage(CComPtr<IMessageIterator> pMembers)
{
	long object, coverage ;
	pMembers->get_NextInt(strobject, &object) ;
	pMembers->get_NextInt(strcoverage, &coverage) ;

	_DebugLog("\n\nSetCoverage %x %x", object, coverage) ;
	if (cWorldData *pData = Data(object)) {
		pData->m_dwCoverage = coverage ;
	}
}



// Gouru: Set container messages often come in pairs, the first setting the container to zero
//	the second to the actual container. In my testing so far they always appear to arrived
//	in the proper order. In the messages.xml, the only description that seems to be 
//	accurate is the object and container number, the sequence, type,, etc do not appear to
//	be as described.
void cWorld::DoSetContainer(CComPtr<IMessageIterator> pMembers) 
{
	long object, container, seq, type, seq2 ;

	pMembers->get_NextInt(strsequence, &seq) ;
	pMembers->get_NextInt(strobject, &object) ;
	pMembers->get_NextInt(strequipType, &type) ;
	pMembers->get_NextInt(strcontainer, &container) ;
	pMembers->get_NextInt(strsequence2, &seq2) ;

	_DebugLog("\n\nSetContainer: %d, %x, %d, %x, %d", seq, object, type, container, seq2) ;

	// special case 'wielding to ground'. In testing, the object is not 'really' being put on
	//	the ground, so we will ignore the message.
	if (type==3 && container==0) {
		_DebugLog(" - Wield to ground ignored") ;
		return ;
	}
	if (cWorldData *pData = Data(object)) {
		// if the container is changing
		if (pData->m_dwContainer != container) {
			cWorldData* pDest ;
			pDest = container ? Data(container) : NULL;
			if (PlayerOwns(pData)) {
				// if moving out of the player
				_DebugLog(" - Moving out") ;
				MoveItems(pData->m_dwContainer, pData->m_Slot, eLeft) ;
				pData->m_Slot.slot = -1 ;
				pData->m_dwWielder = 0 ;
			}
			if (pDest && PlayerOwns(pDest)) {
				_DebugLog(" - Moving in") ;
				// if moving into player
				if (type==3) {
					// if the item being moved in is being wielded
					pData->m_Slot.slot = -1 ;
				} else {
					// moving into pack, make room for it first
					MoveItems(pDest->m_dwGUID, CSlot(0, pData->m_Slot.type), eRight) ;
					pData->m_Slot.slot = 0 ;
				}
			}
			pData->m_dwContainer = container ;
		} else {
			_DebugLog(" - Container did not change") ;
		}
	}
}


void cWorld::DoAdjustStackSize(CComPtr<IMessageIterator> pMembers)
{
	long nItem, nCount, nValue;
	
	pMembers->get_NextInt(stritem, &nItem);
	pMembers->get_NextInt(strcount, &nCount);
	pMembers->get_NextInt(strvalue, &nValue);

	_DebugLog("\n\nAdjustStackSize %x %d %d", nItem, nCount, nValue) ;
	
	// if the object is in our object store
	if (cWorldData *pData = Data(nItem)) {
		// change the object values, reset expiration to 0
		pData->m_tExpires = 0;
		pData->m_nStackCount = WORD(nCount);
		pData->m_dwValue = nValue;
		
		// Fire change events for those items that may have changed
		Fire_ChangeObject(pData->m_p, strSizeChange);
	}
}

void cWorld::DoWearItem(CComPtr<IMessageIterator> pMembers)
{
	long nObject, nSlot;
	pMembers->get_NextInt(stritem, &nObject);
	pMembers->get_NextInt(strslot, &nSlot) ;
	_DebugLog("\n\nWearItem %x %x", nObject, nSlot) ;
	
	if (cWorldData *pData = Data(nObject))
	{
		pData->m_tExpires = 0;
		
		MoveSlotBack(pData);
		pData->m_Slot.slot = -1;
		pData->m_dwContainer = m_objects.player() ;
		
		// Gouru: Changed to capitalized versions of these string for consistency with other
		//	fired events
		Fire_ChangeObject(pData->m_p, strStorageChange);
	}
}

void cWorld::DoDropItem(CComPtr<IMessageIterator> pMembers)
{
	long nItem;
	pMembers->get_NextInt(stritem, &nItem);
	_DebugLog("\n\nDropItem %x", nItem) ;
	
	if (cWorldData *pData = Data(nItem)) {
		pData->m_tExpires = 0;
		if (PlayerOwns(pData)) {
			MoveSlotBack(pData);
			pData->m_Slot.slot = -1;
			pData->m_dwContainer = 0;
			pData->m_dwWielder = 0 ;		// not wielded when on ground
		}
		Fire_ChangeObject(pData->m_p, strStorageChange);
	}
}

void cWorld::DoIdentifyObject(CComPtr<IMessageIterator> pMembers)
{
	USES_CONVERSION ;
	long nObject;
	pMembers->get_NextInt(strobject, &nObject);

	_DebugLog("\n\nIdentifyObject %x", nObject) ;
	
	cWorldData *pData = Data(nObject);

	if (pData != NULL ) 
	{
		pData->m_tExpires = 0;
		pData->m_HasIdData = true ;
		_DebugLog("\n  HasIDData") ;
	} else {
		_DebugLog("  Object not found") ;
		return ;		// we don't have the create, so can't store id info
	}

	long ObjectIdMask ;
	pMembers->get_NextInt(strflags, &ObjectIdMask) ;

	if (ObjectIdMask && 0x0001) {
		_DebugLog("\nChecking dwords") ;
		CComPtr<IMessageIterator> pItems, pItem;

		pMembers->get_NextObject(strdwords, &pItems);

		while (pItems != NULL && SUCCEEDED(pItems->get_NextObjectIndex(&pItem))) {
			long key, value ;
			pItem->get_NextInt(strkey, &key) ;
			pItem->get_NextInt(strvalue, &value) ;
			_DebugLog("\n  key:%x value:%d || ", key, value) ;
			switch (key) {
				case 0x1C:	pData->m_ArmorLevel = value		; _DebugLog("ArmorLevel %d", value)		; break ;
				case 0x24:	pData->m_MagicDef = value		; _DebugLog("MagicDef %d", value)		; break ;
				case 0x6A:	pData->m_Spellcraft = value		; _DebugLog("Spellcraft %d", value)		; break ;
				case 0x6C:	pData->m_MaximumMana = value	; _DebugLog("MaximumMana %d", value)	; break ;
				case 0x6D:	pData->m_LoreReq = value		; _DebugLog("LoreReq %d", value)		; break ;
				case 0x6E:	pData->m_RankReq = value		; _DebugLog("RankReq %d", value)		; break ;
				case 0x73:	pData->m_SkillReq = value		; _DebugLog("SkillReq %d", value)		; break ;
				case 0x9E:	pData->m_WieldReqType = value	; _DebugLog("WieldReqType %d", value)	; break ;
				case 0x9F:	pData->m_WieldReqId = value		; _DebugLog("WieldReqId %d", value)		; break ;
				case 0xA0:	pData->m_WieldReq = value		; _DebugLog("WieldReq %d", value)		; break ;
				case 0xAB:	pData->m_TinkerCount = value	; _DebugLog("TinkerCount %d", value)	; break ;
				case 0xB0:	pData->m_SkillReqId = value		; _DebugLog("SkillReqId %d", value)		; break ;
				case 0xB3:	pData->m_SpecialProps = value	; _DebugLog("SpecialProps %d", value)	; break ;
			}
		}
	}

	if (ObjectIdMask && 0x0004) {
		_DebugLog("\nChecking doubles") ;
		CComPtr<IMessageIterator> pItems, pItem;

		_DebugLog("\nGetting iterator") ;
		pMembers->get_NextObject(strdoubles, &pItems);
		_DebugLog("\nGetting object") ;
		while (pItems != NULL && SUCCEEDED(pItems->get_NextObjectIndex(&pItem))) {
			long key ;
			float value ;
			_DebugLog("\nGetting key") ;
			pItem->get_NextInt(strkey, &key) ;
			_DebugLog("\nGetting value") ;
			pItem->get_NextFloat(strvalue, &value) ;
			_DebugLog("\n  key:%d value:%f || ", key, value) ;
			switch (key) {
				case 0x90:	pData->m_ManaCMod = value		; _DebugLog("ManaCMod %f", value)		; break ;
			}
		}
	}

	if (ObjectIdMask && 0x0008) {
		_DebugLog("\nChecking strings") ;

		CComPtr<IMessageIterator> pItems, pItem;

		pMembers->get_NextObject(strstrings, &pItems);
		while (pItems != NULL && SUCCEEDED(pItems->get_NextObjectIndex(&pItem))) {
			long key ;
			BSTR value ;
			pItem->get_NextInt(strkey, &key) ;
			pItem->get_NextString(strstring, &value) ;
			std::string sValue = OLE2A(value) ;
			_DebugLog("\n  key:%d value:%s || ", key, sValue.c_str()) ;

			switch (key) {
				case 0x07:	pData->m_Inscription = sValue	; _DebugLog("Inscription")	; break ;
				case 0x13:  pData->m_RaceReq = sValue		; _DebugLog("RaceReq")	; break ;
			}
		}
	}

	if (ObjectIdMask && 0x0010) {
		_DebugLog("\nChecking spells") ;
		CComPtr<IMessageIterator> pItems, pItem;

		pMembers->get_NextObject(strspells, &pItems);
		int ix=0 ;
		while (pItems != NULL && SUCCEEDED(pItems->get_NextObjectIndex(&pItem))) {
			long spellID, spellFlag ;
			pItem->get_NextInt(strspellID, &spellID) ;
			pItem->get_NextInt(strspellFlag, &spellFlag) ;

			_DebugLog("\n  key:%d value:%d || ", spellID, spellFlag) ;
			if (spellFlag == 0 && ix < 10) {
				pData->m_Spell[ix++] = spellID ;
			}
		}
		pData->m_SpellCount = ix ;
	}
	if (ObjectIdMask && 0x0020) {
		_DebugLog("\nChecking damages") ;
		pMembers->get_NextInt(strdamageType, &(pData->m_DamageType)) ;
		pMembers->get_NextInt(strspeed, &(pData->m_WeapSpeed)) ;
		pMembers->get_NextInt(strskill, &(pData->m_EquipSkill)) ;
		pMembers->get_NextInt(strdamage, &(pData->m_MaxDamage)) ;
		pMembers->get_NextFloat(strdamageRange, &(pData->m_Variance)) ;
		pMembers->get_NextFloat(strdamageBonus, &(pData->m_DamageBonus)) ;
		pMembers->get_NextFloat(strrange, &(pData->m_Range)) ;
		pMembers->get_NextFloat(strdefenseBonus, &(pData->m_DefenseBonus)) ;
		pMembers->get_NextFloat(strattackBonus, &(pData->m_AttackBonus)) ;
	}
	if (ObjectIdMask && 0x0020) {
		_DebugLog("\nChecking prots") ;
		pMembers->get_NextFloat(strslashProt, &(pData->m_SlashProt)) ;
		pMembers->get_NextFloat(strpierceProt, &(pData->m_PierceProt)) ;
		pMembers->get_NextFloat(strbludgeonProt, &(pData->m_BludProt)) ;
		pMembers->get_NextFloat(strcoldProt, &(pData->m_ColdProt)) ;
		pMembers->get_NextFloat(strfireProt, &(pData->m_FireProt)) ;
		pMembers->get_NextFloat(stracidProt, &(pData->m_AcidProt)) ;
		pMembers->get_NextFloat(strelectricalProt, &(pData->m_ElectProt)) ;
	}
	Fire_ChangeObject(pData->m_p, strIdentReceived);
}


void cWorld::DoSetPackContents(CComPtr<IMessageIterator> pMembers)
{
	CComPtr<IMessageIterator> pItems, pItem;
	long nPack, nItemCount, ixItem = 0, ixPack=0;
	
	pMembers->get_NextInt(strpack, &nPack);
	pMembers->get_NextInt(stritemCount, &nItemCount);
	pMembers->get_NextObject(stritems, &pItems);
	
	_DebugLog("\n\nSetPackContents %x %d", nPack, nItemCount) ;
	
	while (SUCCEEDED(pItems->get_NextObjectIndex(&pItem))) 
	{
		long nItem, nType;
		
		pItem->get_NextInt(stritem, &nItem);
		pItem->get_NextInt(strtype, &nType);
		
		CSlot slot = (nType==0) ? CSlot(ixItem++, 0x00) : CSlot(ixPack++, 0x01) ;

		// if the object has been created
		if (cWorldData *pData = Data(nItem)) 
		{
			pData->m_tExpires = 0;
			pData->m_dwContainer = nPack;
			pData->m_Slot = slot ;
			
			//SetObjectOwner(pData);
			Fire_ChangeObject(pData->m_p, strStorageChange);
		}
		else 
		{
			// store the slot information so it can be inserted when the object is created
			//	later
			m_SlotStore[nItem] = slot ;
		}
		pItem.Release();
	}
}


void cWorld::DoInsertIntoInventory(CComPtr<IMessageIterator> pMembers)
{
	long nItem, nDest, nSlot;
	
	pMembers->get_NextInt(stritem, &nItem);
	pMembers->get_NextInt(strdestination, &nDest);
	pMembers->get_NextInt(strslot, &nSlot);
	
	_DebugLog("\n\nInsertIntoInventory %x %x %d", nItem, nDest, nSlot) ;

	if (cWorldData *pData = Data(nItem)) {	

		// get information about the destination container
		cWorldData* pDest = Data(nDest) ;
		// TODO: Gouru: what is destination if it doesn't exist, comes up with an unknown
		//		destination on death
		if (!pDest) return ;
		
		// we will attempt to update slot information. If we don't have slot information for
		//	the destination (ie, its another player), we assume that it is going into the
		//	first slot. If it later shows up equipped, on the ground, whatever, we will 
		//	remove it from the assumed slot. Since we can never actually access anything in
		//	another players pack, these assumption hurt nothing, even if wrong.
		// move everything in the original pack left/up to fill the old slot
		MoveItems(pData->m_dwContainer, pData->m_Slot, eLeft) ;
		// now move everything after the new position right/down one to make room
		MoveItems(nDest, CSlot(nSlot, pData->m_Slot.type), eRight) ;
		
		pData->m_tExpires = 0;
		pData->m_dwContainer = nDest;
		pData->m_Slot.slot = nSlot;
		pData->m_dwWielder = 0 ;		// not wielded when in inventory
		
		Fire_ChangeObject(pData->m_p, strStorageChange);
	}
}


void cWorld::DoLogin(CComPtr<IMessageIterator> pMembers)
{
	CComPtr<IMessageIterator> pItems, pItem;
	long nCount, ixSlot = 0, ixPack=0 ;
	
	pMembers->get_NextInt(strinventoryCount, &nCount);
	pMembers->get_NextObject(strinventory, &pItems);
	
	while (pItems->get_NextObjectIndex(&pItem) == S_OK)
	{
		long nObject, nIsContainer;
		cWorldData *pData;
		
		pItem->get_NextInt(strobject, &nObject);
		pItem->get_NextInt(strisContainer, &nIsContainer);

		CSlot info ;
		if (nIsContainer) {
			info.type = 0x01 ;
			info.slot = ixPack++ ;
		} else {
			info.type = 0x00 ;
			info.slot = ixSlot++ ;
		}

		// if the item is already in the global store
		if (pData = Data(nObject)) {
			pData->m_Slot = info ;
		} else {
			m_SlotStore[nObject] = info ;
		}
		pItem.Release();
	}
}


// Gouru: This message arrives when an item is put into inventory. Often seen when somebody
//	 picks up something that is lieing on the ground. It does not specify whose inventory it
//	 got added to, so we cannot make any assumptions as to owner, container, etc from this 
//	 message.
void cWorld::DoMoveToInventory(CComPtr<IMessageIterator> pMembers)
{
	long nObject;
	pMembers->get_NextInt(strobject, &nObject);
	
	_DebugLog("\n\nMoveToInventory %x", nObject) ;

	if (cWorldData *pData = Data(nObject)) {
		// if we don't own it, we can't be sure where it went, all we know is that we can
		//	no longers select it.
		if (!PlayerOwns(pData)){
			pData->m_tExpires = 0;
			pData->m_Slot.slot = -1 ;		// unknown
			pData->m_dwContainer = -1 ;		// unknown
		}
		pData->m_dwWielder = 0 ;		// unwielded unless we get a wield msg later
		
		Fire_ChangeObject(pData->m_p, strStorageChange);
	}
}


void cWorld::DoCreateObject(CComPtr<IMessageIterator> pMembers)
{
	USES_CONVERSION ;

	long nObject;
	pMembers->get_NextInt(strobject, &nObject);

	_DebugLog("\n\nCreate/UpdateObject %x", nObject) ;
	
	cWorldData *pCreate = NULL;

	if (cWorldData *pData = Data(nObject)) 
	{
		pCreate = pData;
		pCreate->m_tExpires = 0;
	}
	else
	{
		pCreate = new cWorldData;

		if (!pCreate)
		{
			::MessageBox(NULL, "Decal", "Could not allocate memory for World Data!", MB_OK);
			return ;
		}

		CComObject< cWorldObject > *p;
		CComObject< cWorldObject >::CreateInstance(&p);

		p->m_p = pCreate;
		p->QueryInterface(&pCreate->m_p);

		_DebugLog("\nInserting object") ;
		m_objects.insert(m_objects.end(), std::pair< DWORD, cWorldData * >(nObject, pCreate));
	}

	_ASSERTE(pCreate);

	pCreate->m_dwGUID = nObject;
	pMembers->get_NextInt(strflags1, &pCreate->m_dwFlags1);

	// Location of Object 
	if (pCreate->m_dwFlags1 & 0x00008000) 
	{
		CComPtr< IMessageIterator > pPos;
		pMembers->get_NextObject(strlocation, &pPos);
		
		pPos->get_NextInt(strlandblock, &pCreate->m_dwLandblock);
		_DebugLog("\n   Landblock %d", pCreate->m_dwLandblock) ;
		pPos->get_NextFloat(strxOffset, &pCreate->m_fxOffset);
		_DebugLog("\n   xOffset %f", pCreate->m_fxOffset) ;
		pPos->get_NextFloat(stryOffset, &pCreate->m_fyOffset);
		_DebugLog("\n   yOffset %f", pCreate->m_fyOffset) ;
		pPos->get_NextFloat(strzOffset, &pCreate->m_fzOffset);
		_DebugLog("\n   zOffset %f", pCreate->m_fzOffset) ;
		pPos->get_NextFloat(strxHeading, &pCreate->m_fxHeading);
		_DebugLog("\n   Heading %f", pCreate->m_fxHeading) ;
		// landblock info used to speed up culling
		pCreate->m_LandblockCol = (pCreate->m_dwLandblock>>24) & 0xff ;
		pCreate->m_LandblockRow = (pCreate->m_dwLandblock>>16) & 0xff ;

		pCreate->m_flags |= FLAG_LOCATION;
	}
	
	// Wielder Information
	if (pCreate->m_dwFlags1 & 0x00000020) 
	{
		pMembers->get_NextInt(strwielder, &pCreate->m_dwWielder);
		_DebugLog("\n   Wielder %d", pCreate->m_dwWielder) ;
		pMembers->get_NextInt(strwieldingSlot, &pCreate->m_dwWieldingSlot);
		_DebugLog("\n   Wieldingslot %d", pCreate->m_dwWieldingSlot) ;
		pCreate->m_Slot.slot = -1 ;		// wielded items are slot 1
		pCreate->m_dwContainer = pCreate->m_dwWielder ;
	}

	// Real Model
	if (pCreate->m_dwFlags1 & 0x1) 
	{
		pMembers->get_NextInt(strrealmodel, &pCreate->m_dwRealModel);
		_DebugLog("\n   Real Model %x",pCreate->m_dwRealModel) ;
	}

	// Scale
	if( pCreate->m_dwFlags1 & 0x80 )
	{
		pMembers->get_NextFloat(strunkgreen, &pCreate->m_fScale);
		_DebugLog("\n   Scale %.2f",pCreate->m_fScale) ;
	}

	pMembers->get_NextInt(strflags2, &pCreate->m_dwFlags2);

	BSTR strName;
	pMembers->get_NextString(strobjectName, &strName);
	pCreate->m_strName = OLE2A(strName);
	_DebugLog("\n   Name: %s", pCreate->m_strName.c_str()) ;

	pMembers->get_NextInt(strmodel, &pCreate->m_dwModel);
	_DebugLog("\n   Model %x",pCreate->m_dwModel) ;
	pMembers->get_NextInt(stricon, &pCreate->m_dwIcon);
	_DebugLog("\n   Icon %x",pCreate->m_dwIcon) ;
	pMembers->get_NextInt(strunknown_v0_2, &pCreate->m_dwObjectFlags1);
	pMembers->get_NextInt(strunknown_v0_3, &pCreate->m_dwObjectFlags2);

	// Secondary name
	if (pCreate->m_dwFlags2 & 0x00000001) {
		BSTR strName;
		pMembers->get_NextString(strsecondaryName, &strName);
		pCreate->m_strSecondaryName = OLE2A(strName);
		_DebugLog("\n   SecName: %s", pCreate->m_strSecondaryName.c_str()) ;
	}

	// Item Slots
	if (pCreate->m_dwFlags2 & 0x00000002) 
	{
		pCreate->m_flags |= FLAG_CONTAINS;
		pMembers->get_NextInt(stritemSlots, (long *)&pCreate->m_nItemSlots);
		_DebugLog("\n   ItemSlots %x",pCreate->m_nItemSlots) ;
		// if it has slots for items, must be a container type
		pCreate->m_Slot.type = 1 ;
	}

	// Pack Slots
	if (pCreate->m_dwFlags2 & 0x00000004) 
	{
		pCreate->m_flags |= FLAG_CONTAINS;
		pMembers->get_NextInt(strpackSlots, (long *)&pCreate->m_nPackSlots);
		_DebugLog("\n   PackSlots %x",pCreate->m_nPackSlots) ;
		// if it has slots for packs, must be a container type
		pCreate->m_Slot.type = 1 ;
	}

	// Missile Type
	if (pCreate->m_dwFlags2 & 0x00000100) {
		pMembers->get_NextInt(strunknown_w1, &pCreate->m_MissileType);
		_DebugLog("\n   m_MissileType %x",pCreate->m_MissileType) ;
	}

	// Value
	if (pCreate->m_dwFlags2 & 0x00000008) {
		pMembers->get_NextInt(strvalue, &pCreate->m_dwValue);
		_DebugLog("\n   Value %x",pCreate->m_dwValue) ;
	} else {
		pCreate->m_dwValue = -1;
	}

	
	// Total Value
	if (pCreate->m_dwFlags2 & 0x00000010) {
		pMembers->get_NextInt(strunknown_v2, &pCreate->m_TotalValue);
		_DebugLog("\n   TotValue %x",pCreate->m_TotalValue) ;
	} else {
		pCreate->m_dwValue = -1;
	}

	
	// approachDistance
	if (pCreate->m_dwFlags2 & 0x00000020) {
		pMembers->get_NextFloat(strapproachDistance, &pCreate->m_fApproachDistance);
		_DebugLog("\n   ApproachDist %f",pCreate->m_fApproachDistance) ;
	}

	
	// Usage Mask
	if (pCreate->m_dwFlags2 & 0x00080000) {
		pMembers->get_NextInt(strunknown_v5, &pCreate->m_UsageMask);
		_DebugLog("\n   m_UsageMask: %x",pCreate->m_UsageMask) ;
	}

	// Icon Outline
	if (pCreate->m_dwFlags2 & 0x00000080) {
		_DebugLog("\n   m_IconOutline:", pCreate->m_IconOutline) ;
		pMembers->get_NextInt(strunknown_v4, &pCreate->m_IconOutline);
		_DebugLog(" %x",pCreate->m_IconOutline) ;
	}

	// Equip Type
	if (pCreate->m_dwFlags2 & 0x00000200) {
		pMembers->get_NextInt(strequipmentType, &pCreate->m_dwEquipType);
		_DebugLog("\n   EquipType %x",pCreate->m_dwEquipType) ;
	}

	// Uses Left
	if (pCreate->m_dwFlags2 & 0x00000400) {
		pCreate->m_flags |= FLAG_USEABLE;
		pMembers->get_NextInt(strusesLeft, (long *)&pCreate->m_nUsesLeft);
		_DebugLog("\n   UsesLeft %x",pCreate->m_nUsesLeft) ;
	}

	// Total Uses
	if (pCreate->m_dwFlags2 & 0x00000800) {
		pCreate->m_flags |= FLAG_USEABLE;
		pMembers->get_NextInt(strtotalUses, (long *)&pCreate->m_nTotalUses);
		_DebugLog("\n   TotalUses %x",pCreate->m_nTotalUses) ;
	}

	// Stack Count
	if (pCreate->m_dwFlags2 & 0x00001000) {
		pCreate->m_flags |= FLAG_STACKABLE;
		pMembers->get_NextInt(strstackCount, (long *)&pCreate->m_nStackCount);
		_DebugLog("\n   StackCount %x",pCreate->m_nStackCount) ;
	}

	// Stack Maximum
	if (pCreate->m_dwFlags2 & 0x00002000) {
		pCreate->m_flags |= FLAG_STACKABLE;
		pMembers->get_NextInt(strstackMax, (long *)&pCreate->m_nStackMax);
		_DebugLog("\n   StackMax %x",pCreate->m_nStackMax) ;
	}

	// Container ID
	if (pCreate->m_dwFlags2 & 0x00004000) {
		pMembers->get_NextInt(strcontainer, &pCreate->m_dwContainer);
		_DebugLog("\n   container: %x",pCreate->m_dwContainer) ;
	}

	// Owner ID
	if (pCreate->m_dwFlags2 & 0x00008000) {
		long dword ;
		// gouru, owner is same as container for these purposes, however, the item appears
		//	to be either worn or wielded, assume slot -1
		pMembers->get_NextInt(strowner, &dword);
		_DebugLog("\n   ownerid: %x",dword) ;
		pCreate->m_dwContainer = dword ;
		pCreate->m_Slot.slot = -1 ;
	}

	// Coverage1
	if (pCreate->m_dwFlags2 & 0x00010000) {
		pMembers->get_NextInt(strcoverage1, &pCreate->m_dwCoverage);
		_DebugLog("\n   coverage1: %x",pCreate->m_dwCoverage) ;
	}

	// Coverage2
	if (pCreate->m_dwFlags2 & 0x00020000) {
		pMembers->get_NextInt(strcoverage2, &pCreate->m_dwCoverage2);
		_DebugLog("\n   coverage2: %x",pCreate->m_dwCoverage2) ;
	}

	// Coverage3
	if (pCreate->m_dwFlags2 & 0x00040000) {
		pMembers->get_NextInt(strcoverage3, &pCreate->m_dwCoverage3);
		_DebugLog("\n   coverage3: %x",pCreate->m_dwCoverage3) ;
	}



	//// Tradenote Vendor ID
	//if (pCreate->m_dwFlags2 & 0x00020000) {
	//	pMembers->get_NextInt(strtradenoteVendor, &pCreate->m_dwTradeNoteVendor);
	//	_DebugLog("\n   TradeNoteVendor: %x",pCreate->m_dwTradeNoteVendor) ;
	//}

	
	// Workmanship
	if (pCreate->m_dwFlags2 & 0x01000000) {
		pMembers->get_NextFloat(strworkmanship, &pCreate->m_Workmanship);
		_DebugLog("\n   m_Workmanship: %f", pCreate->m_Workmanship) ;
	}

	// Burden
	if (pCreate->m_dwFlags2 & 0x00200000) {
		pMembers->get_NextInt(strburden, &pCreate->m_Burden);
		_DebugLog("\n   m_Burden: %x",pCreate->m_Burden) ;
	}

	// Associated Spell
	if (pCreate->m_dwFlags2 & 0x00400000) {
		pMembers->get_NextInt(strassociatedSpell, &pCreate->m_dwAssociatedSpell);
		_DebugLog("\n   m_dwAssociatedSpell: %x",pCreate->m_dwAssociatedSpell) ;
	}

	// HouseOwner
	if (pCreate->m_dwFlags2 & 0x02000000) {
		pMembers->get_NextInt(strhouseOwnerID, &pCreate->m_HouseOwner);
		_DebugLog("\n   m_HouseOwner: %x",pCreate->m_HouseOwner) ;
	}

	// Hook Mask
	if (pCreate->m_dwFlags2 & 0x10000000) {
		pMembers->get_NextInt(strunknown10, &pCreate->m_HookMask);
		_DebugLog("\n   m_HookMask: %x",pCreate->m_HookMask) ;
	}


	// Hook Type
	if (pCreate->m_dwFlags2 & 0x20000000) {
		pMembers->get_NextInt(strunknown11b, &pCreate->m_HookType);
		_DebugLog("\n   m_HookType: %x",pCreate->m_HookType) ;
	}


	// Monarch
	if (pCreate->m_dwFlags2 & 0x00000040) {
		pMembers->get_NextInt(strmonarch, &pCreate->m_dwMonarch);
		_DebugLog("\n   Monarch: %x",pCreate->m_dwMonarch) ;
	}

	
	// Material
	if (pCreate->m_dwFlags2 & 0x80000000) {
		pMembers->get_NextInt(strmaterial, &pCreate->m_dwMaterial);
		_DebugLog("\n   m_dwMaterial: %x",pCreate->m_dwMaterial) ;
	}


	// Assume the type is unknown
	pCreate->m_eType = eUnknownObject;

	_DebugLog("\n   m_dwObjectFlags1: %x",pCreate->m_dwObjectFlags1) ;
	// Get the type from ObjectFlags1
	/**/ if (pCreate->m_dwObjectFlags1 & 0x00000001)
		pCreate->m_eType =  eMeleeWeapon;
	else if (pCreate->m_dwObjectFlags1 & 0x00000002)
		pCreate->m_eType =  eArmor;
	else if (pCreate->m_dwObjectFlags1 & 0x00000004)
		pCreate->m_eType =  eClothing;
	else if (pCreate->m_dwObjectFlags1 & 0x00000008)
		pCreate->m_eType =  eJewelry;
	else if (pCreate->m_dwObjectFlags1 & 0x00000010)
		pCreate->m_eType =  eMonster;
	else if (pCreate->m_dwObjectFlags1 & 0x00000020)
		pCreate->m_eType =  eFood;
	else if (pCreate->m_dwObjectFlags1 & 0x00000040)
		pCreate->m_eType =  eMoney;
	else if (pCreate->m_dwObjectFlags1 & 0x00000080)
		pCreate->m_eType =  eMisc;
	else if (pCreate->m_dwObjectFlags1 & 0x00000100)
		pCreate->m_eType =  eMissileWeapon;
	else if (pCreate->m_dwObjectFlags1 & 0x00000200)
		pCreate->m_eType =  eContainer;
	else if (pCreate->m_dwObjectFlags1 & 0x00000400)
		pCreate->m_eType =  eBundle;
	else if (pCreate->m_dwObjectFlags1 & 0x00000800)
		pCreate->m_eType =  eGem;
	else if (pCreate->m_dwObjectFlags1 & 0x00001000)
		pCreate->m_eType =  eSpellComponent;
	else if (pCreate->m_dwObjectFlags1 & 0x00004000)
		pCreate->m_eType =  eKey;
	else if (pCreate->m_dwObjectFlags1 & 0x00008000)
		pCreate->m_eType =  eWandStaffOrb;
	else if (pCreate->m_dwObjectFlags1 & 0x00010000)
		pCreate->m_eType =  ePortal;
	else if (pCreate->m_dwObjectFlags1 & 0x00040000)
		pCreate->m_eType =  eTradeNote;
	else if (pCreate->m_dwObjectFlags1 & 0x00080000)
		pCreate->m_eType =  eManaStone;
	else if (pCreate->m_dwObjectFlags1 & 0x00100000)
		pCreate->m_eType =  eService;
	else if (pCreate->m_dwObjectFlags1 & 0x00200000)
		pCreate->m_eType =  ePlant;
	else if (pCreate->m_dwObjectFlags1 & 0x00400000)
		pCreate->m_eType =  eBaseCooking;
	else if (pCreate->m_dwObjectFlags1 & 0x00800000)
		pCreate->m_eType =  eBaseAlchemy;
	else if (pCreate->m_dwObjectFlags1 & 0x01000000)
		pCreate->m_eType =  eBaseFletching;
	else if (pCreate->m_dwObjectFlags1 & 0x02000000)
		pCreate->m_eType =  eCraftedCooking;
	else if (pCreate->m_dwObjectFlags1 & 0x04000000)
		pCreate->m_eType =  eCraftedAlchemy;
	else if (pCreate->m_dwObjectFlags1 & 0x08000000)
		pCreate->m_eType =  eCraftedFletching;
	else if (pCreate->m_dwObjectFlags1 & 0x20000000)
		pCreate->m_eType =  eUst;
	else if (pCreate->m_dwObjectFlags1 & 0x40000000)
		pCreate->m_eType =  eSalvage;

	_DebugLog("\n   m_dwObjectFlags2: %x",pCreate->m_dwObjectFlags2) ;
	// Get the type from ObjectFlags2 (this means ObjectFlags2 overrides ObjectFlags1)
	/**/ if (pCreate->m_dwObjectFlags2 & 0x00000008)
		pCreate->m_eType =  ePlayer;
	else if (pCreate->m_dwObjectFlags2 & 0x00000200)
		pCreate->m_eType =  eVendor;
	else if (pCreate->m_dwObjectFlags2 & 0x00001000)
		pCreate->m_eType =  eDoor;
	else if (pCreate->m_dwObjectFlags2 & 0x00002000)
		pCreate->m_eType =  eCorpse;
	else if (pCreate->m_dwObjectFlags2 & 0x00004000)
		pCreate->m_eType =  eLifestone;
	else if (pCreate->m_dwObjectFlags2 & 0x00008000)
		pCreate->m_eType =  eFood;
	else if (pCreate->m_dwObjectFlags2 & 0x00010000)
		pCreate->m_eType =  eHealingKit;
	else if (pCreate->m_dwObjectFlags2 & 0x00020000)
		pCreate->m_eType =  eLockpick;
	else if (pCreate->m_dwObjectFlags2 & 0x00040000)
		pCreate->m_eType =  ePortal;
	else if (pCreate->m_dwObjectFlags2 & 0x00000001) // Keep this last (other wise some of the others won't come up right)
		pCreate->m_eType =  eContainer;

	// Is this an informational object???
	if ((pCreate->m_dwObjectFlags1 & 0x00002000) &&
		(pCreate->m_dwObjectFlags2 & 0x00000100) &&
		(pCreate->m_eType == eUnknownObject))
	{
		/**/ if (pCreate->m_dwObjectFlags2 & 0x00000002)
			pCreate->m_eType = eJournal;
		else if (pCreate->m_dwObjectFlags2 & 0x00000004)
			pCreate->m_eType = eSign;
		else if (!(pCreate->m_dwObjectFlags2 & 0x0000000F))
			pCreate->m_eType = eBook;
	}

	// can be inscribed
	if (pCreate->m_dwObjectFlags2 & 0x00000002)
		pCreate->m_flags |= FLAG_INSCRIBABLE;

	// lockpick
	if (pCreate->m_dwObjectFlags1 & 0x00020000)
		pCreate->m_flags |= FLAG_LOCKABLE;

	// if item location was received earlier, put slot into the object
	if (m_SlotStore.find(nObject) != m_SlotStore.end())
	{
		_DebugLog(" | Slot %d", m_SlotStore[nObject].slot) ;
		pCreate->m_Slot = m_SlotStore[nObject];
		m_SlotStore.erase(nObject);
	} else if (pCreate->m_Slot.slot == 0) {
		// if we don't have slot information assumed yet
		long tp = (pCreate->m_nPackSlots) ? 1 : 0 ;
		pCreate->m_Slot.slot = -1 ;
		if (pCreate->m_dwContainer == m_objects.player()) {
			// if this is being created in the player, and slot information has not been 
			//	given (this occurs when buying items) assume slot is zero, push everything
			//	back to make room for it.
			MoveItems(m_objects.player(), CSlot(0, tp), eRight) ;
			pCreate->m_Slot.slot = 0 ;
		} else {
			// -1, slot unknown, will never be greater than a good slot, so won't be moved
			_DebugLog(" | Slot unknown") ;
		}
	}

	// Check if "monster" is really an NPC
	if ((pCreate->m_eType == eMonster) && !(pCreate->m_dwObjectFlags2 & 0x00000010))
	{
		pCreate->m_eType = eNPC;
	}

	// Flag as a housing item (hook, covenant stone, or the house itself)
	if ((pCreate->m_dwIcon == 0x000020C0) || // Hook
		(pCreate->m_dwIcon == 0x000020C1) || // Covenant Crystal
		(pCreate->m_dwIcon == 0x0000218C) || // Covenant Crystal
		(pCreate->m_dwIcon == 0x0000218D) || // Storage
		(pCreate->m_dwIcon == 0x00002181) || // House
		(pCreate->m_dwIcon == 0x00002182) || // House
		(pCreate->m_dwIcon == 0x00002183) || // House
		(pCreate->m_dwIcon == 0x00002184) || // House
		(pCreate->m_dwIcon == 0x00002185) || // House
		(pCreate->m_dwIcon == 0x00002186) || // House
		(pCreate->m_dwIcon == 0x0000218B) || // House
		(pCreate->m_dwIcon == 0x0000218E) || // House
		(pCreate->m_dwIcon == 0x0000218F))   // House
	{
		pCreate->m_eType = eHousing;
	}

	// Check if a misc item is a Foci pack
	if ((pCreate->m_eType == eMisc) && (pCreate->m_strName.find("Foci of ") != std::string::npos))
	{
		pCreate->m_eType = eFoci;
	}
	
	Fire_CreateObject(pCreate->m_p);
}

		
void cWorld::DoRemoveItem(CComPtr<IMessageIterator> pMembers)
{
	long nObject;
	pMembers->get_NextInt(strobject, &nObject);
	
	_DebugLog("\n\nRemoveItem %x", nObject) ;

	// don't remove it if we don't have a record of it
	if (cWorldData *pData = Data(nObject)) {
		DestroyObject(pData) ;
	}
}

void cWorld::DoWieldItem(CComPtr<IMessageIterator> pMembers)
{
	long nObject, nOwner;
	pMembers->get_NextInt(strowner, &nOwner);
	pMembers->get_NextInt(strobject, &nObject);
	_DebugLog("\n\nWieldItem %x %x", nObject, nOwner) ;
	
	if (cWorldData *pData = Data(nObject))
	{
		pData->m_dwWielder = nOwner;
		pData->m_dwContainer = nOwner ;
		MoveSlotBack(pData);		// moves back only if player owns this item
		pData->m_Slot.slot = -1;
		
		Fire_ChangeObject(pData->m_p, strStorageChange);
	}
}

// testing running around the world showed that after running out about 1.5
//	landblock and running back, the CreateObject event was fired again. Therefore we
//	won't hold the data in our memory for those objects. Rather than measuring distance
//	we count land blocks, since it is possible to be 2 blocks away and only be 1.1 clicks
//	away, we cull if the landblock separation is greater than 2
bool cWorld::OutsideCullDistance(cWorldData* data, long row, long col)
{
//	_DebugLog("\nCull Distance %d-%d, %d-%d", data->m_LandblockRow, row,
//				data->m_LandblockCol, col) ;
//	long x = abs(data->m_LandblockRow-row) ;
//	long y = abs(data->m_LandblockCol-col) ;
//	if (x>2 || y>2) {
//		_DebugLog(" <true>") ;
//		return true ;
//	}
//	_DebugLog(" <false>") ;
//	return false ;
	return false ;
}

void cWorld::DoSetObjectPosition(CComPtr<IMessageIterator> pMembers)
{
	long nObject;
	pMembers->get_NextInt(strobject, &nObject);
	// Gouru: not normally logged as we get an S load of these messages, uncomment if you
	//	really need it for testing...
//	_DebugLog("\nSetObjectPosition %x", nObject) ;
	
	cWorldData *pData = Data(nObject);

	if (pData) 
	{
		CComPtr< IMessageIterator > pPos;
		pMembers->get_NextObject(strposition, &pPos);

		DWORD dwLandblock;
		pPos->get_NextInt(strlandblock, (long *)&dwLandblock);

//		long oldLandblock = pData->m_dwLandblock ;
//		long colLandblock = (dwLandblock>>24) & 0xff ;
//		long rowLandblock = (dwLandblock>>16) & 0xff ;
		// store landblock and landblock h/v values so we don't have to recalculate them
		//   everytime since we do this a lot
		pData->m_dwLandblock = dwLandblock;
		pData->m_LandblockCol = (dwLandblock>>24) & 0xff ;
		pData->m_LandblockRow = (dwLandblock>>16) & 0xff ;
		pPos->get_NextFloat(strxOffset, &pData->m_fxOffset);
		pPos->get_NextFloat(stryOffset, &pData->m_fyOffset);
		pPos->get_NextFloat(strzOffset, &pData->m_fzOffset);
		pPos->get_NextFloat(strxHeading, &pData->m_fxHeading);

		// Object culling monster!
		// If moving object is player, and player changed landblocks...
		// if the object changed landblocks
//		if (HIWORD(oldLandblock) != HIWORD(pData->m_dwLandblock)) {
//			if	(nObject == m_objects.player()) {
//				_DebugLog("\n\nPlayer changed landblock!") ;
//				// If the moving object was the player, scan all items and tag those
//				//  too far away with an expiration time
//				for (cWorldDataMap::iterator i = m_objects.begin(); i != m_objects.end(); i++) 
//				{
//					cWorldData *pObject = i->second;
//					if (!pObject) {
//						continue ;		// can't process if we don't have the object...
//					}
//					
//					// get the outmost container of this object, its landblock is used in
//					//	distance checking...
//					cWorldData *pLbData = OuterContainer(pObject) ;
//					
//					// if the object moving is the player, or carried by the player
//					//	dont process it, it should not be culled
//					if (pLbData->m_dwGUID == m_objects.player()) {
//						_DebugLog("\nplayerobj: %x", pObject->m_dwGUID) ;
//						continue ;
//					}
//
//#ifdef LOGGING
//					if (pLbData != pObject) {
//						_DebugLog("object %x contained in %x", 
//							pObject->m_dwGUID, pLbData->m_dwGUID) ;
//					}
//#endif
//					// if the object is outside the culling distance
//					if (OutsideCullDistance(pLbData, rowLandblock, colLandblock)) {
//						// if the item is not already tagged, tag it to expire in 30 seconds
//						if (!pObject->m_tExpires) {
//							_DebugLog("\nculling %x", pObject->m_dwGUID) ;
//							pObject->m_tExpires = time(NULL)+30 ;
//							Fire_ChangeObject(pObject->m_p, strReleasePending);
//						} else {
//							_DebugLog("\n%x already tagged", pObject->m_dwGUID) ;
//						}
//					} else if (pObject->m_tExpires) {
//						// else it is inside the culling distance and if tagged to expire
//						// cance the expiration
//						_DebugLog("\ncancelled cull %x", pObject->m_dwGUID) ;
//						pObject->m_tExpires = 0 ;
//						Fire_ChangeObject(pObject->m_p, strExpirationCancel);
//					}
//				}
//			} else {
//				_DebugLog("\n\nItem %x changed landblock!", nObject) ;
//				// object is not a player, tag it to expire if it has moved to far away
//				cWorldData* pLbData = OuterContainer(pData) ;
//				cWorldData* pPlayer = Data(m_objects.player()) ;
//				if	( OutsideCullDistance(pPlayer, pLbData->m_LandblockRow, pLbData->m_LandblockCol)){
//					// if not already tagged, tag it to expire
//					if (!pData->m_tExpires) {
//						_DebugLog("\nculling %x", pData->m_dwGUID) ;
//						pData->m_tExpires = time(NULL) + 30 ;
//						Fire_ChangeObject(pData->m_p, strReleasePending);
//					} else {
//						_DebugLog("%x already tagged", pData->m_dwGUID) ;
//					}
//				} else if (pData->m_tExpires) {
//					_DebugLog("\ncancelled cull %x", pData->m_dwGUID) ;
//					// else it is inside the culling distance and if tagged to expire
//					// cancel the expiration
//					pData->m_tExpires = 0 ;
//					Fire_ChangeObject(pData->m_p, strExpirationCancel);
//				}
//			}
//		}
		pData->m_flags |= FLAG_LOCATION;
		Fire_MovedObject(pData->m_p);
	}
}


STDMETHODIMP cWorld::get_Inventory(IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByInventory();
	pList->QueryInterface(pVal);

	return S_OK;
}


STDMETHODIMP cWorld::get_Landscape(IWorldIterator **pVal)
{
	CComObject< cWorldIterator > *pList;
	CComObject< cWorldIterator >::CreateInstance(&pList);

	pList->Initialize(&m_objects);
	pList->ByLandscape() ;
	pList->QueryInterface(pVal);

	return S_OK;
}


STDMETHODIMP cWorld::get_NumObjectTypes(long *lVal)
{
	*lVal = (long) eNumObjectTypes;

	return S_OK;
}


// changes the slot of every item the specified container, of the specified type
//	that is after the specified slot position, in the specified direction
void cWorld::MoveItems(
	DWORD container,			// the container being adjusted
	CSlot Slot,					// first slot to be moved
	eDIR direction)				// direction to move -1=Forwards, 1 = Backwards
{
	_DebugLog("\nMove item: %x s:%d t:%d %s",
					container, Slot.slot, Slot.type, direction>0 ? "right" : "left") ;

	if (Slot.slot<0) {
		_DebugLog(" : no move, unequipping...") ;
		return ;
	}

	for (cWorldDataMap::iterator iData = m_objects.begin(); iData!=m_objects.end(); iData++)
	{
		cWorldData& p = *(iData->second) ;
		if	(	p.m_dwContainer==container 
			&&	p.m_Slot.type == Slot.type 
			&&	p.m_Slot.slot >= Slot.slot) {
			p.m_Slot.slot += long(direction) ;
			_DebugLog("\n  %02d %x %s", p.m_Slot.slot, p.m_dwGUID, p.m_strName.c_str()) ;
		}
	}
}



void cWorld::MoveSlotBack(cWorldData *pData)
{
	if (PlayerOwns(pData)) {
		MoveItems(pData->m_dwContainer, pData->m_Slot, eLeft) ;
	}
}


cWorldData* cWorld::OuterContainer(cWorldData* object)
{
	if (!object) return NULL ;
	cWorldData* rv = Data(object->m_dwContainer) ;
	// if no container, return the original object
	if (!rv) return object ;
	// else try to get the container's container ;
	cWorldData* rv2 = Data(rv->m_dwContainer) ;
	// if no container's container, return the container
	if (!rv2) return rv ;
	// else return the containers container
	return rv2 ;
}


bool cWorld::PlayerOwns(cWorldData* pData)
{
	if (!pData)	{
		_DebugLog("\nNull ptr to PlayerOwns") ;
		return false ;
	}
	return (OuterContainer(pData)->m_dwGUID==m_objects.player()) ;
}


float cWorld::EastWest(long landblock, float xOffset)
{
	long n = (((landblock>>24)&0xff)-0x7f)*192 ;
	return float((float(n) + xOffset - 84.0) / 240.0) ;
}



float cWorld::NorthSouth(long landblock, float yOffset)
{
	long n = (((landblock>>16)&0xff)-0x7f)*192 ;
	return float((float(n) + yOffset - 84.0) / 240.0) ;
}


void cWorld::onObjectDestroyed(long nId)
{
	_DebugLog("\nonObjectDestroyed %x", nId) ;
	// if we know about this object
	if (cWorldData *pData = Data(nId))
	{
		bool IsPlayer = pData->m_eType==ePlayer ;
		// remove it
		DestroyObject(pData) ;
		if (IsPlayer) {
			_DebugLog("\n Remove wielded items") ;
		}
	}
}

#ifdef Logging
void cWorld::_DebugLog(LPCSTR fmt, ...)
{
	static FILE	*pfile ;

	if (!pfile) {
		pfile = fopen("C:\\world.log", "a+") ;
		fprintf(pfile,"\n------------- SESSION START -------------\n") ;
	}
	if (!strcmp(fmt,"CLOSEFILE") && pfile) {
		fprintf(pfile,"\n------------- SESSION END -------------\n") ;
		fclose(pfile) ;
		pfile = NULL ;
		return ;
	}

	va_list argList;
	va_start(argList, fmt);
	vfprintf(pfile, fmt, argList) ;
	va_end(argList);
	fflush(pfile) ;
}
#endif
