]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Wizard Staff of Animation (#34649)
authorActiveMammmoth <140334666+ActiveMammmoth@users.noreply.github.com>
Thu, 13 Feb 2025 04:46:02 +0000 (23:46 -0500)
committerGitHub <noreply@github.com>
Thu, 13 Feb 2025 04:46:02 +0000 (23:46 -0500)
26 files changed:
Content.Client/Actions/ActionsSystem.cs
Content.Client/Magic/MagicSystem.cs
Content.Client/Outline/TargetOutlineSystem.cs
Content.Client/UserInterface/Systems/Actions/ActionUIController.cs
Content.Shared/Actions/EntityTargetActionComponent.cs
Content.Shared/Actions/SharedActionsSystem.cs
Content.Shared/Damage/Components/DamageableComponent.cs
Content.Shared/Damage/Systems/DamageableSystem.cs
Content.Shared/Magic/Components/AnimateableComponent.cs [new file with mode: 0644]
Content.Shared/Magic/Events/AnimateSpellEvent.cs [new file with mode: 0644]
Content.Shared/Magic/SharedMagicSystem.cs
Resources/Locale/en-US/store/spellbook-catalog.ftl
Resources/Prototypes/Catalog/spellbook_catalog.yml
Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/staves.yml
Resources/Prototypes/Entities/Objects/base_item.yml
Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml
Resources/Prototypes/Entities/Structures/Furniture/chairs.yml
Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml
Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml
Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml
Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml
Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml
Resources/Prototypes/Entities/Structures/Storage/Tanks/base_structuretanks.yml
Resources/Prototypes/Magic/animate_spell.yml [new file with mode: 0644]
Resources/Prototypes/Magic/staves.yml
Resources/Prototypes/ai_factions.yml

index d836c2ed7a887e2d2e0199c3c86fdfb2ddaf9d73..5f0a8e1f2f408544863be0cb554182d3190e2f38 100644 (file)
@@ -88,6 +88,7 @@ namespace Content.Client.Actions
                 return;
 
             component.Whitelist = state.Whitelist;
+            component.Blacklist = state.Blacklist;
             component.CanTargetSelf = state.CanTargetSelf;
             BaseHandleState<EntityTargetActionComponent>(uid, component, state);
         }
index 086a0f7b42e7e2110a615ef72257ca750b8a2214..06af827b592b072a6f380473e85891c305382870 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Magic;
+using Content.Shared.Magic;
 using Content.Shared.Magic.Events;
 
 namespace Content.Client.Magic;
index c69987fe77c9fa02193f05992eebda6546682832..591bfc171ef2d6fcff307c001e83017afb7f34fc 100644 (file)
@@ -32,6 +32,11 @@ public sealed class TargetOutlineSystem : EntitySystem
     /// </summary>
     public EntityWhitelist? Whitelist = null;
 
+    /// <summary>
+    ///     Blacklist that the target must satisfy.
+    /// </summary>
+    public EntityWhitelist? Blacklist = null;
+
     /// <summary>
     ///     Predicate the target must satisfy.
     /// </summary>
@@ -93,15 +98,16 @@ public sealed class TargetOutlineSystem : EntitySystem
         RemoveHighlights();
     }
 
-    public void Enable(float range, bool checkObstructions, Func<EntityUid, bool>? predicate, EntityWhitelist? whitelist, CancellableEntityEventArgs? validationEvent)
+    public void Enable(float range, bool checkObstructions, Func<EntityUid, bool>? predicate, EntityWhitelist? whitelist, EntityWhitelist? blacklist, CancellableEntityEventArgs? validationEvent)
     {
         Range = range;
         CheckObstruction = checkObstructions;
         Predicate = predicate;
         Whitelist = whitelist;
+        Blacklist = blacklist;
         ValidationEvent = validationEvent;
 
-        _enabled = Predicate != null || Whitelist != null || ValidationEvent != null;
+        _enabled = Predicate != null || Whitelist != null || Blacklist != null || ValidationEvent != null;
     }
 
     public override void Update(float frameTime)
index a6c1cfc94f81e4571bc9724cb40661f087d00fd2..c2ba35f3c58bb4987acb6299ef661429b778d076 100644 (file)
@@ -952,7 +952,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
         var range = entityAction.CheckCanAccess ? action.Range : -1;
 
         _interactionOutline?.SetEnabled(false);
-        _targetOutline?.Enable(range, entityAction.CheckCanAccess, predicate, entityAction.Whitelist, null);
+        _targetOutline?.Enable(range, entityAction.CheckCanAccess, predicate, entityAction.Whitelist, entityAction.Blacklist, null);
     }
 
     /// <summary>
index 7217794b23b90168409d00f484ebc752e45a2b03..aa8c0f4a9943071a7e8c74b73d5b4a12acc472ba 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Whitelist;
+using Content.Shared.Whitelist;
 using Robust.Shared.GameStates;
 using Robust.Shared.Serialization;
 
@@ -25,6 +25,12 @@ public sealed partial class EntityTargetActionComponent : BaseTargetActionCompon
     /// <remarks>No whitelist check when null.</remarks>
     [DataField("whitelist")] public EntityWhitelist? Whitelist;
 
+    /// <summary>
+    /// Determines which entities are NOT valid targets for this action.
+    /// </summary>
+    /// <remarks>No blacklist check when null.</remarks>
+    [DataField] public EntityWhitelist? Blacklist;
+
     /// <summary>
     /// Whether this action considers the user as a valid target entity when using this action.
     /// </summary>
@@ -35,11 +41,13 @@ public sealed partial class EntityTargetActionComponent : BaseTargetActionCompon
 public sealed class EntityTargetActionComponentState : BaseActionComponentState
 {
     public EntityWhitelist? Whitelist;
+    public EntityWhitelist? Blacklist;
     public bool CanTargetSelf;
 
     public EntityTargetActionComponentState(EntityTargetActionComponent component, IEntityManager entManager) : base(component, entManager)
     {
         Whitelist = component.Whitelist;
+        Blacklist = component.Blacklist;
         CanTargetSelf = component.CanTargetSelf;
     }
 }
index 8079885a5ac5a9cd4bae0aa95b193d979f568eda..30f1af846568ed22d01975e35a476e2e37a3c4e6 100644 (file)
@@ -538,6 +538,7 @@ public abstract class SharedActionsSystem : EntitySystem
         if (!ValidateEntityTargetBase(user,
                 target,
                 comp.Whitelist,
+                comp.Blacklist,
                 comp.CheckCanInteract,
                 comp.CanTargetSelf,
                 comp.CheckCanAccess,
@@ -552,6 +553,7 @@ public abstract class SharedActionsSystem : EntitySystem
     private bool ValidateEntityTargetBase(EntityUid user,
         EntityUid? targetEntity,
         EntityWhitelist? whitelist,
+        EntityWhitelist? blacklist,
         bool checkCanInteract,
         bool canTargetSelf,
         bool checkCanAccess,
@@ -563,6 +565,9 @@ public abstract class SharedActionsSystem : EntitySystem
         if (_whitelistSystem.IsWhitelistFail(whitelist, target))
             return false;
 
+        if (_whitelistSystem.IsBlacklistPass(blacklist, target))
+            return false;
+
         if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
             return false;
 
@@ -637,6 +642,7 @@ public abstract class SharedActionsSystem : EntitySystem
         var entityValidated = ValidateEntityTargetBase(user,
             entity,
             comp.Whitelist,
+            null,
             comp.CheckCanInteract,
             comp.CanTargetSelf,
             comp.CheckCanAccess,
index a99840e1ae6d33e26faa455310fc26b97919ba4d..8ea3567b055c8ccd7da9677542de20c955074144 100644 (file)
@@ -84,15 +84,18 @@ namespace Content.Shared.Damage
     public sealed class DamageableComponentState : ComponentState
     {
         public readonly Dictionary<string, FixedPoint2> DamageDict;
+        public readonly string? DamageContainerId;
         public readonly string? ModifierSetId;
         public readonly FixedPoint2? HealthBarThreshold;
 
         public DamageableComponentState(
             Dictionary<string, FixedPoint2> damageDict,
+            string? damageContainerId,
             string? modifierSetId,
             FixedPoint2? healthBarThreshold)
         {
             DamageDict = damageDict;
+            DamageContainerId = damageContainerId;
             ModifierSetId = modifierSetId;
             HealthBarThreshold = healthBarThreshold;
         }
index 3c3e1b736df3120e891df128c645da3227f09972..814609444a18b3f20e5d1cbbe9130736aafec35b 100644 (file)
@@ -228,12 +228,12 @@ namespace Content.Shared.Damage
         {
             if (_netMan.IsServer)
             {
-                args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId, component.HealthBarThreshold);
+                args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageContainerID, component.DamageModifierSetId, component.HealthBarThreshold);
             }
             else
             {
                 // avoid mispredicting damage on newly spawned entities.
-                args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageModifierSetId, component.HealthBarThreshold);
+                args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageContainerID, component.DamageModifierSetId, component.HealthBarThreshold);
             }
         }
 
@@ -266,6 +266,7 @@ namespace Content.Shared.Damage
                 return;
             }
 
+            component.DamageContainerID = state.DamageContainerId;
             component.DamageModifierSetId = state.ModifierSetId;
             component.HealthBarThreshold = state.HealthBarThreshold;
 
diff --git a/Content.Shared/Magic/Components/AnimateableComponent.cs b/Content.Shared/Magic/Components/AnimateableComponent.cs
new file mode 100644 (file)
index 0000000..a0e44d4
--- /dev/null
@@ -0,0 +1,11 @@
+
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Magic.Components;
+
+// Used on whitelist for animate spell/wand
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AnimateableComponent : Component
+{
+
+}
diff --git a/Content.Shared/Magic/Events/AnimateSpellEvent.cs b/Content.Shared/Magic/Events/AnimateSpellEvent.cs
new file mode 100644 (file)
index 0000000..60331b2
--- /dev/null
@@ -0,0 +1,16 @@
+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<string> RemoveComponents = new();
+}
index 878c4bdca4f6b638644ca0b8e4cdc9db4c4230c7..0be5646f4b2535130dea0d6684c8ba8303b652d1 100644 (file)
@@ -1,3 +1,4 @@
+using System.Linq;
 using System.Numerics;
 using Content.Shared.Actions;
 using Content.Shared.Body.Components;
@@ -26,7 +27,10 @@ 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;
 using Robust.Shared.Serialization.Manager;
 using Robust.Shared.Spawners;
@@ -80,6 +84,7 @@ public abstract class SharedMagicSystem : EntitySystem
         SubscribeLocalEvent<RandomGlobalSpawnSpellEvent>(OnRandomGlobalSpawnSpell);
         SubscribeLocalEvent<MindSwapSpellEvent>(OnMindSwapSpell);
         SubscribeLocalEvent<VoidApplauseSpellEvent>(OnVoidApplause);
+        SubscribeLocalEvent<AnimateSpellEvent>(OnAnimateSpell);
     }
 
     private void OnBeforeCastSpell(Entity<MagicComponent> ent, ref BeforeCastSpellEvent args)
@@ -298,22 +303,8 @@ public abstract class SharedMagicSystem : EntitySystem
         ev.Handled = true;
         Speak(ev);
 
-        foreach (var toRemove in ev.ToRemove)
-        {
-            if (_compFact.TryGetRegistration(toRemove, out var registration))
-                RemComp(ev.Target, registration.Type);
-        }
-
-        foreach (var (name, data) in ev.ToAdd)
-        {
-            if (HasComp(ev.Target, data.Component.GetType()))
-                continue;
-
-            var component = (Component)_compFact.GetComponent(name);
-            var temp = (object)component;
-            _seriMan.CopyTo(data.Component, ref temp);
-            EntityManager.AddComponent(ev.Target, (Component)temp!);
-        }
+        RemoveComponents(ev.Target, ev.ToRemove);
+        AddComponents(ev.Target, ev.ToAdd);
     }
     // End Change Component Spells
     #endregion
@@ -370,6 +361,29 @@ public abstract class SharedMagicSystem : EntitySystem
             comp.Uid = performer;
         }
     }
+
+    private void AddComponents(EntityUid target, ComponentRegistry comps)
+    {
+        foreach (var (name, data) in comps)
+        {
+            if (HasComp(target, data.Component.GetType()))
+                continue;
+
+            var component = (Component)_compFact.GetComponent(name);
+            var temp = (object)component;
+            _seriMan.CopyTo(data.Component, ref temp);
+            EntityManager.AddComponent(target, (Component)temp!);
+        }
+    }
+
+    private void RemoveComponents(EntityUid target, HashSet<string> comps)
+    {
+        foreach (var toRemove in comps)
+        {
+            if (_compFact.TryGetRegistration(toRemove, out var registration))
+                RemComp(target, registration.Type);
+        }
+    }
     // End Spell Helpers
     #endregion
     #region Touch Spells
@@ -514,6 +528,33 @@ 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<FixturesComponent>(ev.Target, out var fixtures) ||
+            !TryComp<PhysicsComponent>(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
index 95a8b25e686dad10b6c748afb48d0b1ff9cd4441..0c650c0d4d22be116b5d7645d5581842d7029e49 100644 (file)
@@ -26,6 +26,9 @@ spellbook-ethereal-jaunt-description = Slip into the ethereal plane to slip away
 spellbook-mind-swap-name = Mind Swap
 spellbook-mind-swap-description = Exchange bodies with another person!
 
+spellbook-animate-name = Animate
+spellbook-animate-description = Bring an inanimate object to life!
+
 spellbook-smite-name = Smite
 spellbook-smite-desc = Don't like them? EXPLODE them into giblets! Requires Wizard Robe & Hat.
 
@@ -49,6 +52,9 @@ spellbook-wand-polymorph-carp-description = For when you need a carp filet quick
 spellbook-wand-locker-name = Wand of the Locker
 spellbook-wand-locker-description = Shoot cursed lockers at your enemies and lock em away!
 
+spellbook-staff-animation-name = Staff of Animation
+spellbook-staff-animation-description = Bring inanimate objects to life!
+
 # Events
 
 spellbook-event-summon-ghosts-name = Summon Ghosts
index 3ba3189771bec33397ca137bb20ce76fdba1a2a8..0486330940df0b0d4b69311e9dab88354e801141 100644 (file)
   - !type:ListingLimitedStockCondition
     stock: 1
 
+- type: listing
+  id: SpellbookStaffAnimation
+  name: spellbook-staff-animation-name
+  description: spellbook-staff-animation-description
+  productEntity: AnimationStaff
+  cost:
+    WizCoin: 3
+  categories:
+  - SpellbookEquipment
+  conditions:
+  - !type:ListingLimitedStockCondition
+    stock: 1
+
 # Event
 - type: listing
   id: SpellbookEventSummonGhosts
index 9e4e77fdfd8e430893ce55ef487685d0a825a6aa..f50c8a6d8d31966e5a2a9da3a34881bba166dbe0 100644 (file)
@@ -1,4 +1,4 @@
-# To be implemented: see #9072
+# To be implemented: see #9072
 
 - type: entity
   name: staff of healing
index 61837aa1eb9cf29ff2130e87dc17eeccc9b91d26..bb67d3f4cf7f8084a8964c15153022a6472d16c8 100644 (file)
@@ -5,6 +5,7 @@
   components:
   - type: Item
     size: Small
+  - type: Animateable
   - type: Clickable
   - type: InteractionOutline
   - type: MovedByPressure
index 86b17e2584c030b5dd43be4b3b429089e5c593b3..27cb4d8b686fd7e5c52a9e3fb8247fbc06ce7ddb 100644 (file)
@@ -5,6 +5,7 @@
   description: A square piece of metal standing on four metal legs.
   abstract: true
   components:
+  - type: Animateable
   - type: Damageable
     damageContainer: StructuralInorganic
     damageModifierSet: Metallic
index 33fd5192fad79558080a3304c8f11097b85d671f..3e3d44bbd5c2a0b62dee88e79f99ae6a21beb0af 100644 (file)
@@ -6,6 +6,7 @@
   placement:
     mode: PlaceFree
   components:
+  - type: Animateable
   - type: Clickable
   - type: InteractionOutline
   - type: Physics
index d79348bfa6128ed0a1da51b749ccea87c0babc4d..7cccee81c0da8f09ff119978688e33c025c47919 100644 (file)
@@ -5,6 +5,7 @@
   placement:
     mode: SnapgridCenter
   components:
+  - type: Animateable
   - type: MeleeSound
     soundGroups:
       Brute:
index aab56b455aaf712382602f1949569b0c99e24319..5a5d026f0e38e75dc0fbf8be8f867c83ff0371ac 100644 (file)
@@ -3,6 +3,7 @@
   parent: BaseStructure
   id: BaseMachine
   components:
+  - type: Animateable
   - type: InteractionOutline
   - type: Anchorable
     delay: 2
@@ -57,6 +58,7 @@
   abstract: true
   id: ConstructibleMachine
   components:
+  - type: Animateable
   - type: Machine
   - type: ContainerContainer
     containers:
index c8c03a95e87e1ef70c832dee524921a8ff714c61..b76791cba69ce772f1f7baf49e041b9ef2b88447 100644 (file)
@@ -5,6 +5,7 @@
   name: gas canister
   description: A canister that can contain any type of gas. It can be attached to connector ports using a wrench.
   components:
+    - type: Animateable
     - type: InteractionOutline
     - type: Transform
       noRot: true
index 6777b0f638073124a593d2c19827a6e5a6a93d61..84b25d135140c90ae811b7243bd4f4186d182741 100644 (file)
@@ -5,6 +5,7 @@
   description: A standard-issue Nanotrasen storage unit.
   abstract: true
   components:
+  - type: Animateable
   - type: ResistLocker
   - type: Transform
     noRot: true
index 3e9a09be5a6a5b1b55016240e9679fca434dbe84..55f4dee0418f684d64222bd86aa2035c11742da5 100644 (file)
@@ -5,6 +5,7 @@
   name: crate
   description: A large container for items.
   components:
+  - type: Animateable
   - type: Transform
     noRot: true
   - type: Icon
index 7b56e6d36b55f018cb740bda9b8adcc0a938a71b..dff863f8fa867348ccf9d49403af99fb1a3a1557 100644 (file)
@@ -1,10 +1,11 @@
-- type: entity
+- type: entity
   id: StorageTank
   parent: BaseStructureDynamic
   name: storage tank
   description: A liquids storage tank.
   abstract: true
   components:
+  - type: Animateable
   - type: Sprite
     noRot: true
   - type: InteractionOutline
@@ -82,4 +83,4 @@
         mask:
         - MachineMask
         layer:
-        - WallLayer
\ No newline at end of file
+        - WallLayer
diff --git a/Resources/Prototypes/Magic/animate_spell.yml b/Resources/Prototypes/Magic/animate_spell.yml
new file mode 100644 (file)
index 0000000..b0b3229
--- /dev/null
@@ -0,0 +1,70 @@
+- type: entity
+  id: ActionAnimateSpell
+  name: Animate
+  description: Bring an inanimate object to life!
+  components:
+  - type: EntityTargetAction
+    useDelay: 0
+    charges: 5
+    itemIconStyle: BigAction
+    whitelist:
+      components:
+      - Animateable # Currently on: SeatBase, TableBase, ClosetBase, BaseMachine, ConstructibleMachine, BaseComputer, BaseItem, CrateGeneric, StorageTank, GasCanister
+    blacklist:
+      components:
+      - MindContainer
+      - NukeDisk
+      - GravityGenerator
+      - AnomalyGenerator
+    canTargetSelf: false
+    interactOnMiss: false
+    sound: !type:SoundPathSpecifier
+      path: /Audio/Magic/staff_animation.ogg
+    icon:
+      sprite: Objects/Magic/magicactions.rsi
+      state: spell_default
+    event: !type:AnimateSpellEvent
+      addComponents:
+      - type: MindContainer
+      - type: InputMover
+      - type: MobMover
+      - type: MovementSpeedModifier
+      - type: HTN
+        rootTask:
+          task: SimpleHostileCompound
+      - type: CombatMode
+      - type: MeleeWeapon
+        animation: WeaponArcPunch
+        wideAnimation: WeaponArcPunch
+        altDisarm: false
+        soundHit: /Audio/Weapons/smash.ogg
+        range: 1.2
+        angle: 0.0
+        damage:
+          types:
+            Blunt: 10
+      - type: NpcFactionMember
+        factions:
+        - Wizard
+      - type: NoSlip
+      - type: MovementAlwaysTouching
+      - type: CanMoveInAir
+      - type: Damageable
+        damageContainer: ManifestedSpirit
+        damageModifierSet: ManifestedSpirit
+      - type: Destructible
+        thresholds:
+        - trigger:
+            !type:DamageTrigger
+            damage: 100
+          behaviors:
+          - !type:DoActsBehavior
+            acts: ["Destruction"]
+          - !type:PlaySoundBehavior
+            sound:
+              collection: MetalBreak
+      - type: Hands
+      - type: CanEscapeInventory
+      removeComponents:
+      - RequireProjectileTarget
+      speech: action-speech-spell-animate
index ccabb516fd4cad0e11f00453b28537259fa30f7e..ea42c47d18495c10196c97f5b1e46e4b6bc664ca 100644 (file)
@@ -1,4 +1,4 @@
-# non-projectile / "gun" staves
+# non-projectile / "gun" staves
 
 # wand that gives lights an RGB effect.
 - type: entity
     enabled: true
     radius: 2
 
+- type: entity
+  id: AnimationStaff
+  parent: BaseItem
+  name: staff of animation
+  description: Brings inanimate objects to life!
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Guns/Basic/staves.rsi
+    layers:
+    - state: animation
+  - type: ActionOnInteract
+    actions:
+    - ActionAnimateSpell
+  - type: Item
+    size: Normal
+    inhandVisuals:
+      left:
+      - state: animation-inhand-left
+      right:
+      - state: animation-inhand-right
+  - type: Tag
+    tags:
+    - WizardWand
+
 - type: entity
   id: ActionRgbLight
   components:
index c2b62b5bdc6083f065f257270ea3213a70f873df..80e12bc1668cb9d571dc0f9de30ef3b41cae6957 100644 (file)
@@ -1,13 +1,14 @@
 - type: npcFaction
   id: Dragon
   hostile:
-    - NanoTrasen
-    - Syndicate
-    - Xeno
-    - PetsNT
-    - Zombie
-    - Revolutionary
-    - AllHostile
+  - NanoTrasen
+  - Syndicate
+  - Xeno
+  - PetsNT
+  - Zombie
+  - Revolutionary
+  - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: NanoTrasen
   - Revolutionary
   - Dragon
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: Mouse
   hostile:
-    - PetsNT
-    - AllHostile
+  - PetsNT
+  - AllHostile
 
 - type: npcFaction
   id: Passive
@@ -48,6 +50,7 @@
   - Zombie
   - Revolutionary
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: SimpleNeutral
@@ -62,6 +65,7 @@
   - Zombie
   - Dragon
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: Xeno
@@ -73,6 +77,7 @@
   - Zombie
   - Revolutionary
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: Zombie
@@ -85,6 +90,7 @@
   - PetsNT
   - Revolutionary
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: Revolutionary
   - SimpleHostile
   - Dragon
   - AllHostile
+  - Wizard
 
 - type: npcFaction
   id: AllHostile
   - Xeno
   - Zombie
   - Revolutionary
+  - Wizard
+
+- type: npcFaction
+  id: Wizard
+  hostile:
+  - NanoTrasen
+  - Dragon
+  - SimpleHostile
+  - Syndicate
+  - Xeno
+  - Zombie
+  - Revolutionary
+  - AllHostile