#include "StdAfx.h"
#include "World.h"
#include "Client.h"
#include "PhysicsObj.h"
#include "Monster.h"
#include "Player.h"
#include "ChatMsgs.h"
//Database access
#include "Database.h"
#include "CharacterDatabase.h"
#include "TurbineDungeon.h"
#include "GameMode.h"
CWorld::CWorld()
{
LOG(Temp, Normal, "Initializing World..\n");
m_dwHintStaticGUID = 0x10000000;
m_dwHintPlayerGUID = 0x50000000;
m_dwHintItemGUID = 0x60000000;
m_dwHintDynamicGUID = 0xC0000000;
ZeroMemory(m_pBlocks, sizeof(m_pBlocks));
LoadStateFile();
LoadDungeonsFile();
LoadMOTD();
EnumerateDungeonsFromCellData();
m_fLastSave = g_pGlobals->Time();
m_pGameMode = NULL;
}
void CWorld::SaveWorld()
{
SaveDungeonsFile();
SaveStateFile();
}
CWorld::~CWorld()
{
if (m_pGameMode)
{
delete m_pGameMode;
m_pGameMode = NULL;
}
for (LandblockVector::iterator it = m_vBlocks.begin(); it != m_vBlocks.end(); it++)
delete (*it);
m_vBlocks.clear();
SaveWorld();
m_mDungeons.clear();
for (DungeonDescMap::iterator it = m_mDungeonDescs.begin(); it != m_mDungeonDescs.end(); it++)
{
DungeonDesc_t* pdd = &it->second;
SafeDeleteArray(pdd->szDungeonName);
SafeDeleteArray(pdd->szDescription);
SafeDeleteArray(pdd->szAuthor);
}
m_mDungeonDescs.clear();
}
loc_t CWorld::FindDungeonDrop()
{
if (m_mDungeons.empty())
{
loc_t di;
memset(&di, 0, sizeof(di));
return di;
}
LocationMap::iterator dit = m_mDungeons.begin();
long index = RandomLong(0, (long)m_mDungeons.size() - 1);
while (index > 0) {
index--;
dit++;
}
return dit->second;
}
loc_t CWorld::FindDungeonDrop(WORD wBlockID)
{
LocationMap::iterator i = m_mDungeons.upper_bound(((DWORD(wBlockID) << 16) + 0x100) - 1);
if ((i == m_mDungeons.end()) || (BLOCK_WORD(i->second.landcell) != wBlockID))
{
loc_t di;
memset(&di, 0, sizeof(di));
return di;
}
return i->second;
}
void CWorld::LoadStateFile()
{
FILE *ws = g_pDB->DataFileOpen("worldstate");
if (ws)
{
fread(&m_dwHintStaticGUID, sizeof(DWORD), 1, ws);
fread(&m_dwHintItemGUID, sizeof(DWORD), 1, ws);
fread(&m_dwHintPlayerGUID, sizeof(DWORD), 1, ws);
fread(&m_dwHintDynamicGUID, sizeof(DWORD), 1, ws);
fclose(ws);
}
}
void CWorld::SaveStateFile()
{
FILE *ws = g_pDB->DataFileCreate("worldstate");
if (ws)
{
fwrite(&m_dwHintStaticGUID, sizeof(DWORD), 1, ws);
fwrite(&m_dwHintItemGUID, sizeof(DWORD), 1, ws);
fwrite(&m_dwHintPlayerGUID, sizeof(DWORD), 1, ws);
fwrite(&m_dwHintDynamicGUID, sizeof(DWORD), 1, ws);
fclose(ws);
}
else
MsgBox(MB_ICONHAND, "Error opening WorldState file! Close NOW to avoid corruption!");
}
const char* CWorld::GetMOTD()
{
return m_strMOTD.c_str();
}
void CWorld::LoadMOTD()
{
FILE *motd = g_pDB->DataFileOpen("motd.txt", "rt");
if (motd)
{
long lFileSize = fsize(motd);
char* pcFileData = new char[lFileSize + 1];
long lEnd = (long)fread(pcFileData, sizeof(char), lFileSize, motd);
pcFileData[lEnd] = 0;
m_strMOTD = pcFileData;
delete[] pcFileData;
fclose(motd);
}
else
m_strMOTD = "No MOTD set.";
}
void CWorld::LoadDungeonsFile()
{
FILE *wd = g_pDB->DataFileOpen("worlddesc");
if (wd)
{
long lSize = fsize(wd);
BYTE* pbData = new BYTE[lSize];
long lRead = (long)fread(pbData, sizeof(BYTE), lSize, wd);
BinaryReader input(pbData, lRead);
DWORD dwDungeonCount = input.ReadDWORD();
if (!input.GetLastError())
{
for (DWORD i = 0; i < dwDungeonCount; i++)
{
DungeonDesc_t dd;
dd.wBlockID = input.ReadWORD();
dd.szDungeonName = input.ReadString();
dd.szAuthor = input.ReadString();
dd.szDescription = input.ReadString();
loc_t* origin = (loc_t *)input.ReadArray(sizeof(loc_t));
heading_t* angles = (heading_t *)input.ReadArray(sizeof(heading_t));
if (input.GetLastError()) break;
//Avoid using a buffer thats going to be deleted.
dd.szDungeonName = _strdup(dd.szDungeonName);
dd.szAuthor = _strdup(dd.szAuthor);
dd.szDescription = _strdup(dd.szDescription);
memcpy(&dd.origin, origin, sizeof(loc_t));
memcpy(&dd.angles, angles, sizeof(heading_t));
m_mDungeonDescs[dd.wBlockID] = dd;
}
}
delete[] pbData;
fclose(wd);
}
}
void CWorld::SaveDungeonsFile()
{
FILE *wd = g_pDB->DataFileCreate("worlddesc");
if (wd)
{
BinaryWriter output;
output.WriteDWORD((DWORD)m_mDungeonDescs.size());
for (DungeonDescMap::iterator i = m_mDungeonDescs.begin(); i != m_mDungeonDescs.end(); i++)
{
output.WriteWORD(i->second.wBlockID);
output.WriteString(i->second.szDungeonName);
output.WriteString(i->second.szAuthor);
output.WriteString(i->second.szDescription);
output.AppendData(i->second.origin);
output.AppendData(i->second.angles);
}
fwrite(output.GetData(), output.GetSize(), sizeof(BYTE), wd);
fclose(wd);
}
else
MsgBox(MB_ICONHAND, "Error opening WorldDesc file! Close NOW to avoid corruption!");
}
BOOL CWorld::DungeonExists(WORD wBlockID)
{
LocationMap::iterator i = m_mDungeons.upper_bound(((DWORD(wBlockID) << 16) + 0x100) - 1);
if ((i == m_mDungeons.end()) || (BLOCK_WORD(i->second.landcell) != wBlockID))
return FALSE;
return TRUE;
}
LocationMap* CWorld::GetDungeons()
{
return &m_mDungeons;
}
DungeonDescMap* CWorld::GetDungeonDescs()
{
return &m_mDungeonDescs;
}
DungeonDesc_t* CWorld::GetDungeonDesc(const char* szDungeonName)
{
DungeonDescMap::iterator i = m_mDungeonDescs.begin();
DungeonDescMap::iterator iend = m_mDungeonDescs.end();
while (i != iend)
{
if (!stricmp(szDungeonName, i->second.szDungeonName))
return &i->second;
i++;
}
return NULL;
}
DungeonDesc_t* CWorld::GetDungeonDesc(WORD wBlockID)
{
DungeonDescMap::iterator it = m_mDungeonDescs.find(wBlockID);
if (it != m_mDungeonDescs.end())
return &it->second;
else
return NULL;
}
void CWorld::SetDungeonDesc(WORD wBlockID, const char* szDungeonName, const char* szAuthor, const char* szDescription, loc_t origin, heading_t angles)
{
DungeonDescMap::iterator it = m_mDungeonDescs.find(wBlockID);
if (it != m_mDungeonDescs.end())
{
DungeonDesc_t* pdd = &it->second;
SafeDeleteArray(pdd->szDungeonName);
SafeDeleteArray(pdd->szDescription);
SafeDeleteArray(pdd->szAuthor);
m_mDungeonDescs.erase(it);
}
DungeonDesc_t dd;
dd.wBlockID = wBlockID;
dd.szDungeonName = _strdup(szDungeonName);
dd.szAuthor = _strdup(szAuthor);
dd.szDescription = _strdup(szDescription);
dd.origin = origin;
dd.angles = angles;
m_mDungeonDescs[wBlockID] = dd;
}
void CWorld::InitializeHintGUIDs()
{
_CHARDESC dummy;
CCharacterDatabase *CharDB = g_pDB->CharDB();
while (CharDB->GetCharacterDesc(m_dwHintPlayerGUID, &dummy))
m_dwHintPlayerGUID++;
}
//Hackish.
DWORD CWorld::GenerateGUID(eGUIDClass type)
{
switch (type)
{
case ePresetGUID: return 0;
case ePlayerGUID:
{
// 0x50000000 - 0x60000000
if (m_dwHintPlayerGUID >= 0x60000000)
{
LOG(Temp, Normal, "Player GUID overflow!\n");
return 0;
}
_CHARDESC dummy;
CCharacterDatabase *CharDB = g_pDB->CharDB();
while (CharDB->GetCharacterDesc(m_dwHintPlayerGUID, &dummy))
m_dwHintPlayerGUID++;
//Temporary, use and increment the hint counter.
return (m_dwHintPlayerGUID++);
}
case eStaticGUID:
{
/* 0x10000000 - 0x50000000 */
if (m_dwHintStaticGUID >= 0x50000000)
{
LOG(Temp, Normal, "Static GUID overflow!\n");
return 0;
}
//Temporary, use and increment the hint counter.
return (m_dwHintStaticGUID++);
}
case eDynamicGUID:
{
// 0xC0000000 - 0xF0000000
if (m_dwHintDynamicGUID >= 0xF0000000)
{
LOG(Temp, Normal, "Dynamic GUID overflow!\n");
return 0;
}
//Temporary, use and increment the hint counter.
return (m_dwHintDynamicGUID++);
}
case eItemGUID:
{
// 0x60000000 - 0xC0000000
if (m_dwHintItemGUID >= 0xC0000000)
{
LOG(Temp, Normal, "Item GUID overflow!\n");
return 0;
}
//Temporary, use and increment the hint counter.
return (m_dwHintItemGUID++);
}
}
return 0;
}
void CWorld::ClearAllSpawns()
{
for (DWORD i = 0; i < (256 * 256); i++)
{
if (m_pBlocks[i])
m_pBlocks[i]->ClearSpawns();
}
}
CLandBlock* CWorld::GetLandblock(WORD wHeader)
{
return m_pBlocks[wHeader];
}
CLandBlock* CWorld::ActivateBlock(WORD wHeader)
{
CLandBlock **ppBlock = &m_pBlocks[wHeader];
CLandBlock *pBlock;
#if _DEBUG
pBlock = *ppBlock;
if (pBlock != NULL)
{
LOG(Temp, Normal, "Landblock already active!\n");
return pBlock;
}
#endif
pBlock = new CLandBlock(this, wHeader);
m_vSpawns.push_back(pBlock);
*ppBlock = pBlock;
return pBlock;
}
void CWorld::CreateEntity(CPhysicsObj *pEntity)
{
pEntity->Precache();
#if _DEBUG
if (!pEntity->m_dwGUID)
{
LOG(Temp, Normal, "Null entid being placed in world.\n");
return;
}
#endif
WORD wHeader = BLOCK_WORD(pEntity->GetLandcell());
if (pEntity->IsPlayer())
{
DWORD dwGUID = pEntity->m_dwGUID;
m_mAllPlayers.insert(std::pair< DWORD, CBasePlayer* >(dwGUID, (CBasePlayer *)pEntity));
BroadcastGlobal(ServerBroadcast("System", csprintf("%s has logged in.", pEntity->GetName()), 1), PRIVATE_MSG, dwGUID, FALSE, TRUE);
}
CLandBlock *pBlock = m_pBlocks[wHeader];
if (pBlock)
{
if (pBlock->FindEntity(pEntity->m_dwGUID))
{
// DEBUGOUT("Not spawning duplicate entity!\n");
// Already exists.
delete pEntity;
return;
}
}
if (!pBlock)
pBlock = ActivateBlock(wHeader);
pBlock->Insert(pEntity, 0, TRUE);
pEntity->MakeAware(pEntity);
pEntity->Spawn();
}
void CWorld::InsertTeleportLocation(TeleTownList_s l)
{
m_vTeleTown.push_back(l);
}
std::string CWorld::GetTeleportList()
{
std::string result;
for each (TeleTownList_s var in m_vTeleTown)
{
result.append(var.m_teleString).append(", ");
}
if (result.back() == 0x20) { //Get out behind of bad formatting
result.pop_back();
result.pop_back();
}
return result;
}
TeleTownList_s CWorld::GetTeleportLocation(std::string location)
{
TeleTownList_s val;
std::transform(location.begin(), location.end(), location.begin(), ::tolower);
for each (TeleTownList_s var in m_vTeleTown)
{
//Lets waste a bunch of time with this.. Hey, if its the first one on the list its O(1)
std::string town = var.m_teleString;
std::transform(town.begin(), town.end(), town.begin(), ::tolower);
if (town.find(location) != std::string::npos) {
val = var;
break;
}
}
return val;
}
void CWorld::InsertEntity(CPhysicsObj *pEntity, BOOL bSilent)
{
WORD wHeader = BLOCK_WORD(pEntity->GetLandcell());
CLandBlock *pBlock = m_pBlocks[wHeader];
if (!pBlock)
pBlock = ActivateBlock(wHeader);
if (bSilent)
pBlock->Insert(pEntity, wHeader);
else
pBlock->Insert(pEntity);
if (pEntity->IsPlayer())
m_mAllPlayers.insert(std::pair< DWORD, CBasePlayer* >(pEntity->m_dwGUID, (CBasePlayer *)pEntity));
}
void CWorld::JuggleEntity(WORD wOld, CPhysicsObj* pEntity)
{
if (!pEntity->HasOwner())
{
WORD wHeader = BLOCK_WORD(pEntity->GetLandcell());
CLandBlock *pBlock = GetLandblock(wHeader);
if (!pBlock)
pBlock = ActivateBlock(wHeader);
pBlock->Insert(pEntity, wOld);
}
}
PlayerMap* CWorld::GetPlayers()
{
return &m_mAllPlayers;
}
//==================================================
//Global, player search by GUID.
//==================================================
CBasePlayer* CWorld::FindPlayer(DWORD dwGUID)
{
PlayerMap::iterator result = m_mAllPlayers.find(dwGUID);
if (result == m_mAllPlayers.end())
return NULL;
return result->second;
}
//==================================================
//Global, case insensitive player name search.
//==================================================
CBasePlayer* CWorld::FindPlayer(const char *szName)
{
if (*szName == '+')
szName++;
PlayerMap::iterator pit = m_mAllPlayers.begin();
PlayerMap::iterator pend = m_mAllPlayers.end();
while (pit != pend)
{
CBasePlayer *pPlayer = pit->second;
if (pPlayer)
{
const char* szPN = pPlayer->GetName();
if (*szPN == '+')
szPN++;
if (!stricmp(szName, szPN))
return pPlayer;
}
pit++;
}
return NULL;
}
void CWorld::BroadcastPVS(DWORD dwCell, void *_data, DWORD _len, WORD _group, DWORD ignore_ent, BOOL _game_event)
{
if (!dwCell)
return;
// Don't ask.
WORD block = BLOCK_WORD(dwCell);
WORD cell = CELL_WORD(dwCell);
DWORD basex = BASE_OFFSET(BLOCK_X(block), CELL_X(cell));
DWORD basey = BASE_OFFSET(BLOCK_Y(block), CELL_Y(cell));
DWORD minx = basex;
DWORD maxx = basex;
DWORD miny = basey;
DWORD maxy = basey;
//if ( cell < 0xFF ) //indoor structure
{
if (minx >= (dwMinimumCellX + PVC_RANGE)) minx -= PVC_RANGE; else minx = dwMinimumCellX;
if (maxx <= (dwMaximumCellX - PVC_RANGE)) maxx += PVC_RANGE; else maxx = dwMaximumCellX;
if (miny >= (dwMinimumCellY + PVC_RANGE)) miny -= PVC_RANGE; else miny = dwMinimumCellY;
if (maxy <= (dwMaximumCellY - PVC_RANGE)) maxy += PVC_RANGE; else maxy = dwMaximumCellY;
}
minx = BLOCK_OFFSET(minx) << 8;
miny = BLOCK_OFFSET(miny);
maxx = BLOCK_OFFSET(maxx) << 8;
maxy = BLOCK_OFFSET(maxy);
for (DWORD xit = minx; xit <= maxx; xit += 0x100) {
for (DWORD yit = miny; yit <= maxy; yit += 1)
{
CLandBlock* pBlock = m_pBlocks[xit | yit];
if (pBlock)
pBlock->Broadcast(_data, _len, _group, ignore_ent, _game_event);
}
}
}
void CWorld::BroadcastGlobal(BinaryWriter *food, WORD _group, DWORD ignore_ent, BOOL _game_event, BOOL del)
{
BroadcastGlobal(food->GetData(), food->GetSize(), _group, ignore_ent, _game_event);
if (del)
delete food;
}
void CWorld::BroadcastGlobal(void *_data, DWORD _len, WORD _group, DWORD ignore_ent, BOOL _game_event)
{
//This is a.. very.. very bad.
#if TRUE
//We could send with the player map.
PlayerMap::iterator pit = m_mAllPlayers.begin();
PlayerMap::iterator pend = m_mAllPlayers.end();
while (pit != pend)
{
CBasePlayer *pPlayer;
if (pPlayer = pit->second)
{
if (!ignore_ent || (pPlayer->m_dwGUID != ignore_ent))
pPlayer->SendNetMessage(_data, _len, _group, _game_event);
}
pit++;
}
#else
//We could also send by landblocks instead.
LandblockVector::iterator lit = m_vBlocks.begin();
LandblockVector::iterator lend = m_vBlocks.end();
while (lit != lend)
{
CLandBlock *pBlock;
if (pBlock = (*lit))
pBlock->Broadcast(_data, _len, _group, ignore_ent, _game_event);
lit++;
}
#endif
}
void CWorld::Test()
{
LOG(Temp, Normal, "\n");
LOG(Temp, Normal, "Portal: v%lu, %lu files.\n", g_pPortal->GetVersion(), g_pPortal->GetFileCount());
LOG(Temp, Normal, "Cell: v%lu, %u files.\n", g_pCell->GetVersion(), g_pCell->GetFileCount());
LOG(Temp, Normal, "%u players:\n", m_mAllPlayers.size());
for (PlayerMap::iterator pit = m_mAllPlayers.begin(); pit != m_mAllPlayers.end(); pit++)
{
CBasePlayer* pPlayer = pit->second;
LOG(Temp, Normal, "%08X %s\n", pPlayer->m_dwGUID, pPlayer->GetName());
}
LOG(Temp, Normal, "%u active blocks:\n", m_vBlocks.size());
for (LandblockVector::iterator it = m_vBlocks.begin(); it != m_vBlocks.end(); it++)
{
CLandBlock* pBlock = *it;
LOG(Temp, Normal, "%08X %lu players %lu live %lu dormant\n", pBlock->GetHeader() << 16, pBlock->PlayerCount(), pBlock->LiveCount(), pBlock->DormantCount());
}
LOG(Temp, Normal, "\n");
}
void CWorld::RemoveEntity(CPhysicsObj *pEntity)
{
if (!pEntity)
{
return;
}
if (m_pGameMode)
{
m_pGameMode->OnRemoveEntity(pEntity);
}
DWORD dwGUID = pEntity->m_dwGUID;
if (pEntity->IsPlayer())
{
m_mAllPlayers.erase(dwGUID);
BroadcastGlobal(ServerBroadcast("System", csprintf("%s has logged out.", pEntity->GetName()), 1), PRIVATE_MSG, dwGUID, FALSE, TRUE);
}
CLandBlock* pBlock = pEntity->GetBlock();
if (!pBlock)
{
pEntity->Save();
DELETE_ENTITY(pEntity);
}
else
{
pBlock->Destroy(pEntity);
}
}
void CWorld::Think()
{
LandblockVector::iterator lit = m_vBlocks.begin();
LandblockVector::iterator lend = m_vBlocks.end();
while (lit != lend)
{
CLandBlock *pBlock = *lit;
if (pBlock->Think())
lit++;
else
{
//dead
lit = m_vBlocks.erase(lit);
lend = m_vBlocks.end();
m_pBlocks[pBlock->GetHeader()] = NULL;
delete pBlock;
}
}
if (!m_vSpawns.empty())
{
std::copy(m_vSpawns.begin(), m_vSpawns.end(), std::back_inserter(m_vBlocks));
m_vSpawns.clear();
}
if ((m_fLastSave + 300.0f) <= g_pGlobals->Time())
{
SaveWorld();
m_fLastSave = g_pGlobals->Time();
}
if (m_pGameMode)
{
m_pGameMode->Think();
}
}
CGameMode *CWorld::GetGameMode()
{
return m_pGameMode;
}
void CWorld::SetNewGameMode(CGameMode *pGameMode)
{
if (pGameMode)
{
g_pWorld->BroadcastGlobal(ServerText(csprintf("Setting game mode to %s", pGameMode->GetName())), PRIVATE_MSG);
}
else
{
if (!pGameMode && m_pGameMode)
{
g_pWorld->BroadcastGlobal(ServerText(csprintf("Turning off game mode %s", m_pGameMode->GetName())), PRIVATE_MSG);
}
}
if (m_pGameMode)
{
delete m_pGameMode;
}
m_pGameMode = pGameMode;
}
void CWorld::EnumNearby(CPhysicsObj *pSource, float fRange, std::list *pResults)
{
// Enumerate nearby world objects
if (pSource != NULL && !pSource->HasOwner())
{
DWORD dwCell = pSource->GetLandcell();
WORD block = BLOCK_WORD(dwCell);
WORD cell = CELL_WORD(dwCell);
DWORD basex = BASE_OFFSET(BLOCK_X(block), CELL_X(cell));
DWORD basey = BASE_OFFSET(BLOCK_Y(block), CELL_Y(cell));
DWORD minx = basex;
DWORD maxx = basex;
DWORD miny = basey;
DWORD maxy = basey;
//if ( cell < 0xFF ) // indoor structure
{
if (minx >= (dwMinimumCellX + PVC_RANGE)) minx -= PVC_RANGE; else minx = dwMinimumCellX;
if (maxx <= (dwMaximumCellX - PVC_RANGE)) maxx += PVC_RANGE; else maxx = dwMaximumCellX;
if (miny >= (dwMinimumCellY + PVC_RANGE)) miny -= PVC_RANGE; else miny = dwMinimumCellY;
if (maxy <= (dwMaximumCellY - PVC_RANGE)) maxy += PVC_RANGE; else maxy = dwMaximumCellY;
}
minx = BLOCK_OFFSET(minx) << 8;
miny = BLOCK_OFFSET(miny);
maxx = BLOCK_OFFSET(maxx) << 8;
maxy = BLOCK_OFFSET(maxy);
for (DWORD xit = minx; xit <= maxx; xit += 0x100) {
for (DWORD yit = miny; yit <= maxy; yit += 1)
{
CLandBlock* pBlock = m_pBlocks[xit | yit];
if (pBlock)
{
pBlock->EnumNearby(pSource, fRange, pResults);
}
}
}
}
}
CPhysicsObj* CWorld::FindWithinPVS(CPhysicsObj *pSource, DWORD dwGUID)
{
if (!pSource)
return NULL;
//Find nearby world objects.
if (!pSource->HasOwner())
{
DWORD dwCell = pSource->GetLandcell();
WORD block = BLOCK_WORD(dwCell);
WORD cell = CELL_WORD(dwCell);
DWORD basex = BASE_OFFSET(BLOCK_X(block), CELL_X(cell));
DWORD basey = BASE_OFFSET(BLOCK_Y(block), CELL_Y(cell));
DWORD minx = basex;
DWORD maxx = basex;
DWORD miny = basey;
DWORD maxy = basey;
//if ( cell < 0xFF ) //indoor structure
{
if (minx >= (dwMinimumCellX + PVC_RANGE)) minx -= PVC_RANGE; else minx = dwMinimumCellX;
if (maxx <= (dwMaximumCellX - PVC_RANGE)) maxx += PVC_RANGE; else maxx = dwMaximumCellX;
if (miny >= (dwMinimumCellY + PVC_RANGE)) miny -= PVC_RANGE; else miny = dwMinimumCellY;
if (maxy <= (dwMaximumCellY - PVC_RANGE)) maxy += PVC_RANGE; else maxy = dwMaximumCellY;
}
minx = BLOCK_OFFSET(minx) << 8;
miny = BLOCK_OFFSET(miny);
maxx = BLOCK_OFFSET(maxx) << 8;
maxy = BLOCK_OFFSET(maxy);
for (DWORD xit = minx; xit <= maxx; xit += 0x100) {
for (DWORD yit = miny; yit <= maxy; yit += 1)
{
CLandBlock* pBlock = m_pBlocks[xit | yit];
if (pBlock)
{
CPhysicsObj *pEntity = pBlock->FindEntity(dwGUID);
if (pEntity)
return pEntity;
}
}
}
}
if (pSource->Container_HasContents())
return (CPhysicsObj *)pSource->Container_FindItem(dwGUID);
return NULL;
}
void CWorld::EnumerateDungeonsFromCellData()
{
// TODO Need to fix dungeon parsing for ToD first. Broke because of that.
return;
// This creates a list of dungeons
FILEMAP* pFiles = g_pCell->GetFiles();
FILEMAP::iterator i = pFiles->begin();
FILEMAP::iterator iend = pFiles->end();
while (i != iend)
{
DWORD dwID = i->first;
if (((dwID & 0xFFFF) >= 0xFFFE) || ((dwID & 0xFFFF) < 0x100))
{
i++;
continue;
}
TURBINEFILE* pGeometryFile = g_pCell->GetFile(dwID);
BYTE *_data, *data;
_data = data = pGeometryFile->GetData();
DWORD dwGeoFlags = *((DWORD *)data);
if (!(dwGeoFlags & 9))
{
data += sizeof(DWORD);
DWORD dungeonID = *((DWORD*)data);
data += sizeof(DWORD);
UCHAR textureCount = *((UCHAR *)data);
data += sizeof(UCHAR);
UCHAR connectionCount = *((UCHAR *)data);
data += sizeof(UCHAR);
USHORT visibleBlocksCount = *((USHORT *)data);
data += sizeof(USHORT);
data += textureCount * sizeof(USHORT);
if (textureCount & 1)
data += sizeof(USHORT);
WORD blockID = *((WORD *)data);
data += sizeof(WORD);
WORD partNum = *((WORD *)data);
data += sizeof(WORD);
loc_t di;
di.landcell = dungeonID;
float _xTrans = *((float *)data);
data += sizeof(float);
float _yTrans = *((float *)data);
data += sizeof(float);
float _zTrans = *((float *)data);
data += sizeof(float);
float rw = *((float *)data);
data += sizeof(float);
float rx = *((float *)data);
data += sizeof(float);
float ry = *((float *)data);
data += sizeof(float);
float rz = *((float *)data);
data += sizeof(float);
#if 0 //This code look for the dropsite models in dungeons.
if (dwGeoFlags & 2)
{
data += sizeof(DWORD) * connectionCount * 2;
data += sizeof(USHORT) * visibleBlocksCount;
if (visibleBlocksCount & 1)
data += sizeof(USHORT);
DWORD numObjects = *((DWORD *)data);
data += sizeof(DWORD);
for (unsigned int h = 0; h < numObjects; h++)
{
DWORD dwModelID = *((DWORD *)data);
data += sizeof(DWORD);
if ((dwModelID >= 0x02000C39 && dwModelID <= 0x02000C48) || (dwModelID == 0x02000F4A)) {
//OutputConsole( "%08X has drop site[%08X] @ %f %f %f\r\n", dwID, dwModelID,
// ((float*)data)[0], ((float*)data)[1], ((float*)data)[2]);
break;
}
data += sizeof(float) * 7;
}
}
#endif
//if ( BLOCK_WORD( dwID ) == 0xF924 )
// OutputConsole( "%08X %04X %04X\r\n", dwGeoFlags, blockID, partNum );
DUNGEON* pDungeon = g_pPortal->GetDungeon(0x0D000000 + blockID);
if (pDungeon)
{
loc_t Point = pDungeon->FindLandingZone(partNum);
if (Point.landcell)
{
Vector pt(Point.x, Point.y, Point.z);
matrix mm;
mm.defineByQuaternion(rw, rx, ry, rz);
mm.applyToVector(pt);
//Point.x = pt.x;
//Point.y = pt.y;
//Point.z = pt.z;
di.x = (float)(_xTrans + pt.x);
di.y = (float)(_yTrans + pt.y);
di.z = (float)(_zTrans + pt.z + 0.025f);
//if ( BLOCK_WORD( dwID ) == 0xF924 )
// LOG(Temp, Normal, "%f %f %f\n", di.x, di.y, di.z );
m_mDungeons[dungeonID] = di;
//506e0108
}
else
{
delete pGeometryFile;
i++;
continue;
}
//50520100 is broke
//54500000 is broke
}
else
{
LOG(Temp, Normal, "Dungeon block mismatch. Are portal/cell versions inconsistant?\n");
}
}
delete pGeometryFile;
if (dwID < (DWORD)(0 - 0x10100))
i = pFiles->upper_bound(((dwID & 0xFFFF0000) + 0x10100) - 1);
else
break;
}
}