Slice Combat Depth (MC-3 + wiring + review fixes): Spitter aim-line + player-hit punch, rigged enemies, in-band gate (DR-041)

Completes the Combat Depth slice on top of the MC-2 server spine (56cf60cce):

MC-3 impact juice (client, observe-only):
- 7 FeelConfig fields + ResetDefaults; magnitude-scaled player-dealt-hit camera
  PunchFov on the enemy-Health-decrease edge (camera-only hit-stop, never timeScale).
- Spitter Kind==2 aim-LANE telegraph (BuildLaneMesh) — reads baked SpitterState
  client-side, falls back to a fixed length. True freeze + material flash deferred.

Content / wiring:
- SpitterProjectilePrefabAuthoring (the SpitterProjectilePrefab singleton).
- Both directors rebuilt to a 4-entry KIND-INDEXED roster [Grunt,Charger,Spitter,
  Swarmer] + mix/MaxAlive config + the SpitterProjectileConfig singleton in the subscene.
- Real rigged models: EnemySpitter (re-skinned Kaiju, ranged poker) + EnemySwarmerUndead
  (Undead-Werewolf, fast/low-HP); grunt/charger keep Werewolf/ChargerMuscle. EnemySpit =
  ownerless interpolated ghost (no Health, no collider).

Post-impl adversarial review fixes (wf_febdcfdb-665):
- [MED] in-band fire gate: the Spitter committed its telegraph from ANY range (fired while
  advancing from far). Now commits only when sInBand || sCornered (gives CorneredRange a
  real read site) — a Spitter out-of-band holds fire and repositions.
- [LOW] EnemyProjectileDamageSystem early-returns on !ServerTick.IsValid (sibling parity).
- [LOW] EnemyAuthoring bake-time guard: errors if a prefab composes both Charger+Spitter
  (would match zero AI passes -> never move).
- [LOW] tests: Spitter brain fires from Expedition (kills the Base==0 region false-green);
  a direct partition-exclusion test replaces the order-masked claim; added out-of-band +
  cornered negative tests.

388/388 EditMode green + two Play smokes (clean boot, fire, swept-hit, region, server==
client; rigged Kaiju spitter bakes + fires with zero console errors). Accepted as-is
(documented in DR-041): global spit soft-cap, co-op punch attribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 21:08:59 -07:00
parent 56cf60cce3
commit e32dadbc66
20 changed files with 5907 additions and 16 deletions
+69 -2
View File
@@ -2536,15 +2536,25 @@ MonoBehaviour:
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.WaveDirectorAuthoring
EnemyPrefabs:
- {fileID: 3885353946372160549, guid: a6c2004a3cc32cc44b1bb7a795f86519, type: 3}
- {fileID: 3885353946372160549, guid: f77a36036567c814496e6c59c42b2082, type: 3}
- {fileID: 3885353946372160549, guid: 31d233e9e507acf45a411f8ab0997bed, type: 3}
- {fileID: 3885353946372160549, guid: 0d42b4a8ef76489458ee1ecf51b4dbca, type: 3}
- {fileID: 3885353946372160549, guid: f29273bdfc85a8b49a4e16719e9a2568, type: 3}
- {fileID: 3885353946372160549, guid: b0921d4cb0eedd349a257759a157653a, type: 3}
RingRadius: 16
RingSlots: 10
BaseCount: 4
CountPerWave: 2
SpawnIntervalTicks: 24
LullTicks: 240
MaxAlive: 14
ChargerBase: 0
SpitterBase: 0
SwarmerSlotBase: 0
ChargerPerEpoch: 1
SpitterPerEpoch: 1
SwarmerSlotPerEpoch: 0
SwarmerPackSize: 3
SwarmerPackPerEpoch: 0
ClusterTightRadius: 2.5
--- !u!1 &1379903944
GameObject:
m_ObjectHideFlags: 0
@@ -3160,6 +3170,52 @@ BoxCollider:
serializedVersion: 3
m_Size: {x: 3.5, y: 8, z: 3.5}
m_Center: {x: 0, y: 4, z: 0}
--- !u!1 &1871304248
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1871304250}
- component: {fileID: 1871304249}
m_Layer: 0
m_Name: SpitterProjectileConfig
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1871304249
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1871304248}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4ce5223c5fd56694c81991e1bb1232de, type: 3}
m_Name:
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.SpitterProjectilePrefabAuthoring
ProjectilePrefab: {fileID: 3885353946372160549, guid: 8a13ef653e5266741b0896084f74038f, type: 3}
MaxLiveProjectiles: 24
--- !u!4 &1871304250
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1871304248}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1906259338
GameObject:
m_ObjectHideFlags: 0
@@ -3344,12 +3400,22 @@ MonoBehaviour:
EnemyPrefabs:
- {fileID: 3885353946372160549, guid: a6c2004a3cc32cc44b1bb7a795f86519, type: 3}
- {fileID: 3885353946372160549, guid: 0d42b4a8ef76489458ee1ecf51b4dbca, type: 3}
- {fileID: 3885353946372160549, guid: f29273bdfc85a8b49a4e16719e9a2568, type: 3}
- {fileID: 3885353946372160549, guid: b0921d4cb0eedd349a257759a157653a, type: 3}
MaxAlive: 12
RingRadius: 14
RingSlots: 10
SpawnIntervalTicks: 30
GruntsPerWave: 4
ChargersPerWave: 1
SpitterBase: 0
SwarmerSlotBase: 0
ChargerPerEpoch: 1
SpitterPerEpoch: 1
SwarmerSlotPerEpoch: 1
SwarmerPackSize: 4
SwarmerPackPerEpoch: 0
ClusterTightRadius: 2.5
RewardOre: 25
--- !u!4 &1957070224
Transform:
@@ -3748,3 +3814,4 @@ SceneRoots:
- {fileID: 722706770}
- {fileID: 2145598870}
- {fileID: 1957070224}
- {fileID: 1871304250}