Three-trigger keyboard weapon groups: 1=lasers 2=PPCs 3=missiles (task #43)

Interim pod-like grouping ahead of the authentic ConfigureMappables/
ChooseButton mapper channels (decomp-anchored in open-questions):
- Three fire channels like three pod buttons: gBTWeaponTrigger (lasers,
  key 1 or SPACE), gBTPPCTrigger (PPCs, key 2), gBTMissileTrigger
  (missiles, key 3 or CTRL). Keyboard only per user (mouse buttons
  removed).
- EmitterSimulation picks its channel by classID (PPC 3028 vs Emitter
  3016); BT_AUTOFIRE holds all three.
- The BT_BEAM_LOG sampler modulus 30 aliased to ONE weapon under the
  new synchronized 5-beam volleys (5 | 30) -> 31 (coprime).

Verified: all 5 energy weapons fire (31 samples each), aimed hits land,
kill completes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 08:31:16 -05:00
co-authored by Claude Fable 5
parent ae8aca0f3f
commit 14c0dd06f5
3 changed files with 42 additions and 29 deletions
+32 -25
View File
@@ -618,12 +618,17 @@ static int gShotCount = 0;
static Scalar gBlockCooldown = 0.0f; // seconds since the last blocking contact (counts down)
static const Scalar kBlockHysteresis = 0.4f;
// E8 weapon trigger (bring-up): pulsed per player frame; read by EmitterSimulation
// (emitter.cpp) so the real weapon's CheckFireEdge sees rising edges. Non-static
// (the emitter externs it).
int gBTWeaponTrigger = 0;
int gBTMissileTrigger = 0; // the split missile-fire channel (CTRL)
static int gBTMissileKey = 0; // raw key state (set by the keyboard poll)
// E8 weapon triggers (bring-up): pulsed per player frame; read by the weapon
// sims so CheckFireEdge sees rising edges. Non-static (the weapons extern
// them). WEAPON GROUPS (task #43): three KEYBOARD fire channels -- an interim
// pod-like split standing in for the authentic ConfigureMappables/ChooseButton
// mapper channels: 1/SPACE = lasers, 2 = PPCs, 3/CTRL = missiles.
int gBTWeaponTrigger = 0; // channel 1: lasers (key 1 / SPACE)
int gBTPPCTrigger = 0; // channel 2: PPCs (key 2)
int gBTMissileTrigger = 0; // channel 3: missiles (key 3 / CTRL)
static int gBTLaserKey = 0; // raw key states (set by the keyboard poll)
static int gBTPPCKey = 0;
static int gBTMissileKey = 0;
// Damage: each shot dispatches a REAL Entity::TakeDamageMessage to the target. Now
// that the damage zones are constructed (mech.cpp Pass-3 zone build), the engine base
@@ -1278,14 +1283,16 @@ void
gBTDrive.keyBack = focused && ((pAsync('S') | pAsync(0x28 /*VK_DOWN*/)) & dn) ? 1 : 0;
gBTDrive.keyLeft = focused && ((pAsync('A') | pAsync(0x25 /*VK_LEFT*/)) & dn) ? 1 : 0;
gBTDrive.keyRight = focused && ((pAsync('D') | pAsync(0x27 /*VK_RIGHT*/)) & dn) ? 1 : 0;
// SPLIT WEAPON CONTROLS (interim, toward the real controls-mapper
// weapon groups): SPACE / LMB = the energy weapons (lasers),
// CTRL / RMB = the missile launchers. (The mouse buttons pair
// with the mouse-slewed reticle -- task #36.)
gBTDrive.fire = focused && ((pAsync(0x20 /*VK_SPACE*/) |
pAsync(0x01 /*VK_LBUTTON*/)) & dn) ? 1 : 0;
gBTMissileKey = focused && ((pAsync(0x11 /*VK_CONTROL*/) |
pAsync(0x02 /*VK_RBUTTON*/)) & dn) ? 1 : 0;
// WEAPON GROUPS (task #43, KEYBOARD only per user): three fire
// channels like three pod buttons -- 1/SPACE = lasers, 2 = PPCs,
// 3/CTRL = missiles. (Interim; the authentic system is the
// ConfigureMappables/ChooseButton mapper channels.)
gBTLaserKey = focused && ((pAsync('1') | pAsync(0x20 /*VK_SPACE*/)) & dn) ? 1 : 0;
gBTPPCKey = focused && (pAsync('2') & dn) ? 1 : 0;
gBTMissileKey = focused && ((pAsync('3') | pAsync(0x11 /*VK_CONTROL*/)) & dn) ? 1 : 0;
// gBTDrive.fire = "any weapon trigger down" (feeds the bring-up
// damage dispatcher + the beam-visual keepalive)
gBTDrive.fire = (gBTLaserKey || gBTPPCKey || gBTMissileKey) ? 1 : 0;
static int sPrevX = 0;
const int xNow = focused && (pAsync('X') & dn) ? 1 : 0;
if (xNow && !sPrevX) gBTDrive.allStop = 1; // edge -> one all-stop
@@ -2338,7 +2345,7 @@ void
BTPushBeamKind(mz.x, mz.y, mz.z, bend.x, bend.y, bend.z,
tint, ttl1, 1.0f /* natural model width */,
isPPC ? 1 : 0 /* ppc.bgf : ermlaser.bgf */);
if (getenv("BT_BEAM_LOG") && (s_beamStateLog++ % 30) == 0)
if (getenv("BT_BEAM_LOG") && (s_beamStateLog++ % 31) == 0) // 31: coprime with the 5-beam volley (a %30 sampler aliased to one weapon)
DEBUG_STREAM << "[beam] " << (isPPC ? "PPC" : "laser") << " #" << wi
<< " mz=(" << mz.x << "," << mz.y << "," << mz.z
<< ") end=(" << bend.x << "," << bend.y << "," << bend.z
@@ -2577,17 +2584,17 @@ void
const int fireWanted = gBTDrive.fireForced || gBTDrive.fire;
// E8: pulse the weapon trigger per frame (1,0,1,0...) so the real Emitter's
// CheckFireEdge sees clean rising edges for repeated auto-fire. Read by
// EmitterSimulation. AUTHENTIC gating: the trigger passes through and the
// weapon's OWN HasActiveTarget gate decides (Emitter::FireWeapon fires only
// with a designated target -- part_013.c:7758; no aim/arc test exists).
// targetInArc is the explicit BT_FIRE_ARC presentation clamp (default true).
extern int gBTWeaponTrigger;
gBTWeaponTrigger = (fireWanted && targetInArc) ? (gBTWeaponTrigger ? 0 : 1) : 0;
// the missile channel: CTRL / RMB (or the autofire harness) -- same edge pulse
extern int gBTMissileTrigger;
// E8: pulse the three fire channels per frame (1,0,1,0...) so each
// weapon sim's CheckFireEdge sees clean rising edges. AUTHENTIC
// gating: the trigger passes through and the weapon's OWN
// HasActiveTarget gate decides (FireWeapon -- part_013.c:7758; no
// aim/arc test exists). targetInArc is the explicit BT_FIRE_ARC
// presentation clamp (default true). BT_AUTOFIRE holds all three.
const int laserWanted = gBTDrive.fireForced || gBTLaserKey;
const int ppcWanted = gBTDrive.fireForced || gBTPPCKey;
const int missileWanted = gBTDrive.fireForced || gBTMissileKey;
gBTWeaponTrigger = (laserWanted && targetInArc) ? (gBTWeaponTrigger ? 0 : 1) : 0;
gBTPPCTrigger = (ppcWanted && targetInArc) ? (gBTPPCTrigger ? 0 : 1) : 0;
gBTMissileTrigger = (missileWanted && targetInArc) ? (gBTMissileTrigger ? 0 : 1) : 0;
// Resolve the "explode" effect resource once.