Combat: FIX missile direct damage 6x over-application -- damage once per salvo (task #62)
User live regression: missiles killed a mech in ~2 shots ("takes way more than 2
normally"). Root cause -- DamageZone::TakeDamage (arcade @0041e4e0 == WinTesla
DAMAGE.cpp:379) is `damageLevel += amount*scale` and IGNORES burstCount. So the
arcade's ONE cluster Missile per trigger lands its damageAmount EXACTLY ONCE; the
missileCount/burstCount split is cosmetic for zone damage (only gyro-bounce +
splash-falloff read burstCount). The port re-expresses that one cluster as N
flying rounds and was damaging on EVERY round = ~missileCount x too lethal on the
direct hit (mirrors the splash over-application fixed in 145a69f).
Fix (mislanch.cpp FireWeapon): only the salvo-LEAD round (i==0) carries damage
(damageData.damageAmount) AND the cluster splash; the other N-1 rounds are VISUAL
(damage 0) -- the tracer ripple, no extra damage. AC unaffected (one round/shot,
not a cluster).
Verified (BT_DMG_LOG [dmghit] trace): per-hit missile damage = clean 5.83, burst
1, once. Missiles-ONLY (BT_AF_MISSILE now independent of BT_AUTOFIRE), single
enemy, 45s: 8 damaging hits, top zone reaches only 0.18, NO death (was death in
~3 pulls) -- "way more than 2" restored. Earlier test deaths were BT_AUTOFIRE
firing laser+PPC+missiles combined, not missiles alone.
KB: combat-damage.md documents burstCount-ignored + the N-round cluster trap
(direct + splash both once-per-salvo).
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
145a69f865
commit
fa0b825b60
+29
-19
@@ -125,9 +125,13 @@ Three-layer story, measured live + decomp-verified:
|
||||
1. **The armor economy is POINTS**: every zone streams `damageScale[5]` — 5 cells indexed by
|
||||
`damageType` DIRECTLY (Collision/Ballistic/Explosive/Laser/Energy; task #60 correction — NOT an
|
||||
"even/odd slot" parity), each destructive type's cell ≈ `1/armorPoints` (armor 50–140).
|
||||
`damageLevel += amount × damageScale[type]`, 1.0 = destroyed — engine `DAMAGE.cpp:379`, called
|
||||
from `mechdmg.cpp:427`; the `[zone-armor]` dump, BT_DMG_LOG. Weapons author point-scale amounts
|
||||
(laser 11.77 ≈ 10 torso hits). ✓
|
||||
`damageLevel += amount × damageScale[type]`, 1.0 = destroyed — engine `DAMAGE.cpp:379` (arcade
|
||||
`@0041e4e0`), called from `mechdmg.cpp:427`; the `[zone-armor]` + per-hit `[dmghit]` dumps,
|
||||
BT_DMG_LOG. Weapons author point-scale amounts (laser 11.77 ≈ 10 torso hits). **`burstCount` is
|
||||
NOT in this formula — zone damage IGNORES it** [T1]; one Damage message = one `amount×scale`
|
||||
application regardless of burstCount (burstCount is read only by the gyro-bounce math + the
|
||||
SplashDamage falloff). A cluster missile therefore lands its damageAmount ONCE — see the
|
||||
SALVO-LEAD FIX below for why the port's N-round missiles must damage once per salvo. ✓
|
||||
2. **StaticBounce prices rams with the AUTHORED moverMass ≈ 1.3e6 units** → ~600×v² ≈ 59,000
|
||||
points for a 10 m/s ram (measured: 59221@9.94, 398@0.81; `[collide-tx]` now logs mass/e).
|
||||
The binary DISPATCHES it raw (@part_012:15324-15358) — but in pod MP it landed on the local
|
||||
@@ -471,22 +475,28 @@ destroyed/zoneless mechs, applies the `dist>radius` gate + the burst falloff, de
|
||||
shooter's msgmgr (cross-pod) or `Dispatch`. Hooked at BOTH detonation paths (world-impact + contact).
|
||||
|
||||
**⚠ THE SALVO-LEAD FIX (task #62 bug, found 2026-07-13 by live regression) — the N-round trap.**
|
||||
The arcade fires ONE cluster Missile per trigger (burstCount=missileCount) → ONE SplashDamage event
|
||||
with `baseBurst = missileCount`, floored at 1 ONCE. The port re-expresses that cluster as N flying
|
||||
`BTProjectile` rounds (visual tracers). Firing splash PER ROUND (each `baseBurst=1`, each floored at
|
||||
1) applied the floor N times = **~`missileCount`× too much splash** — a clustered bystander died in
|
||||
~2 salvos (user-reported "missiles suddenly lethal"; direct hits were fine — a single enemy survived
|
||||
24). Fix: `BTProjectile.splashBurst` tags ONLY the salvo-lead round (`FireWeapon` passes `nmiss` on
|
||||
`i==0`, `0` on the rest); splash fires once per salvo with `baseBurst = missileCount`. Replicant
|
||||
mirror rounds carry `0`/damage-0 (master delivers splash cross-pod — no double). **Lesson:** a cluster
|
||||
weapon re-expressed as N rounds must apply per-CLUSTER effects (splash, and note the direct hit's
|
||||
zone-concentration is likewise SPREAD in the port vs the arcade's single-zone cluster — a separate,
|
||||
pre-existing under-concentration) once per salvo, not once per round.
|
||||
**Verified:** radius resolves to 30 for missiles / 0 for AC+Emitters; near-miss dist=15 → 1 burst;
|
||||
live rig (2 clustered mechs, 45s): bystander takes 6 splash events (1/salvo, `baseBurst=6`) and
|
||||
SURVIVES (was ~2 shots pre-fix); primary dies to direct hits in ~3 trigger pulls (36 missiles, ==
|
||||
single-enemy TTK); AC does not splash; no crash. Env `BT_SPLASH_LOG`, `BT_SPLASH_TEST` (synthetic
|
||||
near-miss), `BT_AF_MISSILE` (missile autofire), `BT_SPAWN_ENEMY=2` (clustered bystander rig).
|
||||
**KEY FACT [T1]: `DamageZone::TakeDamage` (arcade `@0041e4e0` == WinTesla `DAMAGE.cpp:379`) is
|
||||
`damageLevel += damageAmount * damageScale[type]` and IGNORES `burstCount`.** So ONE arcade cluster
|
||||
Missile per trigger (damageAmount = authored/missileCount, burstCount = missileCount) applies its hit
|
||||
EXACTLY ONCE to a zone — `burstCount` is cosmetic for zone damage (only the gyro-bounce math
|
||||
`gyro.cpp:834` and the SplashDamage falloff `damage.burstCount/dist^exp` read it). The port
|
||||
re-expresses that ONE cluster as N flying `BTProjectile` rounds (visual tracers), and task #62
|
||||
damaged + splashed on EVERY round → **~`missileCount`× too lethal on BOTH the direct hit and the
|
||||
splash** (user-reported "missiles kill in 2 shots" — a mech that should take many salvos). Fix
|
||||
(`mislanch.cpp` FireWeapon): only the salvo-LEAD round (`i==0`) carries damage (`damageData.
|
||||
damageAmount`) AND the cluster splash (`splashBurst = nmiss`); the other N-1 rounds are VISUAL
|
||||
(damage 0, `splashBurst 0`) — the ripple of tracers. `BTProjectile.splashBurst` gates the two splash
|
||||
hooks; the direct-hit block already skips `p.damage<=0`. Replicant mirror rounds carry 0 (master
|
||||
delivers cross-pod — no double). **Lesson:** a cluster weapon re-expressed as N rounds must apply ALL
|
||||
zone effects (direct damage AND splash) ONCE per salvo, not once per round — the arcade's single
|
||||
Missile is one damage event, `burstCount` notwithstanding.
|
||||
**Verified [T2]:** per-hit missile damage = clean 5.83, burst 1, ONCE (`[dmghit]` trace); radius 30
|
||||
for missiles / 0 for AC+Emitters. Missiles-ONLY, single enemy, 45s: 8 damaging hits, top zone reaches
|
||||
only 0.18, **NO death** (was death in ~3 pulls pre-fix) — "way more than 2 shots" restored. AC (one
|
||||
round/shot, not a cluster) unaffected. Env `BT_SPLASH_LOG`, `BT_DMG_LOG` (per-hit `[dmghit]` +
|
||||
zone-armor), `BT_AF_MISSILE` (missile-only autofire, independent of BT_AUTOFIRE), `BT_SPAWN_ENEMY=N`
|
||||
(N clustered dummies). ⚠ `BT_AUTOFIRE` fires ALL weapon groups (laser+PPC+AC) — use `BT_AF_MISSILE`
|
||||
alone to isolate missile TTK.
|
||||
**Deferred [T3]:** the per-player enable sub-gate `Missile+0x360 = BTPlayer+0x264` (part_013.c:8757) —
|
||||
its decomp writers (4668/10512) read as a per-frame state toggle, not a clean config flag, and the
|
||||
port's `showDamageInflicted` label is itself a guess; port treats authored `SplashRadius>0` as the
|
||||
|
||||
Reference in New Issue
Block a user