BT_SELF_DAMAGE: kill your own pilot in solo, so the RESPAWN family is bench-testable at last
Nothing could kill the LOCAL pilot on a bench. BT_MP_FORCE_DMG only targets REPLICANTS (mech4.cpp:4884 skips anything else), a solo dummy never shoots back, and every other damage path needs a second live pod. So the entire respawn family -- #70 torso twist after respawn, #22 ammo/weapons not resetting, #55 coolant/heat/generator restore, #57 the respawn latch -- could only ever be tested by asking a playtester to die. That is why they are all still open or awaiting-verification. BT_SELF_DAMAGE=<amount/sec> dispatches an unaimed TakeDamage at our OWN mech through the same virtual Entity::Dispatch a real beam hit uses, so the cylinder hit-location lookup, the zone cascade, the vital-subsystem kill and the whole authentic death -> 5s -> DropZone -> Mech::Reset cycle all run for real. No state is poked. =60 kills a fresh MadCat in about a minute. It LATCHES OFF at the first death. That matters more than it sounds: live damage knocks the power bus down, which is exactly the signal a respawn test wants to read. The first run of this harness produced a torso electrical state flapping 4 <-> 1 and I nearly filed it as #70 -- it was the harness still shooting me. One death, then silence, then measure. FIRST RESULT -- #70 does NOT reproduce in solo, but something near it does. After the respawn the MadCat's torso recovers fully: rate back to 0.872665 (the authored 50 deg/s), elec=4 Ready. Twist is not broken by a respawn. However the post-respawn mission shows INTERMITTENT power dropouts that a pristine mission never shows: pristine control (no damage, no death): 48/48 samples elec=4, ZERO dips post-respawn (harness silent): 95/97 elec=4, 2 dips to elec=1 A dip zeroes effectiveTwistRate (torso.cpp:570), so a pilot mid-turn feels the twist cut out -- plausibly what "torso twist stops working after a respawn" actually is: not a permanent stop but a stutter. Both dips are transient and the tail of the run is steady, so it is not a stuck state. Cause not yet found; the watched subsystem's own electrical level (wElec) dips with it, while the generator holds a full 10000V against a 5000V brownout threshold -- so it is NOT the brownout path in PowerWatcher::UpdateWatch. Filed here as the next thread to pull, with the harness that makes it reproducible in one solo run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
034e55c7f5
commit
c5537a1247
@@ -5541,6 +5541,49 @@ void
|
||||
gBTGenSelKey = pulse ? s_gsID : 0;
|
||||
}
|
||||
|
||||
// SELF-DAMAGE HARNESS (BT_SELF_DAMAGE=<amount per second>, off by default).
|
||||
// The whole RESPAWN family -- torso twist after respawn (#70), ammo/weapon
|
||||
// reset (#22), coolant/heat/generator restore (#55), the respawn latch
|
||||
// (#57) -- was untestable on a bench because nothing can kill the LOCAL
|
||||
// pilot in solo: BT_MP_FORCE_DMG only targets REPLICANTS, and a solo
|
||||
// dummy never shoots back. This dispatches an unaimed TakeDamage at our
|
||||
// OWN mech once a second, through the SAME virtual Entity::Dispatch path
|
||||
// a real beam hit uses -- so the cylinder hit-location lookup, the zone
|
||||
// cascade, the vital-subsystem kill and the authentic death/respawn cycle
|
||||
// all run for real. Nothing is poked directly.
|
||||
// e.g. BT_SELF_DAMAGE=40 kills a fresh mech in well under a minute.
|
||||
// ONE DEATH ONLY: latch off as soon as we die, so everything observed
|
||||
// AFTER the respawn is the respawn's own doing and not the harness still
|
||||
// shooting us. (Live damage knocks the power bus down, which is exactly
|
||||
// the signal a respawn test is trying to read.)
|
||||
static int s_sdSpent = 0;
|
||||
if (IsMechDestroyed())
|
||||
s_sdSpent = 1;
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_SELF_DAMAGE") && !s_sdSpent
|
||||
&& !IsMechDestroyed() && damageZoneCount > 0)
|
||||
{
|
||||
static float s_sdAccum = 0.0f;
|
||||
s_sdAccum += dt;
|
||||
if (s_sdAccum >= 1.0f)
|
||||
{
|
||||
s_sdAccum = 0.0f;
|
||||
Damage dmg;
|
||||
dmg.damageType = Damage::ExplosiveDamageType;
|
||||
float want = (float)atof(getenv("BT_SELF_DAMAGE"));
|
||||
dmg.damageAmount = (want > 0.0f) ? want : 20.0f;
|
||||
dmg.burstCount = 1;
|
||||
dmg.impactPoint = localOrigin.linearPosition;
|
||||
Entity::TakeDamageMessage td(
|
||||
Entity::TakeDamageMessageID,
|
||||
sizeof(Entity::TakeDamageMessage),
|
||||
GetEntityID(), -1 /*unaimed -> cylinder table resolves the zone*/, dmg);
|
||||
DEBUG_STREAM << "[selfdmg] " << dmg.damageAmount
|
||||
<< " to own mech (unaimed)" << std::endl << std::flush;
|
||||
Dispatch(&td);
|
||||
}
|
||||
}
|
||||
|
||||
// task #13 scripted verify (BT_VALVE_TEST=1): one MoveValve press at
|
||||
// frame ~600 -- Condenser1's valveState cycles 1 -> 5, so the flow
|
||||
// redistribution gives it 5/10 of the total coolant flow ([valve] log
|
||||
|
||||
Reference in New Issue
Block a user