using System.Collections.Generic; using AfterHours.Core; using AfterHours.Data; using AfterHours.Interaction; using Unity.Netcode; using UnityEngine; namespace AfterHours.Shop { /// /// Kasse. Kunden reihen sich ein; ein Spieler scannt Position für Position /// und schließt ab. Sämtliche Geldbewegung passiert hier auf dem Server. /// public sealed class CashRegister : NetworkBehaviour, IInteractable { [SerializeField] private ProductCatalog _catalog; [SerializeField] private Transform _queueStart; [SerializeField] private float _queueSpacing = 0.8f; /// Server-only. Clients sehen die Schlange über die NPC-Positionen. private readonly List _queue = new(); private readonly NetworkVariable _pendingTotal = new(0f); private readonly NetworkVariable _scannedItems = new(0); public float PendingTotal => _pendingTotal.Value; public int QueueLength => _queue.Count; public string GetPrompt(ulong clientId) { if (_queue.Count == 0) return "Kasse (frei)"; return _scannedItems.Value > 0 ? $"Kassieren — {_pendingTotal.Value:0.00} €" : "Artikel scannen"; } /// Server: ein Klick = ein Artikel scannen, oder abschließen wenn fertig. public void Interact(NetworkObject actor) { if (!IsServer || _queue.Count == 0) return; var customer = _queue[0]; if (customer == null) { _queue.RemoveAt(0); return; } if (_scannedItems.Value < customer.BasketCount) { ScanNext(customer); return; } Finalize(customer); } private void ScanNext(Customers.CustomerAgent customer) { var line = customer.BasketAt(_scannedItems.Value); _pendingTotal.Value += line.Price; _scannedItems.Value++; } private void Finalize(Customers.CustomerAgent customer) { ShopEconomy.Instance.Earn(_pendingTotal.Value); ShopEconomy.Instance.RegisterSale(customer.Comfort); customer.OnPaid(); _queue.RemoveAt(0); _pendingTotal.Value = 0f; _scannedItems.Value = 0; ReflowQueue(); } /// Server: Kunde stellt sich an. Gibt die Zielposition zurück. public Vector3 Enqueue(Customers.CustomerAgent customer) { if (!IsServer) return _queueStart.position; if (!_queue.Contains(customer)) _queue.Add(customer); return SlotPosition(_queue.IndexOf(customer)); } /// Server: Kunde verlässt die Schlange (z. B. weil er aufgibt). public void Remove(Customers.CustomerAgent customer) { if (!IsServer) return; if (_queue.Remove(customer)) ReflowQueue(); } private void ReflowQueue() { for (int i = 0; i < _queue.Count; i++) if (_queue[i] != null) _queue[i].MoveTo(SlotPosition(i)); } private Vector3 SlotPosition(int index) { return _queueStart.position + _queueStart.forward * (-_queueSpacing * index); } } }