mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +03:00
Generic Clothing Equip Functions (#1407)
# Description
This PR was originally going to be called "Psionic Refactor V3 Part 2,
Items Of Power", but I began getting shakes and started vomiting when I
saw the list of Components that make items do things when equipped, and
I had a conniption about how much code there is constantly being
repeated. So instead of this PR adding Items Of Power, I added a
universal modular generic system for making clothing items do things
when equipped and unequipped. Which hooks into the library of
TraitFunctions that we've previously created. I also added a few
"Inverse" versions of trait functions that can be used by these new
clothing functions.
<!--
# Changelog
🆑
- add: Added a universal modular system for making clothing items DO
things when equipped and unequipped. This will be used for "Psionic
Artifacts" in conjunction with the Psionic Refactor V3.
-->
(cherry picked from commit 731e14f100d8161c0f8f7eb1bc5accc2abaa24da)
This commit is contained in:
@@ -133,8 +133,8 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
|
||||
RSI? rsi = null;
|
||||
|
||||
if (clothing.RsiPath != null)
|
||||
rsi = _cache.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / clothing.RsiPath).RSI;
|
||||
if (clothing.Sprite != null)
|
||||
rsi = _cache.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / clothing.Sprite).RSI;
|
||||
else if (TryComp(uid, out SpriteComponent? sprite))
|
||||
rsi = sprite.BaseRSI;
|
||||
|
||||
|
||||
@@ -1,7 +1,35 @@
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Clothing.EntitySystems;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
|
||||
namespace Content.Server.Clothing;
|
||||
|
||||
public sealed class ServerClothingSystem : ClothingSystem
|
||||
{
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ClothingComponent, DidEquipEvent>(OnClothingEquipped);
|
||||
SubscribeLocalEvent<ClothingComponent, DidUnequipEvent>(OnClothingUnequipped);
|
||||
}
|
||||
|
||||
private void OnClothingEquipped(EntityUid uid, ClothingComponent clothingComponent, DidEquipEvent args)
|
||||
{
|
||||
// Yes, this is using the trait system functions. I'm not going to write an entire third function library to do this.
|
||||
// They're generic for a reason.
|
||||
foreach (var function in clothingComponent.OnEquipFunctions)
|
||||
function.OnPlayerSpawn(uid, _componentFactory, EntityManager, _serializationManager);
|
||||
}
|
||||
|
||||
private void OnClothingUnequipped(EntityUid uid, ClothingComponent clothingComponent, DidUnequipEvent args)
|
||||
{
|
||||
// Yes, this is using the trait system functions. I'm not going to write an entire third function library to do this.
|
||||
// They're generic for a reason.
|
||||
foreach (var function in clothingComponent.OnUnequipFunctions)
|
||||
function.OnPlayerSpawn(uid, _componentFactory, EntityManager, _serializationManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,9 @@ public sealed partial class TraitAddPsionics : TraitFunction
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public List<ProtoId<PsionicPowerPrototype>> PsionicPowers { get; private set; } = new();
|
||||
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public bool PlayFeedback;
|
||||
|
||||
public override void OnPlayerSpawn(EntityUid uid,
|
||||
IComponentFactory factory,
|
||||
IEntityManager entityManager,
|
||||
@@ -147,7 +150,34 @@ public sealed partial class TraitAddPsionics : TraitFunction
|
||||
|
||||
foreach (var powerProto in PsionicPowers)
|
||||
if (prototype.TryIndex(powerProto, out var psionicPower))
|
||||
psionic.InitializePsionicPower(uid, psionicPower, false);
|
||||
psionic.InitializePsionicPower(uid, psionicPower, PlayFeedback);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This isn't actually used for any traits, surprise, other systems can use these functions!
|
||||
/// This is used by Items of Power to remove a psionic power when unequipped.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class TraitRemovePsionics : TraitFunction
|
||||
{
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public List<ProtoId<PsionicPowerPrototype>> PsionicPowers { get; private set; } = new();
|
||||
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public bool Forced = true;
|
||||
|
||||
public override void OnPlayerSpawn(EntityUid uid,
|
||||
IComponentFactory factory,
|
||||
IEntityManager entityManager,
|
||||
ISerializationManager serializationManager)
|
||||
{
|
||||
var prototype = IoCManager.Resolve<IPrototypeManager>();
|
||||
var psionic = entityManager.System<PsionicAbilitiesSystem>();
|
||||
|
||||
foreach (var powerProto in PsionicPowers)
|
||||
if (prototype.TryIndex(powerProto, out var psionicPower))
|
||||
psionic.RemovePsionicPower(uid, psionicPower, Forced);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +346,25 @@ public sealed partial class TraitAddArmor : TraitFunction
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class TraitRemoveArmor : TraitFunction
|
||||
{
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public List<string> DamageModifierSets { get; private set; } = new();
|
||||
|
||||
public override void OnPlayerSpawn(EntityUid uid,
|
||||
IComponentFactory factory,
|
||||
IEntityManager entityManager,
|
||||
ISerializationManager serializationManager)
|
||||
{
|
||||
if (!entityManager.TryGetComponent<DamageableComponent>(uid, out var damageableComponent))
|
||||
return;
|
||||
|
||||
foreach (var modifierSet in DamageModifierSets)
|
||||
damageableComponent.DamageModifierSets.Remove(modifierSet);
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class TraitAddSolutionContainer : TraitFunction
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Clothing.EntitySystems;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Traits;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -15,55 +16,69 @@ namespace Content.Shared.Clothing.Components;
|
||||
[Access(typeof(ClothingSystem), typeof(InventorySystem))]
|
||||
public sealed partial class ClothingComponent : Component
|
||||
{
|
||||
[DataField("clothingVisuals")]
|
||||
[DataField]
|
||||
[Access(typeof(ClothingSystem), typeof(InventorySystem), Other = AccessPermissions.ReadExecute)] // TODO remove execute permissions.
|
||||
public Dictionary<string, List<PrototypeLayerData>> ClothingVisuals = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("quickEquip")]
|
||||
[DataField]
|
||||
public bool QuickEquip = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("slots", required: true)]
|
||||
[DataField(required: true)]
|
||||
[Access(typeof(ClothingSystem), typeof(InventorySystem), Other = AccessPermissions.ReadExecute)]
|
||||
public SlotFlags Slots = SlotFlags.NONE;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("equipSound")]
|
||||
[DataField]
|
||||
public SoundSpecifier? EquipSound;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("unequipSound")]
|
||||
[DataField]
|
||||
public SoundSpecifier? UnequipSound;
|
||||
|
||||
[Access(typeof(ClothingSystem))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("equippedPrefix")]
|
||||
[DataField]
|
||||
public string? EquippedPrefix;
|
||||
|
||||
/// <summary>
|
||||
/// Allows the equipped state to be directly overwritten.
|
||||
/// useful when prototyping INNERCLOTHING items into OUTERCLOTHING items without duplicating/modifying RSIs etc.
|
||||
/// Allows the equipped state to be directly overwritten.
|
||||
/// useful when prototyping INNERCLOTHING items into OUTERCLOTHING items without duplicating/modifying RSIs etc.
|
||||
/// </summary>
|
||||
[Access(typeof(ClothingSystem))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("equippedState")]
|
||||
[DataField]
|
||||
public string? EquippedState;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("sprite")]
|
||||
public string? RsiPath;
|
||||
[DataField]
|
||||
public string? Sprite;
|
||||
|
||||
[DataField]
|
||||
public ClothingMask MaleMask = ClothingMask.UniformFull;
|
||||
|
||||
[DataField]
|
||||
public ClothingMask FemaleMask = ClothingMask.UniformFull;
|
||||
|
||||
[DataField]
|
||||
public ClothingMask UnisexMask = ClothingMask.UniformFull;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the inventory slot the clothing is in.
|
||||
/// Name of the inventory slot the clothing is in.
|
||||
/// </summary>
|
||||
public string? InSlot;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public TimeSpan EquipDelay = TimeSpan.Zero;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public TimeSpan UnequipDelay = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// These functions are called when an entity equips an item with this component.
|
||||
/// </summary>
|
||||
[DataField(serverOnly: true)]
|
||||
public TraitFunction[] OnEquipFunctions { get; private set; } = Array.Empty<TraitFunction>();
|
||||
|
||||
/// <summary>
|
||||
/// These functions are called when an entity un-equips an item with this component.
|
||||
/// </summary>
|
||||
[DataField(serverOnly: true)]
|
||||
public TraitFunction[] OnUnequipFunctions { get; private set; } = Array.Empty<TraitFunction>();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
@@ -109,4 +124,3 @@ public sealed partial class ClothingUnequipDoAfterEvent : DoAfterEvent
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +247,8 @@ public abstract class ClothingSystem : EntitySystem
|
||||
|
||||
clothing.ClothingVisuals = otherClothing.ClothingVisuals;
|
||||
clothing.EquippedPrefix = otherClothing.EquippedPrefix;
|
||||
clothing.RsiPath = otherClothing.RsiPath;
|
||||
clothing.Sprite = otherClothing.Sprite;
|
||||
clothing.FemaleMask = otherClothing.FemaleMask;
|
||||
|
||||
_itemSys.VisualsChanged(uid);
|
||||
Dirty(uid, clothing);
|
||||
|
||||
Reference in New Issue
Block a user