|
|
|
|
@@ -23,20 +23,17 @@ namespace Content.Server.Cargo.Systems;
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class PricingSystem : EntitySystem
|
|
|
|
|
{
|
|
|
|
|
[Dependency] private readonly IComponentFactory _factory = default!;
|
|
|
|
|
[Dependency] private readonly IConsoleHost _consoleHost = default!;
|
|
|
|
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
|
|
|
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
|
|
|
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
|
|
|
|
|
|
|
|
[Dependency] private readonly BodySystem _bodySystem = default!;
|
|
|
|
|
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
public override void Initialize()
|
|
|
|
|
{
|
|
|
|
|
SubscribeLocalEvent<StaticPriceComponent, PriceCalculationEvent>(CalculateStaticPrice);
|
|
|
|
|
SubscribeLocalEvent<StackPriceComponent, PriceCalculationEvent>(CalculateStackPrice);
|
|
|
|
|
SubscribeLocalEvent<MobPriceComponent, PriceCalculationEvent>(CalculateMobPrice);
|
|
|
|
|
SubscribeLocalEvent<SolutionContainerManagerComponent, PriceCalculationEvent>(CalculateSolutionPrice);
|
|
|
|
|
|
|
|
|
|
_consoleHost.RegisterCommand("appraisegrid",
|
|
|
|
|
"Calculates the total value of the given grids.",
|
|
|
|
|
@@ -87,6 +84,7 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
|
|
|
|
|
private void CalculateMobPrice(EntityUid uid, MobPriceComponent component, ref PriceCalculationEvent args)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Estimated pricing.
|
|
|
|
|
if (args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
@@ -106,26 +104,9 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CalculateStackPrice(EntityUid uid, StackPriceComponent component, ref PriceCalculationEvent args)
|
|
|
|
|
private double GetSolutionPrice(SolutionContainerManagerComponent component)
|
|
|
|
|
{
|
|
|
|
|
if (args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!TryComp<StackComponent>(uid, out var stack))
|
|
|
|
|
{
|
|
|
|
|
Logger.ErrorS("pricing", $"Tried to get the stack price of {ToPrettyString(uid)}, which has no {nameof(StackComponent)}.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args.Price += stack.Count * component.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CalculateSolutionPrice(EntityUid uid, SolutionContainerManagerComponent component, ref PriceCalculationEvent args)
|
|
|
|
|
{
|
|
|
|
|
if (args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var price = 0f;
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
foreach (var solution in component.Solutions.Values)
|
|
|
|
|
{
|
|
|
|
|
@@ -136,45 +117,11 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
price += (float) reagent.Quantity * reagentProto.PricePerUnit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
args.Price += price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CalculateStaticPrice(EntityUid uid, StaticPriceComponent component, ref PriceCalculationEvent args)
|
|
|
|
|
{
|
|
|
|
|
if (args.Handled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
args.Price += component.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a rough price for an entityprototype. Does not consider contained entities.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double GetEstimatedPrice(EntityPrototype prototype, IComponentFactory? factory = null)
|
|
|
|
|
{
|
|
|
|
|
IoCManager.Resolve(ref factory);
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(factory.GetComponentName(typeof(StaticPriceComponent)),
|
|
|
|
|
out var staticPriceProto))
|
|
|
|
|
{
|
|
|
|
|
var staticComp = (StaticPriceComponent) staticPriceProto.Component;
|
|
|
|
|
|
|
|
|
|
price += staticComp.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(factory.GetComponentName(typeof(StackPriceComponent)), out var stackpriceProto) &&
|
|
|
|
|
prototype.Components.TryGetValue(factory.GetComponentName(typeof(StackComponent)), out var stackProto))
|
|
|
|
|
{
|
|
|
|
|
var stackPrice = (StackPriceComponent) stackpriceProto.Component;
|
|
|
|
|
var stack = (StackComponent) stackProto.Component;
|
|
|
|
|
price += stack.Count * stackPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double GetMaterialPrice(MaterialComponent component)
|
|
|
|
|
private double GetMaterialPrice(MaterialComponent component)
|
|
|
|
|
{
|
|
|
|
|
double price = 0;
|
|
|
|
|
foreach (var (id, quantity) in component.Materials)
|
|
|
|
|
@@ -184,6 +131,32 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a rough price for an entityprototype. Does not consider contained entities.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double GetEstimatedPrice(EntityPrototype prototype)
|
|
|
|
|
{
|
|
|
|
|
var ev = new EstimatedPriceCalculationEvent()
|
|
|
|
|
{
|
|
|
|
|
Prototype = prototype,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RaiseLocalEvent(ref ev);
|
|
|
|
|
|
|
|
|
|
if (ev.Handled)
|
|
|
|
|
return ev.Price;
|
|
|
|
|
|
|
|
|
|
var price = ev.Price;
|
|
|
|
|
price += GetMaterialsPrice(prototype);
|
|
|
|
|
price += GetSolutionsPrice(prototype);
|
|
|
|
|
price += GetStackPrice(prototype);
|
|
|
|
|
price += GetStaticPrice(prototype);
|
|
|
|
|
|
|
|
|
|
// TODO: Proper container support.
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Appraises an entity, returning it's price.
|
|
|
|
|
/// </summary>
|
|
|
|
|
@@ -201,7 +174,31 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
if (ev.Handled)
|
|
|
|
|
return ev.Price;
|
|
|
|
|
|
|
|
|
|
var price = ev.Price;
|
|
|
|
|
//TODO: Add an OpaqueToAppraisal component or similar for blocking the recursive descent into containers, or preventing material pricing.
|
|
|
|
|
// DO NOT FORGET TO UPDATE ESTIMATED PRICING
|
|
|
|
|
price += GetMaterialsPrice(uid);
|
|
|
|
|
price += GetSolutionsPrice(uid);
|
|
|
|
|
price += GetStackPrice(uid);
|
|
|
|
|
price += GetStaticPrice(uid);
|
|
|
|
|
|
|
|
|
|
if (TryComp<ContainerManagerComponent>(uid, out var containers))
|
|
|
|
|
{
|
|
|
|
|
foreach (var container in containers.Containers.Values)
|
|
|
|
|
{
|
|
|
|
|
foreach (var ent in container.ContainedEntities)
|
|
|
|
|
{
|
|
|
|
|
price += GetPrice(ent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetMaterialsPrice(EntityUid uid)
|
|
|
|
|
{
|
|
|
|
|
double price = 0;
|
|
|
|
|
|
|
|
|
|
if (TryComp<MaterialComponent>(uid, out var material) && !HasComp<StackPriceComponent>(uid))
|
|
|
|
|
{
|
|
|
|
|
@@ -209,21 +206,109 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
if (TryComp<StackComponent>(uid, out var stack))
|
|
|
|
|
matPrice *= stack.Count;
|
|
|
|
|
|
|
|
|
|
ev.Price += matPrice;
|
|
|
|
|
price += matPrice;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TryComp<ContainerManagerComponent>(uid, out var containers))
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetMaterialsPrice(EntityPrototype prototype)
|
|
|
|
|
{
|
|
|
|
|
double price = 0;
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(MaterialComponent)), out var materials) &&
|
|
|
|
|
!prototype.Components.ContainsKey(_factory.GetComponentName(typeof(StackPriceComponent))))
|
|
|
|
|
{
|
|
|
|
|
foreach (var container in containers.Containers)
|
|
|
|
|
var materialsComp = (MaterialComponent) materials.Component;
|
|
|
|
|
var matPrice = GetMaterialPrice(materialsComp);
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackComponent)), out var stackProto))
|
|
|
|
|
{
|
|
|
|
|
foreach (var ent in container.Value.ContainedEntities)
|
|
|
|
|
{
|
|
|
|
|
ev.Price += GetPrice(ent);
|
|
|
|
|
}
|
|
|
|
|
matPrice *= ((StackComponent) stackProto.Component).Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
price += matPrice;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ev.Price;
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetSolutionsPrice(EntityUid uid)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (TryComp<SolutionContainerManagerComponent>(uid, out var solComp))
|
|
|
|
|
{
|
|
|
|
|
price += GetSolutionPrice(solComp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetSolutionsPrice(EntityPrototype prototype)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(SolutionContainerManagerComponent)), out var solManager))
|
|
|
|
|
{
|
|
|
|
|
var solComp = (SolutionContainerManagerComponent) solManager.Component;
|
|
|
|
|
price += GetSolutionPrice(solComp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetStackPrice(EntityUid uid)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (TryComp<StackPriceComponent>(uid, out var stackPrice) &&
|
|
|
|
|
TryComp<StackComponent>(uid, out var stack))
|
|
|
|
|
{
|
|
|
|
|
price += stack.Count * stackPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetStackPrice(EntityPrototype prototype)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackPriceComponent)), out var stackpriceProto) &&
|
|
|
|
|
prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackComponent)), out var stackProto))
|
|
|
|
|
{
|
|
|
|
|
var stackPrice = (StackPriceComponent) stackpriceProto.Component;
|
|
|
|
|
var stack = (StackComponent) stackProto.Component;
|
|
|
|
|
price += stack.Count * stackPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetStaticPrice(EntityUid uid)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (TryComp<StaticPriceComponent>(uid, out var staticPrice))
|
|
|
|
|
{
|
|
|
|
|
price += staticPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double GetStaticPrice(EntityPrototype prototype)
|
|
|
|
|
{
|
|
|
|
|
var price = 0.0;
|
|
|
|
|
|
|
|
|
|
if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StaticPriceComponent)), out var staticProto))
|
|
|
|
|
{
|
|
|
|
|
var staticPrice = (StaticPriceComponent) staticProto.Component;
|
|
|
|
|
price += staticPrice.Price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return price;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@@ -256,7 +341,7 @@ public sealed class PricingSystem : EntitySystem
|
|
|
|
|
/// A directed by-ref event fired on an entity when something needs to know it's price. This value is not cached.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ByRefEvent]
|
|
|
|
|
public struct PriceCalculationEvent
|
|
|
|
|
public record struct PriceCalculationEvent()
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The total price of the entity.
|
|
|
|
|
@@ -267,6 +352,23 @@ public struct PriceCalculationEvent
|
|
|
|
|
/// Whether this event was already handled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool Handled = false;
|
|
|
|
|
|
|
|
|
|
public PriceCalculationEvent() { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Raised broadcast for an entity prototype to determine its estimated price.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ByRefEvent]
|
|
|
|
|
public record struct EstimatedPriceCalculationEvent()
|
|
|
|
|
{
|
|
|
|
|
public EntityPrototype Prototype;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The total price of the entity.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double Price = 0;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether this event was already handled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool Handled = false;
|
|
|
|
|
}
|
|
|
|
|
|