BT410 5.3.120: the mech ducks -- the master perf's duck driver landed whole, and the collision cylinder breathes with it
The first block reconstructed from the isolated master performance (@004a9f61..@004aa155, instruction-level read of the ndisasm listing), and with it the Mech's authentic message roster straight from the binary's own handler table: RealMaxSpeed 0x15, BalanceCoolant 0x16, SetBurningState 0x17, ClearBurningState 0x18, EjectPilot 0x19, DuckRequest 0x1A -- the enum now exists in MECH.HPP with those names. The system end to end: a DuckRequest message (@0049fa00) latches ONE evaluation -- the latch is consumed every master frame and cleared by Reset. The phase machine reads the raw simulation state, the mapper's duck button cell and the analog demand (deadzone 1e-4): from gait 0/4 it arms the sqd clip on the LEG channel only (slot 2 -- the slot map, not the enum's walk names), from the ducked hold it arms squ (slot 3), and a mech that starts limping while ducked is stood up by force. The collision-volume alarm (level 1 standing / 0 ducked, guarded by the authentic "Whoa! Bad Collision Volume State!") swaps the collision template's maxY -- the box TOP; the ground probe's minY is untouched -- between the ctor-captured height and 0.6x it (the double at @004a2d38). duckState publishes for the cockpit's crouch selector. Live-verified end to end: BT_FORCE_DUCK (an authentic press every 4s on its own clock) cycles press -> sqd -> volume 9.91->5.94 -> ducked hold -> press -> squ -> standing, continuously, no faults. En route the test machine-checked three neighbors for free: the squat clips resolve and play at the idle rate, the clip-finish transitions for slots 2/3 fire, and the machine correctly REFUSES to duck while walking (legState 5). Deferred, recorded: the per-arm MarkUpdate masks (8, 1) ride the still-empty ForceUpdate (the MP update-record feed), and the mapper duck cell's streamed binding id awaits a BT_MAP_LOG audit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
|||||||
|
# pod_render_norio.conf -- pod_render_rec with the RIO serial port OFF.
|
||||||
|
#
|
||||||
|
# The emulator log shows a steady stream of serial1 RX OVERRUN errors on
|
||||||
|
# the RIO pipe, and controls post their events at HighEventPriority
|
||||||
|
# UNCONDITIONALLY (CONTROLS.HPP:250) -- so a chattering RIO port would
|
||||||
|
# flood a priority the background pump always serves first, starving the
|
||||||
|
# priority-0 renderer events the load gate waits on. This conf tests that
|
||||||
|
# by removing the port entirely. Everything else is identical to the rec
|
||||||
|
# conf, so a launch here and a hang there isolates the RIO.
|
||||||
|
#
|
||||||
|
[sdl]
|
||||||
|
output=opengl
|
||||||
|
# higher,higher not highest: HIGH_PRIORITY_CLASS starved the host desktop;
|
||||||
|
# with the retry patches a rare dropout self-recovers (see gauge_rio.conf).
|
||||||
|
priority=higher,higher
|
||||||
|
[dosbox]
|
||||||
|
memsize=32
|
||||||
|
machine=svga_s3
|
||||||
|
[cpu]
|
||||||
|
core=dynamic
|
||||||
|
cputype=pentium
|
||||||
|
cycles=max
|
||||||
|
[sblaster]
|
||||||
|
sbtype=sb16
|
||||||
|
sbbase=220
|
||||||
|
irq=5
|
||||||
|
dma=1
|
||||||
|
hdma=5
|
||||||
|
[mixer]
|
||||||
|
# match the EMU8000s' native rate (no resample) and buffer ~60ms so brief
|
||||||
|
# emulation-thread stalls (RIO retry recovery) don't audibly chop
|
||||||
|
rate=44100
|
||||||
|
blocksize=1024
|
||||||
|
prebuffer=60
|
||||||
|
[serial]
|
||||||
|
# RIO on COM1 with the low-latency options (rxpollus/rxburst) so the board's
|
||||||
|
# few-ms ACK deadline is met; plasma display on COM2 (real pod has both).
|
||||||
|
# VWE fork namedpipe backend (com0com/realport retired -- COM1/COM2 gone):
|
||||||
|
# DOSBox = pipe client (retry), vRIO/vPLASMA apps = servers; an unconnected
|
||||||
|
# pipe behaves as an unplugged cable so the mission still runs. serialnamedpipe.h
|
||||||
|
serial1=disabled
|
||||||
|
serial2=namedpipe pipe:vplasma
|
||||||
|
# live UNBUFFERED game output: DOS char devices are not buffered, so
|
||||||
|
# redirecting stdout to COM3 lands every line immediately. A normal
|
||||||
|
# '> file' redirect stays 0 bytes until the process exits, which hides
|
||||||
|
# all progress on a run that does NOT crash.
|
||||||
|
serial3=file file:C:\VWE\TeslaRel410\emulator\render-bridge\podlog.txt
|
||||||
|
[autoexec]
|
||||||
|
mount c "C:\VWE\TeslaRel410\ALPHA_1"
|
||||||
|
c:
|
||||||
|
cd \REL410\BT
|
||||||
|
set VIDEOFORMAT=svga
|
||||||
|
rem production pod card init (PARAMETR.BAT:181-186): DIAGNOSE + AWEUTIL per
|
||||||
|
rem card -- AWEUTIL /S does the EMU8000 bring-up and DRAM detect the HMI SOS
|
||||||
|
rem driver relies on; skipping it left the cards uninitialized (silent).
|
||||||
|
rem aweutil /s SKIPPED for now: it verifies the AWE32 GM ROM, which the
|
||||||
|
rem emulated cards lack (hangs in a retry loop) -- restore once the ROM is
|
||||||
|
rem dumped from a real card. diagnose /s kept (passes, sets mixer config).
|
||||||
|
set BLASTER=A220 I5 D1 H5 P330 T6
|
||||||
|
c:\sb16\diagnose /s
|
||||||
|
set BLASTER=A240 I7 D3 H6 P300 T6
|
||||||
|
c:\sb16\diagnose /s
|
||||||
|
set BLASTER=A220 I5 D1 H5 P330 T6
|
||||||
|
set TEMP=c:\
|
||||||
|
rem arena1 city mission (TESTARN.EGG: map=arena1, time=day) with the RIO
|
||||||
|
rem attached; stdout redirected so mission-load progress survives kills.
|
||||||
|
set BT_JOINTS=1
|
||||||
|
set L4VIEWEXT=1
|
||||||
|
set BT_STACK_LOG=1
|
||||||
|
set BT_MECH_LOG=1
|
||||||
|
set BT_FORCE_DUCK=1
|
||||||
|
set BT_GAUGE_LOG=1
|
||||||
|
set BT_FORCE_THROTTLE=0
|
||||||
|
set BT_FORCE_TURN=0
|
||||||
|
set HEAPSIZE=15000000
|
||||||
|
set L4GAUGE=640x480x16
|
||||||
|
call setenv.bat r s n p
|
||||||
|
32rtm.exe -x
|
||||||
|
BTL4REC.EXE -egg testarn.egg > COM3
|
||||||
|
|
||||||
|
echo GAME-RC=%errorlevel% >> RC.TXT
|
||||||
|
32rtm.exe -u
|
||||||
|
echo ALPHA1-RUN-DONE
|
||||||
|
pause
|
||||||
|
|
||||||
@@ -86,7 +86,8 @@ Derivation
|
|||||||
const Receiver::HandlerEntry
|
const Receiver::HandlerEntry
|
||||||
Mech::MessageHandlerEntries[] =
|
Mech::MessageHandlerEntries[] =
|
||||||
{
|
{
|
||||||
MESSAGE_ENTRY(Mech, TakeDamage)
|
MESSAGE_ENTRY(Mech, TakeDamage),
|
||||||
|
MESSAGE_ENTRY(Mech, DuckRequest)
|
||||||
};
|
};
|
||||||
|
|
||||||
Mech::MessageHandlerSet
|
Mech::MessageHandlerSet
|
||||||
@@ -292,6 +293,25 @@ Mech::Mech(
|
|||||||
radarLinearPosition = &localOrigin.linearPosition;
|
radarLinearPosition = &localOrigin.linearPosition;
|
||||||
radarAngularPosition = &localOrigin.angularPosition;
|
radarAngularPosition = &localOrigin.angularPosition;
|
||||||
duckState = 0;
|
duckState = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The duck system's rest state (binary ctor tail @004a1674: the volume
|
||||||
|
// alarm at +0x4c4 initialises to level 1 = STANDING, and the two
|
||||||
|
// cylinder heights capture template maxY and 0.6 x it -- the heights
|
||||||
|
// are seeded after the collision template resolves, below).
|
||||||
|
//
|
||||||
|
duckRequestLatch = 0;
|
||||||
|
duckPhaseRequest = 0;
|
||||||
|
duckDemand = 0.0f;
|
||||||
|
collisionVolumeState.Initialize(2);
|
||||||
|
collisionVolumeState.SetLevel(1);
|
||||||
|
standingVolumeHeight = 0.0f;
|
||||||
|
duckedVolumeHeight = 0.0f;
|
||||||
|
if (collisionTemplate != NULL)
|
||||||
|
{
|
||||||
|
standingVolumeHeight = collisionTemplate->maxY;
|
||||||
|
duckedVolumeHeight = 0.6f * standingVolumeHeight;
|
||||||
|
}
|
||||||
unstablePercentage = 0.0f; // staged: no instability model yet
|
unstablePercentage = 0.0f; // staged: no instability model yet
|
||||||
collisionSpeed = 0.0f; // staged: audio watcher set (see MECH.HPP)
|
collisionSpeed = 0.0f; // staged: audio watcher set (see MECH.HPP)
|
||||||
distanceToMissile = 0.0f;
|
distanceToMissile = 0.0f;
|
||||||
@@ -810,6 +830,50 @@ Logical
|
|||||||
vehicle->GetSimulationState() == 9;
|
vehicle->GetSimulationState() == 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// DuckRequestMessageHandler -- binary @0049fa00 (authentic name "DuckRequest"
|
||||||
|
// from the handler table @0x10bc7c). A positive request latches one duck
|
||||||
|
// evaluation for the next master frame; the frame consumes the latch either
|
||||||
|
// way.
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
void
|
||||||
|
Mech::DuckRequestMessageHandler(Receiver::Message *message)
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
Check_Pointer(message);
|
||||||
|
|
||||||
|
if (((int *)(message + 1))[0] > 0)
|
||||||
|
{
|
||||||
|
duckRequestLatch = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// The collision-volume swap (binaries @004ac04c / @004ac064): write the
|
||||||
|
// template's maxY -- the box TOP; the ground probe's minY is untouched.
|
||||||
|
// Level 1 (standing) restores the captured height; level 0 (ducked) the
|
||||||
|
// 0.6x height.
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
void
|
||||||
|
Mech::SetStandingCollisionVolume()
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
Check(collisionTemplate);
|
||||||
|
collisionTemplate->maxY = standingVolumeHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mech::SetDuckedCollisionVolume()
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
Check(collisionTemplate);
|
||||||
|
collisionTemplate->maxY = duckedVolumeHeight;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//#############################################################################
|
//#############################################################################
|
||||||
// TakeDamageMessageHandler -- the Mech override of the Entity damage entry
|
// TakeDamageMessageHandler -- the Mech override of the Entity damage entry
|
||||||
@@ -1177,6 +1241,12 @@ void
|
|||||||
void
|
void
|
||||||
Mech::Reset(const Origin &origin, Logical full_reset)
|
Mech::Reset(const Origin &origin, Logical full_reset)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// The binary Reset (@0049fb74) drops any pending duck latch with the
|
||||||
|
// rest of the per-life state.
|
||||||
|
//
|
||||||
|
duckRequestLatch = 0;
|
||||||
|
|
||||||
Check(this);
|
Check(this);
|
||||||
|
|
||||||
localOrigin = origin;
|
localOrigin = origin;
|
||||||
@@ -1619,6 +1689,44 @@ void
|
|||||||
//
|
//
|
||||||
legResetLatch = 0;
|
legResetLatch = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// BT_FORCE_DUCK=1: one authentic duck press every ~4s on its own
|
||||||
|
// clock (independent of the one-shot button harness below) -- the
|
||||||
|
// DuckRequest message, plus the held cell and analog demand every
|
||||||
|
// frame. Press one ducks, the next (from the hold) stands: the
|
||||||
|
// full-machine cycle soak.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
static int s_forceDuck = -1;
|
||||||
|
static Scalar s_duckClock = 0.0f;
|
||||||
|
if (s_forceDuck < 0)
|
||||||
|
{
|
||||||
|
s_forceDuck = (getenv("BT_FORCE_DUCK") != NULL) ? 1 : 0;
|
||||||
|
}
|
||||||
|
if (s_forceDuck)
|
||||||
|
{
|
||||||
|
MechControlsMapper
|
||||||
|
*pulse_mapper = (MechControlsMapper *)subsystemArray[0];
|
||||||
|
if (pulse_mapper != NULL)
|
||||||
|
{
|
||||||
|
pulse_mapper->duckCommand = 1;
|
||||||
|
}
|
||||||
|
duckDemand = 1.0f;
|
||||||
|
s_duckClock += time_slice;
|
||||||
|
if (s_duckClock >= 4.0f)
|
||||||
|
{
|
||||||
|
s_duckClock = 0.0f;
|
||||||
|
ReceiverDataMessageOf<int>
|
||||||
|
duck_press(
|
||||||
|
Mech::DuckRequestMessageID,
|
||||||
|
sizeof(ReceiverDataMessageOf<int>),
|
||||||
|
1);
|
||||||
|
Dispatch(&duck_press);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (limping)
|
if (limping)
|
||||||
{
|
{
|
||||||
AdvanceLegAnimationGimp(time_slice);
|
AdvanceLegAnimationGimp(time_slice);
|
||||||
@@ -1641,6 +1749,150 @@ void
|
|||||||
((Gyroscope *)gyroSubsystem)->WriteMechJoint();
|
((Gyroscope *)gyroSubsystem)->WriteMechJoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// THE DUCK DRIVER (master perf @004a9f61..@004aa155, disasm-decoded).
|
||||||
|
//
|
||||||
|
// Phase pick, every frame: not standing (raw state != 0) or duck button
|
||||||
|
// released -> no request. Standing with the button held: from gait
|
||||||
|
// state 0/4 (stand / turn-in-place), request duck-DOWN while the analog
|
||||||
|
// demand clears the 1e-4 deadzone; from gait state 1 (ducked hold),
|
||||||
|
// request duck-UP; anything else, none.
|
||||||
|
//
|
||||||
|
// The arms fire only on a DuckRequest-latched frame of a squat-capable
|
||||||
|
// mech, bind the LEG channel only (squat is a leg figure), and set the
|
||||||
|
// volume alarm: down -> level 0 (ducked), up -> level 1 (standing).
|
||||||
|
// The latch is consumed unconditionally. A mech that STARTS LIMPING
|
||||||
|
// while ducked is stood up by force (modes 3/4 with gait state 1).
|
||||||
|
// On a volume-alarm edge the collision template's top swaps between
|
||||||
|
// the captured heights; any other level is the authentic
|
||||||
|
// "Whoa! Bad Collision Volume State!" Fail. The dirty marks (binary
|
||||||
|
// MarkUpdate(8)+MarkUpdate(1) per arm) ride ForceUpdate -- still a
|
||||||
|
// no-op here until the update-record feed lands.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
int
|
||||||
|
raw_mode = (int)GetSimulationState();
|
||||||
|
//
|
||||||
|
// The mapper lives in roster slot 0 (the binary caches it at
|
||||||
|
// mech+0x190; our tree resolves the same object through the roster).
|
||||||
|
//
|
||||||
|
MechControlsMapper
|
||||||
|
*duck_mapper = (MechControlsMapper *)subsystemArray[0];
|
||||||
|
int
|
||||||
|
duck_held =
|
||||||
|
(duck_mapper != NULL && duck_mapper->DuckCommand() != 0);
|
||||||
|
|
||||||
|
if (raw_mode != 0 || !duck_held)
|
||||||
|
{
|
||||||
|
duckPhaseRequest = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int
|
||||||
|
leg_state = (int)legStateAlarm.GetLevel();
|
||||||
|
if (leg_state == 0 || leg_state == 4)
|
||||||
|
{
|
||||||
|
duckPhaseRequest =
|
||||||
|
(duckDemand <= 0.0001f && duckDemand >= -0.0001f) ? 0 : 1;
|
||||||
|
}
|
||||||
|
else if (leg_state == 1)
|
||||||
|
{
|
||||||
|
duckPhaseRequest = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
duckPhaseRequest = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
static int s_duckEvalLog = -1;
|
||||||
|
if (s_duckEvalLog < 0)
|
||||||
|
{
|
||||||
|
s_duckEvalLog = (getenv("BT_MECH_LOG") != NULL);
|
||||||
|
}
|
||||||
|
if (s_duckEvalLog && duckRequestLatch != 0)
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[duck] eval mode=" << raw_mode
|
||||||
|
<< " held=" << duck_held
|
||||||
|
<< " leg=" << legStateAlarm.GetLevel()
|
||||||
|
<< " phase=" << duckPhaseRequest
|
||||||
|
<< " capable=" << squatCapable << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duckRequestLatch != 0 && squatCapable != 0)
|
||||||
|
{
|
||||||
|
if (duckPhaseRequest == 1)
|
||||||
|
{
|
||||||
|
SetLegAnimation(2); // the sqd (squat-down) clip slot -- the
|
||||||
|
// SLOT map diverges from the enum's walk
|
||||||
|
// names here (MECH2.NOTES.md)
|
||||||
|
ForceUpdate(8);
|
||||||
|
ForceUpdate(1);
|
||||||
|
collisionVolumeState.SetLevel(0);
|
||||||
|
}
|
||||||
|
else if (duckPhaseRequest == 2)
|
||||||
|
{
|
||||||
|
SetLegAnimation(3); // the squ (squat-up) clip slot
|
||||||
|
ForceUpdate(8);
|
||||||
|
ForceUpdate(1);
|
||||||
|
collisionVolumeState.SetLevel(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
duckRequestLatch = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Limping stands you up (modes 3/4 with the legs still in the
|
||||||
|
// ducked hold).
|
||||||
|
//
|
||||||
|
if (
|
||||||
|
(raw_mode == 3 || raw_mode == 4) &&
|
||||||
|
(int)legStateAlarm.GetLevel() == 1
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SetLegAnimation(3); // squ -- forced stand-up
|
||||||
|
ForceUpdate(8);
|
||||||
|
ForceUpdate(1);
|
||||||
|
collisionVolumeState.SetLevel(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// The volume swap on an alarm edge, and the DuckState publish.
|
||||||
|
//
|
||||||
|
if (collisionVolumeState.GetState() != collisionVolumeState.GetOldState())
|
||||||
|
{
|
||||||
|
static int s_duckLog = -1;
|
||||||
|
if (s_duckLog < 0)
|
||||||
|
{
|
||||||
|
s_duckLog = (getenv("BT_MECH_LOG") != NULL);
|
||||||
|
}
|
||||||
|
if (s_duckLog)
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[duck] volume level "
|
||||||
|
<< collisionVolumeState.GetOldState() << " -> "
|
||||||
|
<< collisionVolumeState.GetState()
|
||||||
|
<< " legState=" << legStateAlarm.GetLevel()
|
||||||
|
<< " maxY " << standingVolumeHeight
|
||||||
|
<< "/" << duckedVolumeHeight << endl;
|
||||||
|
}
|
||||||
|
switch (collisionVolumeState.GetLevel())
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
SetStandingCollisionVolume();
|
||||||
|
duckState = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
SetDuckedCollisionVolume();
|
||||||
|
duckState = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Fail("Whoa! Bad Collision Volume State!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collisionVolumeState.SetLevel(collisionVolumeState.GetLevel());
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// THE TURN-IN-PLACE DISPATCHER (master perf @0x4aa505-0x4aa588, decoded
|
// THE TURN-IN-PLACE DISPATCHER (master perf @0x4aa505-0x4aa588, decoded
|
||||||
// from raw disasm -- Ghidra never decompiled the function). From
|
// from raw disasm -- Ghidra never decompiled the function). From
|
||||||
|
|||||||
@@ -221,6 +221,23 @@
|
|||||||
class Mech:
|
class Mech:
|
||||||
public JointedMover
|
public JointedMover
|
||||||
{
|
{
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Message Support -- the authentic roster, read from the binary's own
|
||||||
|
// handler table (ids and NAME STRINGS live at 0x10bbf0../0x50c146..):
|
||||||
|
// 0x12 TakeDamage (Entity overlay), 0x14 PlayerLink (Entity overlay),
|
||||||
|
// then the mech's own block from Entity::NextMessageID.
|
||||||
|
//
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
RealMaxSpeedMessageID = Entity::NextMessageID, // 0x15 @0049f604
|
||||||
|
BalanceCoolantMessageID, // 0x16 @0049f728
|
||||||
|
SetBurningStateMessageID, // 0x17 @0049f674
|
||||||
|
ClearBurningStateMessageID, // 0x18 @0049f700
|
||||||
|
EjectPilotMessageID, // 0x19 @0049f854
|
||||||
|
DuckRequestMessageID, // 0x1A @0049fa00
|
||||||
|
NextMessageID
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// The per-zone damage code walks the roster / segment table / alarms
|
// The per-zone damage code walks the roster / segment table / alarms
|
||||||
// directly (the 1995 arrangement, mirrored by the reconstruction).
|
// directly (the 1995 arrangement, mirrored by the reconstruction).
|
||||||
@@ -885,6 +902,41 @@
|
|||||||
Point3D *radarLinearPosition;
|
Point3D *radarLinearPosition;
|
||||||
Quaternion *radarAngularPosition;
|
Quaternion *radarAngularPosition;
|
||||||
int duckState;
|
int duckState;
|
||||||
|
|
||||||
|
//
|
||||||
|
// THE DUCK SYSTEM (master perf @004a9f61..@004aa155, disasm-decoded).
|
||||||
|
//
|
||||||
|
// duckRequestLatch (+0x398) ONE-SHOT: set by the DuckRequest
|
||||||
|
// message handler (@0049fa00, request > 0), consumed -- and
|
||||||
|
// CLEARED -- every master frame after the arm check; also
|
||||||
|
// cleared by Reset. Only a latched frame may bind squat clips.
|
||||||
|
// duckPhaseRequest (+0x3f8) 0 none / 1 duck-down / 2 duck-up,
|
||||||
|
// recomputed every frame from the raw simulation state, the
|
||||||
|
// mapper's duck button cell, the leg gait state and the duck
|
||||||
|
// analog demand (deadzone 1e-4 @0x4ab16c).
|
||||||
|
// duckDemand (+0x79c) the analog crouch input.
|
||||||
|
// collisionVolumeState (+0x4c4) the volume alarm: level 1 =
|
||||||
|
// STANDING, 0 = DUCKED. On an edge the collision template's
|
||||||
|
// maxY (BoxedSolid +0xc -- the box TOP; the ground probe's
|
||||||
|
// minY is untouched) swaps between the two ctor-captured
|
||||||
|
// heights; any other level Fails ("Whoa! Bad Collision
|
||||||
|
// Volume State!", MECH4.CPP line 417).
|
||||||
|
// standing/duckedVolumeHeight (+0x518/+0x51c) captured at ctor
|
||||||
|
// time: template maxY, and 0.6 x it (the double @004a2d38).
|
||||||
|
//
|
||||||
|
int duckRequestLatch;
|
||||||
|
int duckPhaseRequest;
|
||||||
|
Scalar duckDemand;
|
||||||
|
AlarmIndicator collisionVolumeState;
|
||||||
|
Scalar standingVolumeHeight;
|
||||||
|
Scalar duckedVolumeHeight;
|
||||||
|
|
||||||
|
void
|
||||||
|
DuckRequestMessageHandler(Receiver::Message *message);
|
||||||
|
void
|
||||||
|
SetStandingCollisionVolume(); // binary @004ac04c... see .CPP
|
||||||
|
void
|
||||||
|
SetDuckedCollisionVolume();
|
||||||
//
|
//
|
||||||
// STAGED VALUE (the instability model is not reconstructed).
|
// STAGED VALUE (the instability model is not reconstructed).
|
||||||
// The mech streams the authored unstable* effect constants in its
|
// The mech streams the authored unstable* effect constants in its
|
||||||
|
|||||||
@@ -66,6 +66,11 @@
|
|||||||
void
|
void
|
||||||
Mech::SetLegAnimation(int state)
|
Mech::SetLegAnimation(int state)
|
||||||
{
|
{
|
||||||
|
if ((state == 2 || state == 3) && getenv("BT_MECH_LOG"))
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[duck] arm slot " << state
|
||||||
|
<< " clip=" << animationClips[state] << endl;
|
||||||
|
}
|
||||||
Check(this);
|
Check(this);
|
||||||
//
|
//
|
||||||
// Bounded by the SLOT count, not the name count: slot 0x20 is the
|
// Bounded by the SLOT count, not the name count: slot 0x20 is the
|
||||||
@@ -192,6 +197,10 @@ Scalar
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
if (getenv("BT_MECH_LOG"))
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[duck] sqd finished -> ducked hold" << endl;
|
||||||
|
}
|
||||||
mech->legStateAlarm.SetLevel(1);
|
mech->legStateAlarm.SetLevel(1);
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
|
|||||||
@@ -86,8 +86,24 @@ per contact by `Mover::ProcessCollisionList`. The decomp
|
|||||||
matching our Simulate's structure and locating every staged gap:
|
matching our Simulate's structure and locating every staged gap:
|
||||||
1. controls/demand intake (mech.cpp helpers 0x4a4eab/0x4a4ee9/0x4a4f9e)
|
1. controls/demand intake (mech.cpp helpers 0x4a4eab/0x4a4ee9/0x4a4f9e)
|
||||||
2. three cerr+SetLevel triplets — illegal-state alarm guards
|
2. three cerr+SetLevel triplets — illegal-state alarm guards
|
||||||
3. **THE DUCK DRIVER**: three arms of {mech2 SetAnim 0x4a7fc4,
|
3. **THE DUCK DRIVER** — DECODED + LANDED 5.3.120, live-verified
|
||||||
MarkUpdate ×2, AlarmIndicator::SetLevel} — duck down/hold/up
|
(BT_FORCE_DUCK cycles down/hold/up continuously on the rig). The
|
||||||
|
full system: DuckRequest message 0x1A (authentic name from the
|
||||||
|
binary's handler table; roster = RealMaxSpeed 0x15, BalanceCoolant
|
||||||
|
0x16, SetBurningState 0x17, ClearBurningState 0x18, EjectPilot 0x19,
|
||||||
|
DuckRequest 0x1A) latches one evaluation (+0x398, one-shot, Reset
|
||||||
|
clears); the phase machine reads the RAW simulation state, the
|
||||||
|
mapper's duck cell (+0x25c) and the analog demand (+0x79c, deadzone
|
||||||
|
1e-4 @0x4ab16c): gait 0/4 + input -> down (LEG slot 2, sqd), gait 1
|
||||||
|
-> up (slot 3, squ); limp modes 3/4 force stand-up; the
|
||||||
|
collisionVolumeState alarm (+0x4c4; 1=standing, 0=ducked; "Whoa! Bad
|
||||||
|
Collision Volume State!" guard, line 417) swaps the collision
|
||||||
|
template's maxY (ExtentBox +0xc == the box TOP; the ground probe's
|
||||||
|
minY untouched) between the ctor-captured height and 0.6x it (the
|
||||||
|
double @004a2d38); duckState publishes for the cockpit selector.
|
||||||
|
Still open here: the two MarkUpdate masks (8 then 1) ride our
|
||||||
|
ForceUpdate no-op, and the mapper duck cell's streamed binding id
|
||||||
|
awaits a BT_MAP_LOG audit on a duck-bound RES.
|
||||||
4. verify-guarded state read (mech4 accessors + Fail 0x40385c)
|
4. verify-guarded state read (mech4 accessors + Fail 0x40385c)
|
||||||
5. gyro feed a (vec pair → gyro_b 0x4b2de4, gyro_a 0x4b2d8c)
|
5. gyro feed a (vec pair → gyro_b 0x4b2de4, gyro_a 0x4b2d8c)
|
||||||
6. death arm: InDeathTransition 0x49fb54 → the 1.9KB mech2 advancer
|
6. death arm: InDeathTransition 0x49fb54 → the 1.9KB mech2 advancer
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ MechControlsMapper::MechControlsMapper(
|
|||||||
shared_data
|
shared_data
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
duckCommand = 0;
|
||||||
Check(owner);
|
Check(owner);
|
||||||
//
|
//
|
||||||
// Prime the published control inputs to neutral. Per-frame interpretation
|
// Prime the published control inputs to neutral. Per-frame interpretation
|
||||||
|
|||||||
@@ -1,210 +1,223 @@
|
|||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
// File: mechmppr.hpp //
|
// File: mechmppr.hpp //
|
||||||
// Project: BattleTech //
|
// Project: BattleTech //
|
||||||
// Contents: Implementation details for the mech controls mapper //
|
// Contents: Implementation details for the mech controls mapper //
|
||||||
//---------------------------------------------------------------------------//
|
//---------------------------------------------------------------------------//
|
||||||
// Date Who Modification //
|
// Date Who Modification //
|
||||||
// -------- --- ---------------------------------------------------------- //
|
// -------- --- ---------------------------------------------------------- //
|
||||||
// //
|
// //
|
||||||
//---------------------------------------------------------------------------//
|
//---------------------------------------------------------------------------//
|
||||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||||
// All Rights reserved worldwide //
|
// All Rights reserved worldwide //
|
||||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
|
|
||||||
#if !defined(MECHMPPR_HPP)
|
#if !defined(MECHMPPR_HPP)
|
||||||
# define MECHMPPR_HPP
|
# define MECHMPPR_HPP
|
||||||
|
|
||||||
# if !defined(SUBSYSTM_HPP)
|
# if !defined(SUBSYSTM_HPP)
|
||||||
# include <subsystm.hpp>
|
# include <subsystm.hpp>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if !defined(CSTR_HPP)
|
# if !defined(CSTR_HPP)
|
||||||
# include <cstr.hpp>
|
# include <cstr.hpp>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if !defined(CONTROLS_HPP)
|
# if !defined(CONTROLS_HPP)
|
||||||
# include <controls.hpp>
|
# include <controls.hpp>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if !defined(VECTOR2D_HPP)
|
# if !defined(VECTOR2D_HPP)
|
||||||
# include <vector2d.hpp>
|
# include <vector2d.hpp>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
//##################### Forward Class Declarations #######################
|
//##################### Forward Class Declarations #######################
|
||||||
class Mech;
|
class Mech;
|
||||||
|
|
||||||
//###########################################################################
|
//###########################################################################
|
||||||
//######################## MechControlsMapper ###########################
|
//######################## MechControlsMapper ###########################
|
||||||
//###########################################################################
|
//###########################################################################
|
||||||
|
|
||||||
class MechControlsMapper:
|
class MechControlsMapper:
|
||||||
public Subsystem
|
public Subsystem
|
||||||
{
|
{
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Shared Data Support
|
// The duck button cell (binary mapper+0x25c) -- a device-poll write
|
||||||
//
|
// destination like the torso command cells; the master perf's duck
|
||||||
public:
|
// driver reads it as the held-button gate. The streamed attribute
|
||||||
static Derivation ClassDerivations;
|
// binding id is still to be audited (BT_MAP_LOG) -- until a RES table
|
||||||
static SharedData DefaultData;
|
// binds it, BT_FORCE_DUCK drives it.
|
||||||
|
//
|
||||||
static const IndexEntry AttributePointers[];
|
public:
|
||||||
static AttributeIndexSet AttributeIndex;
|
int
|
||||||
|
DuckCommand()
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
{ Check(this); return duckCommand; }
|
||||||
// Attribute IDs -- the control inputs the streamed mappings bind to.
|
int duckCommand;
|
||||||
// The chain ends at Subsystem::NextAttributeID == 2.
|
|
||||||
//
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
public:
|
// Shared Data Support
|
||||||
enum {
|
//
|
||||||
MechControlsMapperPadFirstAttributeID = 2,
|
public:
|
||||||
StickPositionAttributeID, // 3
|
static Derivation ClassDerivations;
|
||||||
ThrottlePositionAttributeID, // 4
|
static SharedData DefaultData;
|
||||||
PedalsPositionAttributeID, // 5
|
|
||||||
ReverseThrustAttributeID, // 6
|
static const IndexEntry AttributePointers[];
|
||||||
SpeedDemandAttributeID, // 7
|
static AttributeIndexSet AttributeIndex;
|
||||||
TurnDemandAttributeID, // 8
|
|
||||||
LookForwardAttributeID, // 9
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
LookLeftAttributeID, // a
|
// Attribute IDs -- the control inputs the streamed mappings bind to.
|
||||||
LookRightAttributeID, // b
|
// The chain ends at Subsystem::NextAttributeID == 2.
|
||||||
LookBehindAttributeID, // c
|
//
|
||||||
LookDownAttributeID, // d
|
public:
|
||||||
TorsoUpAttributeID, // e
|
enum {
|
||||||
TorsoDownAttributeID, // f
|
MechControlsMapperPadFirstAttributeID = 2,
|
||||||
TorsoLeftAttributeID, // 10
|
StickPositionAttributeID, // 3
|
||||||
TorsoRightAttributeID, // 11
|
ThrottlePositionAttributeID, // 4
|
||||||
TorsoCenterAttributeID, // 12
|
PedalsPositionAttributeID, // 5
|
||||||
ControlModeAttributeID, // 13
|
ReverseThrustAttributeID, // 6
|
||||||
DisplayModeAttributeID, // 14
|
SpeedDemandAttributeID, // 7
|
||||||
PilotArrayPageAttributeID, // 15
|
TurnDemandAttributeID, // 8
|
||||||
PilotArrayAttributeID, // 16
|
LookForwardAttributeID, // 9
|
||||||
TargetRangeExponentAttributeID, // authored watcher
|
LookLeftAttributeID, // a
|
||||||
NextAttributeID
|
LookRightAttributeID, // b
|
||||||
};
|
LookBehindAttributeID, // c
|
||||||
|
LookDownAttributeID, // d
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
TorsoUpAttributeID, // e
|
||||||
// Control modes
|
TorsoDownAttributeID, // f
|
||||||
//
|
TorsoLeftAttributeID, // 10
|
||||||
public:
|
TorsoRightAttributeID, // 11
|
||||||
enum ControlMode {
|
TorsoCenterAttributeID, // 12
|
||||||
BasicMode = 0,
|
ControlModeAttributeID, // 13
|
||||||
StandardMode,
|
DisplayModeAttributeID, // 14
|
||||||
VeteranMode
|
PilotArrayPageAttributeID, // 15
|
||||||
};
|
PilotArrayAttributeID, // 16
|
||||||
|
TargetRangeExponentAttributeID, // authored watcher
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
NextAttributeID
|
||||||
// Look states. A five-state machine off the pod's look buttons; on a state
|
};
|
||||||
// change InterpretControls calls Mech::CommitLookState, which re-aims the
|
|
||||||
// eyepoint from the model's authored look angles (and, once the weapon wave
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// lands, re-arms the per-view weapon fire enables).
|
// Control modes
|
||||||
//
|
//
|
||||||
public:
|
public:
|
||||||
enum LookState {
|
enum ControlMode {
|
||||||
LookNone = 0,
|
BasicMode = 0,
|
||||||
LookLeftState,
|
StandardMode,
|
||||||
LookRightState,
|
VeteranMode
|
||||||
LookBehindState,
|
};
|
||||||
LookDownState
|
|
||||||
};
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Look states. A five-state machine off the pod's look buttons; on a state
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// change InterpretControls calls Mech::CommitLookState, which re-aims the
|
||||||
// Construction and Destruction
|
// eyepoint from the model's authored look angles (and, once the weapon wave
|
||||||
//
|
// lands, re-arms the per-view weapon fire enables).
|
||||||
public:
|
//
|
||||||
MechControlsMapper(
|
public:
|
||||||
Mech *owner,
|
enum LookState {
|
||||||
int subsystem_ID,
|
LookNone = 0,
|
||||||
CString subsystem_name,
|
LookLeftState,
|
||||||
RegisteredClass::ClassID class_ID,
|
LookRightState,
|
||||||
SharedData &shared_data = DefaultData
|
LookBehindState,
|
||||||
);
|
LookDownState
|
||||||
|
};
|
||||||
~MechControlsMapper();
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Logical
|
// Construction and Destruction
|
||||||
TestInstance() const;
|
//
|
||||||
|
public:
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
MechControlsMapper(
|
||||||
// Per-frame control interpretation (the mapper's Performance): reads the
|
Mech *owner,
|
||||||
// engine-pushed raw input attributes (throttle / stick / pedals / buttons)
|
int subsystem_ID,
|
||||||
// and publishes the locomotion + aim demands the mech drive consumes.
|
CString subsystem_name,
|
||||||
//
|
RegisteredClass::ClassID class_ID,
|
||||||
public:
|
SharedData &shared_data = DefaultData
|
||||||
typedef void
|
);
|
||||||
(MechControlsMapper::*Performance)(Scalar time_slice);
|
|
||||||
void
|
~MechControlsMapper();
|
||||||
SetPerformance(Performance performance)
|
|
||||||
{
|
Logical
|
||||||
Check(this);
|
TestInstance() const;
|
||||||
activePerformance = (Simulation::Performance)performance;
|
|
||||||
}
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Per-frame control interpretation (the mapper's Performance): reads the
|
||||||
void
|
// engine-pushed raw input attributes (throttle / stick / pedals / buttons)
|
||||||
InterpretControls(Scalar time_slice);
|
// and publishes the locomotion + aim demands the mech drive consumes.
|
||||||
|
//
|
||||||
Mech*
|
public:
|
||||||
GetMech() { Check(this); return (Mech *)GetEntity(); }
|
typedef void
|
||||||
Scalar
|
(MechControlsMapper::*Performance)(Scalar time_slice);
|
||||||
GetSpeedDemand() const { Check(this); return speedDemand; }
|
void
|
||||||
Scalar
|
SetPerformance(Performance performance)
|
||||||
GetTurnDemand() const { Check(this); return turnDemand; }
|
{
|
||||||
|
Check(this);
|
||||||
//
|
activePerformance = (Simulation::Performance)performance;
|
||||||
// The LIMP machines write the demand cell DOWN to the damaged side's
|
}
|
||||||
// speed cap (binary GimpLegClipFinished @004a7970 preamble writes
|
|
||||||
// mapper+0x128 directly) -- a limping mech cannot command more speed
|
void
|
||||||
// than its limp figure carries.
|
InterpretControls(Scalar time_slice);
|
||||||
//
|
|
||||||
void
|
Mech*
|
||||||
SetSpeedDemand(Scalar demand)
|
GetMech() { Check(this); return (Mech *)GetEntity(); }
|
||||||
{ Check(this); speedDemand = demand; }
|
Scalar
|
||||||
|
GetSpeedDemand() const { Check(this); return speedDemand; }
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Scalar
|
||||||
// Local Data -- the published control inputs (the streamed mappings write
|
GetTurnDemand() const { Check(this); return turnDemand; }
|
||||||
// these; InterpretControls, phase 5.3, reads them to drive the mech).
|
|
||||||
//
|
//
|
||||||
public:
|
// The LIMP machines write the demand cell DOWN to the damaged side's
|
||||||
//
|
// speed cap (binary GimpLegClipFinished @004a7970 preamble writes
|
||||||
// The POD ROSTER (binary mapper attributes PilotArrayPage/PilotArray,
|
// mapper+0x128 directly) -- a limping mech cannot command more speed
|
||||||
// ids 15/16): the comm scoreboard's row source. Zero = no roster
|
// than its limp figure carries.
|
||||||
// authored (a solo mission), which is why the shipped cockpit leaves
|
//
|
||||||
// that page blank.
|
void
|
||||||
//
|
SetSpeedDemand(Scalar demand)
|
||||||
int
|
{ Check(this); speedDemand = demand; }
|
||||||
GetPilotArray() const { Check(this); return pilotArray; }
|
|
||||||
int
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
GetPilotArrayPage() const { Check(this); return pilotArrayPage; }
|
// Local Data -- the published control inputs (the streamed mappings write
|
||||||
|
// these; InterpretControls, phase 5.3, reads them to drive the mech).
|
||||||
|
//
|
||||||
protected:
|
public:
|
||||||
ControlsJoystick stickPosition;
|
//
|
||||||
Scalar throttlePosition;
|
// The POD ROSTER (binary mapper attributes PilotArrayPage/PilotArray,
|
||||||
Scalar pedalsPosition;
|
// ids 15/16): the comm scoreboard's row source. Zero = no roster
|
||||||
ControlsButton reverseThrust;
|
// authored (a solo mission), which is why the shipped cockpit leaves
|
||||||
Scalar speedDemand;
|
// that page blank.
|
||||||
Scalar turnDemand;
|
//
|
||||||
ControlsButton lookForward;
|
int
|
||||||
ControlsButton lookLeft;
|
GetPilotArray() const { Check(this); return pilotArray; }
|
||||||
ControlsButton lookRight;
|
int
|
||||||
ControlsButton lookBehind;
|
GetPilotArrayPage() const { Check(this); return pilotArrayPage; }
|
||||||
ControlsButton lookDown;
|
|
||||||
ControlsButton torsoUp;
|
|
||||||
ControlsButton torsoDown;
|
protected:
|
||||||
ControlsButton torsoLeft;
|
ControlsJoystick stickPosition;
|
||||||
ControlsButton torsoRight;
|
Scalar throttlePosition;
|
||||||
ControlsButton torsoCenter;
|
Scalar pedalsPosition;
|
||||||
int controlMode;
|
ControlsButton reverseThrust;
|
||||||
int displayMode;
|
Scalar speedDemand;
|
||||||
int pilotArrayPage;
|
Scalar turnDemand;
|
||||||
int pilotArray;
|
ControlsButton lookForward;
|
||||||
int lookState;
|
ControlsButton lookLeft;
|
||||||
int previousLookState;
|
ControlsButton lookRight;
|
||||||
//
|
ControlsButton lookBehind;
|
||||||
// Takes one reserved word (Scalar and int are both 4 bytes here), so
|
ControlsButton lookDown;
|
||||||
// the class size and every existing offset stay exactly as they were.
|
ControlsButton torsoUp;
|
||||||
//
|
ControlsButton torsoDown;
|
||||||
Scalar targetRangeExponent; // authored watcher
|
ControlsButton torsoLeft;
|
||||||
int reserved[21];
|
ControlsButton torsoRight;
|
||||||
};
|
ControlsButton torsoCenter;
|
||||||
|
int controlMode;
|
||||||
#endif
|
int displayMode;
|
||||||
|
int pilotArrayPage;
|
||||||
|
int pilotArray;
|
||||||
|
int lookState;
|
||||||
|
int previousLookState;
|
||||||
|
//
|
||||||
|
// Takes one reserved word (Scalar and int are both 4 bytes here), so
|
||||||
|
// the class size and every existing offset stay exactly as they were.
|
||||||
|
//
|
||||||
|
Scalar targetRangeExponent; // authored watcher
|
||||||
|
int reserved[21];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user