#175 FIXED: missiles detonate on the static world again -- the flight sweep's missing half. The push simulator's world test marched only the VISUAL heightfield (BTGroundRayHit), so every round tunneled through geometry that blocks the walk but is not heightfield -- the arena1-garage class, and the field case (LRM duel through a grass mound, user-observed on the #83 bench). The binary's FUN_0042291c swept the real collision world every tick. Fix: the flight step now also rays the STATIC COLLISION SOLID TREE (WorldStructurePick -> Mover::FindStaticSolidHitBy -- the same static-world tail of the engine collider, already proven by the weapon-pick work), earliest hit wins vs the heightfield march; a struck solid's OWNING entity takes the direct zone=-1 dispatch exactly as the binary missile contact does (@004be078 -- trucks/props are missile-killable); salvo-lead world bursts keep the detonation + cluster splash (near-miss splash vs cover, authentic). BT_WORLDHIT=0 restores heightfield-only (A/B lever). Receipt upgraded: [projectile] WORLD burst (terrain|struct[, owner-dispatched]) + dmg/lead. Verified on the exact reported scenario (grass standoff duel, mound in the line): 185/160 WORLD-burst receipts per node -- ALL struct-class (confirming the mound is solid-tree geometry the old test was blind to), direct mech IMPACTs healthy at 20/18 when the line cleared, user-witnessed: rounds burst on the mound instead of passing through, lofted rounds still arc over (the authored seeker loft). Companion bench hook from the same session: BT_DESIGNATE=enemy (no HUD ring -- designation slots only).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016bw71WVsccjwW7uKRg4aWD
This commit is contained in:
co-authored by
Claude Fable 5
parent
df188e737f
commit
7b120531ea
@@ -1916,6 +1916,19 @@ static void
|
||||
// query every frame, FUN_0042291c, and DETONATES on geometry). Ray the
|
||||
// flight step against the terrain/cave solids -- a lofted round in a
|
||||
// low cavern bursts on the CEILING instead of punching through it.
|
||||
// (#175) TWO queries, earliest hit wins: the visual-heightfield march
|
||||
// (BTGroundRayHit) alone let rounds tunnel through everything that
|
||||
// blocks the WALK but is not heightfield -- the arena1-garage class
|
||||
// (open-questions: the visual mesh is not the collision truth), and
|
||||
// the field case that filed the ticket (LRM duel through a mound).
|
||||
// The STATIC COLLISION SOLID TREE (WorldStructurePick ->
|
||||
// Mover::FindStaticSolidHitBy) is the same static-world tail of the
|
||||
// engine collider FUN_0042291c swept, so the round now detonates on
|
||||
// exactly the geometry that stops a walking mech. A struck solid's
|
||||
// OWNING entity takes the direct dispatch (binary missile contact
|
||||
// @004be078 dispatches at the struck entity -- trucks/props are
|
||||
// missile-killable); plain terrain owners ignore it.
|
||||
// BT_WORLDHIT=0 restores the heightfield-only behavior (A/B lever).
|
||||
{
|
||||
extern bool BTGroundRayHit(float,float,float, float,float,float,
|
||||
float, float*,float*,float*);
|
||||
@@ -1926,8 +1939,47 @@ static void
|
||||
Vector3D rd;
|
||||
rd.x = p.vel.x/p.speed; rd.y = p.vel.y/p.speed; rd.z = p.vel.z/p.speed;
|
||||
float hx, hy, hz;
|
||||
int worldHit = 0; // 1 = heightfield, 2 = static solid
|
||||
Entity *structOwner = 0;
|
||||
if (BTGroundRayHit(prev.x, prev.y, prev.z, rd.x, rd.y, rd.z,
|
||||
step + 1.0f, &hx, &hy, &hz))
|
||||
worldHit = 1;
|
||||
{
|
||||
static int s_wh = -1;
|
||||
if (s_wh < 0)
|
||||
{
|
||||
const char *wv = getenv("BT_WORLDHIT");
|
||||
s_wh = (wv != 0 && *wv == '0') ? 0 : 1;
|
||||
}
|
||||
if (s_wh && p.shooter != 0 && BTIsRegisteredMech(p.shooter))
|
||||
{
|
||||
Point3D sHit;
|
||||
Entity *sOwn = 0;
|
||||
Vector3D sd(rd.x, rd.y, rd.z);
|
||||
if (((Mech *)p.shooter)->WorldStructurePick(prev, sd,
|
||||
step + 1.0f, &sHit, &sOwn))
|
||||
{
|
||||
// earlier than the heightfield hit (or the only hit)?
|
||||
int take = 1;
|
||||
if (worldHit == 1)
|
||||
{
|
||||
const float gd2 = (hx-prev.x)*(hx-prev.x)
|
||||
+ (hy-prev.y)*(hy-prev.y) + (hz-prev.z)*(hz-prev.z);
|
||||
const float sd2 = (float)((sHit.x-prev.x)*(sHit.x-prev.x)
|
||||
+ (sHit.y-prev.y)*(sHit.y-prev.y)
|
||||
+ (sHit.z-prev.z)*(sHit.z-prev.z));
|
||||
take = (sd2 < gd2);
|
||||
}
|
||||
if (take)
|
||||
{
|
||||
worldHit = 2;
|
||||
structOwner = sOwn;
|
||||
hx = (float)sHit.x; hy = (float)sHit.y; hz = (float)sHit.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (worldHit != 0)
|
||||
{
|
||||
// burst on the rock: the round's own DETONATION (the binary
|
||||
// missile detonates on ANY geometry, @004bef78) + a tight
|
||||
@@ -1955,12 +2007,40 @@ static void
|
||||
BTApplySplashDamage(p.shooter, p.weaponSubsys, hp, 0, sdmg);
|
||||
}
|
||||
}
|
||||
// (#175) a struck STRUCTURE's owning entity takes the direct
|
||||
// dispatch, exactly as the binary missile contact does
|
||||
// (@004be078: zone=-1 TakeDamageMessage straight at the
|
||||
// struck entity, no class test) -- missiles kill trucks/
|
||||
// props. Plain terrain owners have no zones and ignore it.
|
||||
int ownerDispatched = 0;
|
||||
if (worldHit == 2 && structOwner != 0
|
||||
&& !BTIsRegisteredMech(structOwner)
|
||||
&& structOwner->damageZoneCount > 0
|
||||
&& p.damage > 0.0f)
|
||||
{
|
||||
ownerDispatched = 1;
|
||||
Damage wdmg;
|
||||
wdmg.damageType = (Enumeration)p.damageType;
|
||||
wdmg.damageAmount = p.damage;
|
||||
wdmg.burstCount = 1;
|
||||
wdmg.impactPoint.x = hx; wdmg.impactPoint.y = hy;
|
||||
wdmg.impactPoint.z = hz;
|
||||
Entity::TakeDamageMessage take_damage(
|
||||
Entity::TakeDamageMessageID, sizeof(Entity::TakeDamageMessage),
|
||||
(p.shooter != 0) ? p.shooter->GetEntityID() : EntityID::Null,
|
||||
-1 /*icon handler maps -1 -> zone 0*/, wdmg);
|
||||
structOwner->Dispatch(&take_damage);
|
||||
}
|
||||
extern void BTPfxTrailPuff(int, float, float, float, float, float, float, int);
|
||||
for (int pf = 0; pf < 4; ++pf)
|
||||
BTPfxTrailPuff(0, hx, hy, hz, -rd.x, -rd.y, -rd.z, 2);
|
||||
if (getenv("BT_PROJ_LOG"))
|
||||
DEBUG_STREAM << "[projectile] WORLD burst at(" << hx << ","
|
||||
<< hy << "," << hz << ")" << std::endl;
|
||||
DEBUG_STREAM << "[projectile] WORLD burst ("
|
||||
<< ((worldHit == 2) ? "struct" : "terrain")
|
||||
<< (ownerDispatched ? " owner-dispatched" : "")
|
||||
<< ") at(" << hx << "," << hy << "," << hz << ")"
|
||||
<< " dmg=" << p.damage << " lead=" << p.salvoLead
|
||||
<< std::endl;
|
||||
p.active = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user