Aetheria/Assets/Scripts/ServerShared/StationServices.cs
Meta Vens 39b6d28f3a StationServices: one engine-free owner for sell price, repair cost and the sale and repair commits
Settings gain SellFraction, RepairFraction and StartingCredits. A sale pays the price scaled by condition and moves the
item into a station bay or refuses with everything unchanged; a repair restores every durability and charges the wear,
or refuses when short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:30:31 +02:00

82 lines
4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
// What a station pays for goods and charges to mend gear. The one owner of the sell price, the repair cost, and the
// two commits that move goods or restore durability against the run's credits; TradeMenu shows these numbers and
// decides none of them. It holds no Unity type. Credits are the caller's: a refusal leaves them, the cargo and the
// durabilities exactly as they were.
public static class StationServices
{
// What the station pays for the item: its price, scaled by SellFraction and by its condition. A commodity has no
// wear, so it sells at the fraction alone; a simple commodity's price is per unit.
public static int SellPrice(ItemManager items, ItemInstance item)
{
var fraction = (double) items.GameplaySettings.SellFraction;
switch (item)
{
case CraftedItemInstance crafted:
return (int) Math.Floor(items.GetPrice(crafted) * fraction * Condition(items, crafted));
case SimpleCommodity commodity:
return (int) Math.Floor((long) items.GetData(commodity).Price * commodity.Quantity * fraction);
default:
throw new ArgumentException($"{item?.GetType().Name ?? "null"} has no sell price.", nameof(item));
}
}
// What the station charges to restore the entity's hull and every item it carries to design durability: each
// piece's share of its price in proportion to its wear, scaled by RepairFraction, rounded up.
public static int RepairCost(ItemManager items, Entity entity)
{
long total = 0;
foreach (var gear in Gear(entity)) total += RepairShare(items, gear);
return (int) Math.Min(total, int.MaxValue);
}
// The sale: the item leaves the bay for one of the station's cargo bays and the station pays SellPrice. False,
// with the item in its bay and the credits unchanged, when no station bay can take it.
public static bool TrySell(EquippedCargoBay from, Entity station, ItemInstance item, ref int credits)
{
var price = SellPrice(station.ItemManager, item);
var moved = item is SimpleCommodity commodity
? station.CargoBays.Any(bay => from.TryTransferItem(bay, commodity, commodity.Quantity))
: station.CargoBays.Any(bay => from.TryTransferItem(bay, (CraftedItemInstance) item));
if (!moved) return false;
credits += price;
return true;
}
// The repair: every durability goes back to design and the station charges RepairCost. False, with nothing
// restored, when the credits fall short.
public static bool TryRepair(Entity entity, ref int credits)
{
var items = entity.ItemManager;
var cost = RepairCost(items, entity);
if (cost > credits) return false;
foreach (var gear in Gear(entity))
if (items.GetData(gear) is EquippableItemData design && design.Durability > 0)
gear.Durability = design.Durability;
credits -= cost;
return true;
}
// Equipment holds the hull itself, so the hull is in the sum once.
private static IEnumerable<EquippableItem> Gear(Entity entity) =>
entity.Equipment.Select(equipped => equipped.EquippableItem)
.Concat(entity.CargoBays.Select(bay => bay.EquippableItem))
.Concat(entity.DockingBays.Select(bay => bay.EquippableItem));
// Instance durability over the design's, for gear that wears; everything else is as good as new.
private static double Condition(ItemManager items, CraftedItemInstance item)
{
if (!(item is EquippableItem gear) || !(items.GetData(gear) is EquippableItemData design) || design.Durability <= 0)
return 1;
return Math.Max(0, Math.Min(1, gear.Durability / (double) design.Durability));
}
private static long RepairShare(ItemManager items, EquippableItem gear)
{
var worn = 1 - Condition(items, gear);
return (long) Math.Ceiling(worn * items.GetPrice(gear) * items.GameplaySettings.RepairFraction);
}
}