Files
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

298 lines
6.2 KiB
C++

#pragma once
#include "plug.h"
#include "chain.h"
#include "time.h"
#include "config.h"
#if defined(TRACE_ON)
struct TraceSample
{
Scalar sampleFraction;
Word sampleFrame;
Byte traceNumber;
Byte sampleType;
enum Type
{
GoingUp = 0,
GoingDown,
Marker,
IntegerSnapshot,
ScalarSnapshot,
SuspendSampling,
ResumeSampling
};
};
template <class T> struct SnapshotOf : public TraceSample
{
T snapShot;
};
class Trace : public Plug
{
friend class TraceManager;
public:
enum Type
{
BitType,
IntegerType,
ScalarType
};
protected:
static Byte NextTraceID;
const char *traceName;
long lastFrameActivity;
Scalar lastFractionActivity;
Byte traceNumber;
Byte traceType;
Trace(const char* name, Type type);
MemoryStream *GetTraceLog();
void IncrementSampleCount();
virtual void DumpTraceStatus()=0;
virtual void ResetTrace()=0;
#if defined(USE_TIME_ANALYSIS)
virtual void StartTiming()=0;
virtual Scalar CalcuateUsage(long frame, Scalar fraction, double sample_time)=0;
virtual void PrintUsage(Scalar usage);
#endif
};
class BitTrace : public Trace
{
protected:
static Byte NextActiveLine;
Logical traceUp;
double lastUpTime, totalUpTime;
Byte activeLine;
#if defined(USE_ACTIVE_PROFILE)
static void SetLineImplementation(Byte line);
static void ClearLineImplementation(Byte line);
static Logical IsLineValidImplementation(Byte line);
#endif
void DumpTraceStatus();
void ResetTrace();
#if defined(USE_TIME_ANALYSIS)
void StartTiming();
Scalar CalculateUsage(long frame, Scalar fraction, double sample_time);
void PrintUsage(Scalar usage);
#endif
public:
BitTrace(const char *name);
void Set();
void Clear();
double GetLastUpTime()
{
Check(this);
return lastUpTime;
}
double GetTotalUpTime()
{
Check(this);
return totalUpTime;
}
};
template <class T> class TraceOf : public Trace
{
protected:
double weightedSum;
T currentValue;
TraceSample::Type sampleType;
void DumpTraceStatus();
void ResetTrace();
#if defined(USE_TIME_ANALYSIS)
void StartTiming();
Scalar CalculateUsage(long frame, Scalar fraction, double sample_time);
void PrintUsage(Scalar usage);
#endif
public:
TraceOf(const char* name, const T& initial_value, Type trace_type, TraceSample::Type sample_type);
void TakeSnapshot(const T& value);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> TraceOf<T>::TraceOf(const char* name, const T& initial_value, Type trace_type, TraceSample::Type sample_type) : Trace(name, trace_type)
{
currentValue = initial_value;
sampleType = sample_type;
TraceOf<T>::ResetTrace();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> void TraceOf<T>::DumpTraceStatus()
{
Check(this);
DEBUG_STREAM << currentValue << std::flush;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> void TraceOf<T>::ResetTrace()
{
#if defined(USE_TIME_ANALYSIS)
weightedSum = 0.0;
#endif
}
#if defined(USE_TIME_ANALYSIS)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> void TraceOf<T>::StartTiming()
{
Check(this);
weightedSum = 0.0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> Scalar TraceOf<T>::CalculateUsage(long frame, Scalar fraction, double sample_time)
{
double last_part = frame - lastFrameActivity;
last_part += fraction - lastFractionActivity;
weightedSum += last_part * currentValue;
Scalar result = weightedSum / sample_time;
Check_Fpu();
weightedSum = 0.0;
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> void TraceOf<T>::PrintUsage(Scalar usage)
{
Check(this);
DEBUG_STREAM << usage << std::flush;
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
template <class T> void TraceOf<T>::TakeSnapshot(const T& value)
{
Check(this);
#if defined(USE_TIME_ANALYSIS) || defined(USE_TRACE_LOG)
long frame = Now().ticks;
Scalar fraction = Get_Frame_Percent_Used();
#endif
#if defined(USE_TIME_ANALYSIS)
double last_part = frame - lastFrameActivity;
last_part += fraction - lastFractionActivity;
weightedSum += last_part * currentValue;
lastFrameActivity = frame;
lastFractionActivity = fraction;
#endif
currentValue = value;
#if defined(USE_TRACE_LOG)
IncrementSampleCount();
MemoryStream *log = GetTraceLog();
if (log)
{
Check(log);
SnapshotOf<T> *sample = (SnapshotOf<T>*)log->GetPointer();
sample->sampleType = (Byte)sampleType;
sample->traceNumber = traceNumber;
sample->sampleFrame = (Word)frame;
sample->sampleFraction = fraction;
sample->snapShot = currentValue;
log->AdvancePointer(sizeof(*sample));
}
#endif
}
//#######################################################################
//##################### TraceManager ##############################
//#######################################################################
class TraceManager SIGNATURED
{
friend class Trace;
protected:
ChainOf<Trace*> traceChain;
long sampleStartFrame;
Scalar sampleStartFraction;
int actualSampleCount, ignoredSampleCount;
MemoryStream *allocatedTraceLog, *activeTraceLog;
Byte traceCount;
void Add(Trace *trace);
public:
TraceManager();
~TraceManager();
Byte GetTraceCount()
{
Check(this);
return traceCount;
}
void DumpTracesStatus();
void ResetTraces();
#if defined(USE_TIME_ANALYSIS)
void StartTimingAnalysis();
int SnapshotTimingAnalysis(Logical print = false);
#endif
#if defined(USE_TRACE_LOG)
void CreateTraceLog(size_t max_trace_samples, Logical start_sampling);
void SaveTraceLog(const char* filename);
void MarkTraceLog();
void SuspendTraceLogging();
void ResumeTraceLogging();
#endif
Logical TestInstance() const;
};
extern TraceManager trace_manager;
inline MemoryStream* Trace::GetTraceLog()
{
Check(this);
Check(&trace_manager);
return trace_manager.activeTraceLog;
}
inline void Trace::IncrementSampleCount()
{
Check(this);
Check(&trace_manager);
if (!trace_manager.activeTraceLog)
++trace_manager.ignoredSampleCount;
else
++trace_manager.actualSampleCount;
}
# endif