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

177 lines
4.6 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "random.h"
int RandomGenerator::Numbers[250];
int RandomGenerator::Index = -1;
RandomGenerator Random;
//
//###########################################################################
//###########################################################################
//
void RandomGenerator::Init()
{
int i, msb, mask;
//
//--------------------------------------------------------------------
// After making sure the table is built only once, initialize the
// Borland C++ random numbers with the low word of the current time in
// milliseconds, and initialize the index pointer
//--------------------------------------------------------------------
//
char *seed_spec = getenv("RANDOM");
unsigned seed;
if (seed_spec)
{
seed = (unsigned)atol(seed_spec);
}
else
{
seed = (unsigned)time(NULL);
}
#if defined(TEST_CLASS)
cout << "Random Seed = " << seed << endl;
#endif
srand(seed);
Index = 0;
//
//------------------------------------------------------------------
// Load the random number buffer, then go thru and set the sign bit
// randomly, increasing the range of random numbers from 0..32767 to
// 0..65535
//------------------------------------------------------------------
//
for (i=0; i<250; i++)
{
Numbers[i] = rand();
}
//
//--------------------------------------------------------------------
// In order to preserve a good random number mix for the XOR function,
// mask and set the bits of 16 words in a descending manner as in
// 1xx..., 01xx..., 001xx..., 0001xx..., ...
//--------------------------------------------------------------------
//
mask = RAND_MAX >> 1;
msb = mask + 1;
int rand_size;
for (rand_size=0; !(msb&(1<<rand_size)); ++rand_size);
i = 14;
while (rand_size--)
{
Verify(i<ELEMENTS(Numbers));
Numbers[i] &= mask;
Numbers[i] |= msb;
mask >>= 1;
msb >>= 1;
i += 11;
}
}
//
//###########################################################################
//###########################################################################
//
int RandomGenerator::GetRandomInt()
{
int indent, result;
//
//------------------------------------------------------------------
// The random number generated will be the result of an XOR with the
// element 103 positions further (wrapping around) in the table
//------------------------------------------------------------------
//
indent = (Index>=147)?Index-147:Index+103;
result = Numbers[Index]^Numbers[indent];
//
//------------------------------------------------------------------------
// Replace the current random number with the new one generated, increment
// the buffer index pointer, and return the number
//------------------------------------------------------------------------
//
Numbers[Index] = result;
if (++Index == ELEMENTS(Numbers))
Index=0;
return result;
}
//
//###########################################################################
//###########################################################################
//
RandomGenerator::operator Scalar()
{
Scalar result;
result = GetRandomInt();
result /= (float)(RAND_MAX + 1);
return result;
}
//
//###########################################################################
//###########################################################################
//
int RandomGenerator::operator ()(int range)
{
int result, max;
max = RAND_MAX - ((RAND_MAX + 1)%range);
do
{
result = GetRandomInt();
} while (result>max);
return result%range;
}
//
//###########################################################################
//###########################################################################
//
Die::Die(int n)
{
dieSides = (n>1)?n:2;
highestRandom = RAND_MAX - ((RAND_MAX+1)%dieSides);
}
//
//###########################################################################
//###########################################################################
//
Die::operator int()
{
int result;
//
//------------------------------------------------------------------------
// In order to not skew the probabilities to the low numbers, make sure
// that the random # used is not greater than the limit determined for the
// number of sides.
//------------------------------------------------------------------------
//
do
{
result = Random.GetInt();
} while (result>highestRandom);
//
//-------------------------------------------------------------------
// Once the base random number is determined, do modulus division and
// increment by 1 to map into the die range.
//-------------------------------------------------------------------
//
return result % dieSides + 1;
}
#if defined(TEST_CLASS)
#include "random.tcp"
#endif