WAVE 7 Phase B polish: missiles launch from the mech's missile ports + look like missiles
Two issues the user hit driving the Mad Cat: (1) projectiles appeared to launch from the mech's FEET -- MechWeapon::GetMuzzlePoint falls back to the mech origin (localOrigin) when the weapon's mount segment (this+0xdc) doesn't resolve, so the passed muzzle was at ground level; (2) they rendered as a thin laser-like line, not a missile. Fix: BTPushProjectile now takes the SHOOTER mech and resolves the real launch port by NAME (sitermissleport / sitelmissleport, alternating L/R for a salvo look; then torso ports, then gun ports; then a raised fallback) -- the same segment-name -> world-transform mechanism the visible laser beams use for the gun ports. The tracer is now a 3-part missile look (dim smoke trail behind + orange body + hot flame tip) instead of a single thin beam. FireWeapon (both ProjectileWeapon and MissileLauncher) passes owner as the shooter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
bf44a45ab7
commit
c850ffa26c
@@ -717,12 +717,45 @@ static BTProjectile gProjectiles[64];
|
||||
extern void BTPushBeam(float,float,float, float,float,float, unsigned, float, float);
|
||||
|
||||
// Called from ProjectileWeapon / MissileLauncher::FireWeapon (via the extern below)
|
||||
// with the live muzzle, the owner's locked target entity + point, the launch speed
|
||||
// (|muzzleVelocity|), and the weapon's per-shot damage.
|
||||
// with the live muzzle, the SHOOTER mech (to resolve the real launch port), the owner's
|
||||
// locked target entity + point, the launch speed (|muzzleVelocity|), and per-shot damage.
|
||||
void
|
||||
BTPushProjectile(const Point3D &muzzle, void *target, const Point3D &targetPos,
|
||||
BTPushProjectile(const Point3D &muzzle, void *shooter, void *target, const Point3D &targetPos,
|
||||
Scalar speed, Scalar damage)
|
||||
{
|
||||
// The weapon's GetMuzzlePoint falls back to the mech ORIGIN (feet) when its mount
|
||||
// segment doesn't resolve, so a projectile appeared to launch from the mech's feet.
|
||||
// Resolve the real launch port by NAME off the shooter (same mechanism the visible
|
||||
// laser beams use for the gun ports), alternating the left/right missile ports for a
|
||||
// natural salvo look; fall back to a raised (torso-height) muzzle, then the passed one.
|
||||
Point3D mz = muzzle;
|
||||
if (shooter != 0)
|
||||
{
|
||||
Mech *sm = (Mech *)shooter;
|
||||
static const char *const kPorts[] =
|
||||
{ "sitermissleport", "sitelmissleport", "siterutorsoport", "sitelutorsoport",
|
||||
"siterugunport", "sitelugunport" };
|
||||
static int s_portRot = 0;
|
||||
EntitySegment *seg = 0;
|
||||
int n = (int)(sizeof(kPorts)/sizeof(kPorts[0]));
|
||||
for (int k = 0; k < n && seg == 0; ++k)
|
||||
{
|
||||
s_portRot = (s_portRot + 1) % n;
|
||||
seg = sm->GetSegment(CString(kPorts[s_portRot]));
|
||||
}
|
||||
if (seg != 0)
|
||||
{
|
||||
AffineMatrix mw;
|
||||
mw.Multiply(seg->GetSegmentToEntity(), sm->localToWorld); // port -> world
|
||||
mz = mw; // W_Axis translation
|
||||
}
|
||||
else
|
||||
{
|
||||
mz = sm->localOrigin.linearPosition; // raise to torso height
|
||||
mz.y += 12.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Bring-up: the mech's own target slot (owner+0x388) isn't populated (the visible
|
||||
// fire path targets the gEnemyMech global directly), so fall back to it here.
|
||||
Point3D tpos = targetPos;
|
||||
@@ -732,7 +765,7 @@ void
|
||||
tpos = ((Mech *)gEnemyMech)->localOrigin.linearPosition;
|
||||
}
|
||||
Vector3D d;
|
||||
d.x = tpos.x - muzzle.x; d.y = tpos.y - muzzle.y; d.z = tpos.z - muzzle.z;
|
||||
d.x = tpos.x - mz.x; d.y = tpos.y - mz.y; d.z = tpos.z - mz.z;
|
||||
Scalar len = (Scalar)sqrtf(d.x*d.x + d.y*d.y + d.z*d.z);
|
||||
if (getenv("BT_PROJ_LOG"))
|
||||
DEBUG_STREAM << "[projectile] PUSH target=" << (void*)target << " enemy=" << (void*)gEnemyMech
|
||||
@@ -742,7 +775,7 @@ void
|
||||
{
|
||||
if (gProjectiles[i].active) continue;
|
||||
BTProjectile &p = gProjectiles[i];
|
||||
p.pos = muzzle;
|
||||
p.pos = mz; // resolved launch port
|
||||
p.dir.x = d.x/len; p.dir.y = d.y/len; p.dir.z = d.z/len;
|
||||
p.speed = (speed > 1.0f) ? speed : 120.0f; // |launchVelocity|; sane fallback
|
||||
p.traveled = 0.0f;
|
||||
@@ -767,7 +800,14 @@ static void
|
||||
Scalar step = p.speed * dt;
|
||||
p.pos.x += p.dir.x*step; p.pos.y += p.dir.y*step; p.pos.z += p.dir.z*step;
|
||||
p.traveled += step;
|
||||
BTPushBeam(prev.x, prev.y, prev.z, p.pos.x, p.pos.y, p.pos.z, 0x00FFB030u, 0.18f, 1.4f); // warm tracer
|
||||
// Missile look: a short smoky exhaust trail (behind) + a bright warm body + a
|
||||
// hot flame tip, so it reads as a projectile rather than a thin laser line.
|
||||
Vector3D bd = p.dir;
|
||||
Point3D tail; tail.x = prev.x - bd.x*8.0f; tail.y = prev.y - bd.y*8.0f; tail.z = prev.z - bd.z*8.0f;
|
||||
Point3D tip; tip.x = p.pos.x + bd.x*2.0f; tip.y = p.pos.y + bd.y*2.0f; tip.z = p.pos.z + bd.z*2.0f;
|
||||
BTPushBeam(tail.x, tail.y, tail.z, prev.x, prev.y, prev.z, 0x00804020u, 0.20f, 3.2f); // dim smoke trail
|
||||
BTPushBeam(prev.x, prev.y, prev.z, p.pos.x, p.pos.y, p.pos.z, 0x00FF6010u, 0.15f, 2.6f); // orange body
|
||||
BTPushBeam(p.pos.x, p.pos.y, p.pos.z, tip.x, tip.y, tip.z, 0x00FFF0C0u, 0.15f, 1.4f); // hot flame tip
|
||||
|
||||
Scalar dx = p.targetPos.x - p.pos.x, dy = p.targetPos.y - p.pos.y, dz = p.targetPos.z - p.pos.z;
|
||||
if (dx*dx + dy*dy + dz*dz < (10.0f*10.0f) || p.traveled >= p.range)
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
// WAVE 7 Phase B -- the port-side flying-projectile service (defined in mech4.cpp, a
|
||||
// complete-Mech TU with the render + damage path). A fired missile becomes a tracked
|
||||
// projectile that flies to the target + delivers this weapon's damage on impact.
|
||||
extern void BTPushProjectile(const Point3D &muzzle, void *target, const Point3D &targetPos,
|
||||
Scalar speed, Scalar damage);
|
||||
extern void BTPushProjectile(const Point3D &muzzle, void *shooter, void *target,
|
||||
const Point3D &targetPos, Scalar speed, Scalar damage);
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
@@ -246,7 +246,7 @@ void MissileLauncher::FireWeapon()
|
||||
// slot isn't populated (bring-up); missileCount missiles per salvo.
|
||||
int nmiss = (missileCount > 0 && missileCount < 40) ? missileCount : 1;
|
||||
for (int i = 0; i < nmiss; ++i)
|
||||
BTPushProjectile(muzzle, target, targetPos, speed, damageData.damageAmount);
|
||||
BTPushProjectile(muzzle, o, target, targetPos, speed, damageData.damageAmount);
|
||||
|
||||
simulationFlags |= 0x1; // replication-dirty
|
||||
Check_Fpu();
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
#include <math.h>
|
||||
|
||||
// WAVE 7 Phase B -- the port-side flying-projectile service (defined in mech4.cpp).
|
||||
extern void BTPushProjectile(const Point3D &muzzle, void *target, const Point3D &targetPos,
|
||||
Scalar speed, Scalar damage);
|
||||
extern void BTPushProjectile(const Point3D &muzzle, void *shooter, void *target,
|
||||
const Point3D &targetPos, Scalar speed, Scalar damage);
|
||||
|
||||
|
||||
//#############################################################################
|
||||
@@ -624,7 +624,7 @@ void
|
||||
+ launchVelocity.z*launchVelocity.z);
|
||||
// Always launch -- BTPushProjectile falls back to gEnemyMech when the owner's target
|
||||
// slot isn't populated (bring-up).
|
||||
BTPushProjectile(muzzle, target, targetPos, speed, damageData.damageAmount);
|
||||
BTPushProjectile(muzzle, o, target, targetPos, speed, damageData.damageAmount);
|
||||
|
||||
simulationFlags |= 0x1; // replication-dirty
|
||||
Check_Fpu();
|
||||
|
||||
Reference in New Issue
Block a user