]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Cleanups PolymorphSystem/Components/Prototypes (#23721)
authorAJCM-git <60196617+AJCM-git@users.noreply.github.com>
Thu, 1 Feb 2024 12:17:02 +0000 (08:17 -0400)
committerGitHub <noreply@github.com>
Thu, 1 Feb 2024 12:17:02 +0000 (23:17 +1100)
* Cleanups PolymorphSystem

* forgot this

* Nah

* Fix test

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
17 files changed:
Content.Server/Administration/Commands/AddPolymorphActionCommand.cs
Content.Server/Chemistry/ReagentEffects/Polymorph.cs
Content.Server/Polymorph/Components/PolymorphOnCollideComponent.cs
Content.Server/Polymorph/Components/PolymorphableComponent.cs
Content.Server/Polymorph/Components/PolymorphedEntityComponent.cs
Content.Server/Polymorph/Systems/PolymorphSystem.Collide.cs
Content.Server/Polymorph/Systems/PolymorphSystem.Map.cs
Content.Server/Polymorph/Systems/PolymorphSystem.cs
Content.Server/Polymorph/Toolshed/PolymorphCommand.cs
Content.Server/Polymorph/Toolshed/UnpolymorphCommand.cs
Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyOthersArtifactComponent.cs [moved from Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs with 81% similarity]
Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyOthersArtifactSystem.cs [moved from Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs with 68% similarity]
Content.Shared/Polymorph/PolymorphActions.cs
Content.Shared/Polymorph/PolymorphPrototype.cs
Resources/Prototypes/Polymorphs/admin.yml
Resources/Prototypes/Polymorphs/polymorph.yml
Resources/Prototypes/XenoArch/Effects/normal_effects.yml

index 6223df7a6cb0117deca277ebd4ea64bac8d0fc99..b92cbfc0de9715e6b6b7c25715a2b46545e6e984 100644 (file)
@@ -32,7 +32,7 @@ public sealed class AddPolymorphActionCommand : IConsoleCommand
 
         var polySystem = _entityManager.EntitySysManager.GetEntitySystem<PolymorphSystem>();
 
-        _entityManager.EnsureComponent<PolymorphableComponent>(entityUid.Value);
-        polySystem.CreatePolymorphAction(args[1], entityUid.Value);
+        var polymorphable = _entityManager.EnsureComponent<PolymorphableComponent>(entityUid.Value);
+        polySystem.CreatePolymorphAction(args[1], (entityUid.Value, polymorphable));
     }
 }
index 569da51e39ad341237fee1f8c5a28f6d415b1f49..fea372125eebe227a5840a80c8046c594ee920f0 100644 (file)
@@ -18,7 +18,7 @@ public sealed partial class Polymorph : ReagentEffect
     protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
     => Loc.GetString("reagent-effect-guidebook-make-polymorph",
             ("chance", Probability), ("entityname",
-                prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Entity).Name));
+                prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Configuration.Entity).Name));
 
     public override void Effect(ReagentEffectArgs args)
     {
index 5d513df933867477654706fc94a8d3a1e568c3b5..577dadb5c8d5d63acc3ca3a0f3967ca510182aa0 100644 (file)
@@ -1,21 +1,24 @@
+using Content.Server.Polymorph.Systems;
 using Content.Shared.Polymorph;
 using Content.Shared.Whitelist;
 using Robust.Shared.Audio;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Polymorph.Components;
 
 [RegisterComponent]
+[Access(typeof(PolymorphSystem))]
 public sealed partial class PolymorphOnCollideComponent : Component
 {
-    [DataField("polymorph", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
-    public string Polymorph = default!;
+    [DataField(required: true)]
+    public ProtoId<PolymorphPrototype> Polymorph;
 
-    [DataField("whitelist", required: true)]
+    [DataField(required: true)]
     public EntityWhitelist Whitelist = default!;
 
-    [DataField("blacklist")]
+    [DataField]
     public EntityWhitelist? Blacklist;
 
+    [DataField]
     public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg");
 }
index 2e9c5fee0a5fb79daac206fd374c9d74db571aca..d28aa5a4fbfaa0d70697bea06731f2ba7b0e0bc5 100644 (file)
@@ -1,27 +1,28 @@
+using Content.Server.Polymorph.Systems;
 using Content.Shared.Polymorph;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using Robust.Shared.Prototypes;
 
-namespace Content.Server.Polymorph.Components
+namespace Content.Server.Polymorph.Components;
+
+[RegisterComponent]
+[Access(typeof(PolymorphSystem))]
+public sealed partial class PolymorphableComponent : Component
 {
-    [RegisterComponent]
-    public sealed partial class PolymorphableComponent : Component
-    {
-        /// <summary>
-        /// A list of all the polymorphs that the entity has.
-        /// Used to manage them and remove them if needed.
-        /// </summary>
-        public Dictionary<string, EntityUid>? PolymorphActions = null;
+    /// <summary>
+    /// A list of all the polymorphs that the entity has.
+    /// Used to manage them and remove them if needed.
+    /// </summary>
+    public Dictionary<ProtoId<PolymorphPrototype>, EntityUid>? PolymorphActions = null;
 
-        /// <summary>
-        /// Timestamp for when the most recent polymorph ended.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadOnly)]
-        public TimeSpan? LastPolymorphEnd = null;
+    /// <summary>
+    /// Timestamp for when the most recent polymorph ended.
+    /// </summary>
+    [ViewVariables(VVAccess.ReadOnly)]
+    public TimeSpan? LastPolymorphEnd = null;
 
         /// <summary>
-        /// The polymorphs that the entity starts out being able to do.
-        /// </summary>
-        [DataField("innatePolymorphs", customTypeSerializer : typeof(PrototypeIdListSerializer<PolymorphPrototype>))]
-        public List<string>? InnatePolymorphs;
-    }
+    /// The polymorphs that the entity starts out being able to do.
+    /// </summary>
+    [DataField]
+    public List<ProtoId<PolymorphPrototype>>? InnatePolymorphs;
 }
index c155c538d16681912768030b9ee4f8ea51cce528..7620203a862b070e2a3f22b5c29e56630ef62ca0 100644 (file)
@@ -1,31 +1,32 @@
+using Content.Server.Polymorph.Systems;
 using Content.Shared.Polymorph;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.Polymorph.Components
+namespace Content.Server.Polymorph.Components;
+
+[RegisterComponent]
+[Access(typeof(PolymorphSystem))]
+public sealed partial class PolymorphedEntityComponent : Component
 {
-    [RegisterComponent]
-    public sealed partial class PolymorphedEntityComponent : Component
-    {
-        /// <summary>
-        /// The polymorph prototype, used to track various information
-        /// about the polymorph
-        /// </summary>
-        [DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<PolymorphPrototype>))]
-        public string Prototype = string.Empty;
+    /// <summary>
+    /// The polymorph prototype, used to track various information
+    /// about the polymorph
+    /// </summary>
+    [DataField(required: true)]
+    public PolymorphConfiguration Configuration = new();
 
-        /// <summary>
-        /// The original entity that the player will revert back into
-        /// </summary>
-        [DataField("parent", required: true)]
-        public EntityUid Parent;
+    /// <summary>
+    /// The original entity that the player will revert back into
+    /// </summary>
+    [DataField(required: true)]
+    public EntityUid Parent;
 
-        /// <summary>
-        /// The amount of time that has passed since the entity was created
-        /// used for tracking the duration
-        /// </summary>
-        [DataField("time")]
-        public float Time;
+    /// <summary>
+    /// The amount of time that has passed since the entity was created
+    /// used for tracking the duration
+    /// </summary>
+    [DataField]
+    public float Time;
 
-        [DataField] public EntityUid? Action;
-    }
+    [DataField]
+    public EntityUid? Action;
 }
index 46b962b20e8eaa2dedc7f7b2b53a6d1d0a754d88..b4240d409ad8a5b1bdce019149eb139155ed09f5 100644 (file)
@@ -1,16 +1,25 @@
 using Content.Server.Polymorph.Components;
+using Content.Shared.Polymorph;
 using Content.Shared.Projectiles;
 using Robust.Shared.Audio;
 using Robust.Shared.Physics.Events;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Polymorph.Systems;
 
 public partial class PolymorphSystem
 {
-    // Need to do this so we don't get a collection enumeration error in physics by polymorphing
-    // an entity we're colliding with
+    /// <summary>
+    /// Need to do this so we don't get a collection enumeration error in physics by polymorphing
+    /// an entity we're colliding with
+    /// </summary>
     private Queue<PolymorphQueuedData> _queuedPolymorphUpdates = new();
 
+    private void InitializeCollide()
+    {
+        SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
+    }
+
     public void UpdateCollide()
     {
         while (_queuedPolymorphUpdates.TryDequeue(out var data))
@@ -20,25 +29,18 @@ public partial class PolymorphSystem
 
             var ent = PolymorphEntity(data.Ent, data.Polymorph);
             if (ent != null)
-            {
                 _audio.PlayPvs(data.Sound, ent.Value);
-            }
         }
     }
 
-    private void InitializeCollide()
-    {
-        SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
-    }
-
     private void OnPolymorphCollide(EntityUid uid, PolymorphOnCollideComponent component, ref StartCollideEvent args)
     {
         if (args.OurFixtureId != SharedProjectileSystem.ProjectileFixture)
             return;
 
         var other = args.OtherEntity;
-        if (!component.Whitelist.IsValid(other)
-            || component.Blacklist != null && component.Blacklist.IsValid(other))
+        if (!component.Whitelist.IsValid(other, EntityManager)
+            || component.Blacklist != null && component.Blacklist.IsValid(other, EntityManager))
             return;
 
         _queuedPolymorphUpdates.Enqueue(new (other, component.Sound, component.Polymorph));
@@ -49,9 +51,9 @@ public struct PolymorphQueuedData
 {
     public EntityUid Ent;
     public SoundSpecifier Sound;
-    public string Polymorph;
+    public ProtoId<PolymorphPrototype> Polymorph;
 
-    public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, string polymorph)
+    public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, ProtoId<PolymorphPrototype> polymorph)
     {
         Ent = ent;
         Sound = sound;
index a6f658524d1bd76be790be7a33420e83e9cb547f..120e04eeb08ecf31f45d895adcf3975d78dcbde2 100644 (file)
@@ -1,39 +1,38 @@
 using Content.Shared.GameTicking;
 
-namespace Content.Server.Polymorph.Systems
+namespace Content.Server.Polymorph.Systems;
+
+public sealed partial class PolymorphSystem
 {
-    public sealed partial class PolymorphSystem
-    {
-        public EntityUid? PausedMap { get; private set; }
+    public EntityUid? PausedMap { get; private set; }
 
-        /// <summary>
-        /// Used to subscribe to the round restart event
-        /// </summary>
-        private void InitializeMap()
-        {
-            SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
-        }
+    /// <summary>
+    /// Used to subscribe to the round restart event
+    /// </summary>
+    private void InitializeMap()
+    {
+        SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
+    }
 
-        private void OnRoundRestart(RoundRestartCleanupEvent _)
-        {
-            if (PausedMap == null || !Exists(PausedMap))
-                return;
+    private void OnRoundRestart(RoundRestartCleanupEvent _)
+    {
+        if (PausedMap == null || !Exists(PausedMap))
+            return;
 
-            EntityManager.DeleteEntity(PausedMap.Value);
-        }
+        Del(PausedMap.Value);
+    }
 
-        /// <summary>
-        /// Used internally to ensure a paused map that is
-        /// stores polymorphed entities.
-        /// </summary>
-        private void EnsurePausesdMap()
-        {
-            if (PausedMap != null && Exists(PausedMap))
-                return;
+    /// <summary>
+    /// Used internally to ensure a paused map that is
+    /// stores polymorphed entities.
+    /// </summary>
+    private void EnsurePausedMap()
+    {
+        if (PausedMap != null && Exists(PausedMap))
+            return;
 
-            var newmap = _mapManager.CreateMap();
-            _mapManager.SetMapPaused(newmap, true);
-            PausedMap = _mapManager.GetMapEntityId(newmap);
-        }
+        var newmap = _mapManager.CreateMap();
+        _mapManager.SetMapPaused(newmap, true);
+        PausedMap = _mapManager.GetMapEntityId(newmap);
     }
 }
index 4d3bbcdf7805237b7102d8b65aafd8c26b404f6d..66dc9dab99d5d32eda80ad87714d3b29c3e32312 100644 (file)
@@ -15,7 +15,6 @@ using Content.Shared.Mobs.Components;
 using Content.Shared.Mobs.Systems;
 using Content.Shared.Polymorph;
 using Content.Shared.Popups;
-using JetBrains.Annotations;
 using Robust.Server.Audio;
 using Robust.Server.Containers;
 using Robust.Server.GameObjects;
@@ -24,410 +23,359 @@ using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
 
-namespace Content.Server.Polymorph.Systems
+namespace Content.Server.Polymorph.Systems;
+
+public sealed partial class PolymorphSystem : EntitySystem
 {
-    public sealed partial class PolymorphSystem : EntitySystem
+    [Dependency] private readonly IComponentFactory _compFact = default!;
+    [Dependency] private readonly IMapManager _mapManager = default!;
+    [Dependency] private readonly IPrototypeManager _proto = default!;
+    [Dependency] private readonly IGameTiming _gameTiming = default!;
+    [Dependency] private readonly ActionsSystem _actions = default!;
+    [Dependency] private readonly ActionContainerSystem _actionContainer = default!;
+    [Dependency] private readonly AudioSystem _audio = default!;
+    [Dependency] private readonly SharedBuckleSystem _buckle = default!;
+    [Dependency] private readonly ContainerSystem _container = default!;
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
+    [Dependency] private readonly MobStateSystem _mobState = default!;
+    [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
+    [Dependency] private readonly ServerInventorySystem _inventory = default!;
+    [Dependency] private readonly SharedHandsSystem _hands = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly TransformSystem _transform = default!;
+    [Dependency] private readonly SharedMindSystem _mindSystem = default!;
+    [Dependency] private readonly MetaDataSystem _metaData = default!;
+
+    private const string RevertPolymorphId = "ActionRevertPolymorph";
+
+    public override void Initialize()
     {
-        [Dependency] private readonly IComponentFactory _compFact = default!;
-        [Dependency] private readonly IMapManager _mapManager = default!;
-        [Dependency] private readonly IPrototypeManager _proto = default!;
-        [Dependency] private readonly ActionsSystem _actions = default!;
-        [Dependency] private readonly ActionContainerSystem _actionContainer = default!;
-        [Dependency] private readonly AudioSystem _audio = default!;
-        [Dependency] private readonly SharedBuckleSystem _buckle = default!;
-        [Dependency] private readonly ContainerSystem _container = default!;
-        [Dependency] private readonly DamageableSystem _damageable = default!;
-        [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
-        [Dependency] private readonly MobStateSystem _mobState = default!;
-        [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
-        [Dependency] private readonly ServerInventorySystem _inventory = default!;
-        [Dependency] private readonly SharedHandsSystem _hands = default!;
-        [Dependency] private readonly SharedPopupSystem _popup = default!;
-        [Dependency] private readonly TransformSystem _transform = default!;
-        [Dependency] private readonly SharedMindSystem _mindSystem = default!;
-        [Dependency] private readonly MetaDataSystem _metaData = default!;
-        [Dependency] private readonly IGameTiming _gameTiming = default!;
-
-        private ISawmill _sawmill = default!;
-
-        private const string RevertPolymorphId = "ActionRevertPolymorph";
-
-        public override void Initialize()
-        {
-            base.Initialize();
+        SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnComponentStartup);
+        SubscribeLocalEvent<PolymorphedEntityComponent, MapInitEvent>(OnMapInit);
 
-            SubscribeLocalEvent<PolymorphableComponent, ComponentStartup>(OnStartup);
-            SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
-            SubscribeLocalEvent<PolymorphedEntityComponent, MapInitEvent>(OnMapInit);
-            SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
-            SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
-            SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
-            SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
+        SubscribeLocalEvent<PolymorphableComponent, PolymorphActionEvent>(OnPolymorphActionEvent);
+        SubscribeLocalEvent<PolymorphedEntityComponent, RevertPolymorphActionEvent>(OnRevertPolymorphActionEvent);
 
-            InitializeCollide();
-            InitializeMap();
-
-            _sawmill = Logger.GetSawmill("polymorph");
-        }
+        SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
+        SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
+        SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
 
-        private void OnStartup(EntityUid uid, PolymorphableComponent component, ComponentStartup args)
-        {
-            if (component.InnatePolymorphs != null)
-            {
-                foreach (var morph in component.InnatePolymorphs)
-                {
-                    CreatePolymorphAction(morph, uid);
-                }
-            }
-        }
+        InitializeCollide();
+        InitializeMap();
+    }
 
-        private void OnPolymorphActionEvent(EntityUid uid, PolymorphableComponent component, PolymorphActionEvent args)
-        {
-            PolymorphEntity(uid, args.Prototype);
-        }
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
 
-        private void OnRevertPolymorphActionEvent(EntityUid uid, PolymorphedEntityComponent component, RevertPolymorphActionEvent args)
+        var query = EntityQueryEnumerator<PolymorphedEntityComponent>();
+        while (query.MoveNext(out var uid, out var comp))
         {
-            Revert(uid, component);
-        }
+            comp.Time += frameTime;
 
-        private void OnMapInit(EntityUid uid, PolymorphedEntityComponent component, MapInitEvent args)
-        {
-            if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
+            if (comp.Configuration.Duration != null && comp.Time >= comp.Configuration.Duration)
             {
-                // warning instead of error because of the all-comps one entity test.
-                _sawmill.Warning($"{nameof(PolymorphSystem)} encountered an improperly set up polymorph component while initializing. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
-                RemCompDeferred(uid, component);
-                return;
+                Revert((uid, comp));
+                continue;
             }
 
-            if (proto.Forced)
-                return;
+            if (!TryComp<MobStateComponent>(uid, out var mob))
+                continue;
 
-            if (_actions.AddAction(uid, ref component.Action, out var action, RevertPolymorphId))
+            if (comp.Configuration.RevertOnDeath && _mobState.IsDead(uid, mob) ||
+                comp.Configuration.RevertOnCrit && _mobState.IsIncapacitated(uid, mob))
             {
-                action.EntityIcon = component.Parent;
-                action.UseDelay = TimeSpan.FromSeconds(proto.Delay);
+                Revert((uid, comp));
             }
         }
 
-        private void OnBeforeFullyEaten(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullyEatenEvent args)
-        {
-            if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
-            {
-                _sawmill.Error($"Invalid polymorph prototype {comp.Prototype}");
-                return;
-            }
+        UpdateCollide();
+    }
 
-            if (proto.RevertOnEat)
+    private void OnComponentStartup(Entity<PolymorphableComponent> ent, ref ComponentStartup args)
+    {
+        if (ent.Comp.InnatePolymorphs != null)
+        {
+            foreach (var morph in ent.Comp.InnatePolymorphs)
             {
-                args.Cancel();
-                Revert(uid, comp);
+                CreatePolymorphAction(morph, ent);
             }
         }
+    }
 
-        /// <summary>
-        /// It is possible to be polymorphed into an entity that can't "die", but is instead
-        /// destroyed. This handler ensures that destruction is treated like death.
-        /// </summary>
-        private void OnDestruction(EntityUid uid, PolymorphedEntityComponent comp, DestructionEventArgs args)
-        {
-            if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
-            {
-                _sawmill.Error($"Invalid polymorph prototype {comp.Prototype}");
-                return;
-            }
+    private void OnMapInit(Entity<PolymorphedEntityComponent> ent, ref MapInitEvent args)
+    {
+        var (uid, component) = ent;
+        if (component.Configuration.Forced)
+            return;
 
-            if (proto.RevertOnDeath)
-            {
-                Revert(uid, comp);
-            }
+        if (_actions.AddAction(uid, ref component.Action, out var action, RevertPolymorphId))
+        {
+            action.EntityIcon = component.Parent;
+            action.UseDelay = TimeSpan.FromSeconds(component.Configuration.Delay);
         }
+    }
 
-        private void OnBeforeFullySliced(EntityUid uid, PolymorphedEntityComponent comp, BeforeFullySlicedEvent args)
-        {
-            if (!_proto.TryIndex<PolymorphPrototype>(comp.Prototype, out var proto))
-            {
-                _sawmill.Error("Invalid polymorph prototype {comp.Prototype}");
-                return;
-            }
+    private void OnPolymorphActionEvent(Entity<PolymorphableComponent> ent, ref PolymorphActionEvent args)
+    {
+        PolymorphEntity(ent, args.Prototype.Configuration);
+    }
 
-            if (proto.RevertOnEat)
-            {
-                args.Cancel();
-                Revert(uid, comp);
-            }
-        }
+    private void OnRevertPolymorphActionEvent(Entity<PolymorphedEntityComponent> ent,
+        ref RevertPolymorphActionEvent args)
+    {
+        Revert((ent, ent));
+    }
 
-        /// <summary>
-        /// Polymorphs the target entity into the specific polymorph prototype
-        /// </summary>
-        /// <param name="target">The entity that will be transformed</param>
-        /// <param name="id">The id of the polymorph prototype</param>
-        public EntityUid? PolymorphEntity(EntityUid target, string id)
+    private void OnBeforeFullyEaten(Entity<PolymorphedEntityComponent> ent, ref BeforeFullyEatenEvent args)
+    {
+        var (_, comp) = ent;
+        if (comp.Configuration.RevertOnEat)
         {
-            if (!_proto.TryIndex<PolymorphPrototype>(id, out var proto))
-            {
-                _sawmill.Error("Invalid polymorph prototype {id}");
-                return null;
-            }
+            args.Cancel();
+            Revert((ent, ent));
+        }
+    }
 
-            return PolymorphEntity(target, proto);
+    private void OnBeforeFullySliced(Entity<PolymorphedEntityComponent> ent, ref BeforeFullySlicedEvent args)
+    {
+        var (_, comp) = ent;
+        if (comp.Configuration.RevertOnEat)
+        {
+            args.Cancel();
+            Revert((ent, ent));
         }
+    }
 
-        /// <summary>
-        /// Polymorphs the target entity into the specific polymorph prototype
-        /// </summary>
-        /// <param name="uid">The entity that will be transformed</param>
-        /// <param name="proto">The polymorph prototype</param>
-        public EntityUid? PolymorphEntity(EntityUid uid, PolymorphPrototype proto)
+    /// <summary>
+    /// It is possible to be polymorphed into an entity that can't "die", but is instead
+    /// destroyed. This handler ensures that destruction is treated like death.
+    /// </summary>
+    private void OnDestruction(Entity<PolymorphedEntityComponent> ent, ref DestructionEventArgs args)
+    {
+        if (ent.Comp.Configuration.RevertOnDeath)
         {
-            // if it's already morphed, don't allow it again with this condition active.
-            if (!proto.AllowRepeatedMorphs && HasComp<PolymorphedEntityComponent>(uid))
-                return null;
+            Revert((ent, ent));
+        }
+    }
 
-            // If this polymorph has a cooldown, check if that amount of time has passed since the
-            // last polymorph ended.
-            if (TryComp<PolymorphableComponent>(uid, out var polymorphableComponent) &&
-                polymorphableComponent.LastPolymorphEnd != null &&
-                _gameTiming.CurTime < polymorphableComponent.LastPolymorphEnd + proto.Cooldown)
-                return null;
+    /// <summary>
+    /// Polymorphs the target entity into the specific polymorph prototype
+    /// </summary>
+    /// <param name="uid">The entity that will be transformed</param>
+    /// <param name="protoId">The id of the polymorph prototype</param>
+    public EntityUid? PolymorphEntity(EntityUid uid, ProtoId<PolymorphPrototype> protoId)
+    {
+        var config = _proto.Index(protoId).Configuration;
+        return PolymorphEntity(uid, config);
+    }
 
-            // mostly just for vehicles
-            _buckle.TryUnbuckle(uid, uid, true);
+    /// <summary>
+    /// Polymorphs the target entity into another
+    /// </summary>
+    /// <param name="uid">The entity that will be transformed</param>
+    /// <param name="configuration">Polymorph data</param>
+    /// <returns></returns>
+    public EntityUid? PolymorphEntity(EntityUid uid, PolymorphConfiguration configuration)
+    {
+        // if it's already morphed, don't allow it again with this condition active.
+        if (!configuration.AllowRepeatedMorphs && HasComp<PolymorphedEntityComponent>(uid))
+            return null;
 
-            var targetTransformComp = Transform(uid);
+        // If this polymorph has a cooldown, check if that amount of time has passed since the
+        // last polymorph ended.
+        if (TryComp<PolymorphableComponent>(uid, out var polymorphableComponent) &&
+            polymorphableComponent.LastPolymorphEnd != null &&
+            _gameTiming.CurTime < polymorphableComponent.LastPolymorphEnd + configuration.Cooldown)
+            return null;
 
-            var child = Spawn(proto.Entity, targetTransformComp.Coordinates);
-            MakeSentientCommand.MakeSentient(child, EntityManager);
+        // mostly just for vehicles
+        _buckle.TryUnbuckle(uid, uid, true);
 
-            var comp = _compFact.GetComponent<PolymorphedEntityComponent>();
-            comp.Parent = uid;
-            comp.Prototype = proto.ID;
-            AddComp(child, comp);
+        var targetTransformComp = Transform(uid);
 
-            var childXform = Transform(child);
-            childXform.LocalRotation = targetTransformComp.LocalRotation;
+        var child = Spawn(configuration.Entity, targetTransformComp.Coordinates);
 
-            if (_container.TryGetContainingContainer(uid, out var cont))
-                _container.Insert(child, cont);
+        MakeSentientCommand.MakeSentient(child, EntityManager);
 
-            //Transfers all damage from the original to the new one
-            if (proto.TransferDamage &&
-                TryComp<DamageableComponent>(child, out var damageParent) &&
-                _mobThreshold.GetScaledDamage(uid, child, out var damage) &&
-                damage != null)
-            {
-                _damageable.SetDamage(child, damageParent, damage);
-            }
+        var polymorphedComp = _compFact.GetComponent<PolymorphedEntityComponent>();
+        polymorphedComp.Parent = uid;
+        polymorphedComp.Configuration = configuration;
+        AddComp(child, polymorphedComp);
+
+        var childXform = Transform(child);
+        _transform.SetLocalRotation(child, targetTransformComp.LocalRotation, childXform);
+
+        if (_container.TryGetContainingContainer(uid, out var cont))
+            _container.Insert(child, cont);
+
+        //Transfers all damage from the original to the new one
+        if (configuration.TransferDamage &&
+            TryComp<DamageableComponent>(child, out var damageParent) &&
+            _mobThreshold.GetScaledDamage(uid, child, out var damage) &&
+            damage != null)
+        {
+            _damageable.SetDamage(child, damageParent, damage);
+        }
 
-            if (proto.Inventory == PolymorphInventoryChange.Transfer)
+        if (configuration.Inventory == PolymorphInventoryChange.Transfer)
+        {
+            _inventory.TransferEntityInventories(uid, child);
+            foreach (var hand in _hands.EnumerateHeld(uid))
             {
-                _inventory.TransferEntityInventories(uid, child);
-                foreach (var hand in _hands.EnumerateHeld(uid))
-                {
-                    _hands.TryDrop(uid, hand, checkActionBlocker: false);
-                    _hands.TryPickupAnyHand(child, hand);
-                }
+                _hands.TryDrop(uid, hand, checkActionBlocker: false);
+                _hands.TryPickupAnyHand(child, hand);
             }
-            else if (proto.Inventory == PolymorphInventoryChange.Drop)
+        }
+        else if (configuration.Inventory == PolymorphInventoryChange.Drop)
+        {
+            if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
             {
-                if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
-                {
-                    while (enumerator.MoveNext(out var slot))
-                    {
-                        _inventory.TryUnequip(uid, slot.ID, true, true);
-                    }
-                }
-
-                foreach (var held in _hands.EnumerateHeld(uid))
+                while (enumerator.MoveNext(out var slot))
                 {
-                    _hands.TryDrop(uid, held);
+                    _inventory.TryUnequip(uid, slot.ID, true, true);
                 }
             }
 
-            if (proto.TransferName && TryComp<MetaDataComponent>(uid, out var targetMeta))
-                _metaData.SetEntityName(child, targetMeta.EntityName);
-
-            if (proto.TransferHumanoidAppearance)
+            foreach (var held in _hands.EnumerateHeld(uid))
             {
-                _humanoid.CloneAppearance(uid, child);
+                _hands.TryDrop(uid, held);
             }
+        }
 
-            if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
-                _mindSystem.TransferTo(mindId, child, mind: mind);
-
-            //Ensures a map to banish the entity to
-            EnsurePausesdMap();
-            if (PausedMap != null)
-                _transform.SetParent(uid, targetTransformComp, PausedMap.Value);
+        if (configuration.TransferName && TryComp<MetaDataComponent>(uid, out var targetMeta))
+            _metaData.SetEntityName(child, targetMeta.EntityName);
 
-            return child;
+        if (configuration.TransferHumanoidAppearance)
+        {
+            _humanoid.CloneAppearance(uid, child);
         }
 
-        /// <summary>
-        /// Reverts a polymorphed entity back into its original form
-        /// </summary>
-        /// <param name="uid">The entityuid of the entity being reverted</param>
-        /// <param name="component"></param>
-        public EntityUid? Revert(EntityUid uid, PolymorphedEntityComponent? component = null)
-        {
-            if (Deleted(uid))
-                return null;
+        if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
+            _mindSystem.TransferTo(mindId, child, mind: mind);
 
-            if (!Resolve(uid, ref component))
-                return null;
+        //Ensures a map to banish the entity to
+        EnsurePausedMap();
+        if (PausedMap != null)
+            _transform.SetParent(uid, targetTransformComp, PausedMap.Value);
 
-            var parent = component.Parent;
-            if (Deleted(parent))
-                return null;
+        return child;
+    }
 
-            if (!_proto.TryIndex(component.Prototype, out PolymorphPrototype? proto))
-            {
-                _sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while reverting. Entity {ToPrettyString(uid)}. Prototype: {component.Prototype}");
-                return null;
-            }
+    /// <summary>
+    /// Reverts a polymorphed entity back into its original form
+    /// </summary>
+    /// <param name="uid">The entityuid of the entity being reverted</param>
+    /// <param name="component"></param>
+    public EntityUid? Revert(Entity<PolymorphedEntityComponent?> ent)
+    {
+        var (uid, component) = ent;
+        if (!Resolve(ent, ref component))
+            return null;
 
-            var uidXform = Transform(uid);
-            var parentXform = Transform(parent);
+        if (Deleted(uid))
+            return null;
 
-            _transform.SetParent(parent, parentXform, uidXform.ParentUid);
-            parentXform.Coordinates = uidXform.Coordinates;
-            parentXform.LocalRotation = uidXform.LocalRotation;
+        var parent = component.Parent;
+        if (Deleted(parent))
+            return null;
 
-            if (proto.TransferDamage &&
-                TryComp<DamageableComponent>(parent, out var damageParent) &&
-                _mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
-                damage != null)
-            {
-                _damageable.SetDamage(parent, damageParent, damage);
-            }
+        var uidXform = Transform(uid);
+        var parentXform = Transform(parent);
+
+        _transform.SetParent(parent, parentXform, uidXform.ParentUid);
+        _transform.SetCoordinates(parent, parentXform, uidXform.Coordinates, uidXform.LocalRotation);
 
-            if (proto.Inventory == PolymorphInventoryChange.Transfer)
+        if (component.Configuration.TransferDamage &&
+            TryComp<DamageableComponent>(parent, out var damageParent) &&
+            _mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
+            damage != null)
+        {
+            _damageable.SetDamage(parent, damageParent, damage);
+        }
+
+        if (component.Configuration.Inventory == PolymorphInventoryChange.Transfer)
+        {
+            _inventory.TransferEntityInventories(uid, parent);
+            foreach (var held in _hands.EnumerateHeld(uid))
             {
-                _inventory.TransferEntityInventories(uid, parent);
-                foreach (var held in _hands.EnumerateHeld(uid))
-                {
-                    _hands.TryDrop(uid, held);
-                    _hands.TryPickupAnyHand(parent, held, checkActionBlocker: false);
-                }
+                _hands.TryDrop(uid, held);
+                _hands.TryPickupAnyHand(parent, held, checkActionBlocker: false);
             }
-            else if (proto.Inventory == PolymorphInventoryChange.Drop)
+        }
+        else if (component.Configuration.Inventory == PolymorphInventoryChange.Drop)
+        {
+            if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
             {
-                if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator))
-                {
-                    while (enumerator.MoveNext(out var slot))
-                    {
-                        _inventory.TryUnequip(uid, slot.ID);
-                    }
-                }
-
-                foreach (var held in _hands.EnumerateHeld(uid))
+                while (enumerator.MoveNext(out var slot))
                 {
-                    _hands.TryDrop(uid, held);
+                    _inventory.TryUnequip(uid, slot.ID);
                 }
             }
 
-            if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
-                _mindSystem.TransferTo(mindId, parent, mind: mind);
-
-            if (TryComp<PolymorphableComponent>(parent, out var polymorphableComponent))
-                polymorphableComponent.LastPolymorphEnd = _gameTiming.CurTime;
-
-            // if an item polymorph was picked up, put it back down after reverting
-            Transform(parent).AttachToGridOrMap();
-
-            _popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
-                ("parent", Identity.Entity(uid, EntityManager)),
-                ("child", Identity.Entity(parent, EntityManager))),
-                parent);
-            QueueDel(uid);
-
-            return parent;
-        }
-
-        /// <summary>
-        /// Creates a sidebar action for an entity to be able to polymorph at will
-        /// </summary>
-        /// <param name="id">The string of the id of the polymorph action</param>
-        /// <param name="target">The entity that will be gaining the action</param>
-        public void CreatePolymorphAction(string id, EntityUid target)
-        {
-            if (!_proto.TryIndex<PolymorphPrototype>(id, out var polyproto))
+            foreach (var held in _hands.EnumerateHeld(uid))
             {
-                _sawmill.Error("Invalid polymorph prototype");
-                return;
+                _hands.TryDrop(uid, held);
             }
+        }
 
-            if (!TryComp<PolymorphableComponent>(target, out var polycomp))
-                return;
-
-            polycomp.PolymorphActions ??= new Dictionary<string, EntityUid>();
-            if (polycomp.PolymorphActions.ContainsKey(id))
-                return;
+        if (_mindSystem.TryGetMind(uid, out var mindId, out var mind))
+            _mindSystem.TransferTo(mindId, parent, mind: mind);
 
-            var entproto = _proto.Index<EntityPrototype>(polyproto.Entity);
+        if (TryComp<PolymorphableComponent>(parent, out var polymorphableComponent))
+            polymorphableComponent.LastPolymorphEnd = _gameTiming.CurTime;
 
-            EntityUid? actionId = default!;
-            if (!_actions.AddAction(target, ref actionId, RevertPolymorphId, target))
-                return;
+        // if an item polymorph was picked up, put it back down after reverting
+        _transform.AttachToGridOrMap(parent, parentXform);
 
-            polycomp.PolymorphActions.Add(id, actionId.Value);
-            _metaData.SetEntityName(actionId.Value, Loc.GetString("polymorph-self-action-name", ("target", entproto.Name)));
-            _metaData.SetEntityDescription(actionId.Value, Loc.GetString("polymorph-self-action-description", ("target", entproto.Name)));
+        _popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
+                ("parent", Identity.Entity(uid, EntityManager)),
+                ("child", Identity.Entity(parent, EntityManager))),
+            parent);
+        QueueDel(uid);
 
-            if (!_actions.TryGetActionData(actionId, out var baseAction))
-                return;
+        return parent;
+    }
 
-            baseAction.Icon = new SpriteSpecifier.EntityPrototype(polyproto.Entity);
-            if (baseAction is InstantActionComponent action)
-                action.Event = new PolymorphActionEvent { Prototype = polyproto };
-        }
+    /// <summary>
+    /// Creates a sidebar action for an entity to be able to polymorph at will
+    /// </summary>
+    /// <param name="id">The string of the id of the polymorph action</param>
+    /// <param name="target">The entity that will be gaining the action</param>
+    public void CreatePolymorphAction(ProtoId<PolymorphPrototype> id, Entity<PolymorphableComponent> target)
+    {
+        target.Comp.PolymorphActions ??= new();
+        if (target.Comp.PolymorphActions.ContainsKey(id))
+            return;
 
-        [PublicAPI]
-        public void RemovePolymorphAction(string id, EntityUid target, PolymorphableComponent? component = null)
-        {
-            if (!Resolve(target, ref component, false))
-                return;
-            if (component.PolymorphActions == null)
-                return;
-            if (component.PolymorphActions.TryGetValue(id, out var val))
-                _actions.RemoveAction(target, val);
-        }
+        var polyProto = _proto.Index(id);
+        var entProto = _proto.Index(polyProto.Configuration.Entity);
 
-        public override void Update(float frameTime)
-        {
-            base.Update(frameTime);
+        EntityUid? actionId = default!;
+        if (!_actions.AddAction(target, ref actionId, RevertPolymorphId, target))
+            return;
 
-            var query = EntityQueryEnumerator<PolymorphedEntityComponent>();
-            while (query.MoveNext(out var uid, out var comp))
-            {
-                comp.Time += frameTime;
+        target.Comp.PolymorphActions.Add(id, actionId.Value);
 
-                if (!_proto.TryIndex(comp.Prototype, out PolymorphPrototype? proto))
-                {
-                    _sawmill.Error($"{nameof(PolymorphSystem)} encountered an improperly initialized polymorph component while updating. Entity {ToPrettyString(uid)}. Prototype: {comp.Prototype}");
-                    RemCompDeferred(uid, comp);
-                    continue;
-                }
+        var metaDataCache = MetaData(actionId.Value);
+        _metaData.SetEntityName(actionId.Value, Loc.GetString("polymorph-self-action-name", ("target", entProto.Name)), metaDataCache);
+        _metaData.SetEntityDescription(actionId.Value, Loc.GetString("polymorph-self-action-description", ("target", entProto.Name)), metaDataCache);
 
-                if (proto.Duration != null && comp.Time >= proto.Duration)
-                {
-                    Revert(uid, comp);
-                    continue;
-                }
+        if (!_actions.TryGetActionData(actionId, out var baseAction))
+            return;
 
-                if (!TryComp<MobStateComponent>(uid, out var mob))
-                    continue;
+        baseAction.Icon = new SpriteSpecifier.EntityPrototype(polyProto.Configuration.Entity);
+        if (baseAction is InstantActionComponent action)
+            action.Event = new PolymorphActionEvent(prototype: polyProto);
+    }
 
-                if (proto.RevertOnDeath && _mobState.IsDead(uid, mob) ||
-                    proto.RevertOnCrit && _mobState.IsIncapacitated(uid, mob))
-                {
-                    Revert(uid, comp);
-                }
-            }
+    public void RemovePolymorphAction(ProtoId<PolymorphPrototype> id, Entity<PolymorphableComponent> target)
+    {
+        if (target.Comp.PolymorphActions == null)
+            return;
 
-            UpdateCollide();
-        }
+        if (target.Comp.PolymorphActions.TryGetValue(id, out var val))
+            _actions.RemoveAction(target, val);
     }
 }
index e1eca01aa3dde1a00d3fc01a17e6a9c4f83a3654..f741c24571e54c2bbdaecb908da1b4cf6e128bc9 100644 (file)
@@ -24,7 +24,7 @@ public sealed class PolymorphCommand : ToolshedCommand
     {
         _system ??= GetSys<PolymorphSystem>();
 
-        return _system.PolymorphEntity(input, prototype.Value);
+        return _system.PolymorphEntity(input, prototype.Value.Configuration);
     }
 
     [CommandImplementation]
index 1f3117fe67923c8317e273633ff3d14bc9c6a4c0..54ebf1b5771ce6bbf112d988cc70f86a636ad602 100644 (file)
@@ -2,9 +2,7 @@
 using Content.Server.Administration;
 using Content.Server.Polymorph.Systems;
 using Content.Shared.Administration;
-using Content.Shared.Polymorph;
 using Robust.Shared.Toolshed;
-using Robust.Shared.Toolshed.TypeParsers;
 
 namespace Content.Server.Polymorph.Toolshed;
 
similarity index 81%
rename from Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs
rename to Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyOthersArtifactComponent.cs
index 8edeb77a67b79f5bc055b21da47bec5a7e5c3f1e..2611d78b088ad618f218bd6fb9fb223b6bdce07b 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
 using Robust.Shared.Audio;
 using Content.Shared.Polymorph;
 using Robust.Shared.Prototypes;
@@ -8,7 +9,8 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
 /// Artifact polymorphs surrounding entities when triggered.
 /// </summary>
 [RegisterComponent]
-public sealed partial class PolyArtifactComponent : Component
+[Access(typeof(PolyOthersArtifactSystem))]
+public sealed partial class PolyOthersArtifactComponent : Component
 {
     /// <summary>
     /// The polymorph effect to trigger.
similarity index 68%
rename from Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs
rename to Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyOthersArtifactSystem.cs
index 662abfee62889b7e15fa407374821ab97dd5c7aa..3831bea06cf834fba90a06d978b1c4d126565561 100644 (file)
@@ -7,7 +7,7 @@ using Robust.Shared.Audio.Systems;
 
 namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
 
-public sealed class PolyArtifactSystem : EntitySystem
+public sealed class PolyOthersArtifactSystem : EntitySystem
 {
     [Dependency] private readonly EntityLookupSystem _lookup = default!;
     [Dependency] private readonly MobStateSystem _mob = default!;
@@ -19,25 +19,25 @@ public sealed class PolyArtifactSystem : EntitySystem
     /// </summary>
     public override void Initialize()
     {
-        SubscribeLocalEvent<PolyArtifactComponent, ArtifactActivatedEvent>(OnActivate);
+        SubscribeLocalEvent<PolyOthersArtifactComponent, ArtifactActivatedEvent>(OnActivate);
     }
 
     /// <summary>
     /// Provided target is alive and is not a zombie, polymorphs the target.
     /// </summary>
-    private void OnActivate(EntityUid uid, PolyArtifactComponent component, ArtifactActivatedEvent args)
+    private void OnActivate(Entity<PolyOthersArtifactComponent> ent, ref ArtifactActivatedEvent args)
     {
-        var xform = Transform(uid);
+        var xform = Transform(ent);
         var humanoids = new HashSet<Entity<HumanoidAppearanceComponent>>();
-        _lookup.GetEntitiesInRange(xform.Coordinates, component.Range, humanoids);
+        _lookup.GetEntitiesInRange(xform.Coordinates, ent.Comp.Range, humanoids);
 
         foreach (var comp in humanoids)
         {
             var target = comp.Owner;
             if (_mob.IsAlive(target))
             {
-                _poly.PolymorphEntity(target, component.PolymorphPrototypeName);
-                _audio.PlayPvs(component.PolySound, uid);
+                _poly.PolymorphEntity(target, ent.Comp.PolymorphPrototypeName);
+                _audio.PlayPvs(ent.Comp.PolySound, ent);
             }
         }
     }
index bae2c3e4ddac2a299a96cb5c2c307b9085270737..0f230868f03fb38f1662f4f8248626d83bac91f0 100644 (file)
@@ -9,6 +9,11 @@ public sealed partial class PolymorphActionEvent : InstantActionEvent
     /// the specific polymorph.
     /// </summary>
     public PolymorphPrototype Prototype = default!;
+
+    public PolymorphActionEvent(PolymorphPrototype prototype) : this()
+    {
+        Prototype = prototype;
+    }
 }
 
 public sealed partial class RevertPolymorphActionEvent : InstantActionEvent
index f093489b040abf7266eb5553fb24818155ff026d..6d010711d2e7d5e21cf7605b5a56890293bcff28 100644 (file)
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
 
-namespace Content.Shared.Polymorph
+namespace Content.Shared.Polymorph;
+
+/// <summary>
+/// Polymorphs generally describe any type of transformation that can be applied to an entity.
+/// </summary>
+[Prototype]
+[DataDefinition]
+public sealed partial class PolymorphPrototype : IPrototype, IInheritingPrototype
+{
+    [ViewVariables]
+    [IdDataField]
+    public string ID { get; private set; } = default!;
+
+    [ParentDataField(typeof(AbstractPrototypeIdArraySerializer<PolymorphPrototype>))]
+    public string[]? Parents { get; private set; }
+
+    [NeverPushInheritance]
+    [AbstractDataField]
+    public bool Abstract { get; private set; }
+
+    [DataField(required: true, serverOnly: true)]
+    public PolymorphConfiguration Configuration = new();
+
+}
+
+/// <summary>
+/// Defines information about the polymorph
+/// </summary>
+[DataDefinition]
+public sealed partial record PolymorphConfiguration
 {
     /// <summary>
-    /// Polymorphs generally describe any type of transformation that can be applied to an entity.
+    /// What entity the polymorph will turn the target into
+    /// must be in here because it makes no sense if it isn't
+    /// </summary>
+    [DataField(required: true, serverOnly: true)]
+    public EntProtoId Entity;
+
+    /// <summary>
+    /// The delay between the polymorph's uses in seconds
+    /// Slightly weird as of right now.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public int Delay = 60;
+
+    /// <summary>
+    /// The duration of the transformation in seconds
+    /// can be null if there is not one
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public int? Duration;
+
+    /// <summary>
+    /// whether or not the target can transform as will
+    /// set to true for things like polymorph spells and curses
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool Forced;
+
+    /// <summary>
+    /// Whether or not the entity transfers its damage between forms.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool TransferDamage = true;
+
+    /// <summary>
+    /// Whether or not the entity transfers its name between forms.
     /// </summary>
-    [Prototype("polymorph")]
-    [DataDefinition]
-    public sealed partial class PolymorphPrototype : IPrototype, IInheritingPrototype
-    {
-        [ViewVariables]
-        [IdDataField]
-        public string ID { get; private set; } = default!;
-
-        [DataField("name")]
-        public string Name { get; private set; } = string.Empty;
-
-        [ParentDataField(typeof(AbstractPrototypeIdArraySerializer<PolymorphPrototype>))]
-        public string[]? Parents { get; private set; }
-
-        [NeverPushInheritance]
-        [AbstractDataFieldAttribute]
-        public bool Abstract { get; private set; }
-
-        /// <summary>
-        /// What entity the polymorph will turn the target into
-        /// must be in here because it makes no sense if it isn't
-        /// </summary>
-        [DataField("entity", required: true, serverOnly: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-        public string Entity = string.Empty;
-
-        /// <summary>
-        /// The delay between the polymorph's uses in seconds
-        /// Slightly weird as of right now.
-        /// </summary>
-        [DataField("delay", serverOnly: true)]
-        public int Delay = 60;
-
-        /// <summary>
-        /// The duration of the transformation in seconds
-        /// can be null if there is not one
-        /// </summary>
-        [DataField("duration", serverOnly: true)]
-        public int? Duration = null;
-
-        /// <summary>
-        /// whether or not the target can transform as will
-        /// set to true for things like polymorph spells and curses
-        /// </summary>
-        [DataField("forced", serverOnly: true)]
-        public bool Forced = false;
-
-        /// <summary>
-        /// Whether or not the entity transfers its damage between forms.
-        /// </summary>
-        [DataField("transferDamage", serverOnly: true)]
-        public bool TransferDamage = true;
-
-        /// <summary>
-        /// Whether or not the entity transfers its name between forms.
-        /// </summary>
-        [DataField("transferName", serverOnly: true)]
-        public bool TransferName = false;
-
-        /// <summary>
-        /// Whether or not the entity transfers its hair, skin color, hair color, etc.
-        /// </summary>
-        [DataField("transferHumanoidAppearance", serverOnly: true)]
-        public bool TransferHumanoidAppearance = false;
-
-        /// <summary>
-        /// Whether or not the entity transfers its inventory and equipment between forms.
-        /// </summary>
-        [DataField("inventory", serverOnly: true)]
-        public PolymorphInventoryChange Inventory = PolymorphInventoryChange.None;
-
-        /// <summary>
-        /// Whether or not the polymorph reverts when the entity goes into crit.
-        /// </summary>
-        [DataField("revertOnCrit", serverOnly: true)]
-        public bool RevertOnCrit = true;
-
-        /// <summary>
-        /// Whether or not the polymorph reverts when the entity dies.
-        /// </summary>
-        [DataField("revertOnDeath", serverOnly: true)]
-        public bool RevertOnDeath = true;
-
-        /// <summary>
-        /// Whether or not the polymorph reverts when the entity is eaten or fully sliced.
-        /// </summary>
-        [DataField("revertOnEat", serverOnly: true)]
-        public bool RevertOnEat = false;
-
-        [DataField("allowRepeatedMorphs", serverOnly: true)]
-        public bool AllowRepeatedMorphs = false;
-
-        /// <summary>
-        /// The amount of time that should pass after this polymorph has ended, before a new one
-        /// can occur.
-        /// </summary>
-        [DataField("cooldown", serverOnly: true)]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public TimeSpan Cooldown = TimeSpan.Zero;
-    }
-
-    public enum PolymorphInventoryChange : byte
-    {
-        None,
-        Drop,
-        Transfer,
-    }
+    [DataField(serverOnly: true)]
+    public bool TransferName;
+
+    /// <summary>
+    /// Whether or not the entity transfers its hair, skin color, hair color, etc.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool TransferHumanoidAppearance;
+
+    /// <summary>
+    /// Whether or not the entity transfers its inventory and equipment between forms.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public PolymorphInventoryChange Inventory = PolymorphInventoryChange.None;
+
+    /// <summary>
+    /// Whether or not the polymorph reverts when the entity goes into crit.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool RevertOnCrit = true;
+
+    /// <summary>
+    /// Whether or not the polymorph reverts when the entity dies.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool RevertOnDeath = true;
+
+    /// <summary>
+    /// Whether or not the polymorph reverts when the entity is eaten or fully sliced.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool RevertOnEat;
+
+    /// <summary>
+    /// Whether or not an already polymorphed entity is able to be polymorphed again
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public bool AllowRepeatedMorphs;
+
+    /// <summary>
+    /// The amount of time that should pass after this polymorph has ended, before a new one
+    /// can occur.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    [ViewVariables(VVAccess.ReadWrite)]
+    public TimeSpan Cooldown = TimeSpan.Zero;
+}
+
+public enum PolymorphInventoryChange : byte
+{
+    None,
+    Drop,
+    Transfer,
 }
index 0ae54262441d2d6d4735b0f956d0fa6415d2b592..cb274ec7d4343e5fff3076802d009b6fbcfe4217 100644 (file)
@@ -1,43 +1,49 @@
 - type: polymorph
   id: AdminLizardSmite
-  entity: MobReptilian
-  forced: true
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: Transfer
-  allowRepeatedMorphs: true
+  configuration:
+    entity: MobReptilian
+    forced: true
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: Transfer
+    allowRepeatedMorphs: true
 
 - type: polymorph
   id: AdminMonkeySmite
-  entity: MobMonkey
-  forced: true
-  inventory: Drop
-  allowRepeatedMorphs: true
+  configuration:
+    entity: MobMonkey
+    forced: true
+    inventory: Drop
+    allowRepeatedMorphs: true
 
 - type: polymorph
   id: AdminBreadSmite
-  entity: FoodBreadPlain
-  forced: true
-  inventory: Drop
-  allowRepeatedMorphs: true
+  configuration:
+    entity: FoodBreadPlain
+    forced: true
+    inventory: Drop
+    allowRepeatedMorphs: true
 
 - type: polymorph
   id: AdminInstrumentSmite
-  entity: SuperSynthesizerInstrument
-  forced: true
-  inventory: Drop
-  allowRepeatedMorphs: true
+  configuration:
+    entity: SuperSynthesizerInstrument
+    forced: true
+    inventory: Drop
+    allowRepeatedMorphs: true
 
 - type: polymorph
   id: AdminMouseSmite
-  entity: MobMouse
-  forced: true
-  inventory: Drop
-  allowRepeatedMorphs: true
+  configuration:
+    entity: MobMouse
+    forced: true
+    inventory: Drop
+    allowRepeatedMorphs: true
 
 - type: polymorph
   id: AdminDisposalsSmite
-  entity: DisposalUnit
-  forced: true
-  inventory: Drop
-  allowRepeatedMorphs: true
+  configuration:
+    entity: DisposalUnit
+    forced: true
+    inventory: Drop
+    allowRepeatedMorphs: true
index 46590248aec09cffde65f6201b4578462f245a43..b4249f8a3eaf108308b2c2661f3b8348bf468109 100644 (file)
 - type: polymorph
   id: Mouse
-  entity: MobMouse
-  forced: true
-  duration: 30
+  configuration:
+    entity: MobMouse
+    forced: true
+    duration: 30
 
 - type: polymorph
   id: Chicken
-  entity: MobChicken
-  forced: true
-  inventory: Drop
+  configuration:
+    entity: MobChicken
+    forced: true
+    inventory: Drop
 
 - type: polymorph
   id: Monkey
-  entity: MobMonkey
-  forced: true
-  inventory: Drop
-  revertOnCrit: true
-  revertOnDeath: true
+  configuration:
+    entity: MobMonkey
+    forced: true
+    inventory: Drop
+    revertOnCrit: true
+    revertOnDeath: true
 
 - type: polymorph
   id: WizardForcedCarp
-  entity: MobCarpMagic
-  forced: true
-  inventory: None
-  transferName: true
-  transferDamage: true
-  revertOnCrit: false
-  revertOnDeath: true
+  configuration:
+    entity: MobCarpMagic
+    forced: true
+    inventory: None
+    transferName: true
+    transferDamage: true
+    revertOnCrit: false
+    revertOnDeath: true
 
 - type: polymorph
   id: WizardForcedSkeleton
-  entity: MobSkeletonPerson
-  forced: true
-  inventory: Drop
-  transferName: true
-  transferDamage: true
-  revertOnCrit: false
-  revertOnDeath: false
+  configuration:
+    entity: MobSkeletonPerson
+    forced: true
+    inventory: Drop
+    transferName: true
+    transferDamage: true
+    revertOnCrit: false
+    revertOnDeath: false
 
 - type: polymorph
   id: WizardForcedMonkey
-  entity: MobMonkey
-  forced: true
-  inventory: None
-  transferName: true
-  transferDamage: true
-  revertOnCrit: false
-  revertOnDeath: true
+  configuration:
+    entity: MobMonkey
+    forced: true
+    inventory: None
+    transferName: true
+    transferDamage: true
+    revertOnCrit: false
+    revertOnDeath: true
 
 - type: polymorph
   id: WizardWallDoor
-  entity: WoodDoor
-  forced: true
-  inventory: None
-  transferName: false
-  transferDamage: false
-  revertOnCrit: false
-  revertOnDeath: false
+  configuration:
+    entity: WoodDoor
+    forced: true
+    inventory: None
+    transferName: false
+    transferDamage: false
+    revertOnCrit: false
+    revertOnDeath: false
 
 - type: polymorph
   id: WizardForcedCluwne
-  entity: MobCluwne
-  forced: true
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: Transfer
-  revertOnDeath: true
+  configuration:
+    entity: MobCluwne
+    forced: true
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: Transfer
+    revertOnDeath: true
 
 # this is a test for transferring some visual appearance stuff
 - type: polymorph
   id: TestHumanMorph
-  entity: MobHuman
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: Transfer
+  configuration:
+    entity: MobHuman
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: Transfer
 
 - type: polymorph
   id: AMIVMorph
-  entity: MobMonkey
-  forced: true
-  inventory: Transfer
-  transferName: true
-  revertOnCrit: false
-  revertOnDeath: false
+  configuration:
+    entity: MobMonkey
+    forced: true
+    inventory: Transfer
+    transferName: true
+    revertOnCrit: false
+    revertOnDeath: false
 
 - type: polymorph
   id: BreadMorph
-  entity: FoodBreadPlain
-  forced: true
-  inventory: None
-  transferName: false
-  transferDamage: true
-  revertOnCrit: false
-  revertOnDeath: true
-  revertOnEat: true
+  configuration:
+    entity: FoodBreadPlain
+    forced: true
+    inventory: None
+    transferName: false
+    transferDamage: true
+    revertOnCrit: false
+    revertOnDeath: true
+    revertOnEat: true
 
 - type: polymorph
   id: TreeMorph
-  entity: FloraTree01
-  forced: true
-  transferName: true
-  revertOnDeath: true
-  inventory: Drop
-  cooldown: 160
+  configuration:
+    entity: FloraTree01
+    forced: true
+    transferName: true
+    revertOnDeath: true
+    inventory: Drop
+    cooldown: 160
 
 # this is the monkey polymorph for artifact.
 - type: polymorph
   id: ArtifactMonkey
-  entity: MobMonkey
-  forced: true
-  transferName: true
-  allowRepeatedMorphs: true
-  inventory: Transfer
-  revertOnCrit: true
-  revertOnDeath: true
-  duration: 20
+  configuration:
+    entity: MobMonkey
+    forced: true
+    transferName: true
+    allowRepeatedMorphs: true
+    inventory: Transfer
+    revertOnCrit: true
+    revertOnDeath: true
+    duration: 20
 
 - type: polymorph
   id: ArtifactCluwne
-  entity: MobCluwne
-  forced: true
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: None
-  revertOnDeath: true
-  revertOnCrit: true
-  duration: 30
+  configuration:
+    entity: MobCluwne
+    forced: true
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: None
+    revertOnDeath: true
+    revertOnCrit: true
+    duration: 30
 
 - type: polymorph
   id: ArtifactLizard
-  entity: MobLizard
-  forced: true
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: None
-  revertOnDeath: true
-  revertOnCrit: true
-  duration: 20
+  configuration:
+    entity: MobLizard
+    forced: true
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: None
+    revertOnDeath: true
+    revertOnCrit: true
+    duration: 20
 
 - type: polymorph
   id: ArtifactLuminous
-  entity: MobLuminousPerson
-  forced: true
-  transferName: true
-  transferHumanoidAppearance: true
-  inventory: None
-  revertOnDeath: true
-  revertOnCrit: true
-  duration: 20
+  configuration:
+    entity: MobLuminousPerson
+    forced: true
+    transferName: true
+    transferHumanoidAppearance: true
+    inventory: None
+    revertOnDeath: true
+    revertOnCrit: true
+    duration: 20
index c0c3bf77f8bfc3c0910ffaa66342484188a0486e..4810f0c5467f156bbd631b49c8d94a207e78dfb9 100644 (file)
   targetDepth: 2
   effectHint: artifact-effect-hint-polymorph
   components:
-  - type: PolyArtifact
+  - type: PolyOthersArtifact
 
 - type: artifactEffect
   id: EffectPolyLizard
   targetDepth: 2
   effectHint: artifact-effect-hint-polymorph
   components:
-  - type: PolyArtifact
+  - type: PolyOthersArtifact
     polymorphPrototypeName: ArtifactLizard
 
 - type: artifactEffect
   targetDepth: 3
   effectHint: artifact-effect-hint-polymorph
   components:
-  - type: PolyArtifact
+  - type: PolyOthersArtifact
     polymorphPrototypeName: ArtifactLuminous
 
 - type: artifactEffect