initial
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user