This commit is contained in:
2026-08-10 19:23:04 +02:00
commit 404d15a56c
134 changed files with 5374 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
using System.Collections.Generic;
using AfterHours.Core;
using AfterHours.Data;
using AfterHours.Interaction;
using Unity.Netcode;
using UnityEngine;
namespace AfterHours.Shop
{
/// <summary>
/// Kasse. Kunden reihen sich ein; ein Spieler scannt Position für Position
/// und schließt ab. Sämtliche Geldbewegung passiert hier auf dem Server.
/// </summary>
public sealed class CashRegister : NetworkBehaviour, IInteractable
{
[SerializeField] private ProductCatalog _catalog;
[SerializeField] private Transform _queueStart;
[SerializeField] private float _queueSpacing = 0.8f;
/// <summary>Server-only. Clients sehen die Schlange über die NPC-Positionen.</summary>
private readonly List<Customers.CustomerAgent> _queue = new();
private readonly NetworkVariable<float> _pendingTotal = new(0f);
private readonly NetworkVariable<int> _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";
}
/// <summary>Server: ein Klick = ein Artikel scannen, oder abschließen wenn fertig.</summary>
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();
}
/// <summary>Server: Kunde stellt sich an. Gibt die Zielposition zurück.</summary>
public Vector3 Enqueue(Customers.CustomerAgent customer)
{
if (!IsServer) return _queueStart.position;
if (!_queue.Contains(customer)) _queue.Add(customer);
return SlotPosition(_queue.IndexOf(customer));
}
/// <summary>Server: Kunde verlässt die Schlange (z. B. weil er aufgibt).</summary>
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);
}
}
}