MP: world structures (garages/walls) TARGETABLE -- boresight ray-tests the static collision tree (task #50)

The boresight's non-mech pick only sampled the VISUAL heightfield (BTGroundRayHit),
which on arena1 is a single flat 'sky'-named ground mesh (and class-42 BuildTables
likewise holds only 'sky') -- so shots passed THROUGH the garages/walls and only mechs
moved the HUD range axis (user-reported regression: "buildings used to move the range
axis; now only mechs do, and you can only fire at a peer").

Real fix: the boresight now ALSO ray-tests the ZONE'S STATIC COLLISION SOLID TREE --
the same geometry that already blocks the mech's walk. Authentic engine mechanism:
Mover::FindBoxedSolidHitBy already tests the static world via
zone->GetCollisionRoot()->FindBoundingBoxHitBy(line). Factored its "static world" tail
into Mover::FindStaticSolidHitBy(Line*) (static solids only, no movers), wrapped by
Mech::WorldStructurePick(start,dir,range,&hit) (builds the world-space Line, reads the
entry point back via line->FindEnd since HitByBounded clips line->length=enter).

Boresight pick order is now: closest MECH (PickRayHit, damage zones + lock) -> closest
STRUCTURE (WorldStructurePick; occludes a mech BEHIND it; designates the gBTTerrainEntity
sentinel + entry point, so the range caret reads the structure distance and NO lock ring
draws, mech4.cpp:4529) -> flat ground (BTGroundRayHit) -> sky (fire-at-nothing). Also
un-skips arena1's misnamed-'sky' flat ground so the ground tier works (btvisgnd
geometry-aware skip + [mapent]/[rendent] census).

Verified headless: a BT_WSWEEP horizontal ray-fan on arena1 tracks position (3/24 hits
near the boundary -> 17-21/24 inside the interior garage cluster -> 3/24 past it =
DISCRETE interior solids, not an enclosing box), no crash/assert/AV. Interactive aim
(BTGetAimRay) can't run headless (no window -> noRay), so the sweep is the headless proof;
interactive aim is user-verified.

Note: FindBoundingBoxUnder (the ground/containedByNode BoundingBoxTree) is DOWNWARD-only
(gravity/ground-snap: *height = FindDistanceBelowBounded), useless for a horizontal
boresight; the static SOLID tree's FindBoundingBoxHitBy is the only ray-vs-world query.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-15 10:08:45 -05:00
co-authored by Claude Opus 4.8
parent ee6e19e86e
commit de8f6d02c1
9 changed files with 222 additions and 4 deletions
+28
View File
@@ -1137,6 +1137,34 @@ BoxedSolid*
return solid;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// The "static world" tail of FindBoxedSolidHitBy on its own: ray-test ONLY the
// zone's static solid tree (world structures -- garages, walls, props), NOT the
// tangible movers/doors. Same tree the mech's walk collides against, so a shot
// designated through this lands on exactly the geometry that blocks the mech.
// FindBoundingBoxHitBy clips line->length to the hit distance (HitByBounded ->
// line->length = enter), so the caller reads the entry point via line->FindEnd.
//
BoxedSolid*
Mover::FindStaticSolidHitBy(
Line *line
)
{
Check(this);
Check(line);
InterestManager *interest_mgr = application->GetInterestManager();
Check(interest_mgr);
InterestZone *zone = interest_mgr->GetInterestZone(interestZoneID);
Check(zone);
BoxedSolidTree* tree = zone->GetCollisionRoot();
Check(tree);
BoxedSolid *result = (BoxedSolid*)tree->FindBoundingBoxHitBy(line);
Check_Fpu();
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSolidCollisionList*
+10
View File
@@ -300,6 +300,16 @@ public:
Line *line,
Entity *except_by
);
// STATIC-WORLD-ONLY ray query: the "test against the static world" tail of
// FindBoxedSolidHitBy factored out -- ray-tests ONLY the zone's static solid
// tree (the world structures: garages, walls, props), skipping the tangible
// movers/doors. Used by the weapon boresight pick so a shot lands on the SAME
// static geometry that already blocks the mech's walk (mechs are picked
// separately, with their damage zones/lock). Clips line->length to the entry.
BoxedSolid*
FindStaticSolidHitBy(
Line *line
);
BoxedSolidCollisionList*
CollideCenterOfMotion(
Line *line,