Combat: RESTORE authentic fire-at-nothing + non-mech range axis (task #50 / Discord report)

Determined the authentic behavior from the decomp (HudSimulation + Emitter,
part_013.c:5619-5670 / 7689-7778) and fixed two regressions the players hit:
 (A) You could only fire when a MECH was locked (couldn't fire at nothing).
 (B) Buildings/structures/ground stopped moving the range axis; only mechs did.

AUTHENTIC (T1): a weapon discharges iff the target slot mech+0x388 != 0
(Emitter::FireWeapon FUN_004bace8:7727), and 0x388 is whatever the BORESIGHT
designates -- mech OR world geometry -- NOT a manual mech lock.  The RANGE readout
(HUD+0x1ec) moves for ANY designated target (mech OR structure/ground); the LOCK
ring is mech-only (target has a damage-zone table, HudSim :5619).  So the pod
'fired freely at nothing' and buildings moved the range caret.

ROOT CAUSES (both content-triggered, not a targeting-code change):
 1. arena1's ONLY class-42 world entity is the 10000x10000 FLAT GROUND plane at
    y=0, MISNAMED 'sky' -- SkippedName filtered it out by name, so BuildTables
    ingested 0 geometry and gBTTerrainEntity stayed null -> nothing groundable ->
    mech-only targeting.  (LAST.EGG rewrite ~bb795e2 lost whatever terrain the
    working scene had.)
 2. A boresight that hit nothing set MECH_TARGET_ENTITY=0 -> no discharge.

FIXES:
 - btvisgnd.cpp: geometry-aware skip -- keep a wide, near-flat, near-ground plane
   even if name-skipped (it is the arena floor); still skip true domes/backdrops.
   Adds mesh y-bounds.  arena1 now ingests 1 ground instance (was 0).
 - btl4vid.cpp: capture ANY world-geometry entity as the non-mech pick sentinel
   (the default render case is world-only), not only Terrain-derived ones.
 - mech4.cpp: FIRE-AT-NOTHING -- when nothing pickable is hit, designate a
   max-range point (1200, the HUD default 0x44960000) along the boresight using
   the world sentinel, so 0x388 != 0 and the weapon discharges (no zone damage /
   no lock ring, since the sentinel has no damage-zone table -- mechs only).

Verified autonomous: arena1 ground ingested; [target] shows 'fire-at-nothing
(max-range designate)'; weapon discharges at empty space ([fire] explode
resolved); range axis (sShownRange->BTSetHudTargetRange) slides to the designated
distance.  Diagnostic: BT_GROUND_LOG (world-geometry ingest + skip reasons).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-15 09:10:48 -05:00
co-authored by Claude Opus 4.8
parent 49d73dc8e2
commit ee6e19e86e
3 changed files with 82 additions and 8 deletions
+22 -2
View File
@@ -4397,9 +4397,28 @@ void
MECH_TARGET_SUBIDX(this) = -1;
MECH_TARGET_POS(this) = pickPoint; // beam endpoint = the pick
}
else if (gBTTerrainEntity != 0)
{
// FIRE-AT-NOTHING (authentic, decomp part_013.c:7727): the pod fired
// freely at empty space -- the discharge gate is 0x388!=0 (the boresight
// always DESIGNATES a point, not a manual mech lock). When nothing pickable
// is hit (a level shot flies over the flat ground, or open sky), designate a
// MAX-RANGE point using the world sentinel so the weapon discharges to max
// range. Sentinel has no damage-zone table -> no aimed-zone damage, no lock
// ring (mechs only), per HudSimulation part_013.c:5620.
MECH_TARGET_ENTITY(this) = gBTTerrainEntity;
MECH_TARGET_SUBIDX(this) = -1;
Point3D farPt;
farPt.x = rs[0] + rd[0] * 1200.0f; // 1200 = HUD range default (0x44960000)
farPt.y = rs[1] + rd[1] * 1200.0f;
farPt.z = rs[2] + rd[2] * 1200.0f;
MECH_TARGET_POS(this) = farPt;
targetReticle.targetEntity = gBTTerrainEntity;
targetReticle.rayIntersection = farPt;
}
else
{
MECH_TARGET_ENTITY(this) = 0; // sky: no target, no discharge
MECH_TARGET_ENTITY(this) = 0; // no world sentinel -> no target
MECH_TARGET_SUBIDX(this) = -1;
}
}
@@ -4835,7 +4854,8 @@ void
DEBUG_STREAM << "[target] aim=(" << gBTAimX << "," << gBTAimY << ")"
<< (victim != 0 ? " MECH under boresight (aimed)"
: (pickTarget != 0 ? " terrain downrange (beam at scenery)"
: " sky (no target, no discharge)"))
: (MECH_TARGET_ENTITY(this) != 0 ? " fire-at-nothing (max-range designate)"
: " no target (no world sentinel)")))
<< " range=" << range
<< (anyWeaponInRange ? " IN WEAPON RANGE" : "")
<< " [mechPicks=" << gAimHits << " groundPicks=" << gAimGround