This commit is contained in:
2026-08-10 19:23:04 +02:00
commit 404d15a56c
134 changed files with 5374 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
using System;
namespace AfterHours.Economy
{
/// <summary>
/// Reine Preis-/Nachfragelogik. Engine-frei und damit testbar.
/// Keine UnityEngine-Referenzen in dieser Datei.
/// </summary>
public static class PricingService
{
/// <summary>Ab diesem Aufschlag über Empfehlung kauft niemand mehr.</summary>
public const float RejectionThreshold = 1.75f;
/// <summary>
/// Kaufwahrscheinlichkeit relativ zum empfohlenen Preis.
/// 1.0 bei Empfehlungspreis oder darunter, 0.0 ab RejectionThreshold.
/// Dazwischen quadratisch abfallend kleine Aufschläge tun kaum weh,
/// große brechen die Nachfrage schnell ein.
/// </summary>
public static float PurchaseProbability(float askingPrice, float recommendedPrice)
{
if (recommendedPrice <= 0f) throw new ArgumentOutOfRangeException(nameof(recommendedPrice));
if (askingPrice <= 0f) return 1f;
float ratio = askingPrice / recommendedPrice;
if (ratio <= 1f) return 1f;
if (ratio >= RejectionThreshold) return 0f;
float t = (ratio - 1f) / (RejectionThreshold - 1f); // 0..1
return 1f - (t * t);
}
/// <summary>Marge in Prozent des Verkaufspreises.</summary>
public static float MarginRatio(float askingPrice, float wholesalePrice)
{
if (askingPrice <= 0f) return 0f;
return (askingPrice - wholesalePrice) / askingPrice;
}
/// <summary>
/// Erwarteter Deckungsbeitrag pro angebotenem Stück.
/// Nützlich für den späteren "Preis-Optimum"-Hinweis im Preis-UI.
/// </summary>
public static float ExpectedProfitPerUnit(float askingPrice, float recommendedPrice, float wholesalePrice)
{
return PurchaseProbability(askingPrice, recommendedPrice) * (askingPrice - wholesalePrice);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 488bfdde2f57adf4e8d4ce3a8ec065c0
+42
View File
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
namespace AfterHours.Economy
{
/// <summary>Eine Position einer Großhandelsbestellung.</summary>
[Serializable]
public struct OrderLine
{
public int ProductId;
public int Quantity;
public float UnitPrice;
public float LineTotal => Quantity * UnitPrice;
}
/// <summary>Bestellung beim Großhandel. Wird nur serverseitig gehalten.</summary>
public sealed class PurchaseOrder
{
private readonly List<OrderLine> _lines = new();
public IReadOnlyList<OrderLine> Lines => _lines;
/// <summary>Spielzeit in Sekunden, zu der die Lieferung eintrifft.</summary>
public float DeliveryTime { get; set; }
public bool Delivered { get; set; }
public void Add(int productId, int quantity, float unitPrice)
{
if (quantity <= 0) return;
_lines.Add(new OrderLine { ProductId = productId, Quantity = quantity, UnitPrice = unitPrice });
}
public float Total()
{
float sum = 0f;
foreach (var line in _lines) sum += line.LineTotal;
return sum;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ca74ad78a2bea0e4d985e96612714923