Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,645 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "receiver.h"
|
||||
#include "event.h"
|
||||
|
||||
//#############################################################################
|
||||
//############################# Receiver ################################
|
||||
//#############################################################################
|
||||
|
||||
const Receiver::Handler
|
||||
Receiver::NullHandler=NULL;
|
||||
|
||||
Receiver::SharedData
|
||||
Receiver::DefaultData(
|
||||
Receiver::GetClassDerivations(),
|
||||
Receiver::GetMessageHandlers()
|
||||
);
|
||||
|
||||
Derivation* Receiver::GetClassDerivations()
|
||||
{
|
||||
static Derivation classDerivations("Receiver");
|
||||
return &classDerivations;
|
||||
}
|
||||
|
||||
const Receiver::HandlerEntry
|
||||
Receiver::MessageHandlerEntries[]=
|
||||
{
|
||||
{
|
||||
Receiver::WatcherChangedMessageID,
|
||||
"WatcherChanged",
|
||||
(Receiver::Handler)&Receiver::DefaultMessageHandler
|
||||
},
|
||||
{
|
||||
Receiver::LoadResourceFinishedMessageID,
|
||||
"LoadResourceFinished",
|
||||
(Receiver::Handler)&Receiver::DefaultMessageHandler
|
||||
}
|
||||
};
|
||||
|
||||
Receiver::MessageHandlerSet& Receiver::GetMessageHandlers()
|
||||
{
|
||||
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Receiver::MessageHandlerEntries), Receiver::MessageHandlerEntries);
|
||||
return messageHandlers;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
#if defined(USE_SIGNATURE)
|
||||
int
|
||||
Is_Signature_Bad(const volatile Receiver__Message *)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
#endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
#if DEBUG_LEVEL>0
|
||||
Receiver::DefaultMessageHandler(Message* message)
|
||||
#else
|
||||
Receiver::DefaultMessageHandler(Message*)
|
||||
#endif
|
||||
{
|
||||
Tell(
|
||||
"Default Handler activated on message ID " << message->messageID << endl
|
||||
);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::Receive(Message *what)
|
||||
{
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Service the message taps by creating an iterator to step through all the
|
||||
// MessageTaps registered with the Derivation object for the receiver's
|
||||
// class. Each tap will do whatever it thinks best about this receiver
|
||||
// having received this message
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
Check(this);
|
||||
Check_Pointer(what);
|
||||
ChainIteratorOf<MessageTap*> i(GetDerivation()->activeTaps);
|
||||
MessageTap *tap;
|
||||
while ((tap = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
tap->Scan(this,what);
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Now, see if the receiver can handle this type of message, and if so, send
|
||||
// the message to the returned method handler
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Receiver::SharedData *sharedData = GetSharedData();
|
||||
Handler handler = sharedData->activeMessageHandlers->Find(what->messageID);
|
||||
if (handler != Receiver::NullHandler)
|
||||
{
|
||||
(this->*handler)(what);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::Receive(Event *event)
|
||||
{
|
||||
Receive(event->messageToSend);
|
||||
Unregister_Object(event);
|
||||
delete event;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::FlushEvents(int) // max_priority doesn't work yet!!!!
|
||||
{
|
||||
Check(this);
|
||||
PlugIteratorOf<Event*> i(this);
|
||||
Event *event;
|
||||
while ((event = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (event->GetClassID() == EventClassID)
|
||||
{
|
||||
Unregister_Object(event);
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::FlushMatchingEvents(
|
||||
Receiver::MessageID target_message,
|
||||
int // max_priority doesn't work yet!!!!
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
PlugIteratorOf<Event*>
|
||||
i(this);
|
||||
Event* event;
|
||||
while ((event = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (
|
||||
event->GetClassID() == EventClassID && (
|
||||
target_message == Receiver::AnyMessageID
|
||||
|| event->messageToSend->messageID == target_message
|
||||
)
|
||||
)
|
||||
{
|
||||
Unregister_Object(event);
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::ProcessDeferredQueue()
|
||||
{
|
||||
//
|
||||
//------------------------------------------------
|
||||
// Find a delay queue, and return if there is none
|
||||
//------------------------------------------------
|
||||
//
|
||||
Check(this);
|
||||
PlugIteratorOf<DeferredEventQueue*> i(this);
|
||||
DeferredEventQueue *deferred_queue;
|
||||
while ((deferred_queue = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (deferred_queue->GetClassID() == DeferredEventQueueClassID)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!deferred_queue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------
|
||||
// Now, tell the queue to process all its events, then delete it
|
||||
//--------------------------------------------------------------
|
||||
//
|
||||
deferred_queue->ProcessAllEvents();
|
||||
Unregister_Object(deferred_queue);
|
||||
delete deferred_queue;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Receiver::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(*GetClassDerivations());
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//######################### Receiver::Message ###########################
|
||||
//#############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Receiver::Message::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//######################### Receiver::DynamicMessage ##########################
|
||||
//#############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Receiver__DynamicMessage::Receiver__DynamicMessage(
|
||||
Receiver::MessageID message_ID,
|
||||
size_t message_size
|
||||
)
|
||||
{
|
||||
Receiver::Message new_message(message_ID, message_size);
|
||||
WriteBytes(&new_message, message_size);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
MemoryStream&
|
||||
Receiver::DynamicMessage::WriteBytes(
|
||||
const void *ptr,
|
||||
size_t number_of_bytes
|
||||
)
|
||||
{
|
||||
DynamicMemoryStream::WriteBytes(ptr, number_of_bytes);
|
||||
|
||||
Receiver::Message *message = GetMessagePointer();
|
||||
size_t new_size = GetBytesUsed();
|
||||
message->messageLength = new_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//############################ MessageTap ###############################
|
||||
//#############################################################################
|
||||
|
||||
MemoryBlock *MessageTap::GetAllocatedMemory()
|
||||
{
|
||||
static MemoryBlock allocatedMemory(sizeof(MessageTap), 30, 30, "Message Taps");
|
||||
return &allocatedMemory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
MessageTap::MessageTap(
|
||||
Derivation *derivation,
|
||||
Receiver *client,
|
||||
Receiver::ScanCallback call_back
|
||||
):
|
||||
Plug(MessageTapClassID)
|
||||
{
|
||||
//
|
||||
//---------------------------
|
||||
// Initialize the message tap
|
||||
//---------------------------
|
||||
//
|
||||
Check(client);
|
||||
clientReceiver = client;
|
||||
scanCallback = call_back;
|
||||
matchingReceiver = NULL;
|
||||
matchingMessageID = Receiver::AnyMessageID;
|
||||
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Hook the tap up to the specified derivation
|
||||
//--------------------------------------------
|
||||
//
|
||||
Check(derivation);
|
||||
derivation->AppendMessageTap(this);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
MessageTap::MessageTap(
|
||||
Derivation *derivation,
|
||||
Receiver *client,
|
||||
Receiver::ScanCallback call_back,
|
||||
Receiver::MessageID messageID,
|
||||
Receiver *receiver
|
||||
):
|
||||
Plug(MessageTapClassID)
|
||||
{
|
||||
//
|
||||
//---------------------------
|
||||
// Initialize the message tap
|
||||
//---------------------------
|
||||
//
|
||||
Check(client);
|
||||
clientReceiver = client;
|
||||
scanCallback = call_back;
|
||||
|
||||
matchingReceiver = receiver;
|
||||
matchingMessageID = messageID;
|
||||
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Hook the tap up to the specified derivation
|
||||
//--------------------------------------------
|
||||
//
|
||||
Check(derivation);
|
||||
derivation->AppendMessageTap(this);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
MessageTap::Scan(
|
||||
Receiver *receiver,
|
||||
Receiver::Message *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(message);
|
||||
|
||||
if (
|
||||
(!matchingReceiver || matchingReceiver == receiver)
|
||||
&& (
|
||||
matchingMessageID == Receiver::AnyMessageID
|
||||
|| matchingMessageID == message->messageID
|
||||
)
|
||||
)
|
||||
{
|
||||
(clientReceiver->*scanCallback)(message,receiver);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
MessageTap::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//##################### Receiver::InheritanceSet ########################
|
||||
//#############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Receiver::InheritanceSet::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//#################### Receiver::MessageHandlerSet ######################
|
||||
//#############################################################################
|
||||
|
||||
const Receiver::MessageHandlerSet
|
||||
Receiver::MessageHandlerSet::NullSet;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Receiver__MessageHandlerSet::~Receiver__MessageHandlerSet()
|
||||
{
|
||||
if (messageHandlers)
|
||||
{
|
||||
Unregister_Pointer(messageHandlers);
|
||||
delete[] messageHandlers;
|
||||
messageHandlers = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Receiver::MessageHandlerSet::Build(
|
||||
Receiver::MessageID count,
|
||||
const Receiver::HandlerEntry handler_table[],
|
||||
const Receiver::MessageHandlerSet *inheritance
|
||||
)
|
||||
{
|
||||
//
|
||||
//-------------------------------------------------------
|
||||
// Find out the highest message type we have to deal with
|
||||
//-------------------------------------------------------
|
||||
//
|
||||
Check(this);
|
||||
Check_Pointer(handler_table);
|
||||
entryCount = 0;
|
||||
Receiver::MessageID i;
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
if (handler_table[i].entryID > entryCount)
|
||||
{
|
||||
entryCount = handler_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 (handler_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
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
messageHandlers = new Receiver::HandlerEntry[entryCount];
|
||||
Check_Pointer(messageHandlers);
|
||||
Register_Pointer(messageHandlers);
|
||||
i = 0;
|
||||
if (inheritance)
|
||||
{
|
||||
for (; i<inheritance->entryCount; ++i)
|
||||
{
|
||||
messageHandlers[i] = inheritance->messageHandlers[i];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// Step through the new table supplied, placing each handler in the slot
|
||||
// determined by the message type
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
Receiver::MessageID index = handler_table[i].entryID - 1;
|
||||
Verify(index >= 0 && index < entryCount);
|
||||
messageHandlers[index] = handler_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const Receiver::HandlerEntry*
|
||||
Receiver::MessageHandlerSet::Find(const char* name) const
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
|
||||
for (int i=0; i<entryCount; ++i)
|
||||
{
|
||||
if (!strcmp(name, messageHandlers[i].entryName))
|
||||
{
|
||||
return &messageHandlers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//############################# Derivation ##############################
|
||||
//#############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Derivation::Derivation(char *name):
|
||||
Node(DerivationClassID),
|
||||
classDerivations(this),
|
||||
activeTaps(this)
|
||||
{
|
||||
Dump(name);
|
||||
className = name;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Derivation::Derivation(
|
||||
Derivation *derivation,
|
||||
char *name
|
||||
):
|
||||
Node(DerivationClassID),
|
||||
classDerivations(this),
|
||||
activeTaps(this)
|
||||
{
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
// Add this derivation as a child of the parent's derivation
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
Dump(name);
|
||||
className = name;
|
||||
Check(derivation);
|
||||
if (derivation)
|
||||
derivation->AppendDerivation(this);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
Derivation::AppendMessageTap(MessageTap* tap)
|
||||
{
|
||||
Check(this);
|
||||
Check(tap);
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// Add the tap to the taps chain, then step through all our derivations,
|
||||
// sending each of them this same method
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
activeTaps.Add(tap);
|
||||
ChainIteratorOf<Derivation*>
|
||||
i(classDerivations);
|
||||
Derivation *derivation;
|
||||
while ((derivation = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
derivation->AppendMessageTap(tap);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Derivation::IsDescendedFrom(Derivation& parent)
|
||||
{
|
||||
Check(this);
|
||||
Check(&parent);
|
||||
|
||||
//
|
||||
//------------------------------
|
||||
// We are descended from ourself
|
||||
//------------------------------
|
||||
//
|
||||
if (&parent == this)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// Find our parent derivation, and ask him
|
||||
// sending each of them this same method
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
PlugIteratorOf<Derivation*> i(this);
|
||||
Derivation *derivation;
|
||||
while ((derivation = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (derivation->GetClassID() == DerivationClassID)
|
||||
{
|
||||
return derivation->IsDescendedFrom(parent);
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Derivation::IsDescendedFrom(const char* parent)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(parent);
|
||||
|
||||
//
|
||||
//------------------------------
|
||||
// We are descended from ourself
|
||||
//------------------------------
|
||||
//
|
||||
Check_Pointer(className);
|
||||
if (!strcmp(className, parent))
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// Find our parent derivation, and ask him
|
||||
// sending each of them this same method
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
PlugIteratorOf<Derivation*> i(this);
|
||||
Derivation *derivation;
|
||||
while ((derivation = i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(derivation);
|
||||
if (derivation->GetClassID() == DerivationClassID)
|
||||
{
|
||||
return derivation->IsDescendedFrom(parent);
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//###################### Receiver::SharedData ##########################
|
||||
//#############################################################################
|
||||
|
||||
Logical
|
||||
Receiver::SharedData::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
# include "receiver.tcp"
|
||||
#endif
|
||||
Reference in New Issue
Block a user