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.
623 lines
15 KiB
C++
623 lines
15 KiB
C++
//===========================================================================//
|
|
// File: Effect.cpp //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 2/8/99 DPB Created File
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995-97, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "AdeptHeaders.hpp"
|
|
|
|
#include "Effect.hpp"
|
|
#include "EntityClassData.hpp"
|
|
#include "Tool.hpp"
|
|
#include "RendererManager.hpp"
|
|
#include "Site.hpp"
|
|
|
|
#include <gosFX\gosFX.hpp>
|
|
#include "EntityManager.hpp"
|
|
|
|
//#############################################################################
|
|
//################## Effect::ExecutionStateEngine #######################
|
|
//#############################################################################
|
|
|
|
const StateEngine::StateEntry
|
|
Effect::ExecutionStateEngine::StateEntries[]=
|
|
{
|
|
STATE_ENTRY(Effect__ExecutionStateEngine, Stopped),
|
|
STATE_ENTRY(Effect__ExecutionStateEngine, Stopping),
|
|
STATE_ENTRY(Effect__ExecutionStateEngine, Running),
|
|
STATE_ENTRY(Effect__ExecutionStateEngine, Killing)
|
|
};
|
|
|
|
Effect::ExecutionStateEngine::ClassData*
|
|
Effect::ExecutionStateEngine::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::ExecutionStateEngine::InitializeClass()
|
|
{
|
|
Check_Object(StateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
Effect__ExecutionStateEngineClassID,
|
|
"Adept::Effect::ExecutionStateEngine",
|
|
BaseClass::DefaultData,
|
|
ELEMENTS(StateEntries), StateEntries,
|
|
(Entity::ExecutionStateEngine::Factory)Make,
|
|
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
|
|
&FactoryRequest::ConstructFactoryRequest
|
|
);
|
|
Register_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::ExecutionStateEngine::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect::ExecutionStateEngine*
|
|
Effect::ExecutionStateEngine::Make(
|
|
Effect *effect,
|
|
FactoryRequest *request
|
|
)
|
|
{
|
|
Check_Object(effect);
|
|
Check_Object(request);
|
|
Effect::ExecutionStateEngine* engine =
|
|
new Effect::ExecutionStateEngine(DefaultData, effect, request);
|
|
return engine;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Effect::ExecutionStateEngine::RequestState(
|
|
int new_state,
|
|
void* data
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(owningEntity);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Now, switch the state and tickle the watchers
|
|
//----------------------------------------------
|
|
//
|
|
|
|
switch (StateEngine::RequestState(new_state, data))
|
|
{
|
|
|
|
case StoppingState:
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------
|
|
//We need to tell both our webs that we are going through a Stop state
|
|
//--------------------------------------------------------------------
|
|
//
|
|
for (unsigned i=1; i<RendererManager::RendererTypeCount; ++i)
|
|
{
|
|
RendererComponentWeb *web = owningEntity->GetComponentWeb(i);
|
|
if (web)
|
|
{
|
|
Check_Object(web);
|
|
web->SendCommand(Renderer::StopEffectCommandID);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case RunningState:
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------
|
|
//We need to tell both our webs that we are going through a Stop state
|
|
//--------------------------------------------------------------------
|
|
//
|
|
for (unsigned i=1; i<RendererManager::RendererTypeCount; ++i)
|
|
{
|
|
RendererComponentWeb *web = owningEntity->GetComponentWeb(i);
|
|
if (web)
|
|
{
|
|
Check_Object(web);
|
|
web->SendCommand(Renderer::StartEffectCommandID);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return currentState;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::ExecutionStateEngine::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################# Effect ##################################
|
|
//#############################################################################
|
|
|
|
Effect::ClassData*
|
|
Effect::DefaultData = NULL;
|
|
|
|
static DWORD
|
|
Effect_Entities_Count;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
EffectClassID,
|
|
"Adept::Effect",
|
|
BaseClass::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
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
|
|
CUSTOM_DIRECT_ATTRIBUTE(
|
|
Effect,
|
|
VideoStatus,
|
|
videoStatus,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_ATTRIBUTE(
|
|
Effect,
|
|
AudioStatus,
|
|
audioStatus,
|
|
int,
|
|
IntClassID
|
|
);
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Effect__GameModel,
|
|
StartsRunning,
|
|
startsRunning,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Effect__GameModel,
|
|
Translation,
|
|
translation,
|
|
Point3D
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Effect__GameModel,
|
|
Rotation,
|
|
rotation,
|
|
UnitQuaternion
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Effect__GameModel,
|
|
KillOnAttachedEntityDeath,
|
|
killOnAttachedEntityDeath,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
Effect_Entities_Count = 0;
|
|
#if !defined(NO_STATS)
|
|
AddStatistic("Effect entities Executed", "entities", gos_DWORD, &Effect_Entities_Count, Stat_AutoReset);
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect*
|
|
Effect::Make(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(EntityManager::GetInstance());
|
|
Effect *new_entity;
|
|
Entity *entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID);
|
|
if (entity)
|
|
{
|
|
new_entity = Cast_Object(Effect*, entity);
|
|
new_entity->Reuse(message, base_id);
|
|
}
|
|
else
|
|
{
|
|
gos_PushCurrentHeap(s_Heap);
|
|
new_entity = new Effect(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect::Effect(
|
|
ClassData *class_data,
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Mover(class_data, message, base_id, element),
|
|
followEntity(this),
|
|
followSite(this)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
audioStatus = 0;
|
|
videoStatus = false;
|
|
if (model->startsRunning)
|
|
executionState->RequestState(ExecutionStateEngine::RunningState);
|
|
else
|
|
executionState->RequestState(ExecutionStateEngine::StoppedState);
|
|
|
|
effectOffset = LinearMatrix4D::Identity;
|
|
|
|
switch(model->rotationType)
|
|
{
|
|
case Effect__GameModel::AgainstMotionRotation:
|
|
{
|
|
YawPitchRoll effect_rotation_offset(gosFX::Effect_Against_Motion);
|
|
effectOffset.BuildRotation(effect_rotation_offset);
|
|
break;
|
|
}
|
|
case Effect__GameModel::IntoMotionRotation:
|
|
{
|
|
YawPitchRoll effect_rotation_offset(gosFX::Effect_Into_Motion);
|
|
effectOffset.BuildRotation(effect_rotation_offset);
|
|
break;
|
|
}
|
|
case Effect__GameModel::UseRotation:
|
|
{
|
|
effectOffset = model->rotation;
|
|
break;
|
|
}
|
|
}
|
|
|
|
effectOffset.BuildTranslation(model->translation);
|
|
|
|
#if defined (_ARMOR)
|
|
iAmDead = false;
|
|
#endif
|
|
|
|
// SPEW(("daberger", "CREATING EFFECT %x at time %f", this, gos_GetElapsedTime()));
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect::~Effect()
|
|
{
|
|
DESTRUCTOR("Effect");
|
|
|
|
// SPEW(("daberger", "DELETING EFFECT %x at time %f", this, gos_GetElapsedTime()));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::Reuse(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
BaseClass::Reuse(message, base_id);
|
|
|
|
Check_Pointer(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
audioStatus = 0;
|
|
videoStatus = false;
|
|
if (model->startsRunning)
|
|
executionState->RequestState(ExecutionStateEngine::RunningState);
|
|
else
|
|
executionState->RequestState(ExecutionStateEngine::StoppedState);
|
|
|
|
effectOffset = LinearMatrix4D::Identity;
|
|
|
|
switch(model->rotationType)
|
|
{
|
|
case Effect__GameModel::AgainstMotionRotation:
|
|
{
|
|
YawPitchRoll effect_rotation_offset(gosFX::Effect_Against_Motion);
|
|
effectOffset.BuildRotation(effect_rotation_offset);
|
|
break;
|
|
}
|
|
case Effect__GameModel::IntoMotionRotation:
|
|
{
|
|
YawPitchRoll effect_rotation_offset(gosFX::Effect_Into_Motion);
|
|
effectOffset.BuildRotation(effect_rotation_offset);
|
|
break;
|
|
}
|
|
case Effect__GameModel::UseRotation:
|
|
{
|
|
effectOffset = model->rotation;
|
|
break;
|
|
}
|
|
}
|
|
|
|
effectOffset.BuildTranslation(model->translation);
|
|
|
|
#if defined (_ARMOR)
|
|
iAmDead = false;
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Effect::GetExecutionSlot()
|
|
{
|
|
Check_Object(this);
|
|
return EffectExecutionSlot;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
PRECOLLISION_LOGIC("Effect");
|
|
Set_Statistic(Effect_Entities_Count, Effect_Entities_Count+1);
|
|
UsePostCollision();
|
|
BaseClass::PreCollisionExecute(till);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
void Effect::SyncMatrices(bool update_matrix)
|
|
{
|
|
SYNC_LOGIC("Effect");
|
|
BaseClass::SyncMatrices(update_matrix);
|
|
}
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::PostCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
|
|
POSTCOLLISION_LOGIC("Effect");
|
|
if (IsFollowing())
|
|
{
|
|
if(followEntity.GetCurrent())
|
|
PlaceOnEntity();
|
|
else if(followSite.GetCurrent())
|
|
PlaceOnSite();
|
|
else if (executionState->GetState() != ExecutionStateEngine::StoppingState)
|
|
executionState->RequestState(ExecutionStateEngine::StoppingState);
|
|
}
|
|
|
|
BaseClass::PostCollisionExecute(till);
|
|
|
|
#if defined (_ARMOR)
|
|
Verify(!iAmDead);
|
|
#endif
|
|
|
|
Check_Object(executionState);
|
|
switch(executionState->GetState())
|
|
{
|
|
case ExecutionStateEngine::StoppingState:
|
|
{
|
|
if (!(videoStatus || audioStatus))
|
|
{
|
|
#if defined (_ARMOR)
|
|
iAmDead = true;
|
|
#endif
|
|
executionState->RequestState(ExecutionStateEngine::StoppedState);
|
|
SentenceToDeathRow();
|
|
}
|
|
break;
|
|
}
|
|
case ExecutionStateEngine::RunningState:
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------
|
|
//If the video and audio components are looping this will never happen
|
|
//It is just for the one time play effects
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (!(videoStatus || audioStatus))
|
|
{
|
|
executionState->RequestState(ExecutionStateEngine::StoppingState);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void
|
|
Effect::BecomeInteresting(bool render_me)
|
|
{
|
|
LOAD_LOGIC("Become Interesting::Effect");
|
|
if (Application::GetInstance()->serverFlag && Application::GetInstance()->m_localMissionParameters->m_runDedicated)
|
|
{
|
|
videoStatus = false;
|
|
audioStatus = 0;
|
|
SetInterestMask(SimulationInterestLevel);
|
|
}
|
|
else
|
|
{
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
if (model->startsRunning)
|
|
executionState->RequestState(ExecutionStateEngine::RunningState);
|
|
else
|
|
executionState->RequestState(ExecutionStateEngine::StoppedState);
|
|
BaseClass::BecomeInteresting(render_me);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::SetFollowEntity(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
SetFollowing();
|
|
followEntity.Remove();
|
|
followEntity.Add(entity);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::SetFollowEntity(Site *site)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(site);
|
|
|
|
SetFollowing();
|
|
followSite.Remove();
|
|
followSite.Add(site);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::PlaceOnEntity(LinearMatrix4D offsetOnEntity)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Entity *entity;
|
|
entity = followEntity.GetCurrent();
|
|
Check_Object(entity);
|
|
|
|
if ((entity->IsDestroyed()) && (GetGameModel()->killOnAttachedEntityDeath))
|
|
{
|
|
Check_Object(executionState);
|
|
SentenceToDeathRow();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Rather than add additional data to the object I'm going tack onto the
|
|
// current effect offset.
|
|
//
|
|
|
|
LinearMatrix4D effect_local_to_parent;
|
|
effect_local_to_parent.Multiply(offsetOnEntity, effectOffset);
|
|
effectOffset = effect_local_to_parent;
|
|
|
|
LinearMatrix4D new_position;
|
|
new_position.Multiply(effectOffset, entity->GetLocalToWorld());
|
|
UnitVector3D direction_vector;
|
|
new_position.GetLocalForwardInWorld(&direction_vector);
|
|
SetNewLocalToParent(new_position);
|
|
SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::PlaceOnEntity()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Entity *entity;
|
|
entity = followEntity.GetCurrent();
|
|
Check_Object(entity);
|
|
|
|
if ((entity->IsDestroyed()) && (GetGameModel()->killOnAttachedEntityDeath))
|
|
{
|
|
Check_Object(executionState);
|
|
SentenceToDeathRow();
|
|
}
|
|
else
|
|
{
|
|
LinearMatrix4D new_position;
|
|
new_position.Multiply(effectOffset, entity->GetLocalToWorld());
|
|
UnitVector3D direction_vector;
|
|
new_position.GetLocalForwardInWorld(&direction_vector);
|
|
SetNewLocalToParent(new_position);
|
|
SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::PlaceOnSite()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Site *site;
|
|
site = followSite.GetCurrent();
|
|
Check_Object(site);
|
|
|
|
LinearMatrix4D new_position;
|
|
new_position.Multiply(effectOffset, site->GetLocalToWorld());
|
|
UnitVector3D direction_vector;
|
|
new_position.GetLocalForwardInWorld(&direction_vector);
|
|
SetNewLocalToParent(new_position);
|
|
SyncMatrices(true);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Effect::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|