Files
TeslaRel410/CODE/RP/MUNGA/DOOR.CPP
T
CydandClaude Fable 5 fdd9ac9d97 Initial import: Tesla Release 4.10 (Tesla:BattleTech & Tesla:Red Planet)
Archival snapshot of the Virtual World Entertainment Tesla cockpit
software, 1994-1996: MUNGA engine and L4 pod layer source (Borland
C++ 5.0), BT/RP game code, and game content (models, audio, maps,
gauges, Division renderer data). Includes third-party libraries:
Division dVS/DPL graphics, HMI SOS audio, WATTCP networking.

Files are preserved byte-for-byte (.gitattributes disables all
line-ending conversion). README.md documents the layout, target
hardware, and toolchain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 13:21:58 -05:00

567 lines
14 KiB
C++

//===========================================================================//
// File: door.cc //
// Project: Red Planet //
// Contents: Door subsystem for managing door operation //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
// PROPRIETARY AND CONFIDENTIAL //
//===========================================================================//
#include <munga.hpp>
#pragma hdrstop
#if !defined(DOOR_HPP)
# include <door.hpp>
#endif
#if !defined(FILEUTIL_HPP)
# include <fileutil.hpp>
#endif
#if !defined(BOXSOLID_HPP)
# include <boxsolid.hpp>
#endif
#if !defined(DOORFRAM_HPP)
# include <doorfram.hpp>
#endif
#if !defined(APP_HPP)
#include <app.hpp>
#endif
#if !defined(NOTATION_HPP)
#include <notation.hpp>
#endif
//#############################################################################
// Shared Data Support
//
Door::SharedData
Door::DefaultData(
Door::ClassDerivations,
Door::MessageHandlers,
Door::AttributeIndex,
Door::StateCount
);
Derivation
Door::ClassDerivations(
Subsystem::ClassDerivations,
"Door"
);
//#############################################################################
// Messaging Support
//
//#############################################################################
// Attribute Support
//
const Door::IndexEntry
Door::AttributePointers[]=
{
{
Door::CurrentPositionAttributeID,
"CurrentPosition",
(Simulation::AttributePointer)&Door::currentPosition
},
{
Door::VideoResourceAttributeID,
"VideoResource",
(Simulation::AttributePointer)&Door::videoResource
},
{
Door::PercentOpenAttributeID,
"PercentOpen",
(Simulation::AttributePointer)&Door::percentOpen
},
{
Door::CurrentVelocityAttributeID,
"CurrentVelocity",
(Simulation::AttributePointer)&Door::currentVelocity
}
};
Door::AttributeIndexSet
Door::AttributeIndex(
ELEMENTS(Door::AttributePointers),
Door::AttributePointers,
Subsystem::AttributeIndex
);
//#############################################################################
// Model Support
//
void
Door::ReadUpdateRecord(Simulation::UpdateRecord *message)
{
Check(this);
Check_Pointer(message);
Subsystem::ReadUpdateRecord(message);
UpdateRecord* record = (UpdateRecord*) message;
percentOpen = record->percentOpen;
switch (GetSimulationState())
{
case Opening:
case Closing:
phaseTimeRemaining = travelTime;
break;
case Opened:
case Closed:
phaseTimeRemaining = deadTime;
break;
}
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door updated to state "
// << GetSimulationState() << " @ "
// << application->GetSecondsRemainingInGame() << endl;
MoveCollisionVolume(percentOpen);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model)
{
Check(this);
Check_Pointer(record);
Subsystem::WriteUpdateRecord(record, update_model);
UpdateRecord *update = (UpdateRecord*)record;
update->percentOpen = percentOpen;
update->recordLength = sizeof(*update);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::SlideDoor(Scalar time_slice)
{
Check(this);
//
//------------------------------------------------------------
// Advance the clock, then branch based upon our current state
//------------------------------------------------------------
//
int new_state;
if (time_slice > 1.0f)
{
Check_Fpu();
return;
}
phaseTimeRemaining -= time_slice;
Scalar percent_open;
switch (GetSimulationState())
{
//
//------------------------------------------------------------------------
// If the door is not done opening, set its new position, otherwise branch
// to the opened state
//------------------------------------------------------------------------
//
case Opening:
Door_Opening:
new_state = Opening;
if (phaseTimeRemaining > 0.0f)
{
percent_open = 1.0f - phaseTimeRemaining/travelTime;
}
else
{
phaseTimeRemaining += deadTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door opened @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Opened;
}
currentVelocity.Subtract(
worldExtent,
GetEntity()->localOrigin.linearPosition
);
currentVelocity /= travelTime;
Check_Fpu();
break;
//
//-------------------------------------------------------------
// If the door is ready to start closing, jump to closing state
//-------------------------------------------------------------
//
case Opened:
Door_Opened:
new_state = Opened;
if (phaseTimeRemaining <= 0.0f)
{
phaseTimeRemaining += travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door closing @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Closing;
}
percent_open = 1.0f;
currentVelocity = Vector3D::Identity;
Check_Fpu();
break;
//
//------------------------------------------------------------------------
// If the door is not done closing, set its new position, otherwise branch
// to the closed state
//------------------------------------------------------------------------
//
case DefaultState:
phaseTimeRemaining = travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door default @ "
// << application->GetSecondsRemainingInGame() << endl;
case Closing:
Door_Closing:
new_state = Closing;
if (phaseTimeRemaining > 0.0f)
{
percent_open = phaseTimeRemaining/travelTime;
}
else
{
phaseTimeRemaining += deadTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door closed @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Closed;
}
currentVelocity.Subtract(
GetEntity()->localOrigin.linearPosition,
worldExtent
);
currentVelocity /= travelTime;
Check_Fpu();
break;
//
//-------------------------------------------------------------
// If the door is ready to start opening, jump to opening state
//-------------------------------------------------------------
//
case Closed:
Door_Closed:
new_state = Closed;
if (phaseTimeRemaining <= 0.0f)
{
phaseTimeRemaining += travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door opening @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Opening;
}
percent_open = 0.0f;
currentVelocity = Vector3D::Identity;
Check_Fpu();
break;
}
//
//-------------------------------------------------
// Move the collision volumes and set the new state
//-------------------------------------------------
//
MoveCollisionVolume(percent_open);
SetSimulationState(new_state);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::MoveCollisionVolume(Scalar percent_open)
{
Check(this);
//
//---------------------------------------------------------
// If the door hasn't moved, don't bother updating anything
//---------------------------------------------------------
//
Entity *entity = GetEntity();
Check(entity);
if (
GetSimulationState() != simulationState.GetOldState()
&& entity->GetInstance() == Entity::MasterInstance
&& entity->IsDynamic()
)
{
ForceUpdate();
}
if (percent_open == percentOpen)
{
return;
}
//
//-----------------------------------
// Otherwise, lerp the local position
//-----------------------------------
//
percentOpen = percent_open;
currentPosition.Lerp(Point3D::Identity, localExtent, percentOpen);
//
//-----------------------------------------------------------
// Now, lerp the world position and set the collision volumes
//-----------------------------------------------------------
//
Point3D world;
world.Lerp(
GetEntity()->localOrigin.linearPosition,
worldExtent,
percentOpen
);
BoxedSolid* temp = collisionTemplates;
BoxedSolid* vol = collisionVolumes;
while (temp)
{
Check(temp);
Check(vol);
vol->minX = temp->minX + world.x;
vol->maxX = temp->maxX + world.x;
vol->minY = temp->minY + world.y;
vol->maxY = temp->maxY + world.y;
vol->minZ = temp->minZ + world.z;
vol->maxZ = temp->maxZ + world.z;
vol = vol->GetNextSolid();
temp = temp->GetNextSolid();
}
Verify(!vol);
Check_Fpu();
}
//#############################################################################
// Constructer/Destructor Support
//
Door::Door(
DoorFrame *entity,
int subsystem_ID,
SubsystemResource *subsystem_resource
):
Subsystem(entity, subsystem_ID, subsystem_resource, DefaultData)
{
Check_Pointer(this);
Check(entity);
Check_Pointer(subsystem_resource);
//
// GetStream data NOTE::This must be in the same order as below!!!
//
localExtent = subsystem_resource->motionExtent;
travelTime = subsystem_resource->travelTime;
deadTime = subsystem_resource->deadTime;
//
// Initialize variables
//
phaseTimeRemaining = 0.0f;
currentPosition = Point3D::Identity;
SetPerformance(&Door::SlideDoor);
SetSimulationState(DefaultState);
collisionVolumeCount = 0;
collisionTemplates = NULL;
collisionVolumes = NULL;
percentOpen = -1.0f;
//
//-------------------------------------
// Establish the worldspace coordinates
//-------------------------------------
//
worldExtent.Multiply(localExtent, entity->localToWorld);
Origin local_origin = entity->localOrigin;
local_origin.linearPosition = Point3D::Identity;
//
//------------------------------
// Read in the collision volumes
//------------------------------
//
Check(application);
ResourceFile *res_file = application->GetResourceFile();
Check(res_file);
ResourceDescription *res =
res_file->FindResourceDescription(subsystem_resource->collisionID);
Check(res);
res->Lock();
BoxedSolidResource* box =
(BoxedSolidResource*)res->resourceAddress;
Check_Pointer(box);
collisionVolumeCount = res->resourceSize / sizeof(BoxedSolidResource);
for (int i=0; i<collisionVolumeCount; ++i)
{
BoxedSolidResource world_box,local_box;
world_box.Instance(*box,entity->localOrigin);
local_box.Instance(*box,local_origin);
collisionTemplates =
BoxedSolid::MakeBoxedSolid(&local_box, this, collisionTemplates);
Register_Object(collisionTemplates);
collisionVolumes =
BoxedSolid::MakeBoxedSolid(&world_box, this, collisionVolumes);
Register_Object(collisionVolumes);
++box;
}
res->Unlock();
MoveCollisionVolume(0.0f);
Check(this);
}
Door::~Door()
{
BoxedSolid *box = collisionTemplates;
while (box)
{
BoxedSolid *next_box = box->GetNextSolid();
Unregister_Object(box);
delete box;
box = next_box;
}
box = collisionVolumes;
while (box)
{
BoxedSolid *next_box = box->GetNextSolid();
Unregister_Object(box);
delete box;
box = next_box;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
Logical
Door::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char* subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
const ResourceDirectories *directories,
ResourceFile *res_file
)
{
if (
!Subsystem::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
directories
)
)
{
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::DoorClassID;
//
// Get the motion Extent
//
const char *extent_data;
if(
!subsystem_file->GetEntry(
subsystem_name,
"MotionExtent",
&extent_data
)
)
{
cerr << subsystem_name << " missing MotionExtent!!\n";
return -1;
}
sscanf(
extent_data,
"%f %f %f",
&subsystem_resource->motionExtent.x,
&subsystem_resource->motionExtent.y,
&subsystem_resource->motionExtent.z
);
//
// Get the travelTime
//
if(
!subsystem_file->GetEntry(
subsystem_name,
"TravelTime",
&subsystem_resource->travelTime
)
)
{
cerr << subsystem_name << " missing TravelTime!\n";
return -1;
}
//
// Read in the Deadtime
//
if(
!subsystem_file->GetEntry(
subsystem_name,
"DeadTime",
&subsystem_resource->deadTime
)
)
{
cerr << subsystem_name << " missing DeadTime!\n";
return False;
}
const char* collision_file;
if (
!subsystem_file->GetEntry(
subsystem_name,
"Collision",
&collision_file
)
)
{
cerr << subsystem_name << " missing Collision!\n";
return False;
}
subsystem_resource->collisionID =
BoxedSolidResource::CreateBoxedSolidStream(
collision_file,
res_file,
directories
);
return True;
}
Logical
Door::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}