Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+638
@@ -0,0 +1,638 @@
|
||||
#include "rp.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "chute.h"
|
||||
#include "..\munga\fileutil.h"
|
||||
#include "vtv.h"
|
||||
#include "..\munga\app.h"
|
||||
#include "vtvmppr.h"
|
||||
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
Chute::SharedData
|
||||
Chute::DefaultData(
|
||||
Chute::GetClassDerivations(),
|
||||
Chute::MessageHandlers,
|
||||
Chute::GetAttributeIndex(),
|
||||
Chute::StateCount
|
||||
);
|
||||
|
||||
Derivation* Chute::GetClassDerivations()
|
||||
{ static Derivation classDerivations(VTVSubsystem::GetClassDerivations(), "Chute");
|
||||
return &classDerivations;
|
||||
}
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// Messaging Support
|
||||
//
|
||||
const Receiver::HandlerEntry
|
||||
Chute::MessageHandlerEntries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(Chute, Activate),
|
||||
MESSAGE_ENTRY(Chute, ConfigureMappables),
|
||||
MESSAGE_ENTRY(Chute, ChooseButton)
|
||||
};
|
||||
|
||||
Receiver::MessageHandlerSet
|
||||
Chute::MessageHandlers(
|
||||
ELEMENTS(Chute::MessageHandlerEntries),
|
||||
Chute::MessageHandlerEntries,
|
||||
VTVSubsystem::GetMessageHandlers()
|
||||
);
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::ConfigureMappablesMessageHandler(
|
||||
ReceiverDataMessageOf<ControlsButton> *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(message);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// If the hardwired button was pressed, process presses of the mappable
|
||||
// buttons, otherwise it was released, so erase any temporary mappings
|
||||
//---------------------------------------------------------------------
|
||||
if (message->dataContents > 0)
|
||||
{
|
||||
EnterConfiguration(
|
||||
NULL, // direct target (none here)
|
||||
this, // receiver
|
||||
ActivateMessageID, // activation message ID
|
||||
ChooseButtonMessageID // configuration message ID
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitConfiguration();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::ActivateMessageHandler(
|
||||
ReceiverDataMessageOf<ControlsButton> *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(message);
|
||||
|
||||
VTV* vtv = GetEntity();
|
||||
Check(vtv);
|
||||
Check(application);
|
||||
|
||||
if (
|
||||
vtv->GetSimulationState() == VTV::BurningState
|
||||
|| application->GetApplicationState() != Application::RunningMission
|
||||
)
|
||||
{
|
||||
Check_Fpu();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->dataContents > 0)
|
||||
{
|
||||
switch (GetSimulationState())
|
||||
{
|
||||
case Ready:
|
||||
if (vtv->BoosterOn() || DeviantChute())
|
||||
{
|
||||
Check_Fpu();
|
||||
return;
|
||||
}
|
||||
if (chutesRemaining > 0)
|
||||
{
|
||||
SetSimulationState(Deploy);
|
||||
deployTimeUsed = 0.0f;
|
||||
chuteOn = 1;
|
||||
--chutesRemaining;
|
||||
ForceUpdate();
|
||||
lastPerformance = Now();
|
||||
AlwaysExecute();
|
||||
Check_Fpu();
|
||||
}
|
||||
break;
|
||||
case Dragging:
|
||||
ReleaseChute();
|
||||
Check_Fpu();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::ChooseButtonMessageHandler(
|
||||
ReceiverDataMessageOf<ControlsButton> *message
|
||||
)
|
||||
{
|
||||
if (message->dataContents > 0)
|
||||
{
|
||||
//
|
||||
//---------------------------------------------------------------------
|
||||
// Find the control manager of the vehicle, and have it turn off an
|
||||
// existing mapping of a given type if it is there, otherwise it should
|
||||
// create a new one
|
||||
//---------------------------------------------------------------------
|
||||
//
|
||||
VTV* vtv = GetEntity();
|
||||
Check(vtv);
|
||||
VTVControlsMapper* controls =
|
||||
Cast_Object(
|
||||
VTVControlsMapper*,
|
||||
vtv->GetSubsystem(VTV::ControlsMapperSubsystem)
|
||||
);
|
||||
Check(controls);
|
||||
|
||||
controls->AddOrErase(message->dataContents, this, ActivateMessageID);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Attribute Support
|
||||
//
|
||||
const Chute::IndexEntry
|
||||
Chute::AttributePointers[]=
|
||||
{
|
||||
ATTRIBUTE_ENTRY(Chute, TimeToReady, timeToReady),
|
||||
ATTRIBUTE_ENTRY(Chute, ChutesRemaining, chutesRemaining),
|
||||
ATTRIBUTE_ENTRY(Chute, ChuteDirection, chuteDirection),
|
||||
ATTRIBUTE_ENTRY(Chute, ScaleFactor, scaleFactor),
|
||||
ATTRIBUTE_ENTRY(Chute, ChuteOn, chuteOn),
|
||||
ATTRIBUTE_ENTRY(Chute, PercentDone, percentDone)
|
||||
};
|
||||
|
||||
Chute::AttributeIndexSet& Chute::GetAttributeIndex()
|
||||
{
|
||||
static Chute::AttributeIndexSet attributeIndex(ELEMENTS(Chute::AttributePointers), Chute::AttributePointers, VTVSubsystem::GetAttributeIndex());
|
||||
return attributeIndex;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Model Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::ReadUpdateRecord(Simulation::UpdateRecord *message)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(message);
|
||||
VTVSubsystem::ReadUpdateRecord(message);
|
||||
UpdateRecord* record = (UpdateRecord*) message;
|
||||
|
||||
chuteDirection = record->chuteDirection;
|
||||
chuteOn = record->chuteOn;
|
||||
scaleFactor = record->scaleFactor;
|
||||
lastPerformance = lastUpdate;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(record);
|
||||
|
||||
VTVSubsystem::WriteUpdateRecord(record, update_model);
|
||||
UpdateRecord* update = (UpdateRecord*) record;
|
||||
|
||||
update->recordLength = sizeof(*update);
|
||||
update->chuteDirection = chuteDirection;
|
||||
update->chuteOn = chuteOn;
|
||||
update->scaleFactor = scaleFactor;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
static Vector3D forward(0.0f,0.0f,-1.0f);
|
||||
|
||||
void
|
||||
Chute::ChuteSimulation(Scalar time_slice)
|
||||
{
|
||||
//
|
||||
//-------------------------
|
||||
// Apply the Chute
|
||||
//-------------------------
|
||||
//
|
||||
percentDone = percentDone = (reloadTime - timeToReady)/reloadTime;
|
||||
Check_Fpu();
|
||||
|
||||
if(percentDone > 1.0f)
|
||||
{
|
||||
percentDone = 1.0f;
|
||||
}
|
||||
if(percentDone < 0.0f)
|
||||
{
|
||||
percentDone = 0.0f;
|
||||
}
|
||||
Verify(percentDone >= 0.0f);
|
||||
Verify(percentDone <= 1.0f);
|
||||
|
||||
int sim_state = GetSimulationState();
|
||||
VTV *vtv = GetEntity();
|
||||
Check(vtv);
|
||||
|
||||
switch(sim_state)
|
||||
{
|
||||
case Loading:
|
||||
timeToReady -= time_slice;
|
||||
if (timeToReady <=0.0f)
|
||||
{
|
||||
SetSimulationState(Ready);
|
||||
NeverExecute();
|
||||
}
|
||||
break;
|
||||
|
||||
case Dragging:
|
||||
if (DeviantChute() || vtv->BoosterOn())
|
||||
{
|
||||
ReleaseChute();
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyDrag(time_slice);
|
||||
}
|
||||
break;
|
||||
|
||||
case Deploy:
|
||||
if (DeviantChute() || vtv->BoosterOn())
|
||||
{
|
||||
ReleaseChute();
|
||||
}
|
||||
else
|
||||
{
|
||||
deployTimeUsed += time_slice;
|
||||
if (deployTimeUsed >= deployTime)
|
||||
{
|
||||
scaleFactor.x = 1.0f;
|
||||
scaleFactor.y = 1.0f;
|
||||
scaleFactor.z = 1.0f;
|
||||
SetSimulationState(Dragging);
|
||||
ForceUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
deployTimeUsed += time_slice;
|
||||
scaleFactor.y = scaleFactor.x = ScaleXY();
|
||||
scaleFactor.z = ScaleZ();
|
||||
deployTimeUsed += time_slice;
|
||||
}
|
||||
AlwaysExecute();
|
||||
}
|
||||
ApplyDrag(time_slice);
|
||||
break;
|
||||
|
||||
case Released:
|
||||
SetSimulationState(Loading);
|
||||
break;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::PointChute(Scalar)
|
||||
{
|
||||
if (GetSimulationState() != Dragging || GetSimulationState() != Deploy)
|
||||
{
|
||||
Check_Fpu();
|
||||
return;
|
||||
}
|
||||
|
||||
VTV* vtv = GetEntity();
|
||||
Check(vtv);
|
||||
if (!Small_Enough(vtv->localVelocity.linearMotion.LengthSquared()))
|
||||
{
|
||||
chuteDirection.Subtract(vtv->localVelocity.linearMotion, forward);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar
|
||||
Chute::ScaleZ()
|
||||
{
|
||||
Scalar
|
||||
top_half = 2*(deployTimeUsed) -1 / (deployTimeUsed) + 1;
|
||||
Scalar
|
||||
bottom_half = 2*(deployTime) -1 / (deployTime) + 1;
|
||||
|
||||
Scalar result = top_half/bottom_half;
|
||||
|
||||
Check_Fpu();
|
||||
return result;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar Chute::ScaleXY()
|
||||
{
|
||||
Scalar
|
||||
top_half = (deployTimeUsed)*(deployTimeUsed)*(deployTimeUsed);
|
||||
Check_Fpu();
|
||||
|
||||
Scalar
|
||||
bottom_half = (deployTime)*(deployTime)*(deployTime);
|
||||
|
||||
Check_Fpu();
|
||||
Scalar result = top_half/bottom_half;
|
||||
|
||||
Check_Fpu();
|
||||
|
||||
return result;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::ReleaseChute()
|
||||
{
|
||||
SetSimulationState(Released);
|
||||
chuteOn = 0;
|
||||
ForceUpdate();
|
||||
if (GetEntity()->GetInstance() == VTV::ReplicantInstance)
|
||||
{
|
||||
NeverExecute();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void Chute::ApplyDrag(Scalar)
|
||||
{
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get pointers to the other subsystems we will have to deal with inside the
|
||||
// VTV
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
VTV* vtv = GetEntity();
|
||||
|
||||
//
|
||||
// If slow enough automatically release the chute
|
||||
//
|
||||
Scalar vel2 = vtv->localVelocity.linearMotion.LengthSquared();
|
||||
if(vel2 < minVelocity)
|
||||
{
|
||||
ReleaseChute();
|
||||
Check_Fpu();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the direction to point the chute in
|
||||
//
|
||||
chuteDirection.Subtract(vtv->localVelocity.linearMotion, forward);
|
||||
|
||||
//
|
||||
// Calculate the dragForce to Apply to the VTV
|
||||
//
|
||||
Vector3D force;
|
||||
force.Negate(vtv->localVelocity.linearMotion);
|
||||
force *= dragForce;
|
||||
vtv->ApplyLocalAcceleration(force, chuteOffset);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int
|
||||
Chute::DeviantChute()
|
||||
{
|
||||
Check(this);
|
||||
VTV *vtv = GetEntity();
|
||||
Check(vtv);
|
||||
Check_Fpu();
|
||||
return vtv->localVelocity.linearMotion.z > zDeviation;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Damage Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Chute::DeathReset(int reset_command)
|
||||
{
|
||||
Check(this);
|
||||
if (reset_command == VTV::FootballReset)
|
||||
{
|
||||
chutesRemaining = chuteCount;
|
||||
}
|
||||
if (reset_command != VTV::MissionReviewReset)
|
||||
{
|
||||
SetSimulationState(Ready);
|
||||
timeToReady = 0.0f;
|
||||
}
|
||||
NeverExecute();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
void
|
||||
Chute::DeathShutdown(int)
|
||||
{
|
||||
chuteOn = False;
|
||||
chuteDirection = Quaternion::Identity;
|
||||
NeverExecute();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Contructor and Destructor
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Chute::Chute(
|
||||
VTV *entity,
|
||||
int subsystem_ID,
|
||||
SubsystemResource *subsystem_resource
|
||||
):
|
||||
VTVSubsystem(
|
||||
entity,
|
||||
subsystem_ID,
|
||||
subsystem_resource,
|
||||
DefaultData,
|
||||
NULL, // assumes no direct controls mapping
|
||||
Chute::ActivateMessageID // message ID used for activation
|
||||
),
|
||||
scaleFactor(0.0f,0.0f,0.0f)
|
||||
{
|
||||
//-------------------------------------------
|
||||
// Set values
|
||||
//-------------------------------------------
|
||||
chuteOn = 0;
|
||||
chuteCount = subsystem_resource->chuteCount;
|
||||
chutesRemaining = chuteCount;
|
||||
reloadTime = subsystem_resource->reloadTime;
|
||||
dragForce = subsystem_resource->dragForce;
|
||||
deployTime = subsystem_resource->deployTime;
|
||||
deployTimeUsed = 0.0f;
|
||||
EntitySegment *site_front_segment =
|
||||
entity->GetSegment(subsystem_resource->segmentIndex);
|
||||
|
||||
chuteOffset = site_front_segment->GetSegmentToEntity();
|
||||
|
||||
minVelocity =
|
||||
subsystem_resource->minVelocity * subsystem_resource->minVelocity;
|
||||
zDeviation = subsystem_resource->zDeviation;
|
||||
timeToReady = 0.0f;
|
||||
chuteDirection = Quaternion::Identity;
|
||||
percentDone = 1.0f;
|
||||
SetSimulationState(Ready);
|
||||
SetPerformance(&Chute::ChuteSimulation);
|
||||
NeverExecute();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Chute::~Chute()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Chute::CreateStreamedSubsystem(
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories
|
||||
)
|
||||
{
|
||||
Check(model_file);
|
||||
Check_Pointer(subsystem_name);
|
||||
Check_Pointer(subsystem_resource);
|
||||
Check(subsystem_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::ChuteClassID;
|
||||
|
||||
//
|
||||
// Figure out who our voltage source is
|
||||
//
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"ChuteCount",
|
||||
&subsystem_resource->chuteCount
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing ChuteCount!\n";
|
||||
return False;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"ReloadTime",
|
||||
&subsystem_resource->reloadTime
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing ReloadTime!\n";
|
||||
return False;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"DragForce",
|
||||
&subsystem_resource->dragForce
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing DragForce!\n";
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"MinVelocity",
|
||||
&subsystem_resource->minVelocity
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing MinVelocity!\n";
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"DeployTime",
|
||||
&subsystem_resource->deployTime
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing DeployTime!\n";
|
||||
return False;
|
||||
}
|
||||
Scalar degree;
|
||||
if (
|
||||
!subsystem_file->GetEntry(
|
||||
subsystem_name,
|
||||
"MaxRotation",
|
||||
°ree
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr << subsystem_name << " missing MaxRotation!\n";
|
||||
return False;
|
||||
}
|
||||
else
|
||||
{
|
||||
Radian rad(degree);
|
||||
subsystem_resource->zDeviation = cos(rad);
|
||||
}
|
||||
if (subsystem_resource->dragForce < 0.0f)
|
||||
{
|
||||
std::cerr << subsystem_name << " must have a positive dragForce!\n";
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Chute::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(*GetClassDerivations());
|
||||
}
|
||||
Reference in New Issue
Block a user