6
StarHorizon_Public/Content.Server/_NF/Construction/ConstructionSystem.Machine.Upgrades.cs
2026-01-24 12:49:55 +03:00

176 lines
6.1 KiB
C#

using System.Linq;
using Content.Server.Construction.Components;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Examine;
using Content.Shared.Stacks;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
namespace Content.Server.Construction; //Uses base namespace to extend ConstructionSystem behaviour
// Adopted from Wizard's Den's abandoned ConstructionSystem machine part system.
public struct MachinePartState
{
public MachinePartComponent Part;
public StackComponent? Stack;
// If item is a stack, return the count in the stack, otherwise it's a singular, non-stackable part
public int Quantity()
{
return Stack?.Count ?? 1;
}
}
public sealed partial class ConstructionSystem
{
[Dependency] ExamineSystemShared _examineSystem = default!;
private void InitializeMachineUpgrades()
{
SubscribeLocalEvent<MachineComponent, GetVerbsEvent<ExamineVerb>>(OnMachineExaminableVerb);
}
private void OnMachineExaminableVerb(EntityUid uid, MachineComponent component, GetVerbsEvent<ExamineVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
var markup = new FormattedMessage();
RaiseLocalEvent(uid, new UpgradeExamineEvent(ref markup));
if (markup.IsEmpty)
return; // Not upgradable.
if(!FormattedMessage.TryFromMarkup(markup.ToMarkup().TrimEnd('\n'), out markup)) // Cursed workaround to https://github.com/space-wizards/RobustToolbox/issues/3371
{
markup = FormattedMessage.Empty; // Frontier: attempt sane error handling
}
var verb = new ExamineVerb()
{
Act = () =>
{
_examineSystem.SendExamineTooltip(args.User, uid, markup, getVerbs: false, centerAtCursor: false);
},
Text = Loc.GetString("machine-upgrade-examinable-verb-text"),
Message = Loc.GetString("machine-upgrade-examinable-verb-message"),
Category = VerbCategory.Examine,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/pickup.svg.192dpi.png"))
};
args.Verbs.Add(verb);
}
// Frontier: return type changed to include stack info
public List<MachinePartState> GetAllParts(EntityUid uid, MachineComponent? component = null)
{
if (!Resolve(uid, ref component))
return new List<MachinePartState>();
return GetAllParts(component);
}
// Frontier: return type changed to include stack info
public List<MachinePartState> GetAllParts(MachineComponent component)
{
var parts = new List<MachinePartState>();
foreach (var entity in component.PartContainer.ContainedEntities)
{
if (GetMachinePartState(entity, out var partState))
parts.Add(partState);
}
return parts;
}
public bool GetMachinePartState(EntityUid uid, out MachinePartState state)
{
state = new MachinePartState();
MachinePartComponent? part;
if (TryComp(uid, out part) && part is not null)
state.Part = part;
else
return false;
TryComp(uid, out state.Stack);
return true;
}
public Dictionary<string, float> GetPartsRatings(List<MachinePartState> partStates)
{
var output = new Dictionary<string, float>();
foreach (var type in _prototypeManager.EnumeratePrototypes<MachinePartPrototype>())
{
var amount = 0f;
var sumRating = 0f;
foreach (var state in partStates.Where(part => part.Part.PartType == type.ID))
{
amount += state.Quantity();
sumRating += state.Part.Rating * state.Quantity();
}
var rating = amount != 0 ? sumRating / amount : 1.0f;
output.Add(type.ID, rating);
}
return output;
}
public void RefreshParts(EntityUid uid, MachineComponent component)
{
var parts = GetAllParts(component);
EntityManager.EventBus.RaiseLocalEvent(uid, new RefreshPartsEvent
{
Parts = parts,
PartRatings = GetPartsRatings(parts),
}, true);
}
}
public sealed class RefreshPartsEvent : EntityEventArgs
{
public IReadOnlyList<MachinePartState> Parts = new List<MachinePartState>(); // Frontier: MachinePartComponent<MachinePartState
public Dictionary<string, float> PartRatings = new Dictionary<string, float>();
}
public sealed class UpgradeExamineEvent : EntityEventArgs
{
private FormattedMessage _message;
public UpgradeExamineEvent(ref FormattedMessage message)
{
_message = message;
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a percentage-based increase or decrease.
/// </summary>
public void AddPercentageUpgrade(string upgradedLocId, float multiplier)
{
var percent = Math.Round(100 * MathF.Abs(multiplier - 1), 2);
var locId = multiplier switch
{
< 1 => "machine-upgrade-decreased-by-percentage",
1 or float.NaN => "machine-upgrade-not-upgraded",
> 1 => "machine-upgrade-increased-by-percentage",
};
var upgraded = Loc.GetString(upgradedLocId);
this._message.TryAddMarkup(Loc.GetString(locId, ("upgraded", upgraded), ("percent", percent)) + '\n', out _); // Frontier: AddMarkup<TryAddMarkup
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a numeric increase or decrease.
/// </summary>
public void AddNumberUpgrade(string upgradedLocId, int number)
{
var difference = Math.Abs(number);
var locId = number switch
{
< 0 => "machine-upgrade-decreased-by-amount",
0 => "machine-upgrade-not-upgraded",
> 0 => "machine-upgrade-increased-by-amount",
};
var upgraded = Loc.GetString(upgradedLocId);
this._message.TryAddMarkup(Loc.GetString(locId, ("upgraded", upgraded), ("difference", difference)) + '\n', out _); // Frontier: AddMarkup<TryAddMarkup
}
}