Files
BT412/engine/MUNGA/TREE.cpp
T
arcattackandClaude Opus 4.8 7b7d465e5e 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>
2026-07-05 21:03:40 -05:00

846 lines
16 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "tree.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ TreeNode ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//###########################################################################
// TreeNode
//###########################################################################
//
TreeNode::TreeNode(
Tree *tree,
Plug *plug
):
Link(tree, plug)
{
less = NULL;
greater = NULL;
parent = NULL;
}
//
//###########################################################################
// ~TreeNode
//###########################################################################
//
TreeNode::~TreeNode()
{
Tree *tree = Cast_Object(Tree*, socket);
Check(this);
Check(tree);
//
//-------------------------------------------
// Notify iterators that deletion is occuring
//-------------------------------------------
//
tree->SendIteratorMemo(PlugRemoved, this);
//
//-----------------------------------
// Tell the tree to release this node
//-----------------------------------
//
tree->SeverFromTreeNode(this);
//
//------------------------------------------
// Remove this link from any plug references
//------------------------------------------
//
ReleaseFromPlug();
//
//-------------------------------------------------------------
// Tell the node to release this link. Note that this link
// is not referenced by the plug or the chain at this point in
// time.
//-------------------------------------------------------------
//
if (tree->GetReleaseNode() != NULL)
{
Check(tree->GetReleaseNode());
tree->GetReleaseNode()->ReleaseLinkHandler(tree, plug);
}
}
//
//###########################################################################
// TestInstance
//###########################################################################
//
Logical
TreeNode::TestInstance() const
{
Link::TestInstance();
if (less != NULL)
{
Check_Signature(less);
}
if (greater != NULL)
{
Check_Signature(greater);
}
if (parent != NULL)
{
Check_Signature(parent);
}
return True;
}
//
//###########################################################################
// SetupTreeLinks
//###########################################################################
//
void
TreeNode::SetupTreeLinks(
TreeNode *less,
TreeNode *greater,
TreeNode *parent
)
{
this->less = less;
this->greater = greater;
this->parent = parent;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//###########################################################################
// Tree
//###########################################################################
//
Tree::Tree(
Node *node,
Logical has_unique_entries
):
SortedSocket(node, has_unique_entries)
{
root = NULL;
}
//
//###########################################################################
// ~Tree
//###########################################################################
//
Tree::~Tree()
{
SetReleaseNode(NULL);
while (root != NULL)
{
Unregister_Object(root);
delete root;
}
}
//
//###########################################################################
// TestInstance
//###########################################################################
//
Logical
Tree::TestInstance() const
{
SortedSocket::TestInstance();
//
// Check root if not null
//
if (root != NULL)
{
Check(root);
}
return True;
}
//
//###########################################################################
// AddImplementation
//###########################################################################
//
void
Tree::AddImplementation(
Plug *plug
)
{
AddValueImplementation(plug, NULL);
}
//
//###########################################################################
// AddValueImplementation
//###########################################################################
//
void
Tree::AddValueImplementation(
Plug *plug,
const void *value
)
{
Check(this);
Check(plug);
/*
* Verify that value has not been added
*/
Verify(HasUniqueEntries() ? SearchForValue(value) == NULL : (Logical)True);
/*
* Make new tree node
*/
TreeNode *node;
node = MakeTreeNode(plug, value);
Register_Object(node);
/*
* Add to the tree and send iterators memo to
* update pointers
*/
AddTreeNode(node);
SendIteratorMemo(PlugAdded, node);
}
//
//###########################################################################
// FindImplementation
//###########################################################################
//
Plug*
Tree::FindImplementation(
const void *value
)
{
TreeNode *node;
if ((node = SearchForValue(value)) != NULL)
{
Check(node);
return node->GetPlug();
}
return NULL;
}
//
//###########################################################################
// MakeTreeNode
//###########################################################################
//
TreeNode*
Tree::MakeTreeNode(
Plug*,
const void*
)
{
Fail("Tree::MakeTreeNode - Shoule never reach here");
return NULL;
}
//
//###########################################################################
// CompareTreeNodes
//###########################################################################
//
int
Tree::CompareTreeNodes(
TreeNode*,
TreeNode*
)
{
Fail("Tree::CompareTreeNodes - Shoule never reach here");
return 0;
}
//
//###########################################################################
// CompareValueToTreeNode
//###########################################################################
//
int
Tree::CompareValueToTreeNode(
const void*,
TreeNode*
)
{
Fail("Tree::CompareValueToTreeNode - Shoule never reach here");
return 0;
}
//
//###########################################################################
// AddTreeNode
//###########################################################################
//
void
Tree::AddTreeNode(
TreeNode *newNode
)
{
Check(this);
Check(newNode);
/*
* If root is NULL this is the first item
*/
if (root == NULL)
{
newNode->SetupTreeLinks(NULL, NULL, NULL);
root = newNode;
return;
}
/*
* Search for insertion point
*/
TreeNode *node;
node = root;
while (node != NULL)
{
Check(node);
if (CompareTreeNodes(newNode, node) < 0)
{
if (node->less == NULL)
{
newNode->SetupTreeLinks(NULL, NULL, node);
node->less = newNode;
break;
}
else
node = node->less;
}
else
{
if (node->greater == NULL)
{
newNode->SetupTreeLinks(NULL, NULL, node);
node->greater = newNode;
break;
}
else
node = node->greater;
}
}
}
//
//###########################################################################
// SeverFromTreeNode
//###########################################################################
//
void
Tree::SeverFromTreeNode(
TreeNode *node
)
{
Check(this);
Check(node);
if (node->greater == NULL)
{
if (node->less == NULL)
{
//
//--------------------------------------------------------------------
// The node has no subtrees
//--------------------------------------------------------------------
//
if (node == root)
{
//
// Tree is now empty, set root to null
//
root = NULL;
}
else
{
//
// Set appropiate branch to NULL
//
Check(node->parent);
if (node->parent->less == node)
node->parent->less = NULL;
else
node->parent->greater = NULL;
}
}
else
{
//
//--------------------------------------------------------------------
// The node has a less subtree
//--------------------------------------------------------------------
//
Check(node->less);
if (node == root)
{
//
// Node is root... Set subtree to new root
//
root = node->less;
node->less->parent = NULL;
}
else
{
//
// Node is not root
// Set parents pointer to subtree
//
Check( node->parent );
if (node->parent->less == node)
{
node->parent->less = node->less;
}
else
{
node->parent->greater = node->less;
}
//
// Set subtree parent to node parent
//
node->less->parent = node->parent;
}
}
}
else {
if (node->less == NULL)
{
//
//--------------------------------------------------------------------
// The node has a greater subtree
//--------------------------------------------------------------------
//
Check( node->greater );
if (node == root)
{
//
// Node is root
// Set subtree to new root
//
root = node->greater;
//
// Set new root to have null parent
//
node->greater->parent = NULL;
}
else
{
//
// Node is not root
// Set parents pointer to subtree
//
Check( node->parent );
if (node->parent->less == node)
node->parent->less = node->greater;
else
node->parent->greater = node->greater;
//
// Set subtree parent to node parent
//
node->greater->parent = node->parent;
}
}
else
{
//
//--------------------------------------------------------------------
// The node has lesser and greater sub-trees
//--------------------------------------------------------------------
//
TreeNode *successor;
Check(node->less);
Check(node->greater);
successor = node->greater;
while (successor->less != NULL)
{
successor = successor->less;
Check(successor);
}
//
// Set successor's parent to subtree
//
Check(successor->parent);
if (successor->parent->less == successor)
successor->parent->less = successor->greater;
else
successor->parent->greater = successor->greater;
//
// Set successor's subtree to parent
//
if (successor->greater != NULL)
{
Check(successor->greater);
successor->greater->parent = successor->parent;
}
//
// Place at node
//
successor->parent = node->parent;
successor->less = node->less;
successor->greater = node->greater;
if (root == node)
{
//
// Node was root
//
root = successor;
}
else
{
//
// Set nodes parent to successor
//
Check(successor->parent);
if (successor->parent->less == node)
successor->parent->less = successor;
else
successor->parent->greater = successor;
}
//
// Set subtrees parent to successor
//
if (successor->greater != NULL)
{
Check(successor->greater);
successor->greater->parent = successor;
}
if (successor->less != NULL)
{
Check(successor->less);
successor->less->parent = successor;
}
}
}
}
//
//###########################################################################
// SearchForValue
//###########################################################################
//
TreeNode*
Tree::SearchForValue(
const void *value
)
{
TreeNode *node;
int ret;
node = root;
while (node != NULL)
{
Check(node);
if ((ret = CompareValueToTreeNode(value, node)) == 0)
break;
node = (ret < 0) ? node->less : node->greater;
}
return node;
}
//
//###########################################################################
// TreeIterator
//###########################################################################
//
TreeIterator::TreeIterator(Tree *tree):
SortedIterator(tree)
{
First();
}
//
//###########################################################################
//###########################################################################
//
TreeIterator::~TreeIterator()
{
}
//
//###########################################################################
// TestInstance
//###########################################################################
//
Logical
TreeIterator::TestInstance() const
{
SortedIterator::TestInstance();
if (currentNode != NULL)
{
Check(currentNode);
}
return True;
}
//
//###########################################################################
// First
//###########################################################################
//
void
TreeIterator::First()
{
TreeNode *node;
node = Cast_Object(Tree*, socket)->root;
if (node != NULL)
{
Check(node);
while (node->less != NULL)
{
node = node->less;
Check(node);
}
}
currentNode = node;
}
//
//###########################################################################
// Last
//###########################################################################
//
void
TreeIterator::Last()
{
//
// Should never reach here
//
#ifdef __BCPLUSPLUS__
#pragma warn -ccc
Verify(False);
#pragma warn +ccc
#endif
}
//
//###########################################################################
// Next
//###########################################################################
//
void
TreeIterator::Next()
{
TreeNode *node;
if ((node = currentNode) == NULL)
return;
Check(node);
if (node->greater != NULL)
{
node = node->greater;
Check(node);
while (node->less != NULL)
{
node = node->less;
Check(node);
}
currentNode = node;
return;
}
currentNode = NULL;
while (node->parent != NULL)
{
Check(node->parent);
if (node == node->parent->less)
{
currentNode = node->parent;
return;
}
node = node->parent;
Check(node);
}
}
//
//###########################################################################
// Previous
//###########################################################################
//
void
TreeIterator::Previous()
{
//
// Should never reach here
//
#ifdef __BCPLUSPLUS__
#pragma warn -ccc
Verify(False);
#pragma warn +ccc
#endif
}
#if 0
//
//###########################################################################
// ReadAndNextImplementation
//###########################################################################
//
void
*TreeIterator::ReadAndNextImplementation()
{
void *plug;
if ((plug = GetCurrentImplementation()) != NULL)
{
Next();
}
return plug;
}
#endif
#if 0
//
//###########################################################################
// ReadAndPreviousImplementation
//###########################################################################
//
void
*TreeIterator::ReadAndPreviousImplementation()
{
#ifdef __BCPLUSPLUS__
#pragma warn -ccc
Verify(False);
#pragma warn +ccc
#endif
return(NULL);
}
#endif
//
//###########################################################################
// GetCurrentImplementation
//###########################################################################
//
void
*TreeIterator::GetCurrentImplementation()
{
if (currentNode != NULL)
{
Check(currentNode);
return currentNode->GetPlug();
}
return NULL;
}
//
//###########################################################################
// GetSize
//###########################################################################
//
CollectionSize
TreeIterator::GetSize()
{
TreeIterator iterator(Cast_Object(Tree*, socket));
CollectionSize i = 0;
while (iterator.ReadAndNextImplementation() != NULL)
{
i++;
}
return(i);
}
#if 0
//
//###########################################################################
// GetNthImplementation
//###########################################################################
//
void
*TreeIterator::GetNthImplementation(
CollectionSize index
)
{
CollectionSize i = 0;
void *plug;
First();
while ((plug = GetCurrentImplementation()) != NULL)
{
if (i == index)
return plug;
Next();
i++;
}
return NULL;
}
#endif
//
//###########################################################################
// Remove
//###########################################################################
//
void
TreeIterator::Remove()
{
if (currentNode != NULL)
{
Unregister_Object(currentNode);
delete currentNode;
}
}
//
//###########################################################################
// FindImplementation
//###########################################################################
//
Plug*
TreeIterator::FindImplementation(
const void *value
)
{
TreeNode *node;
if ((node = Cast_Object(Tree*, socket)->SearchForValue(value)) != NULL)
{
Check(node);
return (currentNode = node)->GetPlug();
}
return NULL;
}
//
//###########################################################################
// ReceiveMemo
//###########################################################################
//
void
TreeIterator::ReceiveMemo(
IteratorMemo memo,
void *content
)
{
if (memo == PlugRemoved)
{
if (content == currentNode)
Next();
}
}
#if defined(TEST_CLASS)
# include "tree.tcp"
#endif