Files
TeslaRel410/CODE/RP/MUNGA/SIMULATE.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

734 lines
18 KiB
C++

//===========================================================================//
// File: simulate.cc //
// Project: MUNGA Brick: Model Manager //
// Contents: Implementation details of model class //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 01/25/95 JMA Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
// PROPRIETARY AND CONFIDENTIAL //
//===========================================================================//
#include <munga.hpp>
#pragma hdrstop
#if !defined(SIMULATE_HPP)
# include <simulate.hpp>
#endif
#if !defined(UPDATE_HPP)
# include <update.hpp>
#endif
#if !defined(APP_HPP)
#include <app.hpp>
#endif
#if defined(TRACE_EXECUTE_WATCHERS)
static BitTrace Execute_Watchers("Execute Watchers");
#define SET_EXECUTE_WATCHERS() Execute_Watchers.Set()
#define CLEAR_EXECUTE_WATCHERS() Execute_Watchers.Clear()
#else
#define SET_EXECUTE_WATCHERS()
#define CLEAR_EXECUTE_WATCHERS()
#endif
//#############################################################################
//######################## StateIndicator ###############################
//#############################################################################
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator():
audioWatcherSocket(NULL),
videoWatcherSocket(NULL),
gaugeWatcherSocket(NULL)
{
Check_Pointer(this);
stateCount = 0;
oldState = 0;
currentState = 0;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator(unsigned max_states):
audioWatcherSocket(NULL),
videoWatcherSocket(NULL),
gaugeWatcherSocket(NULL)
{
Check_Pointer(this);
stateCount = max_states;
oldState = max_states;
currentState = max_states;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator(const StateIndicator &state_indicator):
audioWatcherSocket(NULL),
videoWatcherSocket(NULL),
gaugeWatcherSocket(NULL)
{
Check_Pointer(this);
// Do not perform deep copy of watchers
stateCount = state_indicator.stateCount;
oldState = state_indicator.oldState;
currentState = state_indicator.currentState;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::~StateIndicator()
{
Check(this);
//
// Manual deletion of existing watchers
//
{
SChainIteratorOf<Component*> iterator(&audioWatcherSocket);
#if DEBUG_LEVEL>2
Component *component;
while ((component = iterator.ReadAndNext()) != NULL)
{
Check(component);
Dump(component->GetClassID());
}
Warn(iterator.GetSize() != 0);
#endif
iterator.DeletePlugs();
}
{
SChainIteratorOf<Component*> iterator(&videoWatcherSocket);
#if DEBUG_LEVEL>2
Component *component;
while ((component = iterator.ReadAndNext()) != NULL)
{
Check(component);
Dump(component->GetClassID());
}
Warn(iterator.GetSize() != 0);
#endif
iterator.DeletePlugs();
}
{
SChainIteratorOf<Component*> iterator(&gaugeWatcherSocket);
#if DEBUG_LEVEL>2
Component *component;
while ((component = iterator.ReadAndNext()) != NULL)
{
Check(component);
Dump(component->GetClassID());
}
Warn(iterator.GetSize() != 0);
#endif
iterator.DeletePlugs();
}
Check_Fpu();
}
//#############################################################################
// State stuff
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator&
StateIndicator::operator=(const StateIndicator &state_indicator)
{
// Do not perform assignment of watchers
stateCount = state_indicator.stateCount;
oldState = state_indicator.oldState;
currentState = state_indicator.currentState;
Check_Fpu();
return *this;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
StateIndicator::operator==(const StateIndicator &state_indicator) const
{
Check_Fpu();
return
(
stateCount == state_indicator.stateCount &&
oldState == state_indicator.oldState &&
currentState == state_indicator.currentState
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateIndicator::SetState(unsigned new_state)
{
Check(this);
Verify(new_state < stateCount);
//
//--------------------------------------------------------------------------
// See if the state really changes
//
// NOTE - the old state does change to the current state, simulating a loop
// in the state engine. If it turns out that someone is watching the
// level of the state indicator and doing their own edge detection,
// this might possibly maybe screw something up
//--------------------------------------------------------------------------
//
oldState = currentState;
if (new_state == currentState)
{
return;
}
//
//-------------------------------------------------------------------
// If the state has changed, update the state values and then run any
// watchers
//-------------------------------------------------------------------
//
currentState = new_state;
Component *watcher;
SET_EXECUTE_WATCHERS();
// Audio
{
SChainIteratorOf<Component*> iterator(audioWatcherSocket);
Check(&iterator);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
// Video
{
SChainIteratorOf<Component*> iterator(videoWatcherSocket);
Check(&iterator);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
// Gauge
{
SChainIteratorOf<Component*> iterator(gaugeWatcherSocket);
Check(&iterator);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
CLEAR_EXECUTE_WATCHERS();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ostream&
operator << (ostream &strm, const StateIndicator &state_indicator)
{
Check(&state_indicator);
strm << "[" << state_indicator.stateCount << ",";
strm << state_indicator.oldState << ",";
strm << state_indicator.currentState << "]";
return strm;
}
//#############################################################################
// Test Support
//
Logical
StateIndicator::TestInstance() const
{
return True;
}
//#############################################################################
//########################## Simulation #################################
//#############################################################################
//#############################################################################
// Virtual Data support
//
Derivation
Simulation::ClassDerivations(Receiver::ClassDerivations,"Simulation");
Simulation::SharedData
Simulation::DefaultData(
Simulation::ClassDerivations,
Simulation::MessageHandlers,
Simulation::AttributeIndex,
Simulation::StateCount
);
//#############################################################################
// Model support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::ReadUpdateRecord(UpdateRecord *message)
{
Check(this);
Check_Pointer(message);
lastUpdate = Now(); // HACK - should be based upon message->timeStamp
SetSimulationState(message->simulationState);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::WriteUpdateRecord(
UpdateRecord *message,
int update_model
)
{
Check(this);
Check_Pointer(message);
message->timeStamp = lastPerformance;
message->simulationState = GetSimulationState();
message->recordLength = sizeof(*message);
message->recordID = (Word)update_model;
lastUpdate = lastPerformance;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::WriteSimulationUpdate(MemoryStream *update_stream)
{
Check(this);
Check(update_stream);
//
//-----------------
// Write the update
//-----------------
//
int bit=0;
int update_model = updateModel;
updateModel = 0;
while (update_model)
{
if (update_model & 1)
{
UpdateRecord* update = (UpdateRecord*)update_stream->GetPointer();
WriteUpdateRecord(update, bit);
update_stream->AdvancePointer(update->recordLength);
}
update_model >>= 1;
++bit;
}
Check_Fpu();
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::Simulation(
Simulation::ClassID class_ID,
Simulation::SharedData &virtual_data
):
Receiver(class_ID, virtual_data),
simulationState(GetSharedData()->stateCount),
audioWatcherSocket(NULL),
videoWatcherSocket(NULL),
gaugeWatcherSocket(NULL),
effectWatcherSocket(NULL)
{
Check_Pointer(this);
SetSimulationState(DefaultState);
lastPerformance = Now();
lastUpdate = lastPerformance;
activePerformance = &Simulation::DoNothingOnce;
updateModel = 0;
simulationFlags = 0;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::~Simulation()
{
Check(this);
//
// Watchers should be deleted by renderers by now
//
#if DEBUG_LEVEL>0
{
SChainIteratorOf<Component*> iterator(&audioWatcherSocket);
Verify(iterator.GetSize() == 0);
}
{
SChainIteratorOf<Component*> iterator(&videoWatcherSocket);
Verify(iterator.GetSize() == 0);
}
{
SChainIteratorOf<Component*> iterator(&gaugeWatcherSocket);
Verify(iterator.GetSize() == 0);
}
#endif
Check_Fpu();
}
//#############################################################################
// Attribute Support
//
const Simulation::AttributePointer
Simulation::NullAttribute = NULL;
const Simulation::IndexEntry
Simulation::AttributePointers[]=
{
{
Simulation::SimulationStateAttributeID,
"SimulationState",
(Simulation::AttributePointer)&Simulation::simulationState
}
};
Simulation::AttributeIndexSet
Simulation::AttributeIndex(
ELEMENTS(Simulation::AttributePointers),
Simulation::AttributePointers
);
void*
Simulation::GetAttributePointer(Simulation::AttributeID attribute)
{
Check(this);
AttributePointer attr =
GetSharedData()->activeAttributeIndex->Find(attribute);
Check_Fpu();
if (attr == NullAttribute)
{
return NULL;
}
else
{
return &(this->*attr);
}
}
void*
Simulation::GetAttributePointer(const char* attribute_name)
{
Check(this);
AttributePointer attr =
GetSharedData()->activeAttributeIndex->Find(attribute_name);
Check_Fpu();
if (attr == NullAttribute)
{
return NULL;
}
else
{
return &(this->*attr);
}
}
//#############################################################################
// Simulation Support
//
void
Simulation::PerformAndWatch(
const Time& till,
MemoryStream *update_stream
)
{
Check(this);
Check(&till);
Scalar slice = till - lastPerformance;
lastPerformance = till;
Perform(slice);
if (!AreWatchersDelayed())
{
ExecuteWatchers();
}
WriteSimulationUpdate(update_stream);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::DoNothingOnce(Scalar)
{
NeverExecute();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::DoNothing(Scalar)
{
Check_Fpu();
}
//#############################################################################
// Watcher Support
//
void
Simulation::ExecuteWatchers()
{
SET_EXECUTE_WATCHERS();
Component *watcher;
// Audio
{
SChainIteratorOf<Component*> iterator(audioWatcherSocket);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
// Video
{
SChainIteratorOf<Component*> iterator(videoWatcherSocket);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
// Gauge
{
SChainIteratorOf<Component*> iterator(gaugeWatcherSocket);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
// Effect
{
SChainIteratorOf<Component*> iterator(effectWatcherSocket);
while ((watcher = iterator.ReadAndNext()) != NULL)
{
watcher->Execute();
}
}
CLEAR_EXECUTE_WATCHERS();
}
//#############################################################################
// Test Support
//
Logical
Simulation::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
//#############################################################################
//################### Simulation::AttributeIndexSet #####################
//#############################################################################
const Simulation::AttributeIndexSet
Simulation::AttributeIndexSet::NullSet;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation__AttributeIndexSet::~Simulation__AttributeIndexSet()
{
if (attributeIndex)
{
Unregister_Pointer(attributeIndex);
delete[] attributeIndex;
}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Simulation::AttributeIndexSet::Build(
Simulation::AttributeID count,
const Simulation::IndexEntry index_table[],
const Simulation::AttributeIndexSet *inheritance
)
{
//
//-------------------------------------------------------
// Find out the highest message type we have to deal with
//-------------------------------------------------------
//
Check(this);
Check_Pointer(index_table);
entryCount = 0;
Simulation::AttributeID i;
for (i=0; i<count; ++i)
{
if (index_table[i].entryID > entryCount)
{
entryCount = index_table[i].entryID;
}
}
if (inheritance)
{
Check(inheritance);
if (entryCount<inheritance->entryCount)
{
entryCount = inheritance->entryCount;
}
#if DEBUG_LEVEL>0
else if (entryCount > inheritance->entryCount)
{
i = inheritance->entryCount+1;
goto Check_Table;
}
#endif
}
else
{
Verify(entryCount == count);
#if DEBUG_LEVEL>0
i = 1;
Check_Table:
while (i <= entryCount)
{
int j;
for (j=0; j<count; ++j)
{
if (index_table[j].entryID == i)
{
break;
}
}
if (j == count)
{
break;
}
++i;
}
Verify(i > count);
#endif
}
//
//-----------------------------------------------------------------------
// Allocate the memory for the new handler set, and copy the inherited
// handlers to the new table. We are guaranteed to have enough space for
// the inherited table
//-----------------------------------------------------------------------
//
attributeIndex = new Simulation::IndexEntry[entryCount];
Check_Pointer(attributeIndex);
Register_Pointer(attributeIndex);
i = 0;
if (inheritance)
{
for (; i<inheritance->entryCount; ++i)
{
attributeIndex[i] = inheritance->attributeIndex[i];
}
}
//
//----------------------------------------------------------------------
// Step through the new table supplied, placing each handler in the slot
// determined by the message type
//----------------------------------------------------------------------
//
for (i=0; i<count; ++i)
{
Verify(!inheritance || index_table[i].entryID > inheritance->entryCount);
attributeIndex[index_table[i].entryID-1] = index_table[i];
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::AttributePointer
Simulation::AttributeIndexSet::Find(const char* attribute_name) const
{
Check(this);
Check_Pointer(attribute_name);
for (int attribute=0; attribute<entryCount; ++attribute)
{
if (!strcmp(attribute_name, attributeIndex[attribute].entryName))
{
Check_Fpu();
return attributeIndex[attribute].entryAddress;
}
}
Check_Fpu();
return Simulation::NullAttribute;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const Simulation::IndexEntry*
Simulation::AttributeIndexSet::FindEntry(const char* attribute_name) const
{
Check(this);
Check_Pointer(attribute_name);
for (int attribute=0; attribute<entryCount; ++attribute)
{
if (!strcmp(attribute_name, attributeIndex[attribute].entryName))
{
Check_Fpu();
return &attributeIndex[attribute];
}
}
Check_Fpu();
return NULL;
}
void
Simulation::RequestEncore(Encore encore)
{
Check(this);
SetWatcherDelay();
Check(application);
UpdateManager *updater = application->GetUpdateManager();
Check(updater);
updater->RequestEncore(this, encore);
}
#if defined(TEST_CLASS) && 0
# include "model.tcp"
#endif