diff --git a/Assets/_Project/Scripts/Client/Presentation/CombatFeedbackSystem.cs b/Assets/_Project/Scripts/Client/Presentation/CombatFeedbackSystem.cs index 444227777..d7784045f 100644 --- a/Assets/_Project/Scripts/Client/Presentation/CombatFeedbackSystem.cs +++ b/Assets/_Project/Scripts/Client/Presentation/CombatFeedbackSystem.cs @@ -152,7 +152,7 @@ namespace ProjectM.Client _dangerMat.color = new Color(3.2f, 0.28f, 0.18f, 1f); // HDR red (per-zone intensity carried in vertex alpha) _portalMat = MakeParticleMaterial(); _portalMat.name = "RoomPortal"; - _portalMat.color = new Color(0.5f, 2.6f, 3.4f, 0.85f); // DR-046: HDR cyan portal glow (pushes past bloom) + _portalMat.color = new Color(0.25f, 1.2f, 1.55f, 0.85f); // DR-046: HDR cyan portal glow (Phase 0: tamed — 2.6/3.4 bloomed to a white blob) // Health-bar materials (UI/Default = always-included URP-compatible UI shader; per-instance Image.color carries alpha). Shader uiShader = Shader.Find("UI/Default") ?? Shader.Find("Sprites/Default"); @@ -1021,10 +1021,11 @@ void TriggerSlash(Vector3 pos, float2 facing, float range, float halfAngle, int float t = (float)SystemAPI.Time.ElapsedTime; float breathe = 0.5f + 0.5f * math.sin(t * 3.5f); var tr = _portalBeacon.transform; - // Cylinder is 2u tall in local space -> scale.y=3 gives a 6u pillar; lift the centre so the base sits on the ground. - tr.position = new Vector3(pos.x, pos.y + 3f, pos.z); - tr.localScale = new Vector3(1.4f + 0.15f * breathe, 3f, 1.4f + 0.15f * breathe); - _portalMat.color = new Color(0.5f, 2.6f, 3.4f, 0.55f + 0.35f * breathe); // glow throb (beacon-only mat, safe to mutate) + // Cylinder is 2u tall in local space -> scale.y=2.2 gives a 4.4u pillar; lift the centre so the base sits + // on the TERRAIN (y=0) — pos.y is the CC capsule-center plane (GridOrigin.y=1), 1 u above the ground. + tr.position = new Vector3(pos.x, 2.2f, pos.z); + tr.localScale = new Vector3(0.9f + 0.12f * breathe, 2.2f, 0.9f + 0.12f * breathe); + _portalMat.color = new Color(0.25f, 1.2f, 1.55f, 0.45f + 0.3f * breathe); // glow throb (beacon-only mat; Phase 0: tamed + slimmed — the fat 6u pillar bloomed to a white egg swallowing the prompt) } diff --git a/Assets/_Project/Scripts/Client/Presentation/HudSystem.cs b/Assets/_Project/Scripts/Client/Presentation/HudSystem.cs index 8a48474ff..84bce62ab 100644 --- a/Assets/_Project/Scripts/Client/Presentation/HudSystem.cs +++ b/Assets/_Project/Scripts/Client/Presentation/HudSystem.cs @@ -180,10 +180,12 @@ namespace ProjectM.Client int huskCount = _huskQuery.CalculateEntityCount(); // ---- Macro: phase + cycle + countdown (center-top banner) ---- + bool haveRun = SystemAPI.TryGetSingleton(out var runInfo); // hoisted: the phase banner is lifecycle-aware (Phase 0 fix — it read "AT BASE" inside expedition rooms) bool haveCycle = SystemAPI.TryGetSingleton(out var cyc); bool siege = haveCycle && cyc.Phase == CyclePhase.Siege; bool goalFull = SystemAPI.TryGetSingleton(out var goalNow) && goalNow.Target > 0 && goalNow.Charge >= goalNow.Target; bool finalSiege = siege && goalFull; // END-2: the climactic final siege (goal cap reached) + bool onRun = haveRun && !siege && runInfo.Lifecycle != RunLifecycle.Staging; // mid-run: the base's Calm label is wrong if (haveCycle) { var endTick = new NetworkTick(cyc.PhaseEndTick); @@ -199,7 +201,7 @@ namespace ProjectM.Client detail = ""; // END-2: the climax reads distinct (intense red), not a normal incursion/wave. var col = finalSiege || finalArming ? new Color(1f, 0.28f, 0.22f) : PhaseColor(cyc.Phase); - _phaseText.text = (finalSiege ? "HOLD THE ENGINE" : PhaseLabel(cyc.Phase)) + (detail.Length > 0 ? " - " + detail : ""); + _phaseText.text = (finalSiege ? "HOLD THE ENGINE" : onRun ? "ON EXPEDITION" : PhaseLabel(cyc.Phase)) + (detail.Length > 0 ? " - " + detail : ""); _phaseText.style.color = col; _cycleText.text = "CYCLE " + cyc.CycleNumber; _banner.style.borderBottomColor = col; @@ -215,7 +217,6 @@ namespace ProjectM.Client // (the old camera-X + walk-in-gate copy died with the gate; siege/final overrides below still win). var cam = Camera.main; // camera-X region signal still feeds downstream panels (atmosphere/threat) bool onExpedition = cam != null && cam.transform.position.x > ExpeditionRegionXMin; - bool haveRun = SystemAPI.TryGetSingleton(out var runInfo); SystemAPI.TryGetSingleton(out var obj); if (haveRun && !siege && !finalSiege) { @@ -255,6 +256,10 @@ namespace ProjectM.Client _locationText.text = "ROOM CLEARED - choose your boon"; _locationText.style.color = new Color(0.5f, 1f, 0.6f); break; + case RunLifecycle.RoomExplore: // Phase 0: without this case the RoomReward text stuck through the loot window + _locationText.text = "ROOM CLEAR - grab the loot, take the portal to move on"; + _locationText.style.color = new Color(0.5f, 1f, 0.6f); + break; case RunLifecycle.RouteSelect: _locationText.text = "CHOOSE YOUR PATH"; _locationText.style.color = new Color(0.55f, 0.85f, 1f); diff --git a/Assets/_Project/Scripts/Server/HomeBase/SharedStorageSpawnSystem.cs b/Assets/_Project/Scripts/Server/HomeBase/SharedStorageSpawnSystem.cs index 6f69c3212..34c260110 100644 --- a/Assets/_Project/Scripts/Server/HomeBase/SharedStorageSpawnSystem.cs +++ b/Assets/_Project/Scripts/Server/HomeBase/SharedStorageSpawnSystem.cs @@ -39,6 +39,10 @@ namespace ProjectM.Server { var container = ecb.Instantiate(spawner.Prefab); var position = BaseGridMath.CellToWorld(anchor, spawner.Cell); + // Phase 0: the grid Y (GridOrigin.y=1) is the CC capsule-CENTER plane; center-pivot structure + // meshes look grounded there, but the crate's pivot is at its base -> it floated 1 u. Sit it on + // the terrain surface instead. + position.y = 0f; // Preserve the prefab's baked scale/rotation (FromPosition would reset Scale to 1). var xform = SystemAPI.GetComponent(spawner.Prefab); xform.Position = position;