#124 twist-sign VERIFIED correct (live missile bench) + the rig to do it
The frame-adapter's inferred twist-sign flip (SelectSlice theta -= twist, vs the binary's += pre-reflection) was the last unverified half of #124 -- every earlier probe ran at twist 0. Bench: stationary madcat target with the torso PINNED at 0 / +140 / -140 deg, LRM salvos from a fixed shooter (missiles = the authentic cylinder path; the binary DROPPED zone -1 beam damage). Result: slice picks track the physically-facing flank in BOTH directions (twist-left -> right-family zones for left-flank impacts, twist-right -> left-family), deterministic, wrong-sign outcome (slice 7 vs observed slice 1) clearly excluded. No game-code change needed. Instrumentation added (all env-gated): - torso.cpp BT_FORCE_TWIST=<-1..1>: HOLD the sim's analogTwistAxis (the input-level pin was dead -- live input rides the CONTROLS.MAP device push, and Basic mode auto-centers; sim-level is plumbing-independent). - dmgtable.cpp [slice] line: rot flag, live twist, thetaIn/thetaAdj, chosen slice -- the weighted leaf roll made zone-only logs ambiguous. - [dmgresolve] now names the zone (BTMechZoneSegAndName). - mech4.cpp BT_FORCE_TWIST input pin + one-shot mode cycle (kept as doc of the dead path), mechmppr [mppr] mode probe. - scratchpad/night11/twistsign.sh: the 3-config bench. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
952f10b18d
commit
1f995ee35a
@@ -175,6 +175,7 @@ DamageZonePercentTable *
|
||||
{
|
||||
if (sliceCount <= 0) return 0;
|
||||
|
||||
Scalar thetaIn = theta;
|
||||
if (rotateWithTorso) // binary this[3] != 0
|
||||
{
|
||||
// #124 frame adapter, angular half: theta arrives in the 1995 frame
|
||||
@@ -189,6 +190,19 @@ DamageZonePercentTable *
|
||||
int index = (int)floorf(theta * (Scalar)sliceCount * (1.0f / TwoPi));
|
||||
if (index < 0) index = 0;
|
||||
if (index > sliceCount - 1) index = sliceCount - 1;
|
||||
|
||||
// #124 twist-sign bench: expose the twist term itself -- the leaf is a
|
||||
// weighted roll, so the SLICE choice (not the rolled zone) is the signal.
|
||||
if (getenv("BT_DMGTABLE_LOG"))
|
||||
{
|
||||
static int s_sl = 0;
|
||||
if (s_sl++ < 400)
|
||||
DEBUG_STREAM << "[slice] rot=" << (int)rotateWithTorso
|
||||
<< " twist=" << (float)owner->TorsoHeading()
|
||||
<< " thetaIn=" << (float)thetaIn
|
||||
<< " thetaAdj=" << (float)theta
|
||||
<< " -> slice " << index << "/" << sliceCount << std::endl;
|
||||
}
|
||||
return slices[index];
|
||||
}
|
||||
|
||||
@@ -327,6 +341,12 @@ int
|
||||
{
|
||||
static int s_rh = 0;
|
||||
if (s_rh++ < 400)
|
||||
{
|
||||
extern int BTMechZoneSegAndName(void *mech_v, int zone_idx,
|
||||
int *seg_out, const char **name_out);
|
||||
int seg = -1; const char *zname = 0;
|
||||
if (resolved >= 0)
|
||||
BTMechZoneSegAndName((void *)owner, resolved, &seg, &zname);
|
||||
DEBUG_STREAM << "[dmgresolve] impact=(" << impact.x << ","
|
||||
<< impact.y << "," << impact.z << ")"
|
||||
<< " local=(" << local.x << "," << local.y << "," << local.z << ")"
|
||||
@@ -334,7 +354,9 @@ int
|
||||
<< " frac=" << (depth / heightRef)
|
||||
<< " layer=" << layerIndex << "/" << layerCount
|
||||
<< " theta=" << theta
|
||||
<< " -> zone " << resolved << std::endl;
|
||||
<< " -> zone " << resolved
|
||||
<< " '" << (zname ? zname : "?") << "'" << std::endl;
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@@ -3384,6 +3384,34 @@ void
|
||||
}
|
||||
sPrevXT = xtNow;
|
||||
gBTTwistAxis = sTwist;
|
||||
// DIAG (BT_FORCE_TWIST=<-1..1>): pin the twist axis for
|
||||
// the #124 twist-sign bench (the axis is a RATE demand,
|
||||
// so a pinned axis slews the torso to its per-mech
|
||||
// LIMIT and holds -- a known, stable twist state).
|
||||
// Same pattern as BT_FORCE_ELEV below.
|
||||
{
|
||||
static float s_ft = -2.0f;
|
||||
if (s_ft < -1.5f)
|
||||
{
|
||||
const char *ft = getenv("BT_FORCE_TWIST");
|
||||
s_ft = ft ? (float)atof(ft) : -3.0f;
|
||||
}
|
||||
if (s_ft >= -1.0f)
|
||||
{
|
||||
gBTTwistAxis = s_ft;
|
||||
// BASIC mode ignores the twist axis (the stick
|
||||
// steers the legs; the torso auto-centers), so
|
||||
// the pin also cycles the control mode ONCE:
|
||||
// Basic -> Standard puts the mapper's twist
|
||||
// branch in charge.
|
||||
static int s_ftMode = 0;
|
||||
if (!s_ftMode)
|
||||
{
|
||||
s_ftMode = 1;
|
||||
gBTModeCycle = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TORSO ELEVATION (pitch aim -- the pod stick's Y
|
||||
// axis; every 1995 control mode routes it to
|
||||
|
||||
@@ -840,6 +840,15 @@ void
|
||||
extern float gBTElevAxis;
|
||||
stickPosition.y = gBTElevAxis;
|
||||
}
|
||||
// #124 twist-sign bench probe: is the axis routed, and in what mode?
|
||||
if (getenv("BT_TORSO_LOG"))
|
||||
{
|
||||
static int s_mp = 0;
|
||||
if ((s_mp++ % 60) == 0 && s_mp < 1200)
|
||||
DEBUG_STREAM << "[mppr] mode=" << (int)controlMode
|
||||
<< " twistAxis=" << gBTTwistAxis
|
||||
<< " keyTurn=" << key_turn << "\n" << std::flush;
|
||||
}
|
||||
if (controlMode == BasicMode)
|
||||
{
|
||||
stickPosition.x = key_turn;
|
||||
|
||||
@@ -587,6 +587,23 @@ void
|
||||
static int s_sweep = 0;
|
||||
analogTwistAxis = ((++s_sweep / 90) & 1) ? -1.0f : 1.0f; // +/- every ~90 frames
|
||||
}
|
||||
// #124 twist-sign bench (BT_FORCE_TWIST=<-1..1>): HOLD the analog axis at a
|
||||
// constant (the sweep above alternates) -- the sim integrates currentTwist
|
||||
// to the per-mech limit and stays, giving the cylinder-table bench a known
|
||||
// twist state at the SIM level, independent of the input plumbing.
|
||||
{
|
||||
static float s_forceTwist = -2.0f;
|
||||
if (s_forceTwist < -1.5f)
|
||||
{
|
||||
const char *ft = getenv("BT_FORCE_TWIST");
|
||||
s_forceTwist = ft ? (float)atof(ft) : -3.0f;
|
||||
}
|
||||
if (s_forceTwist >= -1.0f)
|
||||
{
|
||||
effectiveTwistRate = baseTwistRate;
|
||||
analogTwistAxis = s_forceTwist;
|
||||
}
|
||||
}
|
||||
|
||||
// TORSO GATE PROBE (BT_TORSO_LOG): why is the twist rate zero?
|
||||
if (getenv("BT_TORSO_LOG"))
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# #124 TWIST-SIGN VERIFY -- the follow-up the frame-adapter work left open:
|
||||
# SelectSlice's torso-twist term sign was INFERRED from the z-negation
|
||||
# reflection, never exercised (every probe ran at twist 0). Rig: stationary
|
||||
# madcat TARGET pinned at full twist (BT_FORCE_TWIST, rate-demand axis ->
|
||||
# slews to the per-mech limit and holds), shooter approaches to a fixed
|
||||
# bearing and pulses LRM salvos (BT_AF_MISSILE -- missiles are the authentic
|
||||
# cylinder-path weapon; beams with zone -1 were DROPPED by the binary).
|
||||
# Two configs: twist +1 vs -1. READ: target's [dmgresolve] zone spread --
|
||||
# hull-fixed wheels (legs/hip) must NOT move between runs (control); torso
|
||||
# wheels must swap L/R families to match the flank visibly facing the
|
||||
# shooter (A's BT_SHOT captures are the ground truth).
|
||||
set -x
|
||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
||||
cd /c/git/bt411/content || exit 1
|
||||
bt_assert_player_env
|
||||
|
||||
for TW in 0 +1 -1; do
|
||||
TAG=Z; [ "$TW" = "+1" ] && TAG=P; [ "$TW" = "-1" ] && TAG=N
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 2
|
||||
rm -f ts_${TAG}_a.log ts_${TAG}_b.log ts${TAG}_*.png
|
||||
bt_expert_egg MP.EGG TS.EGG
|
||||
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" TS.EGG
|
||||
|
||||
# TARGET: stationary, torso pinned; log every cylinder resolution.
|
||||
BT_FORCE_TWIST=$TW BT_DMGTABLE_LOG=1 BT_CYL_LOG=1 BT_DMG_LOG=1 BT_MP_LOG=1 \
|
||||
bt_launch ts_${TAG}_b.log TS.EGG 0x0C -net 1601
|
||||
sleep 2
|
||||
# SHOOTER: approach to fixed range, missile salvos only, periodic captures.
|
||||
BT_GOTO=enemy BT_GOTO_STOP=90 BT_KEY_NOFOCUS=1 \
|
||||
BT_AF_MISSILE=1 BT_AF_PERIOD=6 \
|
||||
BT_DMG_LOG=1 BT_MP_LOG=1 BT_SHOT_EVERY=300 BT_SHOT_PREFIX=ts$TAG \
|
||||
bt_launch ts_${TAG}_a.log TS.EGG 0x03 -net 1501
|
||||
sleep 5
|
||||
python ../tools/btconsole.py TS.EGG 127.0.0.1:1501 127.0.0.1:1601 \
|
||||
> ts_${TAG}_relay.log 2>&1 &
|
||||
RELAY=$!
|
||||
sleep 170
|
||||
kill $RELAY 2>/dev/null
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 3
|
||||
done
|
||||
echo "=== resolves per run:"
|
||||
grep -c dmgresolve ts_Z_b.log ts_P_b.log ts_N_b.log
|
||||
Reference in New Issue
Block a user