diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index 9555312..02b2423 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -837,6 +837,18 @@ struct BTProjectile { int weaponSubsys; // firing weapon's roster index (-1 = unthreaded) -- // resolves the weapon's ExplosionModelFile (mslhit/ // acanhit) in the messmgr, task #7 bundling + int salvoLead; // ONE detonation per salvo (2026-08-02, byte-grounded: + // FireWeapon @004bcc60 spawns ONE Missile per trigger -- + // no loop -- so the arcade made ONE Explosion entity + // (one 4-voice sound + one smoke package) per salvo. + // Our N-round visual ripple is a port addition [T3]; + // detonating EVERY round amplified explosion audio + + // impact smoke + Static3DPatchSource demand by the + // missile count (2-20x): Oracle's 'prolonged smoke and + // explosion including sound', Ronin's smoke screen, and + // a large share of #32's class-1005 saturation. Only + // the lead round spawns the Explosion; the rest keep + // their small tracer end-puffs. int splashBurst; // SALVO-LEAD cluster count for splash (task #62 fix): // >0 ONLY on the first round of a missile salvo -- the // baseBurst for ONE splash event = the whole cluster @@ -1309,7 +1321,7 @@ void BTPushProjectile(const Point3D &muzzle, void *shooter, void *target, const Point3D &targetPos, Scalar speed, Scalar damage, const Vector3D *launch_velocity, int guided, int weapon_subsys, int splash_burst, int muzzle_seg, int damage_type, - Scalar thrust_accel, Scalar thrust_burn) + Scalar thrust_accel, Scalar thrust_burn, int salvo_lead) { // MUZZLE (muzzle wave, 2026-07-12): the passed muzzle is now the weapon's // AUTHENTIC mount segment (GetMuzzlePoint reads the real segmentIndex -- @@ -1438,14 +1450,17 @@ void p.shooter = (Entity *)shooter; p.weaponSubsys = weapon_subsys; p.splashBurst = splash_burst; // >0 only on a salvo-lead round + p.salvoLead = salvo_lead; // 1 = spawns the Explosion at contact p.accel = (thrust_accel > 0.0f) ? thrust_accel : 0.0f; // #84 thruster p.burnLeft = (thrust_burn > 0.0f) ? thrust_burn : 0.0f; - // RACK-TUBE SPREAD [T3, physically grounded]: the binary's Missile - // entities each launch from their own rack tube (per-tube authored - // MuzzlePosition); our single muzzle superimposed a whole salvo onto - // ONE trajectory -- 12 rounds read as one round, and their 12 - // detonations stacked into one frame. Approximate the tube offsets + // RACK-TUBE SPREAD [T3 visual]. ⚠ CORRECTED 2026-08-02: the binary + // fires ONE Missile entity per trigger (FireWeapon @004bcc60 -- no + // loop, byte-verified in the #95 work); there are no "12 binary + // missiles". The N-round ripple below is a PORT VISUAL for the + // cluster; its rounds are damage-0 tracers, and only the salvo LEAD + // spawns the Explosion package at contact (salvoLead), matching the + // arcade's one-explosion-per-salvo economy. Approximate the tube offsets // with a small deterministic per-slot cone (+-~2.5 deg) + lateral // muzzle offset; the seeker re-converges them onto the target so the // volley arrives as the demo's RIPPLE of impacts. @@ -1587,7 +1602,8 @@ static void // puff cluster, no damage { Point3D hp; hp.x = hx; hp.y = hy; hp.z = hz; - BTSpawnRoundDetonation(p.shooter, p.weaponSubsys, hp); + if (p.salvoLead) // ONE Explosion per salvo (@004bcc60) + BTSpawnRoundDetonation(p.shooter, p.weaponSubsys, hp); // SPLASH (task #62): the binary missile detonates on ANY // geometry and still runs SplashDamage (the +0x360 gate sits // inside the collision branch @part_013.c:10045, which fires @@ -1682,11 +1698,12 @@ static void if (getenv("BT_PROJ_LOG")) DEBUG_STREAM << "[projectile] DET at(" << hitPos.x << "," << hitPos.y << "," << hitPos.z << ")" - << " dmg=" << p.damage + << " dmg=" << p.damage << " lead=" << p.salvoLead << " tgt=" << (void *)p.target << " aim(" << p.targetPos.x << "," << p.targetPos.y << "," << p.targetPos.z << ")" << std::endl; - BTSpawnRoundDetonation(p.shooter, p.weaponSubsys, hitPos); + if (p.salvoLead) // ONE Explosion per salvo (@004bcc60) + BTSpawnRoundDetonation(p.shooter, p.weaponSubsys, hitPos); Entity *tgt = p.target; // Deliver to the projectile's target mech -- the launcher set p.target // from the shooter's 0x388 slot (the picked victim; any peer mech in diff --git a/game/reconstructed/mislanch.cpp b/game/reconstructed/mislanch.cpp index 870a93e..c621c11 100644 --- a/game/reconstructed/mislanch.cpp +++ b/game/reconstructed/mislanch.cpp @@ -79,7 +79,8 @@ extern void BTPushProjectile(const Point3D &muzzle, void *shooter, void *target, const Vector3D *launch_velocity = 0, int guided = 1, int weapon_subsys = -1, int splash_burst = 0, int muzzle_seg = -1, int damage_type = 2 /*ExplosiveDamageType default*/, - Scalar thrust_accel = 0.0f, Scalar thrust_burn = 0.0f /*#84 thruster*/); + Scalar thrust_accel = 0.0f, Scalar thrust_burn = 0.0f /*#84 thruster*/, + int salvo_lead = 1 /*ONE Explosion per salvo*/); // #84: resolve this launcher's authored thruster (burn s, accel u/s^2) through // its connected bin's round-model resource. 0/0 when unresolvable (flies at // the old constant eject speed -- never worse than before). @@ -355,7 +356,8 @@ void MissileLauncher::FireWeapon() (i == 0) ? nmiss : 0 /*salvo-lead: cluster splash baseBurst*/, GetSegmentIndex() /*task #67: launch through the MOUNT frame (torso twist)*/, (int)damageData.damageType /*missile = Explosive (authentic)*/, - tAccel, tBurn /*#84: the round ACCELERATES like the binary Missile*/); + tAccel, tBurn /*#84 thruster*/, + (i == 0) /*ONE Explosion per salvo: the lead only*/); // Salvo replication (missile-visibility wave): bump the fire counter + stamp // the aim point; the extended update record carries both to peer nodes. @@ -468,7 +470,8 @@ void rec->salvoTarget, spd, 0.0f /*VISUAL*/, &launchVelocity, 1, subsystemID /*per-round detonation resolve on this node*/, 0, GetSegmentIndex() /*task #67 mount frame*/, - 2 /*Explosive*/, tAccel, tBurn); + 2 /*Explosive*/, tAccel, tBurn, + (i == 0) /*mirror lead: observers see ONE explosion per salvo*/); if (getenv("BT_PROJ_LOG")) DEBUG_STREAM << "[projectile] REPLICANT salvo x" << n << " at(" << rec->salvoTarget.x << "," << rec->salvoTarget.y diff --git a/game/reconstructed/projweap.cpp b/game/reconstructed/projweap.cpp index 3bfc829..91650f6 100644 --- a/game/reconstructed/projweap.cpp +++ b/game/reconstructed/projweap.cpp @@ -99,7 +99,8 @@ extern void BTPushProjectile(const Point3D &muzzle, void *shooter, void *target, const Vector3D *launch_velocity = 0, int guided = 1, int weapon_subsys = -1, int splash_burst = 0, int muzzle_seg = -1, int damage_type = 2 /*ExplosiveDamageType default*/, - Scalar thrust_accel = 0.0f, Scalar thrust_burn = 0.0f); // AC: unpowered (defaults) + Scalar thrust_accel = 0.0f, Scalar thrust_burn = 0.0f, + int salvo_lead = 1); // AC: unpowered; single round = its own lead //#############################################################################