diff --git a/Content.Shared/Magic/Components/AnimateComponent.cs b/Content.Shared/Magic/Components/AnimateComponent.cs new file mode 100644 index 0000000000..5c2af8f7ef --- /dev/null +++ b/Content.Shared/Magic/Components/AnimateComponent.cs @@ -0,0 +1,8 @@ + +using Robust.Shared.GameStates; + +namespace Content.Shared.Magic.Components; + +// Added to objects when they are made animate +[RegisterComponent, NetworkedComponent] +public sealed partial class AnimateComponent : Component; diff --git a/Content.Shared/Magic/Events/AnimateSpellEvent.cs b/Content.Shared/Magic/Events/AnimateSpellEvent.cs deleted file mode 100644 index 60331b2804..0000000000 --- a/Content.Shared/Magic/Events/AnimateSpellEvent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Magic.Events; - -public sealed partial class AnimateSpellEvent : EntityTargetActionEvent, ISpeakSpell -{ - [DataField] - public string? Speech { get; private set; } - - [DataField] - public ComponentRegistry AddComponents = new(); - - [DataField] - public HashSet RemoveComponents = new(); -} diff --git a/Content.Shared/Magic/Events/ChangeComponentSpellEvent.cs b/Content.Shared/Magic/Events/ChangeComponentSpellEvent.cs index 61e75c8b1a..b2b1dc96e8 100644 --- a/Content.Shared/Magic/Events/ChangeComponentSpellEvent.cs +++ b/Content.Shared/Magic/Events/ChangeComponentSpellEvent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Actions; +using Content.Shared.Actions; using Robust.Shared.Prototypes; namespace Content.Shared.Magic.Events; @@ -11,14 +11,17 @@ public sealed partial class ChangeComponentsSpellEvent : EntityTargetActionEvent // TODO allow it to set component data-fields? // for now a Hackish way to do that is to remove & add, but that doesn't allow you to selectively set specific data fields. - [DataField("toAdd")] + [DataField] [AlwaysPushInheritance] public ComponentRegistry ToAdd = new(); - [DataField("toRemove")] + [DataField] [AlwaysPushInheritance] public HashSet ToRemove = new(); - [DataField("speech")] + [DataField] public string? Speech { get; private set; } + + [DataField] + public bool DoSpeech { get; private set; } } diff --git a/Content.Shared/Magic/SharedMagicSystem.cs b/Content.Shared/Magic/SharedMagicSystem.cs index 49f0825ddf..b502ff2fbb 100644 --- a/Content.Shared/Magic/SharedMagicSystem.cs +++ b/Content.Shared/Magic/SharedMagicSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using System.Numerics; using Content.Shared.Actions; using Content.Shared.Body.Components; @@ -27,8 +26,6 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Network; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -84,7 +81,6 @@ public abstract class SharedMagicSystem : EntitySystem SubscribeLocalEvent(OnRandomGlobalSpawnSpell); SubscribeLocalEvent(OnMindSwapSpell); SubscribeLocalEvent(OnVoidApplause); - SubscribeLocalEvent(OnAnimateSpell); } private void OnBeforeCastSpell(Entity ent, ref BeforeCastSpellEvent args) @@ -301,7 +297,8 @@ public abstract class SharedMagicSystem : EntitySystem return; ev.Handled = true; - Speak(ev); + if (ev.DoSpeech) + Speak(ev); RemoveComponents(ev.Target, ev.ToRemove); AddComponents(ev.Target, ev.ToAdd); @@ -532,33 +529,6 @@ public abstract class SharedMagicSystem : EntitySystem _stun.TryParalyze(ev.Performer, ev.PerformerStunDuration, true); } - #endregion - #region Animation Spells - - private void OnAnimateSpell(AnimateSpellEvent ev) - { - if (ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || !TryComp(ev.Target, out var fixtures) || - !TryComp(ev.Target, out var physics)) - return; - - ev.Handled = true; - //Speak(ev); - - RemoveComponents(ev.Target, ev.RemoveComponents); - AddComponents(ev.Target, ev.AddComponents); - - var xform = Transform(ev.Target); - var fixture = fixtures.Fixtures.First(); - - _transform.Unanchor(ev.Target); - _physics.SetCanCollide(ev.Target, true, true, false, fixtures, physics); - _physics.SetCollisionMask(ev.Target, fixture.Key, fixture.Value, (int)CollisionGroup.FlyingMobMask, fixtures, physics); - _physics.SetCollisionLayer(ev.Target, fixture.Key, fixture.Value, (int)CollisionGroup.FlyingMobLayer, fixtures, physics); - _physics.SetBodyType(ev.Target, BodyType.KinematicController, fixtures, physics, xform); - _physics.SetBodyStatus(ev.Target, physics, BodyStatus.InAir, true); - _physics.SetFixedRotation(ev.Target, false, true, fixtures, physics); - } - #endregion // End Spells #endregion diff --git a/Content.Shared/Magic/Systems/AnimateSpellSystem.cs b/Content.Shared/Magic/Systems/AnimateSpellSystem.cs new file mode 100644 index 0000000000..458336dea1 --- /dev/null +++ b/Content.Shared/Magic/Systems/AnimateSpellSystem.cs @@ -0,0 +1,48 @@ +using Content.Shared.Magic.Components; +using Content.Shared.Physics; +using Robust.Shared.Containers; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; +using System.Linq; + +namespace Content.Shared.Magic.Systems; + +public sealed class AnimateSpellSystem : EntitySystem +{ + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnAnimate); + } + + private void OnAnimate(Entity ent, ref MapInitEvent args) + { + // Physics bullshittery necessary for object to behave properly + + if (!TryComp(ent, out var fixtures) || !TryComp(ent, out var physics)) + return; + + var xform = Transform(ent); + var fixture = fixtures.Fixtures.First(); + + _transform.Unanchor(ent); // If left anchored they are effectively stuck/immobile and not a threat + _physics.SetCanCollide(ent, true, true, false, fixtures, physics); + _physics.SetCollisionMask(ent, fixture.Key, fixture.Value, (int)CollisionGroup.FlyingMobMask, fixtures, physics); + _physics.SetCollisionLayer(ent, fixture.Key, fixture.Value, (int)CollisionGroup.FlyingMobLayer, fixtures, physics); + _physics.SetBodyType(ent, BodyType.KinematicController, fixtures, physics, xform); + _physics.SetBodyStatus(ent, physics, BodyStatus.InAir, true); + _physics.SetFixedRotation(ent, false, true, fixtures, physics); + _physics.SetHard(ent, fixture.Value, true, fixtures); + _container.AttachParentToContainerOrGrid((ent, xform)); // Items animated inside inventory now exit, they can't be picked up and so can't escape otherwise + + var ev = new AnimateSpellEvent(); + RaiseLocalEvent(ref ev); + } +} + +[ByRefEvent] +public readonly record struct AnimateSpellEvent; diff --git a/Resources/Prototypes/Magic/animate_spell.yml b/Resources/Prototypes/Magic/animate_spell.yml index b0b322919c..a9609c4f8a 100644 --- a/Resources/Prototypes/Magic/animate_spell.yml +++ b/Resources/Prototypes/Magic/animate_spell.yml @@ -9,13 +9,16 @@ itemIconStyle: BigAction whitelist: components: - - Animateable # Currently on: SeatBase, TableBase, ClosetBase, BaseMachine, ConstructibleMachine, BaseComputer, BaseItem, CrateGeneric, StorageTank, GasCanister + - Animateable # Currently on: SeatBase, TableBase, ClosetBase, BaseMachine, ConstructibleMachine, BaseComputer, BaseItem, CrateGeneric, StorageTank, GasCanister, BaseTarget blacklist: components: - MindContainer - NukeDisk - GravityGenerator - AnomalyGenerator + - TegGenerator + - TegCirculator + - Artifact canTargetSelf: false interactOnMiss: false sound: !type:SoundPathSpecifier @@ -23,8 +26,9 @@ icon: sprite: Objects/Magic/magicactions.rsi state: spell_default - event: !type:AnimateSpellEvent - addComponents: + event: !type:ChangeComponentsSpellEvent + toAdd: + - type: Animate - type: MindContainer - type: InputMover - type: MobMover @@ -65,6 +69,9 @@ collection: MetalBreak - type: Hands - type: CanEscapeInventory - removeComponents: + toRemove: - RequireProjectileTarget + - BlockMovement + - Item speech: action-speech-spell-animate + doSpeech: false diff --git a/Resources/Prototypes/Magic/event_spells.yml b/Resources/Prototypes/Magic/event_spells.yml index a72dc8b217..83bd853a21 100644 --- a/Resources/Prototypes/Magic/event_spells.yml +++ b/Resources/Prototypes/Magic/event_spells.yml @@ -181,8 +181,6 @@ orGroup: Magics - id: BlinkBook orGroup: Magics - - id: SmiteBook - orGroup: Magics - id: KnockSpellbook orGroup: Magics - id: FireballSpellbook @@ -203,4 +201,8 @@ orGroup: Magics - id: WeaponStaffPolymorphDoor orGroup: Magics + - id: AnimationStaff + orGroup: Magics + - id: RGBStaff + orGroup: Magics speech: action-speech-spell-summon-magic diff --git a/Resources/Prototypes/ai_factions.yml b/Resources/Prototypes/ai_factions.yml index 80e12bc166..98cbec24aa 100644 --- a/Resources/Prototypes/ai_factions.yml +++ b/Resources/Prototypes/ai_factions.yml @@ -27,6 +27,7 @@ hostile: - PetsNT - AllHostile + - Wizard - type: npcFaction id: Passive @@ -39,6 +40,7 @@ - Zombie - Xeno - AllHostile + - Wizard - type: npcFaction id: SimpleHostile @@ -123,7 +125,11 @@ hostile: - NanoTrasen - Dragon + - Mouse + - Passive + - PetsNT - SimpleHostile + - SimpleNeutral - Syndicate - Xeno - Zombie