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
+19 -2
View File
@@ -227,9 +227,26 @@ void
// to terrain).
{
extern Entity *gBTTerrainEntity;
// The boresight ground/structure pick needs a non-null world Entity to
// cite in mech+0x388 (the geometry rides in the pick POINT; the entity is
// only the non-mech designation -- the decomp's HudSimulation handles a
// target with no damage-zone table, part_013.c:5620). Previously this
// required a TERRAIN-derived entity, but maps whose world geometry is
// buildings/cultural/props (class-42, NOT Terrain-derived) captured
// nothing -> gBTTerrainEntity stayed 0 -> the ground pick was skipped
// (mech4.cpp:4372) -> only mechs were targetable/firable (task #50
// regression: LAST.EGG rewrite lost its Terrain entity). This `default`
// case is world-geometry ONLY (mechs route elsewhere), so capture the
// first entity reaching it -- preferring a real Terrain, else any world
// entity (building/prop/landmark) as the non-mech pick sentinel.
if (gBTTerrainEntity == 0
&& entity->IsDerivedFrom(*Terrain::GetClassDerivations()))
gBTTerrainEntity = entity;
|| !gBTTerrainEntity->IsDerivedFrom(*Terrain::GetClassDerivations()))
{
if (entity->IsDerivedFrom(*Terrain::GetClassDerivations()))
gBTTerrainEntity = entity; // prefer a true Terrain entity
else if (gBTTerrainEntity == 0)
gBTTerrainEntity = entity; // else the first world entity
}
}
DPLRenderer::MakeEntityRenderables(
entity, model_resource, view_type);