using System.Collections.Generic; using TMPro; using UnityEngine; namespace DepthsOfGreed.HandbookUI { public sealed partial class SupplyBasementController { [Header("Versorgungssystem – optional")] [Tooltip("MonoBehaviour mit ISupplyGameplay. Leer = bisherige Bedien- und Fahrvorschau.")] [SerializeField] private MonoBehaviour supplyBackend; public TMP_Text[] storageAmounts, bufferAmounts, magazineAmounts; public bool HasSupplyBackend => supplyBackend && supplyBackend is ISupplyGameplay; public ISupplyGameplay SupplyBackend => HasSupplyBackend ? (ISupplyGameplay)supplyBackend : null; private SupplyState supplyState; private float commandMessageUntil; private readonly List supplyObjects = new List(); public void BindSupplyBackend(MonoBehaviour backend) { if (backend && !(backend is ISupplyGameplay)) { Debug.LogError("Versorgung: Komponente muss ISupplyGameplay implementieren.", backend); return; } supplyBackend = backend; // Filled on the next UI refresh; safe even before Awake. nextRefresh = 0; } private IReadOnlyList GetSupplyObjects() { if (!HasSupplyBackend) return placement && placement.Backend != null ? placement.Backend.BuiltObjects : null; supplyState = SupplyBackend.ReadState(); supplyObjects.Clear(); if (supplyState?.towers != null) foreach (var t in supplyState.towers) if (t != null && t.type) supplyObjects.Add(new BuiltObjectSnapshot { instanceId = t.instanceId, type = t.type }); Priority = supplyState == null ? -1 : (int)supplyState.priority; RenderPriority(); RenderAmounts(); return supplyObjects; } private TowerSupplyState FindTower(long id) { if (supplyState?.towers != null) foreach (var t in supplyState.towers) if (t != null && t.instanceId == id) return t; return null; } private bool TrySetBackendConnection(long id, bool connected) { if (!HasSupplyBackend) return false; var result = SupplyBackend.SetConnected(id, connected); if (result.accepted) ConnectionChanged?.Invoke(id, connected); else ShowCommandMessage(result.message); RefreshConnections(); return true; } private bool TrySetBackendPriority(int kind) { if (!HasSupplyBackend) return false; int desired = Priority == kind ? -1 : kind; var result = SupplyBackend.SetPriority((SupplyKind)desired); if (result.accepted) PriorityChanged?.Invoke(desired); else ShowCommandMessage(result.message); RefreshConnections(); return true; } private void ShowCommandMessage(string message) { truckStatus.text = string.IsNullOrWhiteSpace(message) ? "Aktion derzeit nicht möglich" : message; commandMessageUntil = Time.unscaledTime + 2; } private void RenderPriority() { for (int i = 0; i < priorityButtons.Length; i++) { priorityButtons[i].GetComponent().color = Priority == i ? ColorFor(i) : new Color(.72f,.72f,.72f); priorityLabels[i].text = Priority == i ? "Vorrang aktiv" : "Vorrang geben"; } } private static string Amount(float value, float capacity) => Mathf.Max(0,value).ToString("0.#") + " / " + Mathf.Max(0,capacity).ToString("0.#"); private void RenderAmounts() { for (int i = 0; i < 3; i++) { SupplyChannelState channel = null; if (supplyState?.channels != null) foreach (var item in supplyState.channels) if (item != null && (int)item.kind == i) { channel = item; break; } if (storageAmounts != null && i < storageAmounts.Length && storageAmounts[i]) storageAmounts[i].text = channel == null ? "— / —" : Amount(channel.storage, channel.storageCapacity); if (bufferAmounts != null && i < bufferAmounts.Length && bufferAmounts[i]) bufferAmounts[i].text = channel == null ? "Vorrat: —" : Amount(channel.buffer, channel.bufferCapacity); } } private void RenderMagazine(int slot, long id) { if (magazineAmounts == null || slot >= magazineAmounts.Length || !magazineAmounts[slot]) return; var state = HasSupplyBackend ? FindTower(id) : null; magazineAmounts[slot].gameObject.SetActive(state != null); if (state != null) magazineAmounts[slot].text = "Magazin: " + Amount(state.magazine, state.magazineCapacity); } private float StopX(SupplyStop stop) => stop == SupplyStop.Distributor ? unloadingPosition : loadingPositions[Mathf.Clamp((int)stop,0,2)]; private void RenderBackendTruck() { var state = supplyState?.truck; if (state == null) { if(Time.unscaledTime >= commandMessageUntil)truckStatus.text = "LKW bereit"; return; } var p = truck.anchoredPosition; p.x = state.phase == SupplyTruckPhase.Driving ? Mathf.Lerp(StopX(state.from), StopX(state.to), Mathf.Clamp01(state.progress)) : StopX(state.to); truck.anchoredPosition = p; float direction = StopX(state.to) - StopX(state.from); if (state.phase == SupplyTruckPhase.Driving && Mathf.Abs(direction) > .1f) truck.localScale = new Vector3(Mathf.Abs(truckScale.x)*Mathf.Sign(direction),truckScale.y,truckScale.z); if(Time.unscaledTime < commandMessageUntil)return; string phase = state.phase == SupplyTruckPhase.Loading ? "Beladen" : state.phase == SupplyTruckPhase.Unloading ? "Abladen" : state.phase == SupplyTruckPhase.Driving ? "Unterwegs" : "Bereit"; int kind = (int)state.cargoKind; truckStatus.text = phase + (kind >= 0 && kind < kinds.Length ? " · " + kinds[kind] + " " + Amount(state.cargo,state.cargoCapacity) : ""); } } }