Commit Graph
3 Commits
Author SHA1 Message Date
arcattackandClaude Opus 4.8 de8f6d02c1 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>
2026-07-15 10:08:45 -05:00
arcattackandClaude Opus 4.8 ee6e19e86e 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>
2026-07-15 09:10:48 -05:00
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00