Handbuch Scroll-Listen entfernt. Handbuch offen und tabs eingefügt. Upgrades eingefügt. "Garage" eingefügt. Anbindung eines echten Gameplaymanager möglich (theoretisch)

This commit is contained in:
2026-10-15 03:24:48 +02:00
parent dadd1fcad0
commit 5486444dde
132 changed files with 55540 additions and 4807 deletions
@@ -0,0 +1,109 @@
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<BuiltObjectSnapshot> supplyObjects = new List<BuiltObjectSnapshot>();
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<BuiltObjectSnapshot> 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<UnityEngine.UI.Image>().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) : "");
}
}
}