Files
wwdpublic/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs
VMSolidus b9e2c6f34d Magboots Refactor (#2273)
# Description

Yea so it turns out that magboots were previously extremely dependent on
having other components work with them to do the "Magboot" ability. This
doesn't at all comply with ECS standards, since the expectation I have
is that the MagbootComponent ALONE should be sufficient to make an item
into "Magboots". This PR addresses this issue by refactoring
Magboots(and also ClothingSpeedModifier) to no longer depend on each
other for this behavior. MagbootsComponent is now responsible for
handling its own NoSlip, Gravity Immunity, and Movement Speed. This
behavior will also be extremly useful for supporting things such as
Modsuits and Hardsuit/Tacsuit upgrades, as well as Clothing Attachments
in general(which is another thing I'm working on).

I have attached a video demonstrating that I have tested this PR and
verified that it works.

<details><summary><h1>Media</h1></summary>
<p>

https://github.com/user-attachments/assets/f4b602ff-54b9-4df2-a0a0-e3f691c45bf2

</p>
</details>

# Changelog

🆑
- fix: Fixed various bugs related to Magboots and Integrated Magboots on
hardsuits.
- tweak: All Modsuits as well as tacsuits contributed by Goobstation now
also include Integrated Magsuits.

(cherry picked from commit a69ba8bbf606d1b59c5a509482ef7fdc1713956c)
2025-04-19 17:05:56 +03:00

127 lines
5.8 KiB
C#

using Content.Shared.Clothing.Components;
using Content.Shared.Examine;
using Content.Shared.Inventory;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.PowerCell;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
namespace Content.Shared.Clothing;
public sealed class ClothingSpeedModifierSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly ClothingSpeedModifierSystem _clothingSpeedModifier = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
[Dependency] private readonly ItemToggleSystem _toggle = default!;
[Dependency] private readonly SharedPowerCellSystem _powerCell = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ClothingSpeedModifierComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<ClothingSpeedModifierComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<ClothingSpeedModifierComponent, InventoryRelayedEvent<RefreshMovementSpeedModifiersEvent>>(OnRefreshMoveSpeed);
SubscribeLocalEvent<ClothingSpeedModifierComponent, GetVerbsEvent<ExamineVerb>>(OnClothingVerbExamine);
SubscribeLocalEvent<ClothingSpeedModifierComponent, ItemToggledEvent>(OnToggled);
}
private void OnGetState(EntityUid uid, ClothingSpeedModifierComponent component, ref ComponentGetState args)
{
args.State = new ClothingSpeedModifierComponentState(component.WalkModifier, component.SprintModifier);
}
private void OnHandleState(EntityUid uid, ClothingSpeedModifierComponent component, ref ComponentHandleState args)
{
if (args.Current is not ClothingSpeedModifierComponentState state)
return;
var diff = !MathHelper.CloseTo(component.SprintModifier, state.SprintModifier) ||
!MathHelper.CloseTo(component.WalkModifier, state.WalkModifier);
component.WalkModifier = state.WalkModifier;
component.SprintModifier = state.SprintModifier;
// Avoid raising the event for the container if nothing changed.
// We'll still set the values in case they're slightly different but within tolerance.
if (diff && _container.TryGetContainingContainer((uid, null, null), out var container))
{
_movementSpeed.RefreshMovementSpeedModifiers(container.Owner);
}
}
private void OnRefreshMoveSpeed(EntityUid uid, ClothingSpeedModifierComponent component, InventoryRelayedEvent<RefreshMovementSpeedModifiersEvent> args)
{
if (component.RequiresToggle && !_toggle.IsActivated(uid))
return;
args.Args.ModifySpeed(component.WalkModifier, component.SprintModifier);
}
private void OnClothingVerbExamine(EntityUid uid, ClothingSpeedModifierComponent component, GetVerbsEvent<ExamineVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
var walkModifierPercentage = MathF.Round((1.0f - component.WalkModifier) * 100f, 1);
var sprintModifierPercentage = MathF.Round((1.0f - component.SprintModifier) * 100f, 1);
if (walkModifierPercentage == 0.0f && sprintModifierPercentage == 0.0f)
return;
var msg = new FormattedMessage();
if (walkModifierPercentage == sprintModifierPercentage)
{
if (walkModifierPercentage < 0.0f)
msg.AddMarkup(Loc.GetString("clothing-speed-increase-equal-examine", ("walkSpeed", MathF.Abs(walkModifierPercentage)), ("runSpeed", MathF.Abs(sprintModifierPercentage))));
else
msg.AddMarkup(Loc.GetString("clothing-speed-decrease-equal-examine", ("walkSpeed", walkModifierPercentage), ("runSpeed", sprintModifierPercentage)));
}
else
{
if (sprintModifierPercentage < 0.0f)
{
msg.AddMarkup(Loc.GetString("clothing-speed-increase-run-examine", ("runSpeed", MathF.Abs(sprintModifierPercentage))));
}
else if (sprintModifierPercentage > 0.0f)
{
msg.AddMarkup(Loc.GetString("clothing-speed-decrease-run-examine", ("runSpeed", sprintModifierPercentage)));
}
if (walkModifierPercentage != 0.0f && sprintModifierPercentage != 0.0f)
{
msg.PushNewline();
}
if (walkModifierPercentage < 0.0f)
{
msg.AddMarkup(Loc.GetString("clothing-speed-increase-walk-examine", ("walkSpeed", MathF.Abs(walkModifierPercentage))));
}
else if (walkModifierPercentage > 0.0f)
{
msg.AddMarkup(Loc.GetString("clothing-speed-decrease-walk-examine", ("walkSpeed", walkModifierPercentage)));
}
}
_examine.AddDetailedExamineVerb(args, component, msg, Loc.GetString("clothing-speed-examinable-verb-text"), "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png", Loc.GetString("clothing-speed-examinable-verb-message"));
}
private void OnToggled(Entity<ClothingSpeedModifierComponent> ent, ref ItemToggledEvent args)
{
// make sentient boots slow or fast too
_movementSpeed.RefreshMovementSpeedModifiers(ent);
if (_container.TryGetContainingContainer((ent.Owner, null, null), out var container))
{
// inventory system will automatically hook into the event raised by this and update accordingly
_movementSpeed.RefreshMovementSpeedModifiers(container.Owner);
}
}
}