Files
BT411/engine/MUNGA_L4/L4RIO.h
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

321 lines
6.1 KiB
C++

#pragma once
#include "l4pcspak.h"
#include "..\munga\notation.h"
#include "..\munga\average.h"
// These are purposely grouped as two parameters in one equate
// (See PCSPAK.HH).
// The standard PC COM ports ALWAYS use these combinations.
//#define RIO_COM1 PCSP_COM1
//#define RIO_COM2 PCSP_COM2
//#define RIO_COM3 PCSP_COM3
//#define RIO_COM4 PCSP_COM4
class FilterChannel SIGNATURED
{
public:
static const char *highName;
static const char *centerName;
static const char *lowName;
static const char *joystickXName;
static const char *joystickYName;
static const char *throttleName;
static const char *leftPedalName;
static const char *rightPedalName;
enum AlignMode { unaligned, normal };
enum PolarMode { unipolar, bipolar };
FilterChannel();
FilterChannel(
NotationFile *init_file,
const char *page_name,
int default_min, int default_max
);
FilterChannel(
NotationFile *init_file,
const char *page_name,
int default_min, int default_center, int default_max
);
~FilterChannel();
void
SetPolarity(PolarMode newPolarity);
void
SetDeadBand(Scalar amount_of_deadband);
virtual void
BeginAlignment();
virtual void
EndAlignment(NotationFile *init_file=NULL);
virtual Scalar
Update(int value);
Logical
TestInstance() const;
protected:
void
CalculateDeadBands();
const char *pageName;
PolarMode polarity;
AlignMode mode;
int previousValue, min, max, center;
int lowerRange, lowerDeadband;
int upperRange, upperDeadband;
Scalar deadbandScalar;
Logical valuesFromFile;
AverageOf<int> average;
};
class RIO;
class Ranger SIGNATURED
{
friend class RIO;
protected:
Ranger(
const char *page_name,
int default_min,
int default_max,
Scalar deadband_scalar
);
~Ranger();
void
ForceToZero();
void
SetDeadBand(Scalar amount_of_deadband);
Scalar
Update(int input);
Logical
TestInstance() const;
void
Statistics(NotationFile *stat_file);
const char
*pageName;
Logical
sampledInputFlag;
int
offset,
hardwareMinimum,
hardwareMaximum,
hardwareRange,
deadbandInteger,
highestInput,
lowestInput;
};
class RIO :
public PCSerialPacket
{
protected:
enum RIOCommand{
CheckRequest=0x80,
VersionRequest,
AnalogRequest,
ResetRequest,
LampRequest,
CheckReply,
VersionReply,
AnalogReply,
ButtonPressed,
ButtonReleased,
KeyPressed,
KeyReleased,
TestModeChange
};
public:
enum RIOStatusType {
BoardOk=0, BoardMissing=1, BoardBad=2,
LampBad=3,
RestartCount=4, AbandonCount=5, FullBufferCount=6
};
enum LampState{
solid=0, flashSlow=1, flashMed=2, flashFast=3,
state1Off=0x00, state1Dim=0x04, state1Bright=0x0C,
state2Off=0x00, state2Dim=0x10, state2Bright=0x30,
};
enum RIOEventType {
ButtonPressedEvent,
ButtonReleasedEvent,
KeyEvent,
AnalogEvent,
VersionEvent
};
struct RIOKeyPair
{
int Unit;
int Key;
};
struct RIOEvent
{
RIOEventType Type;
union
{
int Unit;
RIOKeyPair Keyboard;
}Data;
};
//Win32 Serial support: ADB 02/13/07
//RIO(Word port, Word intNum, Logical perform_tests = True);
RIO(const char* port, Logical perform_tests = True);
~RIO();
Logical
TestInstance() const;
Logical
GetNextEvent(RIOEvent *destinationPointer);
void
ForceCenterJoystick(),
SetJoystickDeadBand(Scalar dead_band),
SetThrottleDeadBand(Scalar dead_band),
SetPedalsDeadBand(Scalar dead_band);
void
RequestCheck(),
RequestVersion(),
RequestAnalogUpdate();
void
GeneralReset(),
ResetThrottle(),
ResetLeftPedal(),
ResetRightPedal(),
ResetVerticalJoystick(),
ResetHorizontalJoystick();
void
SetLamp(int lampNumber, int state);
void
TestCheckReply(int type, int location)
{
RIO::reply_check_string[1] = (Byte) (type & 0x7F);
RIO::reply_check_string[2] = (Byte) (location & 0x7F);
SendPacket((Byte *)reply_check_string);
}
void
TestVersionReply(int major, int minor)
{
RIO::reply_version_string[1] = (Byte) (major & 0x7F);
RIO::reply_version_string[2] = (Byte) (minor & 0x7F);
SendPacket((Byte *)reply_version_string);
}
void
TestAnalogReply()
{
SendPacket((Byte *)reply_analog_string);
}
void
TestButtonPressed(int button)
{
RIO::reply_button_press_string[1] = (Byte) (button & 0x7F);
SendPacket((Byte *)reply_button_press_string);
}
void
TestButtonReleased(int button)
{
RIO::reply_button_release_string[1] = (Byte) (button & 0x7F);
SendPacket((Byte *)reply_button_release_string);
}
void
TestKeyPressed(int board, int key)
{
RIO::reply_key_press_string[1] = (Byte) (board & 0x7F);
RIO::reply_key_press_string[2] = (Byte) (key & 0x7F);
SendPacket((Byte *)reply_key_press_string);
}
void
TestKeyReleased(int board, int key)
{
RIO::reply_key_release_string[1] = (Byte) (board & 0x7F);
RIO::reply_key_release_string[2] = (Byte) (key & 0x7F);
SendPacket((Byte *)reply_key_release_string);
}
void
TestEnterTestMode()
{SendPacket((Byte *)reply_test_enter_string);}
void
TestExitTestMode()
{SendPacket((Byte *)reply_test_exit_string);}
int
ReceiveQueueCount()
{ return PCSerialPacket::ReceiveQueueCount(); }
int
TransmitQueueCount()
{ return PCSerialPacket::TransmitQueueCount(); }
int
TestModeActive;
Scalar
Throttle, LeftPedal, RightPedal, JoystickX, JoystickY;
int
MajorRevision, MinorRevision;
int remoteRetryCount;
int remoteAbandonCount;
int remoteFullBufferCount;
int lineErrorCount;
int abandonCount;
int overrunCount;
int discardCount; // used by BeginAnalogCalibration()
protected:
void
OpenFailureFile();
void
CloseFailureFile();
void
CheckErrors();
Logical
operational;
Ranger
*leftPedalRanger, *rightPedalRanger;
Ranger
*throttleRanger;
Ranger
*joystickXRanger, *joystickYRanger;
NotationFile
*failureFile;
int
failureFileOpenCount;
static Byte reply_check_string[];
static Byte reply_version_string[];
static Byte reply_analog_string[];
static Byte reply_button_press_string[];
static Byte reply_button_release_string[];
static Byte reply_key_press_string[];
static Byte reply_key_release_string[];
static Byte reply_test_enter_string[];
static Byte reply_test_exit_string[];
};