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:
@@ -0,0 +1,206 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace DepthsOfGreed.HandbookUI
|
||||
{
|
||||
// Presentation prototype. Connection intent is separate from real ammunition accounting.
|
||||
public sealed partial class SupplyBasementController : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
public bool IsInBasement { get; private set; }
|
||||
public bool IsTravelling { get; private set; }
|
||||
public int Priority { get; private set; } = -1;
|
||||
public event System.Action<long, bool> ConnectionChanged;
|
||||
public event System.Action<int> PriorityChanged;
|
||||
[Header("Authored scene references")]
|
||||
public GameObject basementView;
|
||||
public GameObject handbookRoot;
|
||||
public CanvasGroup handbookVisibility;
|
||||
public HandbookController handbook;
|
||||
public TestPlacementController placement;
|
||||
public Button liftButton;
|
||||
public RectTransform liftSign;
|
||||
public TMP_Text liftLabel;
|
||||
public CanvasGroup doorGroup;
|
||||
public RectTransform leftDoor, rightDoor;
|
||||
public Button[] connectionButtons;
|
||||
public TMP_Text[] connectionNames, connectionStates;
|
||||
public Image[] connectionIcons, cables;
|
||||
public Button[] priorityButtons;
|
||||
public TMP_Text[] priorityLabels;
|
||||
public RectTransform truck;
|
||||
public TMP_Text truckStatus;
|
||||
[Header("Lift timing")]
|
||||
[Min(0.05f)] public float doorDuration = 0.3f;
|
||||
[Min(0)] public float travelDuration = 0.35f;
|
||||
[Min(0.05f)] public float signHalfFlipDuration = 0.1f;
|
||||
[Header("Truck display test (no ammunition is consumed)")]
|
||||
public bool animateTruckPreview = true;
|
||||
public float truckSpeed = 100f;
|
||||
public float[] loadingPositions = { -530f, 0f, 530f };
|
||||
public float unloadingPosition = 710f;
|
||||
public float loadingPause = 1.2f;
|
||||
public Color physicalColor = new Color(.35f,.35f,.35f);
|
||||
public Color cellColor = new Color(.48f,.48f,.48f);
|
||||
public Color specialColor = new Color(.60f,.60f,.60f);
|
||||
private readonly long[] slotIds = new long[8];
|
||||
private readonly Dictionary<long, bool> connections = new Dictionary<long, bool>();
|
||||
private bool hovered, labelBack;
|
||||
private Coroutine flipRoutine;
|
||||
private float nextRefresh, truckPauseUntil;
|
||||
private int previewKind;
|
||||
private bool unloading;
|
||||
private Vector3 signScale;
|
||||
private Vector3 truckScale;
|
||||
private readonly string[] kinds = { "Physisch", "Energiezellen", "Sondermunition" };
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
signScale = liftSign.localScale;
|
||||
truckScale = truck.localScale;
|
||||
basementView.SetActive(false);
|
||||
doorGroup.gameObject.SetActive(false);
|
||||
liftButton.onClick.AddListener(UseLift);
|
||||
for (int i = 0; i < connectionButtons.Length; i++)
|
||||
{ int slot = i; connectionButtons[i].onClick.AddListener(() => ToggleConnection(slot)); }
|
||||
for (int i = 0; i < priorityButtons.Length; i++)
|
||||
{ int kind = i; priorityButtons[i].onClick.AddListener(() => SetPriority(kind)); }
|
||||
if (!HasSupplyBackend) SetPriority(-1);
|
||||
else if (supplyBackend && !(supplyBackend is ISupplyGameplay)) Debug.LogError("Versorgung: ISupplyGameplay fehlt.", this);
|
||||
RefreshSign();
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData e) { hovered = true; FlipSign(); }
|
||||
public void OnPointerExit(PointerEventData e) { hovered = false; FlipSign(); }
|
||||
private void FlipSign()
|
||||
{
|
||||
if (flipRoutine != null) StopCoroutine(flipRoutine);
|
||||
flipRoutine = StartCoroutine(Flip());
|
||||
}
|
||||
private IEnumerator Flip()
|
||||
{
|
||||
float start = liftSign.localScale.x;
|
||||
for (float t = 0; t < signHalfFlipDuration; t += Time.unscaledDeltaTime)
|
||||
{ liftSign.localScale = new Vector3(Mathf.Lerp(start, 0.02f, t / signHalfFlipDuration), signScale.y, signScale.z); yield return null; }
|
||||
labelBack = hovered; RefreshSign();
|
||||
for (float t = 0; t < signHalfFlipDuration; t += Time.unscaledDeltaTime)
|
||||
{ liftSign.localScale = new Vector3(Mathf.Lerp(0.02f, signScale.x, t / signHalfFlipDuration), signScale.y, signScale.z); yield return null; }
|
||||
liftSign.localScale = signScale; flipRoutine = null;
|
||||
}
|
||||
private void RefreshSign() => liftLabel.text = labelBack
|
||||
? (IsInBasement ? "ZUR\nTURMEBENE" : "ZUM\nVERSORGUNGS-\nKELLER")
|
||||
: (IsInBasement ? "▲\nAUFZUG" : "▼\nAUFZUG");
|
||||
public void UseLift()
|
||||
{
|
||||
if (IsTravelling) return;
|
||||
if (placement && (placement.IsDragging || placement.IsWaitingForReturn)) return;
|
||||
StartCoroutine(Travel());
|
||||
}
|
||||
private IEnumerator Travel()
|
||||
{
|
||||
IsTravelling = true; liftButton.interactable = false;
|
||||
doorGroup.gameObject.SetActive(true); doorGroup.blocksRaycasts = true;
|
||||
yield return Doors(true);
|
||||
if (handbook) handbook.Close();
|
||||
IsInBasement = !IsInBasement;
|
||||
basementView.SetActive(IsInBasement);
|
||||
// Hide only the presentation. The backend on HandbookRoot must keep updating.
|
||||
handbookVisibility.alpha = IsInBasement ? 0f : 1f;
|
||||
handbookVisibility.interactable = !IsInBasement;
|
||||
handbookVisibility.blocksRaycasts = !IsInBasement;
|
||||
hovered = false; labelBack = false; RefreshSign(); RefreshConnections();
|
||||
yield return new WaitForSecondsRealtime(travelDuration);
|
||||
yield return Doors(false);
|
||||
doorGroup.blocksRaycasts = false; doorGroup.gameObject.SetActive(false);
|
||||
liftButton.interactable = true; IsTravelling = false;
|
||||
}
|
||||
private IEnumerator Doors(bool close)
|
||||
{
|
||||
float width = ((RectTransform)leftDoor.parent).rect.width * 0.5f;
|
||||
for (float t = 0; t < doorDuration; t += Time.unscaledDeltaTime)
|
||||
{
|
||||
float p = Mathf.SmoothStep(0, 1, t / doorDuration); if (!close) p = 1 - p;
|
||||
leftDoor.anchoredPosition = new Vector2(-width * (1 - p), 0);
|
||||
rightDoor.anchoredPosition = new Vector2(width * (1 - p), 0);
|
||||
yield return null;
|
||||
}
|
||||
leftDoor.anchoredPosition = new Vector2(close ? 0 : -width, 0);
|
||||
rightDoor.anchoredPosition = new Vector2(close ? 0 : width, 0);
|
||||
}
|
||||
public bool IsConnectionEnabled(long instanceId) => HasSupplyBackend ? FindTower(instanceId)?.connected == true : !connections.TryGetValue(instanceId, out bool enabled) || enabled;
|
||||
public void ToggleConnection(int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= slotIds.Length || slotIds[slot] == 0) return;
|
||||
long id = slotIds[slot];
|
||||
if (TrySetBackendConnection(id, !IsConnectionEnabled(id))) return;
|
||||
connections[id] = !IsConnectionEnabled(id);
|
||||
ConnectionChanged?.Invoke(id, connections[id]); RefreshConnections();
|
||||
}
|
||||
public void SetPriority(int kind)
|
||||
{
|
||||
if (kind < -1 || kind > 2) return;
|
||||
if (TrySetBackendPriority(kind)) return;
|
||||
Priority = Priority == kind ? -1 : kind;
|
||||
PriorityChanged?.Invoke(Priority);
|
||||
for (int i = 0; i < priorityButtons.Length; i++)
|
||||
{ priorityButtons[i].GetComponent<Image>().color = Priority == i ? ColorFor(i) : new Color(.72f,.72f,.72f); priorityLabels[i].color = new Color(.18f,.18f,.18f); priorityLabels[i].text = Priority == i ? "Vorrang aktiv" : "Vorrang geben"; }
|
||||
}
|
||||
private Color ColorFor(int kind) => kind == 0 ? physicalColor : kind == 1 ? cellColor : specialColor;
|
||||
private static bool UsesSupply(HandbookTowerEntry t) => t && t.use == BuildUse.Structure && t.supply != null && t.supply.kind != SupplyKind.None;
|
||||
private void RefreshConnections()
|
||||
{
|
||||
var list = GetSupplyObjects();
|
||||
for (int i = 0; i < slotIds.Length; i++)
|
||||
{
|
||||
bool exists = false;
|
||||
if (list != null) foreach (var obj in list) if (obj.instanceId == slotIds[i] && UsesSupply(obj.type)) { exists = true; break; }
|
||||
if (!exists) { connections.Remove(slotIds[i]); slotIds[i] = 0; }
|
||||
}
|
||||
if (list != null) foreach (var obj in list)
|
||||
{
|
||||
if (!UsesSupply(obj.type) || System.Array.IndexOf(slotIds, obj.instanceId) >= 0) continue;
|
||||
int free = System.Array.IndexOf(slotIds, 0L); if (free >= 0) slotIds[free] = obj.instanceId;
|
||||
}
|
||||
for (int i = 0; i < connectionButtons.Length; i++)
|
||||
{
|
||||
BuiltObjectSnapshot found = null;
|
||||
if (list != null) foreach (var obj in list) if (obj.instanceId == slotIds[i]) { found = obj; break; }
|
||||
RenderMagazine(i, found == null ? 0 : found.instanceId);
|
||||
connectionButtons[i].interactable = found != null;
|
||||
connectionIcons[i].gameObject.SetActive(found != null && found.type.icon);
|
||||
if (found == null) { connectionNames[i].text = ""; connectionStates[i].text = "Frei"; cables[i].color = new Color(.48f,.48f,.48f); continue; }
|
||||
bool enabled = IsConnectionEnabled(found.instanceId);
|
||||
int kind = Mathf.Clamp((int)found.type.supply.kind, 0, 2);
|
||||
connectionIcons[i].sprite = found.type.icon;
|
||||
connectionNames[i].text = found.type.displayName + " #" + found.instanceId;
|
||||
connectionStates[i].text = (enabled ? "Verbunden" : "Getrennt") + "\n" + kinds[kind];
|
||||
cables[i].color = enabled ? ColorFor(kind) : new Color(.48f,.48f,.48f);
|
||||
}
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
if (!IsInBasement) return;
|
||||
if (Time.unscaledTime > nextRefresh) { nextRefresh = Time.unscaledTime + 0.25f; RefreshConnections(); }
|
||||
if (HasSupplyBackend) { RenderBackendTruck(); return; }
|
||||
if (!animateTruckPreview) { truckStatus.text = "LKW bereit"; return; }
|
||||
if (Time.unscaledTime < truckPauseUntil) return;
|
||||
float destination = unloading ? unloadingPosition : loadingPositions[previewKind];
|
||||
var p = truck.anchoredPosition;
|
||||
float direction = destination - p.x;
|
||||
if (Mathf.Abs(direction) > 0.1f)
|
||||
truck.localScale = new Vector3(Mathf.Abs(truckScale.x) * Mathf.Sign(direction), truckScale.y, truckScale.z);
|
||||
p.x = Mathf.MoveTowards(p.x, destination, Mathf.Max(0, truckSpeed) * Time.unscaledDeltaTime); truck.anchoredPosition = p;
|
||||
truckStatus.text = (unloading ? "Zur Verteilerstation" : "Zum Behälter: " + kinds[previewKind]);
|
||||
if (Mathf.Abs(p.x - destination) < 0.1f)
|
||||
{
|
||||
truckStatus.text = (unloading ? "Abladen" : "Beladen: " + kinds[previewKind]);
|
||||
truckPauseUntil = Time.unscaledTime + loadingPause;
|
||||
if (unloading) previewKind = Priority >= 0 ? Priority : (previewKind + 1) % 3;
|
||||
unloading = !unloading;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user