#124 RESOLVED against the authored skeleton: the pick's zone is the
struck drawn segment's dzone, ALWAYS -- the cylinder embellishment removed
The open question ('what zone did 1995 designate for hull hits') was
already answered in the KB's #73 dig [T0+T1]: no software pick writer
exists -- the pod's pick was a dpl scene intersection, struck triangle
-> DCS segment -> its SKL-authored dzone; the cylinder lottery was only
ever the UNAIMED path (missiles/splash/rams). The live segpick dump
completes it with the authored data: the madcat's pickable skeleton is
18 segments -- hip, shoulders, guns, thighs, knees, ankles+toes, and
ONE hull piece (jointshakey -> dtorso). No ltorso/rtorso/utorso/rear/
door/searchlight segments exist. Aimed fire at any torso panel
authentically designates CENTER TORSO; the side/rear/upper panels strip
via the unaimed path.
Changes:
* the shared-carrier -> cylinder override (yesterday's embellishment)
is REMOVED: triangle hit -> that segment's dzone, period;
* SegAimPoint: the walker's hull anchor moves from the joint ORIGIN
(crotch gap -- rays sailed between the legs to the terrain sentinel)
to the carrier segment's cull center (the chest);
* [picktri]/[pickwin] diagnostics grew tri/seg/zone fields -- three
consecutive 'mystery' regressions in this stretch were the STALE-EXE
trap (CWD-relative cmake --build from content/ resolved to a
nonexistent dir and the old binary kept running) -- the harness doc's
warning, hit again.
Final zone-walk matrix (spinning target, real MP, full cycles):
limbs 55/70 in-zone (legs/feet 6/6; arm strays = hull/occlusion);
hull-family aims -> dtorso 56/69; victim consumption matches. The
night-10 field table now reads as this model's fingerprint: 'only LCT
gets hits' from aimed energy IS the pod -- one hull piece, dtorso.
What was actually broken and is now fixed: the sphere mis-picks
(rgun-from-a-dtorso-aim class), the unaimed path's 180-degree frame,
and the vertical scatter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1a3c268278
commit
00dfbf8f9f
@@ -1681,29 +1681,16 @@ int
|
|||||||
int triBestSeg = -1;
|
int triBestSeg = -1;
|
||||||
int triHit = 0;
|
int triHit = 0;
|
||||||
|
|
||||||
// #124: segments claimed as CARRIER by TWO OR MORE zones (the shared hull
|
// #124 RESOLVED against the authored data (2026-08-03): the pick's zone is
|
||||||
// -- e.g. madcat seg 4 carries dtorso AND ltorso AND rtorso AND utorso AND
|
// the struck DRAWN segment's own SKL dzone, ALWAYS -- the 1995 model (dpl
|
||||||
// the rears) cannot resolve a single zone from geometry. The authentic
|
// scene intersection -> DCS -> segment dzone; combat-damage.md "the #73
|
||||||
// route for their hits is the CYLINDER: return zone -1 with the accurate
|
// pick dig" [T0+T1]). The madcat's pickable skeleton authors ONE hull
|
||||||
// triangle hit point, and the victim's point resolver assigns the panel
|
// piece (jointshakey -> dtorso) and no ltorso/rtorso/utorso/rear/door
|
||||||
// by band/wedge. Unique-carrier segments (legs, feet, arms, gun pods)
|
// segments -- aimed fire at any torso panel authentically designates
|
||||||
// keep their direct zone.
|
// dtorso; the side/rear/upper panels are UNAIMED-path territory (missiles/
|
||||||
unsigned char segClaims[192];
|
// splash through the cylinder). The night-10 audit table is this model's
|
||||||
memset(segClaims, 0, sizeof(segClaims));
|
// exact fingerprint. (An earlier shared-carrier -> cylinder override here
|
||||||
{
|
// was an embellishment and is removed.)
|
||||||
extern int BTMechZoneSegAndName(void *mech_v, int zone_idx,
|
|
||||||
int *seg_out, const char **name_out);
|
|
||||||
int zsi;
|
|
||||||
const char *znm;
|
|
||||||
for (int zi = 0; zi < 64; ++zi)
|
|
||||||
{
|
|
||||||
if (!BTMechZoneSegAndName((void *)mech, zi, &zsi, &znm))
|
|
||||||
break;
|
|
||||||
if (zsi >= 0 && zsi < (int)sizeof(segClaims)
|
|
||||||
&& segClaims[zsi] < 255)
|
|
||||||
++segClaims[zsi];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<int, MechRenderTree::SegPick>::iterator sp;
|
std::map<int, MechRenderTree::SegPick>::iterator sp;
|
||||||
for (sp = it->second.segPick.begin(); sp != it->second.segPick.end(); ++sp)
|
for (sp = it->second.segPick.begin(); sp != it->second.segPick.end(); ++sp)
|
||||||
@@ -1737,6 +1724,15 @@ int
|
|||||||
|
|
||||||
// ---- TRIANGLE TEST (#124): the sphere only nominates ----
|
// ---- TRIANGLE TEST (#124): the sphere only nominates ----
|
||||||
BTPickMesh *pm = BTGetPickMesh(obj);
|
BTPickMesh *pm = BTGetPickMesh(obj);
|
||||||
|
if (pm == 0 && getenv("BT_PICK_LOG"))
|
||||||
|
{
|
||||||
|
static int s_nt = 0;
|
||||||
|
if (s_nt++ < 40)
|
||||||
|
DEBUG_STREAM << "[picktri] seg=" << sp->first << " zone="
|
||||||
|
<< sp->second.zone << " NO TRIS (vb=" << (void *)obj->mBgfVB
|
||||||
|
<< " ib=" << (void *)obj->mBgfIB
|
||||||
|
<< " stride=" << obj->mBgfStride << ")\n" << std::flush;
|
||||||
|
}
|
||||||
if (pm != 0)
|
if (pm != 0)
|
||||||
{
|
{
|
||||||
// ray into object-local space (affine inverse; segment poses are
|
// ray into object-local space (affine inverse; segment poses are
|
||||||
@@ -1797,12 +1793,9 @@ int
|
|||||||
if (triHit)
|
if (triHit)
|
||||||
{
|
{
|
||||||
bestT = triBestT;
|
bestT = triBestT;
|
||||||
bestZone = triBestZone;
|
bestZone = triBestZone; // the struck segment's dzone
|
||||||
hitAny = 1;
|
hitAny = 1;
|
||||||
// shared-carrier segment -> the cylinder decides (accurate point kept)
|
(void)triBestSeg;
|
||||||
if (triBestSeg >= 0 && triBestSeg < (int)sizeof(segClaims)
|
|
||||||
&& segClaims[triBestSeg] > 1)
|
|
||||||
bestZone = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #92 probe: which spheres did the ray actually THREAD, and which won?
|
// #92 probe: which spheres did the ray actually THREAD, and which won?
|
||||||
@@ -1865,7 +1858,9 @@ int
|
|||||||
static int s_pl = 0;
|
static int s_pl = 0;
|
||||||
if ((s_pl++ % 60) == 0)
|
if ((s_pl++ % 60) == 0)
|
||||||
DEBUG_STREAM << "[pickwin] zone=" << bestZone
|
DEBUG_STREAM << "[pickwin] zone=" << bestZone
|
||||||
<< " score=" << bestScore << " t=" << bestT << "\n" << std::flush;
|
<< " score=" << bestScore << " t=" << bestT
|
||||||
|
<< " tri=" << triHit << " triSeg=" << triBestSeg
|
||||||
|
<< " triZone=" << triBestZone << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit_out[0] = ray_start[0] + bestT * ray_dir[0];
|
hit_out[0] = ray_start[0] + bestT * ray_dir[0];
|
||||||
@@ -1902,6 +1897,39 @@ int
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The carrier-SEGMENT variant: anchor at segPick[seg]'s cull center (the
|
||||||
|
// piece's visual middle). For hull-family zones no object claims the zone,
|
||||||
|
// and the zone table's carrier is the hull joint whose ORIGIN sits in the
|
||||||
|
// crotch gap -- rays aimed there sail between the legs to the terrain
|
||||||
|
// sentinel. The cull center is the chest.
|
||||||
|
int
|
||||||
|
BTL4VideoRenderer::SegAimPoint(Entity *mech, int seg, float out3[3])
|
||||||
|
{
|
||||||
|
std::map<Entity*, MechRenderTree>::iterator it = mMechRenderTrees.find(mech);
|
||||||
|
if (it == mMechRenderTrees.end() || it->second.wrecked)
|
||||||
|
return 0;
|
||||||
|
std::map<int, MechRenderTree::SegPick>::iterator sp = it->second.segPick.find(seg);
|
||||||
|
if (sp == it->second.segPick.end() || sp->second.obj == NULL
|
||||||
|
|| sp->second.obj->mCullRadius <= 0.0f)
|
||||||
|
return 0;
|
||||||
|
D3DXMATRIX l2w = sp->second.obj->GetLocalToWorld();
|
||||||
|
D3DXVECTOR3 cw;
|
||||||
|
D3DXVec3TransformCoord(&cw, &sp->second.obj->mCullCenter, &l2w);
|
||||||
|
out3[0] = cw.x; out3[1] = cw.y; out3[2] = cw.z;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTMechSegAimPoint(void *mech, int seg, float out3[3])
|
||||||
|
{
|
||||||
|
if (mech == NULL || application == NULL)
|
||||||
|
return 0;
|
||||||
|
BTL4VideoRenderer *renderer =
|
||||||
|
(BTL4VideoRenderer *)application->GetVideoRenderer();
|
||||||
|
if (renderer == NULL)
|
||||||
|
return 0;
|
||||||
|
return renderer->SegAimPoint((Entity *)mech, seg, out3);
|
||||||
|
}
|
||||||
|
|
||||||
int BTMechZoneAimPoint(void *mech, int zone, float out3[3])
|
int BTMechZoneAimPoint(void *mech, int zone, float out3[3])
|
||||||
{
|
{
|
||||||
if (mech == NULL || application == NULL)
|
if (mech == NULL || application == NULL)
|
||||||
|
|||||||
@@ -803,6 +803,8 @@ extern void BTDrawReticle(struct IDirect3DDevice9 *device);
|
|||||||
// above). 0 when the zone has no pick geometry.
|
// above). 0 when the zone has no pick geometry.
|
||||||
int
|
int
|
||||||
ZoneAimPoint(Entity *mech, int zone, float out3[3]);
|
ZoneAimPoint(Entity *mech, int zone, float out3[3]);
|
||||||
|
int
|
||||||
|
SegAimPoint(Entity *mech, int seg, float out3[3]);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -6127,14 +6127,17 @@ void
|
|||||||
<< target->GetEntityID() << "\n" << std::flush;
|
<< target->GetEntityID() << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
extern int BTMechZoneAimPoint(void *mech, int zone, float out3[3]);
|
extern int BTMechZoneAimPoint(void *mech, int zone, float out3[3]);
|
||||||
|
extern int BTMechSegAimPoint(void *mech, int seg, float out3[3]);
|
||||||
int haveAim = 0;
|
int haveAim = 0;
|
||||||
if (BTMechZoneSegAndName(target, s_zwZone, &segIdx, &zname)
|
if (BTMechZoneSegAndName(target, s_zwZone, &segIdx, &zname)
|
||||||
&& segIdx >= 0)
|
&& segIdx >= 0)
|
||||||
{
|
{
|
||||||
// prefer the zone's VISUAL center (its pick geometry's
|
// anchor order: the zone's own pick geometry -> the
|
||||||
// cull-center); the segment ORIGIN sits at the joint
|
// CARRIER segment's cull center (hull-family zones own
|
||||||
// and made feet/lower legs strike the part above.
|
// no geometry; the joint ORIGIN sits in the crotch gap
|
||||||
|
// and rays sail between the legs) -> the raw joint.
|
||||||
haveAim = BTMechZoneAimPoint(target, s_zwZone, sp)
|
haveAim = BTMechZoneAimPoint(target, s_zwZone, sp)
|
||||||
|
|| BTMechSegAimPoint(target, segIdx, sp)
|
||||||
|| BTResolveSegmentWorld((void *)target, segIdx, sp, rows);
|
|| BTResolveSegmentWorld((void *)target, segIdx, sp, rows);
|
||||||
}
|
}
|
||||||
if (haveAim)
|
if (haveAim)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ BT_SPIN_SELF=15 BT_DMG_LOG=1 BT_DEATH_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1 \
|
|||||||
bt_launch zw_b.log ZW.EGG 0x0C -net 1601
|
bt_launch zw_b.log ZW.EGG 0x0C -net 1601
|
||||||
sleep 2
|
sleep 2
|
||||||
# SHOOTER second (foreground -- owns the pick focus): the walker.
|
# SHOOTER second (foreground -- owns the pick focus): the walker.
|
||||||
BT_ZONE_WALK=6 BT_GOTO=enemy BT_GOTO_STOP=90 BT_KEY_NOFOCUS=1 \
|
BT_ZONE_WALK=6 BT_PICK_LOG=1 BT_GOTO=enemy BT_GOTO_STOP=90 BT_KEY_NOFOCUS=1 \
|
||||||
BT_DMG_LOG=1 BT_RANGE_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1 \
|
BT_DMG_LOG=1 BT_RANGE_LOG=1 BT_MP_LOG=1 BT_MATCHLOG=1 \
|
||||||
bt_launch zw_a.log ZW.EGG 0x03 -net 1501
|
bt_launch zw_a.log ZW.EGG 0x03 -net 1501
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|||||||
Reference in New Issue
Block a user