Files
Ilya246 a75a27b456 Mom Can We Have Upstream Merge (#4049)
Co-authored-by: Moony <moony@hellomouse.net>
Co-authored-by: J <billsmith116@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Co-authored-by: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Co-authored-by: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: Cojoke <83733158+Cojoke-dot@users.noreply.github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Co-authored-by: TemporalOroboros <TemporalOroboros@gmail.com>
Co-authored-by: Lordbrandon12 <107556696+Lordbrandon12@users.noreply.github.com>
Co-authored-by: Perry Fraser <perryprog@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Co-authored-by: Krunklehorn <42424291+Krunklehorn@users.noreply.github.com>
Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Co-authored-by: paige404 <59348003+paige404@users.noreply.github.com>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
Co-authored-by: M4rchy-S <89603088+M4rchy-S@users.noreply.github.com>
Co-authored-by: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com>
Co-authored-by: Connor Huffine <chuffine@gmail.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>
Co-authored-by: Errant <35878406+Errant-4@users.noreply.github.com>
Co-authored-by: Schrödinger <132720404+Schrodinger71@users.noreply.github.com>
Co-authored-by: Samuka-C <47865393+Samuka-C@users.noreply.github.com>
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
Co-authored-by: beck-thompson <107373427+beck-thompson@users.noreply.github.com>
Co-authored-by: psykana <36602558+psykana@users.noreply.github.com>
Co-authored-by: thetuerk <46725294+ThanosDeGraf@users.noreply.github.com>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
Co-authored-by: MilenVolf <63782763+MilenVolf@users.noreply.github.com>
Co-authored-by: YotaXP <yotaxp+git@gmail.com>
Co-authored-by: BarryNorfolk <barrynorfolkman@protonmail.com>
Co-authored-by: JesterX666 <32009105+JesterX666@users.noreply.github.com>
Co-authored-by: mtrs163 <153596133+mtrs163@users.noreply.github.com>
Co-authored-by: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com>
2026-05-24 17:53:41 +00:00

128 lines
5.5 KiB
C#

using System.Linq;
using Content.Client.Items;
using Content.Client.Storage.Systems;
using Content.Shared.Stacks;
using Content.Shared.Stacks.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Stack
{
[UsedImplicitly]
public sealed partial class StackSystem : SharedStackSystem
{
[Dependency] private AppearanceSystem _appearanceSystem = default!;
[Dependency] private ItemCounterSystem _counterSystem = default!;
[Dependency] private SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StackComponent, AppearanceChangeEvent>(OnAppearanceChange);
Subs.ItemStatus<StackComponent>(ent => new StackStatusControl(ent));
}
public override void SetCount(EntityUid uid, int amount, StackComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
base.SetCount(uid, amount, component);
if (component.Lingering &&
TryComp<SpriteComponent>(uid, out var sprite))
{
// tint the stack gray and make it transparent if it's lingering.
var color = component.Count == 0 && component.Lingering
? Color.DarkGray.WithAlpha(0.65f)
: Color.White;
for (var i = 0; i < sprite.AllLayers.Count(); i++)
{
_sprite.LayerSetColor((uid, sprite), i, color);
}
}
// TODO PREDICT ENTITY DELETION: This should really just be a normal entity deletion call.
if (component.Count <= 0 && !component.Lingering)
{
Xform.DetachEntity(uid, Transform(uid));
return;
}
component.UiUpdateNeeded = true;
}
private void OnAppearanceChange(EntityUid uid, StackComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null || comp.LayerStates.Count < 1)
return;
// Skip processing if no actual
if (!_appearanceSystem.TryGetData<int>(uid, StackVisuals.Actual, out var actual, args.Component))
return;
if (!_appearanceSystem.TryGetData<int>(uid, StackVisuals.MaxCount, out var maxCount, args.Component))
maxCount = comp.LayerStates.Count;
if (!_appearanceSystem.TryGetData<bool>(uid, StackVisuals.Hide, out var hidden, args.Component))
hidden = false;
if (comp.LayerFunction != StackLayerFunction.None) // Frontier: use stack layer function to modify appearance if provided.
ApplyLayerFunction((uid, comp), ref actual, ref maxCount); // Frontier: definition in _NF/Stack/StackSystem.Layers.cs
if (comp.IsComposite)
_counterSystem.ProcessCompositeSprite(uid, actual, maxCount, comp.LayerStates, hidden, sprite: args.Sprite);
else
_counterSystem.ProcessOpaqueSprite(uid, comp.BaseLayer, actual, maxCount, comp.LayerStates, hidden, sprite: args.Sprite);
}
/// <summary>
/// Adjusts the actual and maxCount to change how stack amounts are displayed.
/// </summary>
/// <param name="ent">The entity considered.</param>
/// <param name="actual">The actual number of items in the stack. Altered depending on the function to run.</param>
/// <param name="maxCount">The maximum number of items in the stack. Altered depending on the function to run.</param>
/// <returns>Whether or not a function was applied.</returns>
private bool ApplyLayerFunction(Entity<StackComponent> ent, ref int actual, ref int maxCount)
{
switch (ent.Comp.LayerFunction)
{
case StackLayerFunction.Threshold:
if (TryComp<StackLayerThresholdComponent>(ent, out var threshold))
{
ApplyThreshold(threshold, ref actual, ref maxCount);
return true;
}
break;
}
// No function applied.
return false;
}
/// <summary>
/// Selects which layer a stack applies based on a list of thresholds.
/// Each threshold passed results in the next layer being selected.
/// </summary>
/// <param name="comp">The threshold parameters to apply.</param>
/// <param name="actual">The number of items in the stack. Will be set to the index of the layer to use.</param>
/// <param name="maxCount">The maximum possible number of items in the stack. Will be set to the number of selectable layers.</param>
private static void ApplyThreshold(StackLayerThresholdComponent comp, ref int actual, ref int maxCount)
{
// We must stop before we run out of thresholds or layers, whichever's smaller.
maxCount = Math.Min(comp.Thresholds.Count + 1, maxCount);
var newActual = 0;
foreach (var threshold in comp.Thresholds)
{
//If our value exceeds threshold, the next layer should be displayed.
//Note: we must ensure actual <= MaxCount.
if (actual >= threshold && newActual < maxCount)
newActual++;
else
break;
}
actual = newActual;
}
}
}