Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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));
}