diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index d836c2ed7a..5f0a8e1f2f 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -88,6 +88,7 @@ namespace Content.Client.Actions return; component.Whitelist = state.Whitelist; + component.Blacklist = state.Blacklist; component.CanTargetSelf = state.CanTargetSelf; BaseHandleState(uid, component, state); } diff --git a/Content.Client/Magic/MagicSystem.cs b/Content.Client/Magic/MagicSystem.cs index 086a0f7b42..06af827b59 100644 --- a/Content.Client/Magic/MagicSystem.cs +++ b/Content.Client/Magic/MagicSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Magic; +using Content.Shared.Magic; using Content.Shared.Magic.Events; namespace Content.Client.Magic; diff --git a/Content.Client/Outline/TargetOutlineSystem.cs b/Content.Client/Outline/TargetOutlineSystem.cs index c69987fe77..591bfc171e 100644 --- a/Content.Client/Outline/TargetOutlineSystem.cs +++ b/Content.Client/Outline/TargetOutlineSystem.cs @@ -32,6 +32,11 @@ public sealed class TargetOutlineSystem : EntitySystem /// public EntityWhitelist? Whitelist = null; + /// + /// Blacklist that the target must satisfy. + /// + public EntityWhitelist? Blacklist = null; + /// /// Predicate the target must satisfy. /// @@ -93,15 +98,16 @@ public sealed class TargetOutlineSystem : EntitySystem RemoveHighlights(); } - public void Enable(float range, bool checkObstructions, Func? predicate, EntityWhitelist? whitelist, CancellableEntityEventArgs? validationEvent) + public void Enable(float range, bool checkObstructions, Func? 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) diff --git a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs index a6c1cfc94f..c2ba35f3c5 100644 --- a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs +++ b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs @@ -952,7 +952,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged diff --git a/Content.Shared/Actions/EntityTargetActionComponent.cs b/Content.Shared/Actions/EntityTargetActionComponent.cs index 7217794b23..aa8c0f4a99 100644 --- a/Content.Shared/Actions/EntityTargetActionComponent.cs +++ b/Content.Shared/Actions/EntityTargetActionComponent.cs @@ -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 /// No whitelist check when null. [DataField("whitelist")] public EntityWhitelist? Whitelist; + /// + /// Determines which entities are NOT valid targets for this action. + /// + /// No blacklist check when null. + [DataField] public EntityWhitelist? Blacklist; + /// /// Whether this action considers the user as a valid target entity when using this action. /// @@ -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; } } diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 8079885a5a..30f1af8465 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -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, diff --git a/Content.Shared/Damage/Components/DamageableComponent.cs b/Content.Shared/Damage/Components/DamageableComponent.cs index a99840e1ae..8ea3567b05 100644 --- a/Content.Shared/Damage/Components/DamageableComponent.cs +++ b/Content.Shared/Damage/Components/DamageableComponent.cs @@ -84,15 +84,18 @@ namespace Content.Shared.Damage public sealed class DamageableComponentState : ComponentState { public readonly Dictionary DamageDict; + public readonly string? DamageContainerId; public readonly string? ModifierSetId; public readonly FixedPoint2? HealthBarThreshold; public DamageableComponentState( Dictionary damageDict, + string? damageContainerId, string? modifierSetId, FixedPoint2? healthBarThreshold) { DamageDict = damageDict; + DamageContainerId = damageContainerId; ModifierSetId = modifierSetId; HealthBarThreshold = healthBarThreshold; } diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 3c3e1b736d..814609444a 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -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 index 0000000000..a0e44d4bb4 --- /dev/null +++ b/Content.Shared/Magic/Components/AnimateableComponent.cs @@ -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 index 0000000000..60331b2804 --- /dev/null +++ b/Content.Shared/Magic/Events/AnimateSpellEvent.cs @@ -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 RemoveComponents = new(); +} diff --git a/Content.Shared/Magic/SharedMagicSystem.cs b/Content.Shared/Magic/SharedMagicSystem.cs index 878c4bdca4..0be5646f4b 100644 --- a/Content.Shared/Magic/SharedMagicSystem.cs +++ b/Content.Shared/Magic/SharedMagicSystem.cs @@ -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(OnRandomGlobalSpawnSpell); SubscribeLocalEvent(OnMindSwapSpell); SubscribeLocalEvent(OnVoidApplause); + SubscribeLocalEvent(OnAnimateSpell); } private void OnBeforeCastSpell(Entity 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 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(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/Resources/Locale/en-US/store/spellbook-catalog.ftl b/Resources/Locale/en-US/store/spellbook-catalog.ftl index 95a8b25e68..0c650c0d4d 100644 --- a/Resources/Locale/en-US/store/spellbook-catalog.ftl +++ b/Resources/Locale/en-US/store/spellbook-catalog.ftl @@ -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 diff --git a/Resources/Prototypes/Catalog/spellbook_catalog.yml b/Resources/Prototypes/Catalog/spellbook_catalog.yml index 3ba3189771..0486330940 100644 --- a/Resources/Prototypes/Catalog/spellbook_catalog.yml +++ b/Resources/Prototypes/Catalog/spellbook_catalog.yml @@ -197,6 +197,19 @@ - !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 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/staves.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/staves.yml index 9e4e77fdfd..f50c8a6d8d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/staves.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/staves.yml @@ -1,4 +1,4 @@ -# To be implemented: see #9072 +# To be implemented: see #9072 - type: entity name: staff of healing diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml index 61837aa1eb..bb67d3f4cf 100644 --- a/Resources/Prototypes/Entities/Objects/base_item.yml +++ b/Resources/Prototypes/Entities/Objects/base_item.yml @@ -5,6 +5,7 @@ components: - type: Item size: Small + - type: Animateable - type: Clickable - type: InteractionOutline - type: MovedByPressure diff --git a/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml b/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml index 86b17e2584..27cb4d8b68 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml index 33fd5192fa..3e3d44bbd5 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml @@ -6,6 +6,7 @@ placement: mode: PlaceFree components: + - type: Animateable - type: Clickable - type: InteractionOutline - type: Physics diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml index d79348bfa6..7cccee81c0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml @@ -5,6 +5,7 @@ placement: mode: SnapgridCenter components: + - type: Animateable - type: MeleeSound soundGroups: Brute: diff --git a/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml b/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml index aab56b455a..5a5d026f0e 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml @@ -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: diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index c8c03a95e8..b76791cba6 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml index 6777b0f638..84b25d1351 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml @@ -5,6 +5,7 @@ description: A standard-issue Nanotrasen storage unit. abstract: true components: + - type: Animateable - type: ResistLocker - type: Transform noRot: true diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml index 3e9a09be5a..55f4dee041 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml @@ -5,6 +5,7 @@ name: crate description: A large container for items. components: + - type: Animateable - type: Transform noRot: true - type: Icon diff --git a/Resources/Prototypes/Entities/Structures/Storage/Tanks/base_structuretanks.yml b/Resources/Prototypes/Entities/Structures/Storage/Tanks/base_structuretanks.yml index 7b56e6d36b..dff863f8fa 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Tanks/base_structuretanks.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Tanks/base_structuretanks.yml @@ -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 index 0000000000..b0b322919c --- /dev/null +++ b/Resources/Prototypes/Magic/animate_spell.yml @@ -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 diff --git a/Resources/Prototypes/Magic/staves.yml b/Resources/Prototypes/Magic/staves.yml index ccabb516fd..ea42c47d18 100644 --- a/Resources/Prototypes/Magic/staves.yml +++ b/Resources/Prototypes/Magic/staves.yml @@ -1,4 +1,4 @@ -# non-projectile / "gun" staves +# non-projectile / "gun" staves # wand that gives lights an RGB effect. - type: entity @@ -32,6 +32,30 @@ 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: diff --git a/Resources/Prototypes/ai_factions.yml b/Resources/Prototypes/ai_factions.yml index c2b62b5bdc..80e12bc166 100644 --- a/Resources/Prototypes/ai_factions.yml +++ b/Resources/Prototypes/ai_factions.yml @@ -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 @@ -19,12 +20,13 @@ - 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 @@ -94,6 +100,7 @@ - SimpleHostile - Dragon - AllHostile + - Wizard - type: npcFaction id: AllHostile @@ -109,3 +116,16 @@ - Xeno - Zombie - Revolutionary + - Wizard + +- type: npcFaction + id: Wizard + hostile: + - NanoTrasen + - Dragon + - SimpleHostile + - Syndicate + - Xeno + - Zombie + - Revolutionary + - AllHostile