G6+G4: Cone damage-at-contact + zone fill telegraph (ZoneEffect GhostFields) + co-op saturation budget

Cone/SpecialSlam damage lands at its visual contact via ConeContactPending (knob 32, 0=legacy;
early-flush + resolve re-validate; death + BOTH class-swap paths drop armed pendings — fixes the
shipped melee death-strand in the same stroke). Zones: [GhostField] Caster/Radius/NextTick +
ZoneTelegraphSystem (Geyser latch contract on InterpolationTick; rim = true radius; arm grows,
persistent phase drains). Cone cues latch to contact (FireStartRaw, C14); TuningConfig.Defaults()
fallback at client cue sites (release-build timing fix). G4: SaturationMath ally-FX degrade
(living-enemy census, solo-exempt; enemy telegraphs structurally exempt) + CombatStressDebug +
overlay saturation rows. Reviews wf_98bf1268 (13 confirmed folded) / wf_9757d214 (5 confirmed fixed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 13:27:50 -07:00
parent 9d6977cd64
commit 2aebc37115
25 changed files with 598 additions and 64 deletions
@@ -204,5 +204,32 @@ namespace ProjectM.Client
m.RecalculateBounds();
return m;
}
// Unit-radius thin RING (annulus) on the XZ plane — the always-on rim of a zone telegraph (rim = the TRUE
// damage radius, guidelines G2) while a separate fill disc grows inside it. Scale x/z to the radius; inner
// edge fixed at innerFrac of the outer. No vertex colours (white) so an MPB _Color fully tints + fades it.
public static Mesh BuildRing(int segments, float innerFrac = 0.92f)
{
if (segments < 6) segments = 6;
innerFrac = Mathf.Clamp(innerFrac, 0.05f, 0.98f);
var m = new Mesh { name = "Ring" };
var v = new Vector3[segments * 2];
var tris = new int[segments * 6];
for (int i = 0; i < segments; i++)
{
float a = i / (float)segments * Mathf.PI * 2f;
var dir = new Vector3(Mathf.Cos(a), 0f, Mathf.Sin(a));
v[i * 2] = dir * innerFrac;
v[i * 2 + 1] = dir;
int n = (i + 1) % segments;
int b = i * 6;
tris[b] = i * 2; tris[b + 1] = n * 2 + 1; tris[b + 2] = i * 2 + 1;
tris[b + 3] = i * 2; tris[b + 4] = n * 2; tris[b + 5] = n * 2 + 1;
}
m.vertices = v;
m.triangles = tris;
m.RecalculateBounds();
return m;
}
}
}