Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1036 lines
29 KiB
C++
1036 lines
29 KiB
C++
//===========================================================================//
|
|
// File: Map.cpp //
|
|
// Project: MUNGA Brick: Interest Manager //
|
|
// Contents: Interface specifications for interest manager //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- -----------------------------------------------------------//
|
|
// 11/04/94 ECH Initial coding. //
|
|
// 11/29/94 JMA Changed Identities to IDs //
|
|
// 02/10/95 CPB Added GaugeInterestType //
|
|
// 08/25/97 ECH Infrastructure changes. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "AdeptHeaders.hpp"
|
|
#include "Map.hpp"
|
|
#include "VideoRenderer.hpp"
|
|
#include "VideoComponentWeb.hpp"
|
|
#include "Application.hpp"
|
|
#include "Zone.hpp"
|
|
#include <ElementRenderer\GridElement.hpp>
|
|
#include "GUITextManager.hpp"
|
|
#include <Compost\TerrainTextureLogistic.hpp>
|
|
#include <Compost\TexturePool.hpp>
|
|
#include "CollisionGrid.hpp"
|
|
#include "Tile.hpp"
|
|
#include <MLR\MLRCulturShape.hpp>
|
|
#include <MLR\MLRFootstep.hpp>
|
|
#include <GameOS\ToolOS.hpp>
|
|
#include "EntityManager.hpp"
|
|
|
|
//#define HIERARCHY "your_loginname_here" // used to display attachment info
|
|
#define HUNT_ADD_EFFECT_BUG
|
|
|
|
//#############################################################################
|
|
//################################### Map ###############################
|
|
//#############################################################################
|
|
|
|
Map::ClassData*
|
|
Map::DefaultData = NULL;
|
|
|
|
int Map::LoadRadius = 1;
|
|
static bool __stdcall CheckFullZoneLoad() {return Map::LoadRadius==4;}
|
|
static void __stdcall EnableFullZoneLoad() {Map::LoadRadius = 5-Map::LoadRadius;}
|
|
|
|
DECLARE_TIMER(static, Attaching_To_Map);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::InitializeClass(Stuff::NotationFile *startup_ini)
|
|
{
|
|
Verify(!DefaultData);
|
|
Check_Object(ExecutionStateEngine::DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
MapClassID,
|
|
"Adept::Map",
|
|
Entity::DefaultData,
|
|
0, NULL,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
NULL,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
|
|
);
|
|
Check_Object(DefaultData);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Map__GameModel,
|
|
DamageCraterResource,
|
|
m_damageCraterResourceID,
|
|
ResourceID
|
|
);
|
|
|
|
Initialize_Timer(Attaching_To_Map, "Attaching To Map");
|
|
AddDebuggerMenuItem("Libraries\\Adept\\Load All Zones", CheckFullZoneLoad, EnableFullZoneLoad, 0 );
|
|
|
|
if (startup_ini)
|
|
{
|
|
Check_Object(startup_ini);
|
|
Stuff::Page *page = startup_ini->FindPage("Graphics Options");
|
|
if (page)
|
|
{
|
|
Check_Object(page);
|
|
page->GetEntry("LoadRadius", &LoadRadius);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::TerminateClass(Stuff::NotationFile *startup_ini)
|
|
{
|
|
if (startup_ini)
|
|
{
|
|
Check_Object(startup_ini);
|
|
Stuff::Page *page = startup_ini->SetPage("Graphics Options");
|
|
Check_Object(page);
|
|
page->SetEntry("LoadRadius", LoadRadius);
|
|
}
|
|
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
#if 0
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Map*
|
|
Map::Make(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// We need to open up the game model specified by the message in order to
|
|
// find the ResourceID of our grid element
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Resource model_resource;
|
|
GetGameModelResourceFromDataListID(&model_resource, message->dataListID);
|
|
GameModel *model = Cast_Pointer(GameModel*, model_resource.GetPointer());
|
|
Check_Object(model);
|
|
Resource grid_resource(model->m_gridElementResourceID);
|
|
Check_Object(&grid_resource);
|
|
Verify(grid_resource.DoesResourceExist());
|
|
|
|
ElementRenderer::GridElement *grid =
|
|
Cast_Object(
|
|
ElementRenderer::GridElement*,
|
|
ElementRenderer::Element::Create(
|
|
&grid_resource,
|
|
ElementRenderer::ReadERFVersion(&grid_resource)
|
|
)
|
|
);
|
|
Map *new_entity = new Map(DefaultData, message, base_id, grid);
|
|
Check_Object(new_entity);
|
|
|
|
return new_entity;
|
|
}
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Replicator::CreateMessage*
|
|
Map::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Make sure there is enough room for the factory request on the stream
|
|
//---------------------------------------------------------------------
|
|
//
|
|
stream->AllocateBytes(sizeof(CreateMessage));
|
|
Entity::SaveMakeMessage(stream, res_file);
|
|
CreateMessage *message =
|
|
Cast_Pointer(CreateMessage*, stream->GetPointer());
|
|
message->messageLength = sizeof(*message);
|
|
|
|
//
|
|
//----------------------------------------
|
|
// Create the memory stream for the props
|
|
//----------------------------------------
|
|
//
|
|
DynamicMemoryStream prop_stream(sizeof(WORD));
|
|
ReplicatorID span = ReplicatorID::Null;
|
|
prop_stream << span.localID;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Tell each prop to save itself and bump the stream pointer afterword
|
|
//--------------------------------------------------------------------
|
|
//
|
|
ChainIteratorOf<Entity *> iterator(&childEntityChain);
|
|
Entity *entity;
|
|
while ((entity = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
if (entity->GetPropType() == MapPropType)
|
|
{
|
|
Replicator::CreateMessage *create_message =
|
|
entity->SaveMakeMessage(&prop_stream, NULL);
|
|
if (create_message)
|
|
{
|
|
Check_Object(create_message);
|
|
prop_stream.AdvancePointer(create_message->messageLength);
|
|
span += create_message->replicatorID.localID;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (prop_stream.GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
prop_stream.Rewind();
|
|
Verify(span.localID > 0);
|
|
prop_stream << span.localID;
|
|
Resource prop_resource(NULL);
|
|
prop_resource.Save(&prop_stream, NULL);
|
|
STOP(("Not updated"));
|
|
Check_Object(&prop_resource);
|
|
message->m_propStreamResourceID = prop_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
}
|
|
else
|
|
message->m_propStreamResourceID = ResourceID::Null;
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Map::Map(
|
|
ClassData *class_data,
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::GridElement *element,
|
|
int execution_slots
|
|
):
|
|
Entity(class_data, message, base_id, element),
|
|
m_executingZones(NULL),
|
|
m_renderedZones(NULL),
|
|
m_renderOrigin(NULL),
|
|
m_executionSlots(execution_slots)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// We will get our size directly from the .erf file that has the grid
|
|
// element in it. In the mean time, set up the structures for one zone
|
|
//---------------------------------------------------------------------
|
|
//
|
|
ElementRenderer::GridElement *grid =
|
|
Cast_Object(ElementRenderer::GridElement*, entityElement);
|
|
grid->GetSize(&m_rowZoneCount, &m_columnZoneCount);
|
|
m_zoneCount = static_cast<WORD>(m_columnZoneCount * m_rowZoneCount);
|
|
|
|
grid->SetSize(m_zoneCount);
|
|
|
|
Scalar row_size, column_size;
|
|
grid->GetDimensions(
|
|
&m_rowZoneOrigin,
|
|
&m_columnZoneOrigin,
|
|
&row_size,
|
|
&column_size
|
|
);
|
|
Verify(!Small_Enough(row_size));
|
|
m_rowZoneScale = 1.0f / row_size;
|
|
Verify(!Small_Enough(column_size));
|
|
m_columnZoneScale = 1.0f / column_size;
|
|
Verify(Close_Enough(m_columnZoneScale, m_rowZoneScale));
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Set up the game model and set up the list of erfs
|
|
//--------------------------------------------------
|
|
//
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
m_zonesResource.FindID(model->m_zoneArrayResourceID);
|
|
Verify(m_zonesResource.DoesResourceExist());
|
|
Verify(m_zoneCount*sizeof(Zone::ResourceData) == m_zonesResource.GetSize());
|
|
|
|
//
|
|
//---------------------
|
|
// Create the supergrid
|
|
//---------------------
|
|
//
|
|
Verify(!CollisionGrid::Instance);
|
|
gos_PushCurrentHeap(s_CollisionHeap);
|
|
CollisionGrid::Instance =
|
|
new CollisionGrid(
|
|
static_cast<BYTE>(m_rowZoneCount*e_TilesPerZone),
|
|
static_cast<BYTE>(m_columnZoneCount*e_TilesPerZone),
|
|
m_rowZoneOrigin,
|
|
m_columnZoneOrigin,
|
|
row_size * m_rowZoneCount,
|
|
column_size * m_columnZoneCount,
|
|
model->m_waterLevel
|
|
);
|
|
Check_Object(CollisionGrid::Instance);
|
|
gos_PopCurrentHeap();
|
|
|
|
//
|
|
//------------------------------------
|
|
// Build the Texture logistics manager
|
|
//------------------------------------
|
|
//
|
|
bool manage_textures = model->m_textureDataResourceID != ResourceID::Null;
|
|
bool dedicated_server = Application::GetInstance()->m_localMissionParameters->m_runDedicated!=0 ? true : false;
|
|
if (manage_textures && Compost::TerrainTextureLogistic::GetResolution()>0 && !dedicated_server)
|
|
{
|
|
gos_PushCurrentHeap(Compost::Heap);
|
|
Compost::TexturePool::Instance = new Compost::TexturePool;
|
|
Check_Object(Compost::TexturePool::Instance);
|
|
//
|
|
//-----------------------------------------------------------
|
|
// Set up the texture path until texture data stream is coded
|
|
//-----------------------------------------------------------
|
|
//
|
|
char name[1024];
|
|
gos_GetCurrentPath(name, 1024);
|
|
Compost::TexturePool::Instance->SetTexturePath("Content\\Textures\\CompostTexture");
|
|
|
|
Verify(model->m_tcfResourceID!=ResourceID::Null);
|
|
Resource tcf_resource(model->m_tcfResourceID);
|
|
|
|
NotationFile tcf_data(&tcf_resource);
|
|
|
|
Compost::TexturePool::Instance->LoadIndex(&tcf_data);
|
|
|
|
Resource texture_spec(model->m_textureDataResourceID);
|
|
Verify(texture_spec.DoesResourceExist());
|
|
Compost::TerrainTextureLogistic::Instance =
|
|
new Compost::TerrainTextureLogistic(
|
|
m_columnZoneCount*e_TilesPerZone,
|
|
m_rowZoneCount*e_TilesPerZone,
|
|
c_TileSize,
|
|
c_TileSize,
|
|
&texture_spec
|
|
);
|
|
Check_Object(Compost::TerrainTextureLogistic::Instance);
|
|
|
|
Compost::TerrainTextureLogistic::Instance->SetOffset(
|
|
m_rowZoneOrigin,
|
|
m_columnZoneOrigin
|
|
);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
//
|
|
//----------------------------
|
|
// Allocate the array of Zones
|
|
//----------------------------
|
|
//
|
|
Verify(m_zoneCount > 0 && m_zoneCount == m_columnZoneCount * m_rowZoneCount);
|
|
m_zones = new Zone[m_zoneCount];
|
|
Check_Pointer(m_zones);
|
|
Zone *zone=m_zones;
|
|
WORD index=0;
|
|
for (BYTE row=0; row<m_rowZoneCount; ++row)
|
|
{
|
|
for (BYTE column=0; column<m_columnZoneCount; ++column, ++index, ++zone)
|
|
{
|
|
//
|
|
//----------------------------------------
|
|
// Load the erf for the zone and attach it
|
|
//----------------------------------------
|
|
//
|
|
Check_Object(zone);
|
|
zone->m_row = row;
|
|
zone->m_column = column;
|
|
zone->LockBounds();
|
|
zone->CreateTileGrid(
|
|
m_rowZoneOrigin + row*c_ZoneSize,
|
|
m_columnZoneOrigin + column*c_ZoneSize
|
|
);
|
|
grid->AttachIndexedChild(row, column, zone);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------
|
|
// Create the props
|
|
//-----------------
|
|
//
|
|
propListResourceID = ResourceID::Null;
|
|
|
|
if (message->m_propStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource stream(message->m_propStreamResourceID);
|
|
Verify(stream.DoesResourceExist());
|
|
stream.AdvancePointer(replicatorID.localID);
|
|
while (stream.GetBytesRemaining() > 0)
|
|
{
|
|
Entity::CreateMessage *message =
|
|
Cast_Pointer(Entity::CreateMessage*, stream.GetPointer());
|
|
Check_Object(message);
|
|
Entity *entity = CreateEntity(&stream, base_id);
|
|
Check_Object(entity);
|
|
entity->SetPropType(MapPropType);
|
|
AddChild(entity);
|
|
stream.AdvancePointer(message->messageLength);
|
|
}
|
|
propListResourceID = message->m_propStreamResourceID;
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
// Build the cultural data
|
|
//------------------------
|
|
//
|
|
bool manage_culturals = model->m_culturalDataResourceID != ResourceID::Null;
|
|
if (manage_culturals) // switch to turn off cuturals
|
|
{
|
|
Resource culturalData_resource(model->m_culturalDataResourceID);
|
|
|
|
int mlr_version = MidLevelRenderer::ReadMLRVersion(&culturalData_resource);
|
|
|
|
OBB obb;
|
|
culturalData_resource >> obb;
|
|
|
|
if(mlr_version>13)
|
|
{
|
|
RegisteredClass::ClassID class_id;
|
|
culturalData_resource >> class_id;
|
|
}
|
|
|
|
MidLevelRenderer::MLRCulturShape::culturalRevolution = MidLevelRenderer::MLRShape::Make(&culturalData_resource, mlr_version);
|
|
}
|
|
else
|
|
{
|
|
if(MidLevelRenderer::MLRCulturShape::culturalRevolution!=NULL)
|
|
{
|
|
MidLevelRenderer::MLRCulturShape::culturalRevolution->DetachReference();
|
|
|
|
MidLevelRenderer::MLRCulturShape::culturalRevolution = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
//Set up the footstep pool
|
|
//------------------------
|
|
//
|
|
Verify(!MidLevelRenderer::MLRFootStep::Instance);
|
|
MidLevelRenderer::MLRFootStep::Instance = new MidLevelRenderer::MLRFootStep(64);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Map::~Map()
|
|
{
|
|
Check_Object(this);
|
|
|
|
GlobalPointers::ClearPointer(MapGlobalPointerIndex);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Tell all the children to become uninteresting
|
|
//----------------------------------------------
|
|
//
|
|
ChainIteratorOf<Entity*> children(&childEntityChain);
|
|
Entity *entity;
|
|
while ((entity = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entity);
|
|
entity->BecomeUninteresting();
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------
|
|
// Turn off the terrain compositing controllers
|
|
//---------------------------------------------
|
|
//
|
|
if (Compost::TerrainTextureLogistic::Instance)
|
|
{
|
|
Check_Object(Compost::TerrainTextureLogistic::Instance);
|
|
delete Compost::TerrainTextureLogistic::Instance;
|
|
Compost::TerrainTextureLogistic::Instance = NULL;
|
|
}
|
|
if (Compost::TexturePool::Instance)
|
|
{
|
|
Check_Object(Compost::TexturePool::Instance);
|
|
delete Compost::TexturePool::Instance;
|
|
Compost::TexturePool::Instance = NULL;
|
|
}
|
|
|
|
//
|
|
//-----------------
|
|
// Delete our zones
|
|
//-----------------
|
|
//
|
|
Check_Pointer(m_zones);
|
|
delete[] m_zones;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Delete our collision grid - our parent class will take care of our
|
|
// child entities
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Check_Object(CollisionGrid::Instance);
|
|
delete CollisionGrid::Instance;
|
|
CollisionGrid::Instance = NULL;
|
|
|
|
//
|
|
//----------------------
|
|
//Kill the FootStep pool
|
|
//----------------------
|
|
//
|
|
if (MidLevelRenderer::MLRFootStep::Instance)
|
|
{
|
|
delete MidLevelRenderer::MLRFootStep::Instance;
|
|
MidLevelRenderer::MLRFootStep::Instance = NULL;
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
//Kill the cultural meshes
|
|
//------------------------
|
|
//
|
|
if(MidLevelRenderer::MLRCulturShape::culturalRevolution!=NULL)
|
|
{
|
|
MidLevelRenderer::MLRCulturShape::culturalRevolution->DetachReference();
|
|
|
|
MidLevelRenderer::MLRCulturShape::culturalRevolution = NULL;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::AddChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
//
|
|
//------------------------------------------
|
|
// Find the zone that this entity belongs to
|
|
//------------------------------------------
|
|
//
|
|
Start_Timer(Attaching_To_Map);
|
|
ElementRenderer::Element *child_element = entity->GetElement();
|
|
Check_Object(child_element);
|
|
|
|
#ifdef HUNT_ADD_EFFECT_BUG
|
|
|
|
if (entity == NULL)
|
|
{
|
|
STOP(("ADDING OBJECT FAILED : ENTITY NULL"));
|
|
}
|
|
if (child_element == NULL)
|
|
{
|
|
STOP(("ADDING OBJECT FAILED : CHILD ELEMENT NULL"));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
Point3D translation(child_element->GetNewLocalToParent());
|
|
int index = FindZone(translation);
|
|
Verify(static_cast<unsigned>(index) < m_zoneCount);
|
|
Zone *zone = &m_zones[index];
|
|
Check_Object(zone);
|
|
|
|
|
|
#ifdef HUNT_ADD_EFFECT_BUG
|
|
|
|
if (zone == NULL)
|
|
{
|
|
STOP(("ADDING OBJECT FAILED : location : %f %f %f Zone : %d", translation.x, translation.y, translation.z, index));
|
|
}
|
|
|
|
if (static_cast<unsigned>(index) >= m_zoneCount)
|
|
{
|
|
STOP(("ADDING OBJECT FAILED : location : %f %f %f Zone : %d", translation.x, translation.y, translation.z, index));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
//-----------------------------
|
|
// Hook up the entity hierarchy
|
|
//-----------------------------
|
|
//
|
|
Verify(!entity->parentEntity);
|
|
entity->parentEntity = this;
|
|
childEntityChain.Add(entity);
|
|
entity->NeedMatrixSync();
|
|
#if defined(HIERARCHY)
|
|
SPEW((0, "Attaching %s(+", entity->GetClassString()));
|
|
Spew(0, entity->GetReplicatorID());
|
|
SPEW((0, ") to %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
#endif
|
|
zone->AttachChild(child_element);
|
|
Stop_Timer(Attaching_To_Map);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::RemoveChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Unhook the entity from the zone
|
|
//--------------------------------
|
|
//
|
|
ElementRenderer::Element *element = entity->GetElement();
|
|
Check_Object(element);
|
|
|
|
ElementRenderer::Element *parent_ele=element->GetParentElement();
|
|
Check_Object(parent_ele);
|
|
|
|
Zone *zone;
|
|
if(parent_ele->GetClassID() == TileClassID)
|
|
{
|
|
Verify(parent_ele->IsDerivedFrom(Tile::DefaultData));
|
|
zone = Cast_Object(Zone*, parent_ele->GetParentElement()->GetParentElement());
|
|
}
|
|
else
|
|
{
|
|
zone = Cast_Object(Zone*, parent_ele);
|
|
}
|
|
|
|
zone->DetachChild(element);
|
|
|
|
//
|
|
//---------------------------------
|
|
// Unook the entity from the parent
|
|
//---------------------------------
|
|
//
|
|
entity->parentEntity = NULL;
|
|
childEntityChain.Remove(entity);
|
|
entity->NeedMatrixSync();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::ChildPreCollisionChanged(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
//
|
|
//-----------------------------
|
|
// Find the zone for the entity
|
|
//-----------------------------
|
|
//
|
|
ElementRenderer::Element *element = entity->GetElement();
|
|
Check_Object(element);
|
|
|
|
ElementRenderer::Element *parent_ele=element->GetParentElement();
|
|
Check_Object(parent_ele);
|
|
|
|
Zone *zone;
|
|
if(parent_ele->GetClassID() == TileClassID)
|
|
{
|
|
Verify(parent_ele->IsDerivedFrom(Tile::DefaultData));
|
|
zone = Cast_Object(Zone*, parent_ele->GetParentElement()->GetParentElement());
|
|
}
|
|
else
|
|
{
|
|
zone = Cast_Object(Zone*, parent_ele);
|
|
}
|
|
|
|
//
|
|
//-------------------
|
|
// Turn the entity on
|
|
//-------------------
|
|
//
|
|
if((entity->executionState->GetOldState() == ExecutionStateEngine::NeverExecuteState)
|
|
&&(entity->executionState->GetState() != ExecutionStateEngine::NeverExecuteState))
|
|
{
|
|
zone->AddExecutor(entity);
|
|
}
|
|
|
|
//
|
|
//--------------------
|
|
// Turn off the entity
|
|
//--------------------
|
|
//
|
|
else if((entity->executionState->GetOldState() != ExecutionStateEngine::NeverExecuteState)
|
|
&&(entity->executionState->GetState() == ExecutionStateEngine::NeverExecuteState))
|
|
{
|
|
zone->RemoveExecutor(entity);
|
|
}
|
|
}
|
|
|
|
#if defined(NDEBUG)
|
|
#pragma optimize("a",off)
|
|
#endif
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::UpdateZone(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
Verify(entity->parentEntity == this);
|
|
Verify(this == Map::GetInstance());
|
|
Verify(!entity->IsTileBound());
|
|
|
|
//
|
|
//------------------------------------------
|
|
// Find out where the child wants to move to
|
|
//------------------------------------------
|
|
//
|
|
ElementRenderer::Element *child_element = entity->GetElement();
|
|
Check_Object(child_element);
|
|
Zone *old_zone = Cast_Object(Zone*, child_element->GetParentElement());
|
|
Point3D translation(entity->GetLocalToWorld());
|
|
|
|
//
|
|
//------------------
|
|
// Find the new zone
|
|
//------------------
|
|
//
|
|
Scalar column = translation.x - m_columnZoneOrigin;
|
|
Scalar row = translation.z - m_rowZoneOrigin;
|
|
column *= m_columnZoneScale;
|
|
row *= m_rowZoneScale;
|
|
Verify(column>=0.0f && column<m_columnZoneCount && row>=0.0f && row<m_rowZoneCount);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// See if the child is moving to a new zone. If so, change the zones of the
|
|
// child. We are manipulating the entity's element flags directly rather
|
|
// than calling a sync because we are only changing parentage, and both are
|
|
// rooted at the origin.
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
int index = Truncate_Float_To_Byte(row)*m_columnZoneCount + Truncate_Float_To_Byte(column);
|
|
Verify(static_cast<unsigned>(index) < m_zoneCount);
|
|
Zone *new_zone = &m_zones[index];
|
|
Check_Object(new_zone);
|
|
if (old_zone != new_zone || entity->GetCollisionMask() == EditorIsMovingFlag)
|
|
{
|
|
AbstractEvent *event = entity->m_pendingInterestMessage.GetCurrent();
|
|
if (event)
|
|
event->Process();
|
|
InterestLevel level = entity->GetInterestLevel();
|
|
unsigned element_state = child_element->GetElementState();
|
|
old_zone->DetachChild(child_element);
|
|
new_zone->AttachChild(child_element);
|
|
if (level == entity->GetInterestLevel())
|
|
child_element->SetElementState(element_state);
|
|
}
|
|
|
|
//
|
|
//------------------------------
|
|
// Clear the entity's dirty flag
|
|
//------------------------------
|
|
//
|
|
entity->replicatorFlags &= ~DirtyZoneFlag;
|
|
}
|
|
#if defined(NDEBUG)
|
|
#pragma optimize("a",on)
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Map::FindZone(const Stuff::Point3D &where)
|
|
{
|
|
Check_Object(this);
|
|
Verify(
|
|
Close_Enough(
|
|
GetElement()->GetLocalToWorld(),
|
|
LinearMatrix4D::Identity
|
|
)
|
|
);
|
|
Verify(
|
|
Close_Enough(
|
|
GetElement()->GetNewLocalToParent(),
|
|
LinearMatrix4D::Identity
|
|
)
|
|
);
|
|
unsigned index = GetElement()->FindElementIndex(where.z, where.x);
|
|
if (index < GetElement()->GetActiveCount())
|
|
return index;
|
|
return -1;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::GetMapExtents(
|
|
Stuff::Scalar *min_z,
|
|
Stuff::Scalar *max_z,
|
|
Stuff::Scalar *min_x,
|
|
Stuff::Scalar *max_x
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(min_z);
|
|
Check_Pointer(max_z);
|
|
Check_Pointer(min_x);
|
|
Check_Pointer(max_x);
|
|
|
|
*min_x = m_columnZoneOrigin;
|
|
*max_x = m_columnZoneOrigin + m_columnZoneCount/m_columnZoneScale;
|
|
*min_z = m_rowZoneOrigin;
|
|
*max_z = m_rowZoneOrigin + m_rowZoneCount/m_rowZoneScale;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
PRECOLLISION_LOGIC("Map");
|
|
|
|
//
|
|
//---------------------------------
|
|
// Verify that this always executes
|
|
//---------------------------------
|
|
//
|
|
Check_Object(executionState);
|
|
Verify(
|
|
executionState->GetState() !=
|
|
ExecutionStateEngine::NeverExecuteState
|
|
);
|
|
Entity::PreCollisionExecute(till);
|
|
|
|
//
|
|
//-------------------------------
|
|
// Clear out the execution hashes
|
|
//-------------------------------
|
|
//
|
|
int i;
|
|
for (i=0; i<m_executionSlots.GetLength(); ++i)
|
|
m_executionSlots[i] = NULL;
|
|
|
|
//
|
|
//--------------
|
|
// Execute zones
|
|
//--------------
|
|
//
|
|
ChainIteratorOf<Zone*> zones(&m_executingZones);
|
|
Zone *zone;
|
|
while ((zone = zones.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(zone);
|
|
Verify(zone->GetInterestLevel() != DormantInterestLevel);
|
|
zone->PreCollisionExecute(till);
|
|
}
|
|
|
|
//
|
|
//-------------------------
|
|
// Now execute the entities
|
|
//-------------------------
|
|
//
|
|
for (i=0; i<m_executionSlots.GetLength(); ++i)
|
|
{
|
|
Entity *entity = m_executionSlots[i];
|
|
while (entity)
|
|
{
|
|
Check_Object(entity);
|
|
entity->PreCollisionExecute(till);
|
|
Verify(!entity->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(entity));
|
|
entity = entity->nextPreExecution;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::SyncMatrices(bool update_matrix)
|
|
{
|
|
Check_Object(this);
|
|
SYNC_LOGIC("Map");
|
|
|
|
#if defined(HIERARCHY)
|
|
if (update_matrix)
|
|
{
|
|
SPEW((HIERARCHY, "Map::SyncMatrices %s(+", GetClassString()));
|
|
Spew(HIERARCHY, GetReplicatorID());
|
|
SPEW((HIERARCHY, ")"));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// If we have a dirty locator, sync with it
|
|
//-----------------------------------------
|
|
//
|
|
if (IsMatrixDirty())
|
|
{
|
|
if (update_matrix)
|
|
{
|
|
Check_Object(entityElement);
|
|
entityElement->Sync();
|
|
update_matrix = false;
|
|
}
|
|
ClearNeedMatrixSync();
|
|
}
|
|
|
|
//
|
|
//-------------------------
|
|
// Sync the executing zones
|
|
//-------------------------
|
|
//
|
|
ChainIteratorOf<Zone*> zones(&m_executingZones);
|
|
Zone *zone;
|
|
while ((zone = zones.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(zone);
|
|
Verify(zone->GetInterestLevel() != DormantInterestLevel);
|
|
zone->SyncMatrices(update_matrix);
|
|
}
|
|
|
|
#if defined(HIERARCHY)
|
|
if (update_matrix)
|
|
SPEW((0, ""));
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::UpdateRenderOrigin(const Stuff::Point3D &location)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(&location);
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Find the zone that this entity belongs to, and if the zone hasn't
|
|
// changed, we are done
|
|
//------------------------------------------------------------------
|
|
//
|
|
int index = FindZone(location);
|
|
Verify(static_cast<unsigned>(index) < m_zoneCount);
|
|
Zone *new_zone = &m_zones[index];
|
|
Check_Object(new_zone);
|
|
if (new_zone == m_renderOrigin)
|
|
return;
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Find the bounds on where the render will be
|
|
//--------------------------------------------
|
|
//
|
|
unsigned row = index / m_columnZoneCount;
|
|
unsigned column = index - row*m_columnZoneCount;
|
|
unsigned min_column = (column>=LoadRadius) ? column-LoadRadius : 0;
|
|
unsigned min_row = (row>=LoadRadius) ? row-LoadRadius : 0;
|
|
unsigned max_column = (column+LoadRadius >= m_columnZoneCount) ? m_columnZoneCount : column+LoadRadius+1;
|
|
unsigned max_row = (row+LoadRadius >= m_rowZoneCount) ? m_rowZoneCount : row+LoadRadius+1;
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// Make any active zone not in the active zone uninteresting
|
|
//----------------------------------------------------------
|
|
//
|
|
ChainIteratorOf<Zone*> zones(&m_renderedZones);
|
|
Zone *zone;
|
|
while ((zone = zones.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(zone);
|
|
if (
|
|
zone->m_row < min_row || zone->m_row >= max_row
|
|
|| zone->m_column < min_column || zone->m_column >= max_column
|
|
)
|
|
zone->DisableRendering();
|
|
}
|
|
|
|
//
|
|
//-------------------------------------
|
|
// Tell each zone to become interesting
|
|
//-------------------------------------
|
|
//
|
|
m_renderOrigin = new_zone;
|
|
for (row=min_row; row<max_row; ++row)
|
|
{
|
|
zone = &m_zones[row*m_columnZoneCount + min_column];
|
|
for (column=min_column; column<max_column; ++column,++zone)
|
|
{
|
|
if (zone->GetInterestLevel() != RenderingInterestLevel)
|
|
zone->EnableRendering();
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::ActivateZones()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//-------------------------------------
|
|
// Tell each zone to become interesting
|
|
//-------------------------------------
|
|
//
|
|
for (int row=0; row<m_rowZoneCount; ++row)
|
|
{
|
|
for (int column=0; column<m_columnZoneCount; ++column)
|
|
{
|
|
m_zones[row*m_columnZoneCount + column].ActivateZone();
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Zone::ResourceData*
|
|
Map::GetZoneResourceData(unsigned index)
|
|
{
|
|
Check_Object(this);
|
|
return &Cast_Pointer(Zone::ResourceData*, m_zonesResource.GetPointer())[index];
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Map::WorldToZoneCoords(Stuff::Scalar& x, Stuff::Scalar& y) const
|
|
{
|
|
x = (x - m_columnZoneOrigin) * m_columnZoneScale;
|
|
y = (y - m_rowZoneOrigin) * m_rowZoneScale; // jcem - m_columnZoneScale->m_rowZoneScale
|
|
}
|