diff --git a/Content.Client/Aliens/JumpVisualsComponent.cs b/Content.Client/Aliens/JumpVisualsComponent.cs
new file mode 100644
index 00000000000..f87a92478a3
--- /dev/null
+++ b/Content.Client/Aliens/JumpVisualsComponent.cs
@@ -0,0 +1,17 @@
+using Robust.Client.Graphics;
+
+namespace Content.Client.Aliens;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class JumpVisualsComponent : Component
+{
+
+}
+
+public enum JumpLayers : byte
+{
+ Jumping
+}
diff --git a/Content.Client/Aliens/Systems/AlienSystem.cs b/Content.Client/Aliens/Systems/AlienSystem.cs
new file mode 100644
index 00000000000..850ce1a1ebb
--- /dev/null
+++ b/Content.Client/Aliens/Systems/AlienSystem.cs
@@ -0,0 +1,43 @@
+using Content.Client.Movement.Systems;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using ToggleLightingAlienActionEvent = Content.Shared.Aliens.Components.ToggleLightingAlienActionEvent;
+
+namespace Content.Client.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienSystem : EntitySystem
+{
+ [Dependency] private readonly ContentEyeSystem _contentEye = default!;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnStartup);
+
+ SubscribeLocalEvent(OnToggleLighting);
+ }
+
+ private void OnStartup(EntityUid uid, AlienComponent component, ComponentStartup args)
+ {
+ // _action.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction);
+ }
+
+ private void OnToggleLighting(EntityUid uid, EyeComponent component, ToggleLightingAlienActionEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ RequestToggleLight(uid, component);
+ args.Handled = true;
+ }
+
+ private void RequestToggleLight(EntityUid uid, EyeComponent? eye = null)
+ {
+ if (Resolve(uid, ref eye, false))
+ _contentEye.RequestEye(eye.DrawFov, !eye.DrawLight);
+ }
+}
diff --git a/Content.Client/Aliens/Systems/PlasmaVesselSystem.cs b/Content.Client/Aliens/Systems/PlasmaVesselSystem.cs
new file mode 100644
index 00000000000..79efdd1132a
--- /dev/null
+++ b/Content.Client/Aliens/Systems/PlasmaVesselSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Client.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class PlasmaVesselSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Client/Chat/Managers/ChatManager.cs b/Content.Client/Chat/Managers/ChatManager.cs
index 18f03cd7db0..316f3c6842b 100644
--- a/Content.Client/Chat/Managers/ChatManager.cs
+++ b/Content.Client/Chat/Managers/ChatManager.cs
@@ -72,11 +72,15 @@ public void SendMessage(string text, ChatSelectChannel channel)
_consoleHost.ExecuteCommand($"tsay \"{CommandParsing.Escape(str)}\"");
break;
+ case ChatSelectChannel.XenoHivemind:
+ _consoleHost.ExecuteCommand($"aliensay \"{CommandParsing.Escape(str)}\"");
+ break;
+
default:
throw new ArgumentOutOfRangeException(nameof(channel), channel, null);
}
}
- //Nyano - Summary: fires off the update permissions script.
+ //Nyano - Summary: fires off the update permissions script.
public void UpdatePermissions()
{
PermissionsUpdated?.Invoke();
diff --git a/Content.Client/Overlays/ShowInfectedIconsSystem.cs b/Content.Client/Overlays/ShowInfectedIconsSystem.cs
new file mode 100644
index 00000000000..445452d5441
--- /dev/null
+++ b/Content.Client/Overlays/ShowInfectedIconsSystem.cs
@@ -0,0 +1,40 @@
+using System.Linq;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Mobs;
+using Content.Shared.StatusIcon;
+using Content.Shared.StatusIcon.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Overlays;
+
+///
+/// This handles...
+///
+public sealed class ShowInfectedIconsSystem : EquipmentHudSystem
+{
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnGetStatusIconsEvent);
+ }
+
+ private void OnGetStatusIconsEvent(EntityUid uid, AlienInfectedComponent component, ref GetStatusIconsEvent ev)
+ {
+ if (!IsActive)
+ return;
+ if (component.GrowthStage <= 5)
+ {
+ if (_prototype.TryIndex(component.InfectedIcons.ElementAt(component.GrowthStage), out var iconPrototype))
+ ev.StatusIcons.Add(iconPrototype);
+ }
+ else
+ {
+ if (_prototype.TryIndex(component.InfectedIcons.ElementAt(5), out var iconPrototype))
+ ev.StatusIcons.Add(iconPrototype);
+ }
+
+ }
+}
diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
index ff4972d9d08..68b669304d2 100644
--- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
+++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
@@ -82,7 +82,8 @@ public sealed class ChatUIController : UIController
{SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin},
{SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio},
{SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead},
- {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //Nyano - Summary: adds the telepathic prefix =.
+ {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic}, //Nyano - Summary: adds the telepathic prefix =.
+ {SharedChatSystem.XenoHivemindPrefix, ChatSelectChannel.XenoHivemind}
};
public static readonly Dictionary ChannelPrefixes = new()
@@ -96,7 +97,8 @@ public sealed class ChatUIController : UIController
{ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix},
{ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix},
{ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix},
- {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //Nyano - Summary: associates telepathic with =.
+ {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix }, //Nyano - Summary: associates telepathic with =.
+ {ChatSelectChannel.XenoHivemind, SharedChatSystem.XenoHivemindPrefix }
};
///
@@ -221,6 +223,9 @@ public override void Initialize()
_input.SetInputCommand(ContentKeyFunctions.FocusConsoleChat,
InputCmdHandler.FromDelegate(_ => FocusChannel(ChatSelectChannel.Console)));
+ _input.SetInputCommand(ContentKeyFunctions.FocusXenoHivemindChat,
+ InputCmdHandler.FromDelegate(_ => FocusChannel(ChatSelectChannel.XenoHivemind)));
+
_input.SetInputCommand(ContentKeyFunctions.CycleChatChannelForward,
InputCmdHandler.FromDelegate(_ => CycleChatChannel(true)));
@@ -499,6 +504,7 @@ private void UpdateChannelPermissions()
FilterableChannels |= ChatChannel.Emotes;
FilterableChannels |= ChatChannel.Notifications;
+
// Can only send local / radio / emote when attached to a non-ghost entity.
// TODO: this logic is iffy (checking if controlling something that's NOT a ghost), is there a better way to check this?
if (_ghost is not {IsGhost: true})
@@ -507,6 +513,9 @@ private void UpdateChannelPermissions()
CanSendChannels |= ChatSelectChannel.Whisper;
CanSendChannels |= ChatSelectChannel.Radio;
CanSendChannels |= ChatSelectChannel.Emotes;
+
+ CanSendChannels |= ChatSelectChannel.XenoHivemind;
+ FilterableChannels |= ChatChannel.XenoHivemind;
}
}
@@ -535,6 +544,7 @@ private void UpdateChannelPermissions()
}
// /Nyano - End modified code block
+
SelectableChannels = CanSendChannels;
// Necessary so that we always have a channel to fall back to.
diff --git a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs
index 1d2a4314462..1db0855e8da 100644
--- a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs
+++ b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelFilterPopup.xaml.cs
@@ -24,6 +24,7 @@ public sealed partial class ChannelFilterPopup : Popup
ChatChannel.Admin,
ChatChannel.AdminAlert,
ChatChannel.AdminChat,
+ ChatChannel.XenoHivemind,
ChatChannel.Server
};
diff --git a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorButton.cs b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorButton.cs
index 041d8075e35..886475d1b66 100644
--- a/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorButton.cs
+++ b/Content.Client/UserInterface/Systems/Chat/Controls/ChannelSelectorButton.cs
@@ -64,7 +64,8 @@ public Color ChannelSelectColor(ChatSelectChannel channel)
ChatSelectChannel.OOC => Color.LightSkyBlue,
ChatSelectChannel.Dead => Color.MediumPurple,
ChatSelectChannel.Admin => Color.HotPink,
- ChatSelectChannel.Telepathic => Color.PaleVioletRed, //Nyano - Summary: determines the color for the chat.
+ ChatSelectChannel.Telepathic => Color.PaleVioletRed, //Nyano - Summary: determines the color for the chat.
+ ChatSelectChannel.XenoHivemind => Color.FromHex("#5b0c82"),
_ => Color.DarkGray
};
}
diff --git a/Content.Server/Aliens/Components/AlienAcidComponent.cs b/Content.Server/Aliens/Components/AlienAcidComponent.cs
new file mode 100644
index 00000000000..ec008c37e14
--- /dev/null
+++ b/Content.Server/Aliens/Components/AlienAcidComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienAcidComponent : Component
+{
+ [DataField("corrosiveAcidPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string AcidPrototype = "CorrosiveAcid";
+}
diff --git a/Content.Server/Aliens/Components/AlienEggHatchComponent.cs b/Content.Server/Aliens/Components/AlienEggHatchComponent.cs
new file mode 100644
index 00000000000..04fd6184d86
--- /dev/null
+++ b/Content.Server/Aliens/Components/AlienEggHatchComponent.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienEggHatchComponent : Component
+{
+ [DataField(required: true)]
+ public ProtoId PolymorphPrototype;
+
+ [DataField]
+ public float ActivationRange = 1f;
+}
diff --git a/Content.Server/Aliens/Components/QueenEvolutionComponent.cs b/Content.Server/Aliens/Components/QueenEvolutionComponent.cs
new file mode 100644
index 00000000000..33dd287fdd4
--- /dev/null
+++ b/Content.Server/Aliens/Components/QueenEvolutionComponent.cs
@@ -0,0 +1,25 @@
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class QueenEvolutionComponent : Component
+{
+ [DataField]
+ public ProtoId QueenPolymorphPrototype = "AlienEvolutionQueen";
+
+ [DataField("queenEvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? QueenEvolutionAction = "ActionEvolveQueen";
+
+ [DataField("queenEvolutionActionEntity")]
+ public EntityUid? QueenEvolutionActionEntity;
+
+ [DataField("plasmaCost")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float PlasmaCost = 500f;
+}
diff --git a/Content.Server/Aliens/Systems/AlienAcidSystem.cs b/Content.Server/Aliens/Systems/AlienAcidSystem.cs
new file mode 100644
index 00000000000..5cc1f3c760f
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienAcidSystem.cs
@@ -0,0 +1,36 @@
+using Content.Server.Aliens.Components;
+using Content.Server.Weapons.Melee;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Coordinates;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Tag;
+using Content.Shared.Weapons.Melee;
+using Content.Shared.Weapons.Melee.Events;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienAcidSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly MeleeWeaponSystem _meleeWeapon = default!;
+ [Dependency] private readonly TagSystem _tag = default!;
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnHit);
+ }
+
+ private void OnHit(EntityUid uid, AlienAcidComponent component, MeleeHitEvent args)
+ {
+ foreach (var hitEntity in args.HitEntities)
+ {
+ if (_tag.HasTag(hitEntity, "Wall"))
+ {
+ Spawn(component.AcidPrototype, hitEntity.ToCoordinates());
+ }
+ }
+ }
+}
diff --git a/Content.Server/Aliens/Systems/AlienEggHatchSystem.cs b/Content.Server/Aliens/Systems/AlienEggHatchSystem.cs
new file mode 100644
index 00000000000..bb45d881c72
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienEggHatchSystem.cs
@@ -0,0 +1,51 @@
+using System.Linq;
+using Content.Server.Aliens.Components;
+using Content.Server.Polymorph.Systems;
+using Content.Server.Speech.Components;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Hands.Components;
+using Content.Shared.Humanoid;
+using Content.Shared.Interaction;
+using Content.Shared.Inventory;
+using Content.Shared.Mobs.Components;
+using Robust.Server.GameObjects;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienEggHatchSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly PolymorphSystem _polymorph = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly InventorySystem _inventory = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInteract);
+ }
+
+ private void OnInteract(EntityUid uid, AlienEggHatchComponent component, InteractHandEvent args)
+ {
+ _polymorph.PolymorphEntity(uid, component.PolymorphPrototype);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var alienEgg))
+ {
+ foreach (var entity in _lookup.GetEntitiesInRange(uid, alienEgg.ActivationRange)
+ .Where(entity => _inventory.HasSlot(entity, "mask")))
+ {
+ _polymorph.PolymorphEntity(uid, alienEgg.PolymorphPrototype);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Aliens/Systems/AlienEvolutionSystem.cs b/Content.Server/Aliens/Systems/AlienEvolutionSystem.cs
new file mode 100644
index 00000000000..6a429e62bc9
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienEvolutionSystem.cs
@@ -0,0 +1,60 @@
+using Content.Server.Polymorph.Systems;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienEvolutionSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly PolymorphSystem _polymorphSystem = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnEvolveDrone);
+ SubscribeLocalEvent(OnEvolveSentinel);
+ SubscribeLocalEvent(OnEvolveHunter);
+ }
+
+ private void OnComponentInit(EntityUid uid, AlienEvolutionComponent component, ComponentInit args)
+ {
+ _actionsSystem.AddAction(uid, ref component.DroneEvolutionActionEntity, component.DroneEvolutionAction, uid);
+ _actionsSystem.AddAction(uid, ref component.SentinelEvolutionActionEntity, component.SentinelEvolutionAction, uid);
+ _actionsSystem.AddAction(uid, ref component.HunterEvolutionActionEntity, component.HunterEvolutionAction, uid);
+
+ _actionsSystem.SetCooldown(component.DroneEvolutionActionEntity, component.EvolutionCooldown);
+ _actionsSystem.SetCooldown(component.SentinelEvolutionActionEntity, component.EvolutionCooldown);
+ _actionsSystem.SetCooldown(component.HunterEvolutionActionEntity, component.EvolutionCooldown);
+ }
+
+ private void OnEvolveDrone(EntityUid uid, AlienEvolutionComponent component, AlienDroneEvolveActionEvent args)
+ {
+ Evolve(uid, component.DronePolymorphPrototype);
+ }
+
+ private void OnEvolveSentinel(EntityUid uid, AlienEvolutionComponent component, AlienSentinelEvolveActionEvent args)
+ {
+ Evolve(uid, component.SentinelPolymorphPrototype);
+ }
+
+ private void OnEvolveHunter(EntityUid uid, AlienEvolutionComponent component, AlienHunterEvolveActionEvent args)
+ {
+ Evolve(uid, component.HunterPolymorphPrototype);
+ }
+
+ public void Evolve(EntityUid uid, ProtoId polymorphProtoId)
+ {
+ _polymorphSystem.PolymorphEntity(uid, polymorphProtoId);
+ }
+}
+
+
diff --git a/Content.Server/Aliens/Systems/AlienInfectedSystem.cs b/Content.Server/Aliens/Systems/AlienInfectedSystem.cs
new file mode 100644
index 00000000000..22d624a74ef
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienInfectedSystem.cs
@@ -0,0 +1,93 @@
+using System.Linq;
+using System.Threading;
+using Content.Server.Aliens.Components;
+using Content.Server.Body.Systems;
+using Content.Server.Ghost.Roles;
+using Content.Server.Ghost.Roles.Components;
+using Content.Server.Mind;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Body.Components;
+using Content.Shared.Body.Events;
+using Content.Shared.Body.Part;
+using Content.Shared.Damage;
+using Content.Shared.Ghost.Roles;
+using Content.Shared.Gibbing.Components;
+using Content.Shared.Gibbing.Events;
+using Content.Shared.Gibbing.Systems;
+using Content.Shared.Inventory.Events;
+using Content.Shared.Mobs;
+using Content.Shared.Random;
+using Content.Shared.StatusIcon;
+using Content.Shared.StatusIcon.Components;
+using FastAccessors;
+using Robust.Shared.Containers;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+using AlienInfectedComponent = Content.Shared.Aliens.Components.AlienInfectedComponent;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienInfectedSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly BodySystem _body = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnComponentInit);
+ SubscribeLocalEvent(OnComponentShutdown);
+ }
+
+ private void OnComponentInit(EntityUid uid, AlienInfectedComponent component, ComponentInit args)
+ {
+ // var torsoPart = Comp(uid).RootContainer.ContainedEntities[0];
+ // _body.TryCreateOrganSlot(torsoPart, "alienLarvaOrgan", out _);
+ // _body.InsertOrgan(torsoPart, Spawn(component.OrganProtoId, Transform(uid).Coordinates), "alienLarvaOrgan");
+ component.NextGrowRoll = _timing.CurTime + TimeSpan.FromSeconds(component.GrowTime);
+ component.Stomach = _container.EnsureContainer(uid, "stomach");
+ }
+
+ private void OnComponentShutdown(EntityUid uid, AlienInfectedComponent component, ComponentShutdown args)
+ {
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var infected))
+ {
+ if (_timing.CurTime < infected.NextGrowRoll)
+ continue;
+
+ if (HasComp(infected.SpawnedLarva) &&
+ Comp(infected.SpawnedLarva).IsGrown)
+ {
+ _container.EmptyContainer(infected.Stomach);
+ _body.GibBody(uid, true, CompOrNull(uid), true, null, 5f);
+ }
+
+ if (infected.GrowthStage == 5)
+ {
+ var larva = Spawn(infected.Prototype, Transform(uid).Coordinates);
+ _container.Insert(larva, infected.Stomach);
+ infected.SpawnedLarva = larva;
+ infected.GrowthStage++;
+ }
+
+ if (_random.Prob(infected.GrowProb))
+ {
+ infected.GrowthStage++;
+ }
+ infected.NextGrowRoll = _timing.CurTime + TimeSpan.FromSeconds(infected.GrowTime);
+ }
+ }
+}
diff --git a/Content.Server/Aliens/Systems/AlienQueenSystem.cs b/Content.Server/Aliens/Systems/AlienQueenSystem.cs
new file mode 100644
index 00000000000..af5f34f857d
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienQueenSystem.cs
@@ -0,0 +1,116 @@
+using Content.Server.Actions;
+using Content.Server.Aliens.Components;
+using Content.Server.Animals.Components;
+using Content.Server.Popups;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.Hands.Components;
+using Content.Shared.Maps;
+using Content.Shared.Physics;
+using Content.Shared.Tag;
+using Robust.Shared.Containers;
+using Robust.Shared.Map;
+using AlienEggActionEvent = Content.Shared.Aliens.Components.AlienEggActionEvent;
+using AlienQueenComponent = Content.Shared.Aliens.Components.AlienQueenComponent;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienQueenSystem : EntitySystem
+{
+ [Dependency] private readonly AlienEvolutionSystem _evolution = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+ [Dependency] private readonly ActionsSystem _actions = default!;
+ [Dependency] private readonly EntityLookupSystem _lookupSystem = default!;
+ [Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVessel = default!;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnEgg);
+ SubscribeLocalEvent(OnRoyalLarva);
+ }
+
+ private void OnMapInit(EntityUid uid, AlienQueenComponent component, MapInitEvent args)
+ {
+ _actions.AddAction(uid, ref component.EggActionEntity, component.EggAction);
+ }
+
+ private void OnEgg(EntityUid uid, AlienQueenComponent component, AlienEggActionEvent args)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma < component.PlasmaCostEgg)
+ {
+ _popup.PopupClient(Loc.GetString(Loc.GetString("alien-action-fail-plasma")), uid, uid);
+ return;
+ }
+ CreateStructure(uid, component);
+ args.Handled = true;
+ }
+
+ public void CreateStructure(EntityUid uid, AlienQueenComponent component)
+ {
+
+ if (_container.IsEntityOrParentInContainer(uid))
+ return;
+
+ var xform = Transform(uid);
+ // Get the tile in front of the drone
+ var coords = xform.Coordinates.SnapToGrid(EntityManager, _mapMan);
+ var tile = coords.GetTileRef(EntityManager, _mapMan);
+ if (tile == null)
+ return;
+
+ // Check there are no walls there
+ if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+ }
+
+ foreach (var entity in _lookupSystem.GetEntitiesInRange(coords, 0.1f))
+ {
+ if (Prototype(entity) == null)
+ continue;
+ if (Prototype(entity)!.ID != component.EggPrototype)
+ continue;
+ _popup.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+
+ }
+
+ _plasmaVessel.ChangePlasmaAmount(uid, -component.PlasmaCostEgg);
+ Spawn(component.EggPrototype, _turf.GetTileCenter(tile.Value));
+ }
+
+ public void OnRoyalLarva(EntityUid uid, AlienQueenComponent component, RoyalLarvaActionEvent args)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma < component.PlasmaCostRoyalLarva)
+ {
+ _popup.PopupEntity(Loc.GetString("alien-action-fail-plasma"), uid, uid);
+ return;
+ }
+
+ if (!HasComp(args.Target) ||
+ !HasComp(args.Target) ||
+ HasComp(args.Target) ||
+ HasComp(args.Target))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-promotion-fail"), uid, uid);
+ return;
+ }
+
+ _plasmaVessel.ChangePlasmaAmount(uid, -component.PlasmaCostRoyalLarva);
+ _evolution.Evolve(args.Target, component.PraetorianPolymorphPrototype);
+ _actions.RemoveAction(component.ActionEntity);
+ }
+}
diff --git a/Content.Server/Aliens/Systems/AlienSystem.cs b/Content.Server/Aliens/Systems/AlienSystem.cs
new file mode 100644
index 00000000000..73f4f2c0e6a
--- /dev/null
+++ b/Content.Server/Aliens/Systems/AlienSystem.cs
@@ -0,0 +1,176 @@
+using Content.Server.Actions;
+using Content.Server.Aliens.Systems;
+using Content.Server.Animals.Components;
+using Content.Server.Chat.Managers;
+using Content.Server.Ghost.Roles.Components;
+using Content.Server.Mind;
+using Content.Server.NPC.HTN;
+using Content.Server.Popups;
+using Content.Server.Roles;
+using Content.Shared.Aliens;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Devour;
+using Content.Shared.Devour.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Item;
+using Content.Shared.Maps;
+using Content.Shared.Mind;
+using Content.Shared.Mind.Components;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Physics;
+using Content.Shared.Players;
+using Content.Shared.Tag;
+using Robust.Shared.Containers;
+using Robust.Shared.Map;
+using Robust.Shared.Player;
+using AlienComponent = Content.Shared.Aliens.Components.AlienComponent;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienSystem : EntitySystem
+{
+ [Dependency] private readonly TagSystem _tag = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+ [Dependency] private readonly ActionsSystem _actions = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVessel = default!;
+ [Dependency] private readonly RoleSystem _role = default!;
+ [Dependency] private readonly MindSystem _mind = default!;
+ [Dependency] private readonly IChatManager _chatMan = default!;
+
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPickup);
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnNode);
+ SubscribeLocalEvent(OnTakeRole);
+ }
+
+ private void OnMapInit(EntityUid uid, AlienComponent component, MapInitEvent args)
+ {
+ _actions.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction);
+ _actions.AddAction(uid, ref component.WeednodeActionEntity, component.WeednodeAction);
+
+ }
+
+ private void OnTakeRole(EntityUid uid, AlienComponent component, PlayerAttachedEvent args)
+ {
+ switch (component.Caste)
+ {
+ case "larva":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-role-greeting"));
+ break;
+ case "drone":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-drone-greeting"));
+ break;
+ case "sentinel":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-sentinel-greeting"));
+ break;
+ case "hunter":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-hunter-greeting"));
+ break;
+ case "praetorian":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-praetorian-greeting"));
+ break;
+ case "queen":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-queen-greeting"));
+ break;
+ case "maid":
+ _chatMan.DispatchServerMessage(args.Player, Loc.GetString("alien-maid-greeting"));
+ break;
+ }
+
+ }
+
+ private void OnPickup(EntityUid uid, AlienComponent component, PickupAttemptEvent args)
+ {
+ if (!_tag.HasTag(args.Item, "AlienItem"))
+ {
+ args.Cancel();
+ _popup.PopupEntity(Loc.GetString("alien-pickup-item-fail"), uid, uid);
+ }
+ }
+
+ private void OnNode(EntityUid uid, AlienComponent component, WeednodeActionEvent args)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma < component.PlasmaCostNode)
+ {
+ _popup.PopupClient(Loc.GetString(Loc.GetString("alien-action-fail-plasma")), uid, uid);
+ return;
+ }
+ CreateStructure(uid, component);
+ args.Handled = true;
+ }
+
+ public void CreateStructure(EntityUid uid, AlienComponent component)
+ {
+
+ if (_container.IsEntityOrParentInContainer(uid))
+ return;
+
+ var xform = Transform(uid);
+ // Get the tile in front of the drone
+ var coords = xform.Coordinates.SnapToGrid(EntityManager, _mapMan);
+ var tile = coords.GetTileRef(EntityManager, _mapMan);
+ if (tile == null)
+ return;
+
+ // Check there are no walls there
+ if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+ }
+
+ foreach (var entity in _lookup.GetEntitiesInRange(coords, 0.1f))
+ {
+ if (Prototype(entity) == null)
+ continue;
+ if (Prototype(entity)!.ID == component.WeednodePrototype)
+ return;
+ }
+
+ _plasmaVessel.ChangePlasmaAmount(uid, -component.PlasmaCostNode);
+ Spawn(component.WeednodePrototype, _turf.GetTileCenter(tile.Value));
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+
+ while (query.MoveNext(out var uid, out var alien))
+ {
+ var weed = false;
+ var passiveDamageComponent = EnsureComp(uid);
+ foreach (var entity in _lookup.GetEntitiesInRange(Transform(uid).Coordinates, 0.1f))
+ {
+ if (HasComp(entity) && passiveDamageComponent.Damage.Empty)
+ {
+ passiveDamageComponent.Damage = alien.WeedHeal;
+ weed = true;
+ }
+ }
+
+ if (!weed)
+ passiveDamageComponent.Damage = new DamageSpecifier();
+ }
+ }
+
+}
diff --git a/Content.Server/Aliens/Systems/FacehuggerSystem.cs b/Content.Server/Aliens/Systems/FacehuggerSystem.cs
new file mode 100644
index 00000000000..9d952291201
--- /dev/null
+++ b/Content.Server/Aliens/Systems/FacehuggerSystem.cs
@@ -0,0 +1,71 @@
+using Content.Server.Aliens.Components;
+using Content.Server.Polymorph.Components;
+using Content.Server.Polymorph.Systems;
+using Content.Server.Stunnable;
+using Content.Shared.Aliens.Components;
+using Content.Shared.IdentityManagement.Components;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Systems;
+using Robust.Shared.Timing;
+using AlienInfectedComponent = Content.Shared.Aliens.Components.AlienInfectedComponent;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class FacehuggerSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly StunSystem _stun = default!;
+ [Dependency] private readonly PolymorphSystem _polymorph = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnEquipped);
+ SubscribeLocalEvent(OnUnequipped);
+ }
+
+ public void OnEquipped(EntityUid uid, FacehuggerComponent component, GotEquippedEvent args)
+ {
+ if(!component.Active || args.Slot != "mask")
+ return;
+ _stun.TryParalyze(args.Equipee, TimeSpan.FromSeconds(25), false);
+ component.Equipped = true;
+ component.Equipee = args.Equipee;
+ component.Active = false;
+ var curTime = _timing.CurTime;
+ component.GrowTime = curTime + TimeSpan.FromSeconds(component.EmbryoTime);
+ }
+
+ private static void OnUnequipped(EntityUid uid, FacehuggerComponent component, GotUnequippedEvent args)
+ {
+ component.Equipped = false;
+ component.Active = true;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ var growedLarva = new Dictionary();
+ while (query.MoveNext(out var uid, out var facehugger))
+ {
+ if(_timing.CurTime < facehugger.GrowTime || !facehugger.Equipped)
+ continue;
+ growedLarva.TryAdd(uid, facehugger);
+ }
+
+ foreach (var facehugger in growedLarva)
+ {
+ if(!HasComp(facehugger.Value.Equipee))
+ AddComp(facehugger.Value.Equipee);
+ _polymorph.PolymorphEntity(facehugger.Key, facehugger.Value.FacehuggerPolymorphPrototype);
+ }
+ }
+}
diff --git a/Content.Server/Aliens/Systems/InsideAlienLarvaSystem.cs b/Content.Server/Aliens/Systems/InsideAlienLarvaSystem.cs
new file mode 100644
index 00000000000..d055378c66e
--- /dev/null
+++ b/Content.Server/Aliens/Systems/InsideAlienLarvaSystem.cs
@@ -0,0 +1,39 @@
+using Content.Server.Body.Systems;
+using Content.Server.Polymorph.Systems;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Robust.Server.Containers;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class InsideAlienLarvaSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly PolymorphSystem _polymorphSystem = default!;
+ [Dependency] private readonly BodySystem _body = default!;
+ [Dependency] private readonly ContainerSystem _container = default!;
+ [Dependency] private readonly EntityManager _entityManager = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnGrow);
+ }
+
+ private void OnComponentInit(EntityUid uid, InsideAlienLarvaComponent component, ComponentInit args)
+ {
+ _actionsSystem.AddAction(uid, ref component.EvolutionActionEntity, component.EvolutionAction, uid);
+
+ _actionsSystem.SetCooldown(component.EvolutionActionEntity, component.EvolutionCooldown);
+ }
+
+ public void OnGrow(EntityUid uid, InsideAlienLarvaComponent component, AlienLarvaGrowActionEvent args)
+ {
+ component.IsGrown = true;
+ _polymorphSystem.PolymorphEntity(uid, component.PolymorphPrototype);
+ }
+}
diff --git a/Content.Server/Aliens/Systems/PlasmaVesselSystem.cs b/Content.Server/Aliens/Systems/PlasmaVesselSystem.cs
new file mode 100644
index 00000000000..1365f4b83d6
--- /dev/null
+++ b/Content.Server/Aliens/Systems/PlasmaVesselSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class PlasmaVesselSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Server/Aliens/Systems/PraetorianEvolutionSystem.cs b/Content.Server/Aliens/Systems/PraetorianEvolutionSystem.cs
new file mode 100644
index 00000000000..4d21dc0b834
--- /dev/null
+++ b/Content.Server/Aliens/Systems/PraetorianEvolutionSystem.cs
@@ -0,0 +1,58 @@
+using Content.Server.Aliens.Components;
+using Content.Server.Polymorph.Systems;
+using Content.Server.Popups;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+using Content.Shared.Maps;
+using Content.Shared.Polymorph;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class PraetorianEvolutionSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly AlienEvolutionSystem _alienEvolution = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnEvolvePraetorian);
+ }
+
+ private void OnComponentInit(EntityUid uid, PraetorianEvolutionComponent component, ComponentInit args)
+ {
+
+ _actionsSystem.AddAction(uid, ref component.PraetorianEvolutionActionEntity, component.PraetorianEvolutionAction, uid);
+ }
+
+ private void OnEvolvePraetorian(EntityUid uid, PraetorianEvolutionComponent component, AlienPraetorianEvolveActionEvent args)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma <= component.PlasmaCost)
+ {
+ _popup.PopupEntity(Loc.GetString("alien-action-fail-plasma"), uid, uid);
+ return;
+ }
+
+ if (EntityQueryEnumerator().MoveNext(out _, out _))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-evolution-fail"), uid, uid);
+ return;
+ }
+
+ _alienEvolution.Evolve(uid, component.PraetorianPolymorphPrototype);
+ }
+
+}
+
+
diff --git a/Content.Server/Aliens/Systems/QueenEvolutionSystem.cs b/Content.Server/Aliens/Systems/QueenEvolutionSystem.cs
new file mode 100644
index 00000000000..94a3e0e7ba8
--- /dev/null
+++ b/Content.Server/Aliens/Systems/QueenEvolutionSystem.cs
@@ -0,0 +1,51 @@
+using Content.Server.Aliens.Components;
+using Content.Server.Popups;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class QueenEvolutionSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly AlienEvolutionSystem _alienEvolution = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnEvolveQueen);
+ }
+
+ private void OnComponentInit(EntityUid uid, QueenEvolutionComponent component, ComponentInit args)
+ {
+
+ _actionsSystem.AddAction(uid, ref component.QueenEvolutionActionEntity, component.QueenEvolutionAction, uid);
+ }
+
+ private void OnEvolveQueen(EntityUid uid, QueenEvolutionComponent component, AlienQueenEvolveActionEvent args)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma <= component.PlasmaCost)
+ {
+ _popup.PopupEntity(Loc.GetString("alien-action-fail-plasma"), uid, uid);
+ return;
+ }
+
+ if (EntityQueryEnumerator().MoveNext(out _, out _))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-evolution-fail"), uid, uid);
+ return;
+ }
+
+ _alienEvolution.Evolve(uid, component.QueenPolymorphPrototype);
+ }
+
+}
diff --git a/Content.Server/Aliens/Systems/ResinSpinnerSystem.cs b/Content.Server/Aliens/Systems/ResinSpinnerSystem.cs
new file mode 100644
index 00000000000..751a87698cc
--- /dev/null
+++ b/Content.Server/Aliens/Systems/ResinSpinnerSystem.cs
@@ -0,0 +1,113 @@
+using System.Linq;
+using System.Numerics;
+using Content.Server.Popups;
+using Content.Shared.Actions;
+using Content.Shared.Alert;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Aliens.Systems;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.Maps;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Physics;
+using Robust.Shared.Containers;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class ResinSpinnerSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly EntityLookupSystem _lookupSystem = default!;
+ [Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVessel = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnWallDoAfter);
+ SubscribeLocalEvent(OnWindowDoAfter);
+ SubscribeLocalEvent(OnNestDoAfter);
+ }
+
+ private void OnWallDoAfter(EntityUid uid, ResinSpinnerComponent component, ResinWallDoAfterEvent args)
+ {
+ if (args.Cancelled || args.Handled || component.Deleted)
+ return;
+
+ CreateStructure(uid, component, component.WallPrototype);
+ args.Handled = true;
+ }
+
+ private void OnWindowDoAfter(EntityUid uid, ResinSpinnerComponent component, ResinWindowDoAfterEvent args)
+ {
+ if (args.Cancelled || args.Handled || component.Deleted)
+ return;
+
+ CreateStructure(uid, component, component.WindowPrototype);
+ args.Handled = true;
+ }
+
+ private void OnNestDoAfter(EntityUid uid, ResinSpinnerComponent component, AlienNestDoAfterEvent args)
+ {
+ if (args.Cancelled || args.Handled || component.Deleted)
+ return;
+
+ CreateStructure(uid, component, component.NestPrototype, false);
+ args.Handled = true;
+ }
+
+ public void CreateStructure(EntityUid uid, ResinSpinnerComponent component, string structurePrototype, bool offset = true)
+ {
+
+ if (_container.IsEntityOrParentInContainer(uid))
+ return;
+
+ var xform = Transform(uid);
+ var offsetValue = new Vector2(0, 0);
+ if (offset)
+ offsetValue = xform.LocalRotation.ToWorldVec();
+
+ var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan);
+ var tile = coords.GetTileRef(EntityManager, _mapMan);
+ if (tile == null)
+ return;
+
+ // Check there are no walls there
+ if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable))
+ {
+ _popupSystem.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+ }
+
+ // Check there are no mobs there
+ if (offset)
+ {
+ if (_lookupSystem.GetLocalEntitiesIntersecting(tile.Value, 0f).Any(entity => HasComp(entity) && entity != uid))
+ {
+ _popupSystem.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+ }
+ }
+
+ foreach (var entity in _lookupSystem.GetEntitiesInRange(coords, 0.1f))
+ {
+ if (Prototype(entity) == null)
+ continue;
+ if (Prototype(entity)!.ID != structurePrototype)
+ continue;
+ _popupSystem.PopupEntity(Loc.GetString("alien-create-structure-failed"), uid, uid);
+ return;
+ }
+ // Make sure we set the invisible wall to despawn properly
+ Spawn(structurePrototype, _turf.GetTileCenter(tile.Value));
+ _plasmaVessel.ChangePlasmaAmount(uid, -component.PlasmaCostWall);
+ }
+}
diff --git a/Content.Server/Chat/Commands/AliensayCommand.cs b/Content.Server/Chat/Commands/AliensayCommand.cs
new file mode 100644
index 00000000000..4adaee3f4e0
--- /dev/null
+++ b/Content.Server/Chat/Commands/AliensayCommand.cs
@@ -0,0 +1,46 @@
+using Content.Server.Chat.Managers;
+using Content.Server.Chat.Systems;
+using Content.Shared.Administration;
+using Robust.Shared.Console;
+using Robust.Shared.Enums;
+
+namespace Content.Server.Chat.Commands
+{
+ [AnyCommand]
+ internal sealed class AliensayCommand : IConsoleCommand
+ {
+ public string Command => "aliensay";
+ public string Description => "Send message to your hivemind";
+ public string Help => "aliensay ";
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ if (shell.Player is not { } player)
+ {
+ shell.WriteError("This command cannot be run from the server.");
+ return;
+ }
+
+ if (player.Status != SessionStatus.InGame)
+ return;
+
+ if (player.AttachedEntity is not {} playerEntity)
+ {
+ shell.WriteError("You don't have an entity!");
+ return;
+ }
+
+ if (args.Length < 1)
+ return;
+
+ var message = string.Join(" ", args).Trim();
+ if (string.IsNullOrEmpty(message))
+ return;
+
+ IoCManager.Resolve().GetEntitySystem()
+ .TrySendXenoHivemindMessage(playerEntity, message, InGameOOCChatType.HiveXeno, false, shell, player);
+
+
+ }
+ }
+}
diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs
index be6e8b78fef..dbd89d42d0b 100644
--- a/Content.Server/Chat/Systems/ChatSystem.cs
+++ b/Content.Server/Chat/Systems/ChatSystem.cs
@@ -13,6 +13,7 @@
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.ActionBlocker;
+using Content.Shared.Aliens.Components;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Database;
@@ -307,6 +308,38 @@ public void TrySendInGameOOCMessage(
}
}
+ public void TrySendXenoHivemindMessage(
+ EntityUid source,
+ string message,
+ InGameOOCChatType type,
+ bool hideChat,
+ IConsoleShell? shell = null,
+ ICommonSession? player = null
+ )
+ {
+ if (!CanSendInGame(message, shell, player))
+ return;
+
+ if (player != null && !_chatManager.HandleRateLimit(player))
+ return;
+
+ // It doesn't make any sense for a non-player to send in-game OOC messages, whereas non-players may be sending
+ // in-game IC messages.
+ if (player?.AttachedEntity is not { Valid: true } entity || source != entity)
+ return;
+
+ message = SanitizeInGameOOCMessage(message);
+
+ var sendType = type;
+
+ switch (sendType)
+ {
+ case InGameOOCChatType.HiveXeno:
+ SendXenoHivemindChat(source, player, message, hideChat);
+ break;
+ }
+ }
+
#region Announcements
///
@@ -619,6 +652,36 @@ private void SendDeadChat(EntityUid source, ICommonSession player, string messag
_chatManager.ChatMessageToMany(ChatChannel.Dead, message, wrappedMessage, source, hideChat, true, clients.ToList(), author: player.UserId);
}
+
+ private void SendXenoHivemindChat(EntityUid source, ICommonSession player, string message, bool hideChat)
+ {
+ var clients = GetXenoChatClients();
+ var playerName = Name(source);
+ var speech = GetSpeechVerb(source, message);
+ string wrappedMessage;
+ if (!HasComp(source))
+ {
+ wrappedMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message",
+ ("entityName", playerName),
+ ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
+ ("fontType", speech.FontId),
+ ("fontSize", speech.FontSize),
+ ("message", FormattedMessage.EscapeText(message)));
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Xeno Hivemind chat from {player:Player}: {message}");
+ }
+ else
+ {
+ wrappedMessage = Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message",
+ ("entityName", playerName),
+ ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))),
+ ("fontType", speech.FontId),
+ ("fontSize", 25),
+ ("message", FormattedMessage.EscapeText(message)));
+ _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Xeno Hivemind chat from queen {player:Player}: {message}");
+ }
+ if (HasComp(source))
+ _chatManager.ChatMessageToMany(ChatChannel.XenoHivemind, message, wrappedMessage, source, hideChat, true, clients.ToList(), author: player.UserId);
+ }
#endregion
#region Utility
@@ -766,6 +829,14 @@ private IEnumerable GetDeadChatClients()
.Select(p => p.Channel);
}
+ private IEnumerable GetXenoChatClients()
+ {
+ return Filter.Empty()
+ .AddWhereAttachedEntity(HasComp)
+ .Recipients
+ .Select(p => p.Channel);
+ }
+
private string SanitizeMessagePeriod(string message)
{
if (string.IsNullOrEmpty(message))
@@ -960,7 +1031,8 @@ public enum InGameICChatType : byte
public enum InGameOOCChatType : byte
{
Looc,
- Dead
+ Dead,
+ HiveXeno
}
///
diff --git a/Content.Server/Devour/DevourSystem.cs b/Content.Server/Devour/DevourSystem.cs
index febbd093a6c..86116bd6877 100644
--- a/Content.Server/Devour/DevourSystem.cs
+++ b/Content.Server/Devour/DevourSystem.cs
@@ -46,4 +46,3 @@ private void OnDoAfter(EntityUid uid, DevourerComponent component, DevourDoAfter
_audioSystem.PlayPvs(component.SoundDevour, uid);
}
}
-
diff --git a/Content.Server/Medical/VomitActionSystem.cs b/Content.Server/Medical/VomitActionSystem.cs
new file mode 100644
index 00000000000..4f21543782a
--- /dev/null
+++ b/Content.Server/Medical/VomitActionSystem.cs
@@ -0,0 +1,26 @@
+using Content.Server.Body.Systems;
+using Content.Server.Medical.Components;
+using Content.Shared.Medical;
+
+namespace Content.Server.Medical;
+
+///
+/// This handles...
+///
+public sealed class VomitActionSystem : SharedVomitActionSystem
+{
+ ///
+ [Dependency] private readonly VomitSystem _vomit = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnVomitAction);
+ }
+
+ protected void OnVomitAction(EntityUid uid, VomitActionComponent component, VomitActionEvent args)
+ {
+ _vomit.Vomit(uid, component.ThirstAdded, component.HungerAdded);
+ ContainerSystem.EmptyContainer(component.Stomach, true);
+ }
+}
diff --git a/Content.Server/Polymorph/Components/TimedPolymorphComponent.cs b/Content.Server/Polymorph/Components/TimedPolymorphComponent.cs
new file mode 100644
index 00000000000..8a918e8b356
--- /dev/null
+++ b/Content.Server/Polymorph/Components/TimedPolymorphComponent.cs
@@ -0,0 +1,28 @@
+using System.Threading;
+using Content.Shared.Polymorph;
+using Content.Shared.Whitelist;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Polymorph.Components;
+
+///
+/// This is used for polymorphing entity after time
+///
+[RegisterComponent]
+public sealed partial class TimedPolymorphComponent : Component
+{
+ [DataField(required: true)]
+ public ProtoId PolymorphPrototype;
+
+ [DataField]
+ public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/forcewall.ogg");
+
+ [DataField]
+ public float PolymorphTime = 5f;
+
+ [DataField]
+ public bool Enabled = true;
+
+ public CancellationTokenSource? TokenSource;
+}
diff --git a/Content.Server/Polymorph/Systems/TimedPolymorphSystem.cs b/Content.Server/Polymorph/Systems/TimedPolymorphSystem.cs
new file mode 100644
index 00000000000..3474692ff52
--- /dev/null
+++ b/Content.Server/Polymorph/Systems/TimedPolymorphSystem.cs
@@ -0,0 +1,38 @@
+using System.Threading;
+
+using Content.Server.Polymorph.Components;
+
+namespace Content.Server.Polymorph.Systems;
+
+///
+/// This handles polymorphing entity after time
+///
+public sealed class TimedPolymorphSystem : EntitySystem
+{
+ [Dependency] private readonly PolymorphSystem _polymorph = default!;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnPolymorphInit);
+ SubscribeLocalEvent(OnTimedPolymorphShutdown);
+ }
+
+ private void OnPolymorphInit(EntityUid uid, TimedPolymorphComponent component, ComponentInit args)
+ {
+ component.TokenSource?.Cancel();
+ component.TokenSource = new CancellationTokenSource();
+ uid.SpawnRepeatingTimer(TimeSpan.FromSeconds(component.PolymorphTime), () => OnTimerFired(uid, component), component.TokenSource.Token);
+ }
+
+ private void OnTimerFired(EntityUid uid, TimedPolymorphComponent component)
+ {
+ if (component.Enabled)
+ _polymorph.PolymorphEntity(uid, component.PolymorphPrototype);
+ }
+
+ private void OnTimedPolymorphShutdown(EntityUid uid, TimedPolymorphComponent component, ComponentShutdown args)
+ {
+ component.TokenSource?.Cancel();
+ }
+}
diff --git a/Content.Server/Spawners/Components/AreaSpawnerComponent.cs b/Content.Server/Spawners/Components/AreaSpawnerComponent.cs
new file mode 100644
index 00000000000..1bef3537e26
--- /dev/null
+++ b/Content.Server/Spawners/Components/AreaSpawnerComponent.cs
@@ -0,0 +1,37 @@
+using System.Threading;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Spawners.Components;
+
+///
+/// Spawns Entities in area around spawner
+///
+[RegisterComponent]
+public sealed partial class AreaSpawnerComponent : Component
+{
+ // Maximum offset of entities spawned.
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField]
+ public float Radius;
+
+ // Prototype of entity spawned
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("spawnPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string SpawnPrototype;
+
+ ///
+ /// Length of the interval between spawn attempts.
+ ///
+ [DataField]
+ public int IntervalSeconds = 20;
+
+ // This will spawn entities to every tile in spawn radius
+ [DataField]
+ public bool SpawnToAllValidTiles = true;
+
+ [ViewVariables]
+ public int SpawnRadius;
+
+ public CancellationTokenSource? TokenSource;
+}
diff --git a/Content.Server/Spawners/EntitySystems/AreaSpawnerSystem.cs b/Content.Server/Spawners/EntitySystems/AreaSpawnerSystem.cs
new file mode 100644
index 00000000000..e7556c2e447
--- /dev/null
+++ b/Content.Server/Spawners/EntitySystems/AreaSpawnerSystem.cs
@@ -0,0 +1,167 @@
+using System.Linq;
+using System.Numerics;
+using System.Threading;
+using Content.Server.Spawners.Components;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.Directions;
+using Content.Shared.Maps;
+using Content.Shared.Physics;
+using Content.Shared.Random;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Spawners.EntitySystems;
+
+///
+/// Spawns entities in area around core, progressing from center to edges.
+///
+public sealed class AreaSpawnerSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly IPrototypeManager _protoMan = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnSpawnerInit);
+ SubscribeLocalEvent(OnTimedSpawnerShutdown);
+ }
+
+ private void OnSpawnerInit(EntityUid uid, AreaSpawnerComponent component, ComponentInit args)
+ {
+ component.TokenSource?.Cancel();
+ component.TokenSource = new CancellationTokenSource();
+ uid.SpawnRepeatingTimer(TimeSpan.FromSeconds(component.IntervalSeconds), () => OnTimerFired(uid, component), component.TokenSource.Token);
+ }
+
+ ///
+ /// If there is any space near the core, spawning entity, else increasing spawn radius, until it will be equal to radius in the component.
+ ///
+ /// Entity uid
+ /// AreaSpawner component
+ private void OnTimerFired(EntityUid uid, AreaSpawnerComponent component)
+ {
+ var validTiles = GetValidTilesInRadius(uid, component, component.SpawnRadius);
+ while (validTiles.Count == 0 && component.SpawnRadius <= component.Radius)
+ {
+ component.SpawnRadius++;
+ validTiles = GetValidTilesInRadius(uid, component, component.SpawnRadius);
+ }
+
+ validTiles = GetValidTilesInRadius(uid, component, component.SpawnRadius);
+ RandomlySpawnEntity(uid, component, validTiles);
+ }
+
+ ///
+ /// Spawning entity in random chosen location from the list
+ ///
+ /// Entity uid
+ /// AreaSpawner component
+ /// List of possible location offsets from the core
+ public void RandomlySpawnEntity(EntityUid uid, AreaSpawnerComponent component, List locations)
+ {
+ if (component.SpawnToAllValidTiles)
+ {
+ foreach (var location in locations)
+ {
+ Spawn(component.SpawnPrototype, Transform(uid).Coordinates.Offset(location));
+ }
+ }
+ else
+ {
+ var location = locations.ElementAt(_random.Next(0, locations.Count));
+ Spawn(component.SpawnPrototype, Transform(uid).Coordinates.Offset(location));
+ }
+
+ }
+
+ ///
+ /// Getting valid for spawn tiles in radius
+ ///
+ /// Entity uid
+ /// AreaSpawner component
+ /// Radius in which we should search
+ /// List of location offsets from the core
+ public List GetValidTilesInRadius(EntityUid uid, AreaSpawnerComponent component, int radius)
+ {
+ var validTiles = new List();
+ for (var y = -radius; y <= radius; y++)
+ {
+ for (var x = -radius; x <= radius; x++)
+ {
+ var tile = new Vector2(x, y);
+ if (IsTileValidForSpawn(tile,
+ component.SpawnPrototype, uid))
+ validTiles.Add(tile);
+ }
+ }
+
+ return validTiles;
+ }
+
+ ///
+ /// Checking if there is neither walls, nor same entity in the tile
+ ///
+ ///
+ ///
+ ///
+ /// True if tile is valid for spawn, else if not
+ public bool IsTileValidForSpawn(Vector2 offset, string entityPrototype, EntityUid uid)
+ {
+ // Get the tile of spawn checker
+ var xform = Transform(uid);
+ var coords = xform.Coordinates.Offset(offset);
+ var tile = coords.GetTileRef(EntityManager, _mapMan);
+ if (tile == null)
+ return false;
+
+ // Check there are no walls there
+ if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable))
+ {
+ return false;
+ }
+
+ // Check there are no same entities in tile
+ foreach (var entity in _lookup.GetEntitiesInRange(coords, 0.1f))
+ {
+ if (Prototype(entity) == null)
+ continue;
+ if (Prototype(entity)!.ID == entityPrototype || Prototype(entity) == Prototype(uid))
+ return false;
+ }
+
+ var offsets = new List();
+
+ offsets.Add(new Vector2(0, 1));
+ offsets.Add(new Vector2(0, -1));
+ offsets.Add(new Vector2(1, 0));
+ offsets.Add(new Vector2(-1, 0));
+
+ foreach (var check in offsets)
+ {
+ foreach (var entity in _lookup.GetEntitiesInRange(coords.Offset(check), 0.1f))
+ {
+ if (Prototype(entity) == null)
+ continue;
+ if (Prototype(entity)!.ID == entityPrototype || Prototype(entity) == Prototype(uid))
+ return true;
+ }
+ }
+
+
+ return false;
+ }
+
+ private void OnTimedSpawnerShutdown(EntityUid uid, AreaSpawnerComponent component, ComponentShutdown args)
+ {
+ component.TokenSource?.Cancel();
+ }
+}
diff --git a/Content.Shared/Alert/AlertCategory.cs b/Content.Shared/Alert/AlertCategory.cs
index 7450f585a4e..8f64f3fd7ed 100644
--- a/Content.Shared/Alert/AlertCategory.cs
+++ b/Content.Shared/Alert/AlertCategory.cs
@@ -16,5 +16,6 @@ public enum AlertCategory
Hunger,
Thirst,
Toxins,
- Battery
+ Battery,
+ Counter
}
diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs
index b917dd692d7..19884301685 100644
--- a/Content.Shared/Alert/AlertType.cs
+++ b/Content.Shared/Alert/AlertType.cs
@@ -23,6 +23,9 @@ public enum AlertType : byte
HumanCrit,
HumanDead,
HumanHealth,
+ AlienCrit,
+ AlienDead,
+ AlienHealth,
BorgBattery,
BorgBatteryNone,
PilotingShuttle,
@@ -40,6 +43,7 @@ public enum AlertType : byte
VowOfSilence,
VowBroken,
Essence,
+ PlasmaCounter,
Corporeal,
Bleed,
Pacified,
diff --git a/Content.Shared/Aliens/Components/AcidMakerComponent.cs b/Content.Shared/Aliens/Components/AcidMakerComponent.cs
new file mode 100644
index 00000000000..fc2b7e648ee
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AcidMakerComponent.cs
@@ -0,0 +1,49 @@
+using Content.Shared.Aliens.Systems;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, NetworkedComponent, Access(typeof(AcidMakerSystem)), AutoGenerateComponentState]
+public sealed partial class AcidMakerComponent : Component
+{
+ ///
+ /// The text that pops up whenever making acid fails for not having enough plasma.
+ ///
+ [DataField("popupText")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string PopupText = "alien-action-fail-plasma";
+
+ ///
+ /// What will be produced at the end of the action.
+ ///
+ [DataField(required: true)]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public EntProtoId EntityProduced;
+
+ ///
+ /// The entity needed to actually make acid. This will be granted (and removed) upon the entity's creation.
+ ///
+ [DataField(required: true)]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public EntProtoId Action;
+
+ [AutoNetworkedField]
+ [DataField("actionEntity")]
+ public EntityUid? ActionEntity;
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making acid.
+ ///
+ [DataField("plasmaCost")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float PlasmaCost = 150f;
+
+}
diff --git a/Content.Shared/Aliens/Components/AlienComponent.cs b/Content.Shared/Aliens/Components/AlienComponent.cs
new file mode 100644
index 00000000000..e457f76b267
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienComponent.cs
@@ -0,0 +1,56 @@
+using Content.Shared.Actions;
+using Content.Shared.Damage;
+using Content.Shared.FixedPoint;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState(true)]
+public sealed partial class AlienComponent : Component
+{
+ // Actions
+ [DataField]
+ public EntProtoId ToggleLightingAction = "ActionToggleLightingAlien";
+
+ [DataField, AutoNetworkedField]
+ public EntityUid? ToggleLightingActionEntity;
+
+ [DataField("devourAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? DevourAction = "ActionDevour";
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making node.
+ ///
+ [DataField("plasmaCostNode")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float PlasmaCostNode = 50f;
+
+ ///
+ /// The node prototype to use.
+ ///
+ [DataField("nodePrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string WeednodePrototype = "AlienWeednode";
+
+ [DataField("nodeAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? WeednodeAction = "ActionAlienNode";
+
+ [DataField]
+ public string Caste;
+
+ [DataField("nodeActionEntity")] public EntityUid? WeednodeActionEntity;
+
+ [DataField(required: true)]
+ public DamageSpecifier WeedHeal;
+
+}
+
+public sealed partial class ToggleLightingAlienActionEvent : InstantActionEvent { }
+
+public sealed partial class WeednodeActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Aliens/Components/AlienEvolutionComponent.cs b/Content.Shared/Aliens/Components/AlienEvolutionComponent.cs
new file mode 100644
index 00000000000..98a21338343
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienEvolutionComponent.cs
@@ -0,0 +1,44 @@
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienEvolutionComponent : Component
+{
+ [DataField]
+ public ProtoId DronePolymorphPrototype = "AlienEvolutionDrone";
+
+ [DataField("droneEvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? DroneEvolutionAction = "ActionEvolveDrone";
+
+ [DataField("droneEvolutionActionEntity")]
+ public EntityUid? DroneEvolutionActionEntity;
+
+ [DataField]
+ public ProtoId SentinelPolymorphPrototype = "AlienEvolutionSentinel";
+
+ [DataField("sentinelEvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? SentinelEvolutionAction = "ActionEvolveSentinel";
+
+ [DataField("sentinelEvolutionActionEntity")]
+ public EntityUid? SentinelEvolutionActionEntity;
+
+ [DataField]
+ public ProtoId HunterPolymorphPrototype = "AlienEvolutionHunter";
+
+ [DataField("hunterEvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? HunterEvolutionAction = "ActionEvolveHunter";
+
+ [DataField("hunterEvolutionActionEntity")]
+ public EntityUid? HunterEvolutionActionEntity;
+
+ [DataField("evolutionCooldown")]
+ public TimeSpan EvolutionCooldown;
+
+
+}
diff --git a/Content.Shared/Aliens/Components/AlienInfectedComponent.cs b/Content.Shared/Aliens/Components/AlienInfectedComponent.cs
new file mode 100644
index 00000000000..2a31e1f7f74
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienInfectedComponent.cs
@@ -0,0 +1,52 @@
+using System.Threading;
+using Content.Shared.StatusIcon;
+using Robust.Shared.Containers;
+using Robust.Shared.GameStates;
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AlienInfectedComponent : Component
+{
+
+ [DataField]
+ public float GrowTime = 2f;
+
+ [DataField]
+ public EntProtoId Prototype = "MobAlienLarvaInside";
+
+ [DataField]
+ public EntProtoId OrganProtoId = "AlienLarvaOrgan";
+
+ [DataField]
+ public EntProtoId PartProtoId = "AlienLarvaPart";
+
+ public readonly HashSet> InfectedIcons =
+ [
+ "AlienInfectedIconStageZero",
+ "AlienInfectedIconStageOne",
+ "AlienInfectedIconStageTwo",
+ "AlienInfectedIconStageThree",
+ "AlienInfectedIconStageFour",
+ "AlienInfectedIconStageFive"
+ ];
+
+ [ViewVariables]
+ public int GrowthStage = 0;
+
+ [DataField]
+ public float GrowProb = 0.03f;
+
+ [DataField]
+ public TimeSpan NextGrowRoll = TimeSpan.Zero;
+
+ public Container Stomach = default!;
+
+ public EntityUid SpawnedLarva;
+}
diff --git a/Content.Shared/Aliens/Components/AlienJumpComponent.cs b/Content.Shared/Aliens/Components/AlienJumpComponent.cs
new file mode 100644
index 00000000000..6583f1f37c4
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienJumpComponent.cs
@@ -0,0 +1,45 @@
+using Content.Shared.Actions;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienJumpComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite)]
+ public EntProtoId Action = "ActionJumpAlien";
+
+ [DataField("actionEntity")]
+ public EntityUid? ActionEntity;
+
+ [DataField]
+ public float JumpTime = 1f;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("jumpSprite")]
+ public ResPath JumpSprite { get; set; }
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("sprite")]
+ public ResPath Sprite { get; set; }
+
+ [ViewVariables]
+ public SpriteSpecifier? OldSprite;
+
+ [ViewVariables]
+ public bool Hit = false;
+}
+
+public sealed partial class AlienJumpActionEvent : WorldTargetActionEvent { }
+
+[NetSerializable]
+[Serializable]
+public enum JumpVisuals : byte
+{
+ Jumping
+}
diff --git a/Content.Shared/Aliens/Components/AlienQueenComponent.cs b/Content.Shared/Aliens/Components/AlienQueenComponent.cs
new file mode 100644
index 00000000000..fb3a5329f78
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienQueenComponent.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Actions;
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienQueenComponent : Component
+{
+ [DataField("plasmaCostNode")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float PlasmaCostEgg = 75f;
+
+ ///
+ /// The egg prototype to use.
+ ///
+ [DataField("eggPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string EggPrototype = "AlienEggGrowing";
+
+ [DataField("eggAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? EggAction = "ActionAlienEgg";
+
+ [DataField("eggActionEntity")] public EntityUid? EggActionEntity;
+
+ ///
+ /// The entity needed to actually make acid. This will be granted (and removed) upon the entity's creation.
+ ///
+ [DataField(required: true)]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public EntProtoId Action;
+
+ [DataField("actionEntity")]
+ public EntityUid? ActionEntity;
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making acid.
+ ///
+ [DataField("plasmaCost")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float PlasmaCostRoyalLarva = 300f;
+
+ [DataField("praetorianEvolutionPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string PraetorianPolymorphPrototype = "AlienEvolutionPraetorian";
+}
+
+public sealed partial class AlienEggActionEvent : InstantActionEvent { }
+
+public sealed partial class RoyalLarvaActionEvent : EntityTargetActionEvent { }
diff --git a/Content.Shared/Aliens/Components/AlienRoleComponent.cs b/Content.Shared/Aliens/Components/AlienRoleComponent.cs
new file mode 100644
index 00000000000..aaa22769691
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienRoleComponent.cs
@@ -0,0 +1,12 @@
+using Content.Shared.Roles;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, ExclusiveAntagonist]
+public sealed partial class AlienRoleComponent : AntagonistRoleComponent
+{
+
+}
diff --git a/Content.Shared/Aliens/Components/AlienStalkComponent.cs b/Content.Shared/Aliens/Components/AlienStalkComponent.cs
new file mode 100644
index 00000000000..dde7cc87805
--- /dev/null
+++ b/Content.Shared/Aliens/Components/AlienStalkComponent.cs
@@ -0,0 +1,26 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AlienStalkComponent : Component
+{
+
+ [DataField("stalkAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? StalkAction = "ActionStalkAlien";
+
+ [DataField("stalkActionEntity")]
+ public EntityUid? StalkActionEntity;
+
+ [DataField]
+ public int PlasmaCost = 5;
+
+ [ViewVariables]
+ public bool IsActive;
+
+ public float Sprint;
+}
diff --git a/Content.Shared/Aliens/Components/FacehuggerComponent.cs b/Content.Shared/Aliens/Components/FacehuggerComponent.cs
new file mode 100644
index 00000000000..4baa76f3a43
--- /dev/null
+++ b/Content.Shared/Aliens/Components/FacehuggerComponent.cs
@@ -0,0 +1,31 @@
+using System.Threading;
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class FacehuggerComponent : Component
+{
+ [DataField]
+ public float Range = 3f;
+
+ [DataField]
+ public bool Active = true;
+
+ [ViewVariables]
+ public TimeSpan GrowTime = TimeSpan.Zero;
+
+ [DataField]
+ public float EmbryoTime = 10f;
+
+ [DataField]
+ public ProtoId FacehuggerPolymorphPrototype = "FacehuggerToInactive";
+
+ public bool Equipped;
+
+ public EntityUid Equipee;
+}
diff --git a/Content.Shared/Aliens/Components/InsideAlienLarvaComponent.cs b/Content.Shared/Aliens/Components/InsideAlienLarvaComponent.cs
new file mode 100644
index 00000000000..1ca7e9b69fc
--- /dev/null
+++ b/Content.Shared/Aliens/Components/InsideAlienLarvaComponent.cs
@@ -0,0 +1,29 @@
+using Content.Shared.Actions;
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class InsideAlienLarvaComponent : Component
+{
+ [DataField]
+ public ProtoId PolymorphPrototype = "AlienLarvaGrow";
+
+ [DataField("EvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? EvolutionAction = "ActionLarvaGrow";
+
+ [DataField("EvolutionActionEntity")]
+ public EntityUid? EvolutionActionEntity;
+
+ [DataField("evolutionCooldown")]
+ public TimeSpan EvolutionCooldown = TimeSpan.Zero;
+
+ public bool IsGrown;
+}
+
+public sealed partial class AlienLarvaGrowActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Aliens/Components/PlasmaGainModifierComponent.cs b/Content.Shared/Aliens/Components/PlasmaGainModifierComponent.cs
new file mode 100644
index 00000000000..25b282aede4
--- /dev/null
+++ b/Content.Shared/Aliens/Components/PlasmaGainModifierComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for marking entity as plasma gaining modificator, when alien stands on it
+///
+[RegisterComponent]
+public sealed partial class PlasmaGainModifierComponent : Component
+{
+
+}
diff --git a/Content.Shared/Aliens/Components/PlasmaTransferComponent.cs b/Content.Shared/Aliens/Components/PlasmaTransferComponent.cs
new file mode 100644
index 00000000000..bea3d2ab7dd
--- /dev/null
+++ b/Content.Shared/Aliens/Components/PlasmaTransferComponent.cs
@@ -0,0 +1,24 @@
+using Content.Shared.Actions;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class PlasmaTransferComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite)]
+ public EntProtoId Action = "ActionAlienTransferPlasma";
+
+ [DataField("actionEntity")]
+ public EntityUid? ActionEntity;
+
+ [DataField]
+ public float Amount = 50f;
+}
+
+public sealed partial class TransferPlasmaActionEvent : EntityTargetActionEvent { }
+
+
diff --git a/Content.Shared/Aliens/Components/PlasmaVesselComponent.cs b/Content.Shared/Aliens/Components/PlasmaVesselComponent.cs
new file mode 100644
index 00000000000..24e763fa433
--- /dev/null
+++ b/Content.Shared/Aliens/Components/PlasmaVesselComponent.cs
@@ -0,0 +1,42 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class PlasmaVesselComponent : Component
+{
+ ///
+ /// The total amount of plasma the alien has.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public FixedPoint2 Plasma = 0;
+
+ ///
+ /// The entity's current max amount of essence. Can be increased
+ /// through harvesting player souls.
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("maxPlasma")]
+ public FixedPoint2 PlasmaRegenCap = 500;
+
+ [ViewVariables]
+ public FixedPoint2 PlasmaPerSecond = 1f;
+
+ ///
+ /// The amount of plasma passively generated per second.
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("plasmaPerSecond")]
+ public FixedPoint2 PlasmaUnmodified = 1f;
+
+ [ViewVariables]
+ public float Accumulator = 0;
+
+ ///
+ /// The amount of plasma to which plasma per second will be equal, when alien stands on weeds
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("plasmaModified")]
+ public float WeedModifier = 1.5f;
+}
diff --git a/Content.Shared/Aliens/Components/PraetorianEvolutionComponent.cs b/Content.Shared/Aliens/Components/PraetorianEvolutionComponent.cs
new file mode 100644
index 00000000000..1494b24d1e1
--- /dev/null
+++ b/Content.Shared/Aliens/Components/PraetorianEvolutionComponent.cs
@@ -0,0 +1,25 @@
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class PraetorianEvolutionComponent : Component
+{
+ [DataField]
+ public ProtoId PraetorianPolymorphPrototype = "AlienEvolutionPraetorian";
+
+ [DataField("praetorianEvolutionAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? PraetorianEvolutionAction = "ActionEvolvePraetorian";
+
+ [DataField("praetorianEvolutionActionEntity")]
+ public EntityUid? PraetorianEvolutionActionEntity;
+
+ [DataField("plasmaCost")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float PlasmaCost = 150f;
+}
diff --git a/Content.Shared/Aliens/Components/ResinSpinnerComponent.cs b/Content.Shared/Aliens/Components/ResinSpinnerComponent.cs
new file mode 100644
index 00000000000..15a69bbd0a7
--- /dev/null
+++ b/Content.Shared/Aliens/Components/ResinSpinnerComponent.cs
@@ -0,0 +1,97 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, AutoGenerateComponentState]
+public sealed partial class ResinSpinnerComponent : Component
+{
+ [DataField("popupText")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string PopupText = "alien-action-fail-plasma";
+
+ ///
+ /// How long will it take to make.
+ ///
+ [DataField("productionLengthWall")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float ProductionLengthWall = 2f;
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making structure.
+ ///
+ [DataField("plasmaCostWall")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float PlasmaCostWall = 60f;
+
+ ///
+ /// The wall prototype to use.
+ ///
+ [DataField("wallPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string WallPrototype = "WallResin";
+
+ [DataField("resinWallAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? ResinWallAction = "ActionAlienDroneWall";
+
+ [DataField("resinWallActionEntity")] public EntityUid? ResinWallActionEntity;
+
+ ///
+ /// How long will it take to make.
+ ///
+ [DataField("productionLengthWindow")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float ProductionLengthWindow = 2f;
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making structure.
+ ///
+ [DataField("plasmaCostWindow")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float PlasmaCostWindow = 60f;
+
+ ///
+ /// The wall prototype to use.
+ ///
+ [DataField("windowPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string WindowPrototype = "WindowResin";
+
+ [DataField("resinWindowAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? ResinWindowAction = "ActionWindowResin";
+
+ [DataField("resinWindowActionEntity")] public EntityUid? ResinWindowActionEntity;
+
+ ///
+ /// How long will it take to make.
+ ///
+ [DataField("productionLengthNest")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float ProductionLengthNest = 1f;
+
+ ///
+ /// This will subtract (not add, don't get this mixed up) from the current plasma of the mob making structure.
+ ///
+ [DataField("plasmaCostNest")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float PlasmaCostNest = 30f;
+
+ ///
+ /// The wall prototype to use.
+ ///
+ [DataField("nestPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string NestPrototype = "AlienNest";
+
+ [DataField("nestWindowAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? NestAction = "ActionAlienNest";
+
+ [DataField("nestActionEntity")] public EntityUid? NestActionEntity;
+}
diff --git a/Content.Shared/Aliens/Components/ShowInfectedIconsComponent.cs b/Content.Shared/Aliens/Components/ShowInfectedIconsComponent.cs
new file mode 100644
index 00000000000..bd889c26656
--- /dev/null
+++ b/Content.Shared/Aliens/Components/ShowInfectedIconsComponent.cs
@@ -0,0 +1,14 @@
+using Content.Shared.StatusIcon;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ShowInfectedIconsComponent : Component
+{
+
+}
diff --git a/Content.Shared/Aliens/Components/TailLashComponent.cs b/Content.Shared/Aliens/Components/TailLashComponent.cs
new file mode 100644
index 00000000000..fffa12dfc48
--- /dev/null
+++ b/Content.Shared/Aliens/Components/TailLashComponent.cs
@@ -0,0 +1,32 @@
+using Content.Shared.Actions;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Aliens.Components;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class TailLashComponent : Component
+{
+ [DataField("tailLashAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? TailLashAction = "ActionTailLash";
+
+ [DataField("tailLashActionEntity")] public EntityUid? TailLashActionEntity;
+
+ [DataField]
+ public float LashRange = 2f;
+
+ [DataField]
+ public int StunTime = 5;
+
+ [DataField]
+ public int Cooldown = 11;
+
+ [DataField("disarmSuccessSound")]
+ public SoundSpecifier LashSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg");
+}
+
+public sealed partial class TailLashActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Aliens/Systems/AcidMakerSystem.cs b/Content.Shared/Aliens/Systems/AcidMakerSystem.cs
new file mode 100644
index 00000000000..7041864a11d
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/AcidMakerSystem.cs
@@ -0,0 +1,74 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Popups;
+using Content.Shared.Stacks;
+using Robust.Shared.Network;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AcidMakerSystem : EntitySystem
+{
+ // Managers
+ [Dependency] private readonly INetManager _netManager = default!;
+
+ // Systems
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+ [Dependency] private readonly SharedStackSystem _stackSystem = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVesselSystem = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnCompRemove);
+ SubscribeLocalEvent(OnAcidMakingStart);
+ }
+
+ ///
+ /// Giveths the action to preform making acid on the entity
+ ///
+ private void OnMapInit(EntityUid uid, AcidMakerComponent comp, MapInitEvent args)
+ {
+ _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.Action);
+ }
+
+ ///
+ /// Takeths away the action to preform making acid from the entity.
+ ///
+ private void OnCompRemove(EntityUid uid, AcidMakerComponent comp, ComponentShutdown args)
+ {
+ _actionsSystem.RemoveAction(uid, comp.ActionEntity);
+ }
+
+ private void OnAcidMakingStart(EntityUid uid, AcidMakerComponent comp, AcidMakeActionEvent args)
+ {
+
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma < comp.PlasmaCost)
+ {
+ _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid);
+ return;
+ }
+
+ _plasmaVesselSystem.ChangePlasmaAmount(uid, -comp.PlasmaCost);
+ if (_netManager.IsClient) // Have to do this because spawning stuff in shared is CBT.
+ return;
+ var newEntity = Spawn(comp.EntityProduced, Transform(uid).Coordinates);
+
+ _stackSystem.TryMergeToHands(newEntity, uid);
+ }
+}
+
+///
+/// Should be relayed upon using the action.
+///
+public sealed partial class AcidMakeActionEvent : InstantActionEvent { }
+
diff --git a/Content.Shared/Aliens/Systems/AlienJumpSystem.cs b/Content.Shared/Aliens/Systems/AlienJumpSystem.cs
new file mode 100644
index 00000000000..ce1a5f7e04b
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/AlienJumpSystem.cs
@@ -0,0 +1,82 @@
+using System.Numerics;
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Maps;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Physics;
+using Content.Shared.Pinpointer;
+using Content.Shared.StatusEffect;
+using Content.Shared.Stunnable;
+using Content.Shared.Throwing;
+using Robust.Shared.Map;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class AlienJumpSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly ThrowingSystem _throwing = default!;
+ [Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly SharedStunSystem _stun = default!;
+ [Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnJump);
+ SubscribeLocalEvent(OnHit);
+ SubscribeLocalEvent(OnStop);
+ }
+
+ private void OnInit(EntityUid uid, AlienJumpComponent comp, ComponentStartup args)
+ {
+ _actions.AddAction(uid, ref comp.ActionEntity, comp.Action);
+ }
+
+ private void OnJump(EntityUid uid, AlienJumpComponent comp, AlienJumpActionEvent args)
+ {
+ args.Handled = true;
+
+ _throwing.TryThrow(uid, args.Target, 15f);
+ _appearance.SetData(uid, JumpVisuals.Jumping, true, Comp(uid));
+ }
+
+ private void OnHit(EntityUid uid, AlienJumpComponent comp, ThrowDoHitEvent args)
+ {
+ var xform = Transform(args.Target);
+ var coords = xform.Coordinates;
+ var tile = coords.GetTileRef(EntityManager, _mapMan);
+
+ if (tile == null)
+ return;
+
+ if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable))
+ {
+ _stun.TryParalyze(uid, TimeSpan.FromSeconds(4), true);
+ return;
+ }
+
+ if (HasComp(args.Target) && _statusEffect.CanApplyEffect(args.Target, "Stun"))
+ {
+ _stun.TryParalyze(args.Target, TimeSpan.FromSeconds(10), true);
+ _physics.SetBodyStatus(EnsureComp(uid), BodyStatus.OnGround);
+ }
+ }
+
+ private void OnStop(EntityUid uid, AlienJumpComponent comp, StopThrowEvent args)
+ {
+ _appearance.SetData(uid, JumpVisuals.Jumping, false, Comp(uid));
+ }
+}
diff --git a/Content.Shared/Aliens/Systems/SharedAlienEvolutionSystem.cs b/Content.Shared/Aliens/Systems/SharedAlienEvolutionSystem.cs
new file mode 100644
index 00000000000..e8a355225ce
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedAlienEvolutionSystem.cs
@@ -0,0 +1,25 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedAlienEvolutionSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
+
+public sealed partial class AlienDroneEvolveActionEvent : InstantActionEvent { }
+
+public sealed partial class AlienSentinelEvolveActionEvent : InstantActionEvent { }
+
+public sealed partial class AlienPraetorianEvolveActionEvent : InstantActionEvent { }
+
+public sealed partial class AlienHunterEvolveActionEvent : InstantActionEvent { }
+
+public sealed partial class AlienQueenEvolveActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Aliens/Systems/SharedAlienQueenSystem.cs b/Content.Shared/Aliens/Systems/SharedAlienQueenSystem.cs
new file mode 100644
index 00000000000..8c0f50c9aa0
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedAlienQueenSystem.cs
@@ -0,0 +1,41 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Popups;
+using Content.Shared.Stacks;
+using Robust.Shared.Network;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedAlienQueenSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnCompInit);
+ SubscribeLocalEvent(OnCompRemove);
+
+ }
+
+ ///
+ /// Giveths the action to preform making acid on the entity
+ ///
+ private void OnCompInit(EntityUid uid, AlienQueenComponent comp, ComponentStartup args)
+ {
+ _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.Action);
+ }
+
+ ///
+ /// Takeths away the action to preform making acid from the entity.
+ ///
+ private void OnCompRemove(EntityUid uid, AlienQueenComponent comp, ComponentShutdown args)
+ {
+ _actionsSystem.RemoveAction(uid, comp.ActionEntity);
+ }
+}
+
diff --git a/Content.Shared/Aliens/Systems/SharedAlienStalkSystem.cs b/Content.Shared/Aliens/Systems/SharedAlienStalkSystem.cs
new file mode 100644
index 00000000000..3f8c47b9146
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedAlienStalkSystem.cs
@@ -0,0 +1,65 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Stealth;
+using Content.Shared.Stealth.Components;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedAlienStalkSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly SharedStealthSystem _stealth = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVessel = default!;
+ public override void Initialize()
+ {
+ base. Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+ SubscribeLocalEvent(OnStalk);
+ }
+
+ private void OnComponentInit(EntityUid uid, AlienStalkComponent component, ComponentInit args)
+ {
+ _actionsSystem.AddAction(uid, ref component.StalkActionEntity, component.StalkAction, uid);
+
+ component.Sprint = EnsureComp(uid).BaseWalkSpeed;
+ }
+
+ private void OnStalk(EntityUid uid, AlienStalkComponent component, AlienStalkActionEvent args)
+ {
+ var stealth = EnsureComp(uid);
+ var movementSpeedMofifier = EnsureComp(uid);
+ var sprint = component.Sprint;
+ component.Sprint = movementSpeedMofifier.BaseSprintSpeed;
+ _movementSpeedModifier.ChangeBaseSpeed(uid, movementSpeedMofifier.BaseWalkSpeed, sprint,
+ movementSpeedMofifier.Acceleration);
+ _stealth.SetVisibility(uid, 0.2f, stealth);
+ _stealth.SetEnabled(uid, !component.IsActive, stealth);
+ component.IsActive = !component.IsActive;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var alien))
+ {
+ if(TryComp(uid, out var stalk)
+ && alien.Plasma >= stalk.PlasmaCost
+ && stalk.IsActive)
+ {
+ _plasmaVessel.ChangePlasmaAmount(uid, -stalk.PlasmaCost, alien);
+ }
+ }
+ }
+}
+
+public sealed partial class AlienStalkActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Aliens/Systems/SharedFacehuggerSystem.cs b/Content.Shared/Aliens/Systems/SharedFacehuggerSystem.cs
new file mode 100644
index 00000000000..401accd9778
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedFacehuggerSystem.cs
@@ -0,0 +1,87 @@
+using System.Linq;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Ghost;
+using Content.Shared.Hands.Components;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.IdentityManagement.Components;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedFacehuggerSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly InventorySystem _inventory = default!;
+ public override void Initialize()
+ {
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+
+ var validEntities = new Dictionary();
+
+ while (query.MoveNext(out var uid, out var alien))
+ {
+ foreach (var entity in _lookup.GetEntitiesInRange(uid, alien.Range)
+ .Where(entity => _inventory.HasSlot(entity, "mask")))
+ {
+ if (!_inventory.CanAccess(uid, entity, uid) ||
+ EnsureComp(uid).CurrentState != MobState.Alive)
+ continue;
+ if(Prototype(entity) != null && Prototype(entity)!.ID == "AdminObserver")
+ continue;
+ if(!HasComp(entity) || Comp(entity).CurrentState == MobState.Dead)
+ continue;
+ if(HasComp(entity))
+ continue;
+ if(HasComp(entity))
+ continue;
+ if(!alien.Active)
+ continue;
+ validEntities.TryAdd(uid, entity);
+ }
+ }
+
+ var invalidEntities = new Dictionary();
+
+ foreach (var entity in validEntities)
+ {
+
+ var queryHelmets = EntityQueryEnumerator();
+ while (queryHelmets.MoveNext(out var helmet, out _))
+ {
+ var hands = CompOrNull(entity.Value);
+ if (!_inventory.GetHandOrInventoryEntities(entity.Value, SlotFlags.HEAD).Contains(helmet))
+ continue;
+ if (_inventory.GetHandOrInventoryEntities(entity.Value, SlotFlags.HEAD).Contains(helmet) &&
+ hands != null &&
+ _hands.IsHolding(entity.Value, helmet, out _, hands))
+ continue;
+
+ validEntities.Remove(entity.Key);
+ invalidEntities.TryAdd(entity.Key, entity.Value);
+ break;
+ }
+
+ if (invalidEntities.ContainsKey(entity.Key))
+ continue;
+ _inventory.TryUnequip(entity.Value, "mask", true);
+ _inventory.TryEquip(entity.Value, entity.Key, "mask", true);
+
+
+ }
+ }
+}
diff --git a/Content.Shared/Aliens/Systems/SharedPlasmaGainModifierSystem.cs b/Content.Shared/Aliens/Systems/SharedPlasmaGainModifierSystem.cs
new file mode 100644
index 00000000000..4b59cb90a2b
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedPlasmaGainModifierSystem.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Aliens.Components;
+using Content.Shared.StepTrigger.Systems;
+using Robust.Shared.Physics.Events;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedPlasmaGainModifierSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+
+ }
+
+}
diff --git a/Content.Shared/Aliens/Systems/SharedPlasmaTransferSystem.cs b/Content.Shared/Aliens/Systems/SharedPlasmaTransferSystem.cs
new file mode 100644
index 00000000000..c392d7fd6a7
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedPlasmaTransferSystem.cs
@@ -0,0 +1,68 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Popups;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedPlasmaTransferSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPlasmaVesselSystem _plasmaVessel = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnCompInit);
+ SubscribeLocalEvent(OnCompRemove);
+ SubscribeLocalEvent(OnPlasmaTransfer);
+
+ }
+
+ ///
+ /// Giveths the action to preform making acid on the entity
+ ///
+ private void OnCompInit(EntityUid uid, PlasmaTransferComponent comp, ComponentStartup args)
+ {
+ _actions.AddAction(uid, ref comp.ActionEntity, comp.Action);
+ }
+
+ public void OnPlasmaTransfer(EntityUid uid, PlasmaTransferComponent component, TransferPlasmaActionEvent args)
+ {
+ if (args.Handled)
+ {
+ return;
+ }
+
+ args.Handled = true;
+ if (!HasComp(args.Target))
+ {
+ _popup.PopupEntity(Loc.GetString("alien-transfer-fail"), uid);
+ return;
+ }
+
+ var plasmaVesselSelf = Comp(uid);
+ var plasmaVesselTarget = Comp(args.Target);
+ if (plasmaVesselSelf.Plasma >= component.Amount && component.Amount + plasmaVesselTarget.Plasma < plasmaVesselTarget.PlasmaRegenCap)
+ {
+ _plasmaVessel.ChangePlasmaAmount(uid, -component.Amount);
+ _plasmaVessel.ChangePlasmaAmount(args.Target, component.Amount);
+ }
+ else
+ {
+ _popup.PopupEntity(Loc.GetString("alien-transfer-fail"), uid);
+ }
+ }
+
+ ///
+ /// Takeths away the action to preform plasma transfer from the entity.
+ ///
+ private void OnCompRemove(EntityUid uid, PlasmaTransferComponent comp, ComponentShutdown args)
+ {
+ _actions.RemoveAction(uid, comp.ActionEntity);
+ }
+}
diff --git a/Content.Shared/Aliens/Systems/SharedPlasmaVesselSystem.cs b/Content.Shared/Aliens/Systems/SharedPlasmaVesselSystem.cs
new file mode 100644
index 00000000000..4efaa2b5519
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedPlasmaVesselSystem.cs
@@ -0,0 +1,91 @@
+using Content.Shared.Alert;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Chat;
+using Content.Shared.FixedPoint;
+using Content.Shared.Popups;
+using PlasmaVesselComponent = Content.Shared.Aliens.Components.PlasmaVesselComponent;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedPlasmaVesselSystem : EntitySystem
+{
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly AlertsSystem _alerts = default!;
+ public override void Initialize()
+ {
+
+ }
+
+ public bool ChangePlasmaGain(EntityUid uid, float modifier, PlasmaVesselComponent? component = null)
+ {
+ if (component == null)
+ {
+ return false;
+ }
+ component.PlasmaPerSecond *= modifier;
+
+ return true;
+ }
+
+ public bool ChangePlasmaAmount(EntityUid uid, FixedPoint2 amount, PlasmaVesselComponent? component = null, bool regenCap = false)
+ {
+ if (!Resolve(uid, ref component))
+ return false;
+
+ component.Plasma += amount;
+
+ if (regenCap)
+ FixedPoint2.Min(component.Plasma, component.PlasmaRegenCap);
+
+ var stalk = CompOrNull(uid);
+ if (stalk != null && stalk.IsActive)
+ {
+ return true;
+ }
+ if(amount != component.PlasmaUnmodified && amount != component.WeedModifier)
+ {
+ _popup.PopupEntity(Loc.GetString("alien-plasma-left", ("value", component.Plasma)), uid, uid);
+ }
+
+ _alerts.ShowAlert(uid, AlertType.PlasmaCounter, (short) Math.Clamp(Math.Round(component.Plasma.Float() / 50f), 0, 10));
+
+ return true;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var alien))
+ {
+ alien.Accumulator += frameTime;
+
+ if (alien.Accumulator <= 1)
+ continue;
+ alien.Accumulator -= 1;
+
+ var weed = false;
+ foreach (var entity in _lookup.GetEntitiesInRange(Transform(uid).Coordinates, 0.1f))
+ {
+ if (HasComp(entity))
+ {
+ alien.PlasmaPerSecond = alien.WeedModifier;
+ weed = true;
+ }
+ }
+
+ if (!weed)
+ alien.PlasmaPerSecond = alien.PlasmaUnmodified;
+
+ if (alien.Plasma < alien.PlasmaRegenCap)
+ {
+ ChangePlasmaAmount(uid, alien.PlasmaPerSecond, alien, regenCap: true);
+ }
+ }
+ }
+}
diff --git a/Content.Shared/Aliens/Systems/SharedPraetorianEvolutionSystem.cs b/Content.Shared/Aliens/Systems/SharedPraetorianEvolutionSystem.cs
new file mode 100644
index 00000000000..f98094ca49b
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedPraetorianEvolutionSystem.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class SharedPraetorianEvolutionSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
+
+
diff --git a/Content.Shared/Aliens/Systems/SharedResinSpinnerSystem.cs b/Content.Shared/Aliens/Systems/SharedResinSpinnerSystem.cs
new file mode 100644
index 00000000000..5edbf521578
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/SharedResinSpinnerSystem.cs
@@ -0,0 +1,92 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.DoAfter;
+using Content.Shared.Maps;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Physics;
+using Content.Shared.Popups;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+/// .
+public sealed class SharedResinSpinnerSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
+ [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnWall);
+ SubscribeLocalEvent(OnWindow);
+ SubscribeLocalEvent(OnNest);
+ }
+
+ private void OnComponentInit(EntityUid uid, ResinSpinnerComponent component, ComponentInit args)
+ {
+ _actionsSystem.AddAction(uid, ref component.ResinWallActionEntity, component.ResinWallAction, uid);
+ _actionsSystem.AddAction(uid, ref component.ResinWindowActionEntity, component.ResinWindowAction, uid);
+ _actionsSystem.AddAction(uid, ref component.NestActionEntity, component.NestAction, uid);
+ }
+
+ private void OnWall(EntityUid uid, ResinSpinnerComponent component, ResinWallActionEvent args)
+ {
+ OnStructureMaking(uid, component.PlasmaCostWall, component.ProductionLengthWall, component, new ResinWallDoAfterEvent());
+ }
+
+ private void OnWindow(EntityUid uid, ResinSpinnerComponent component, ResinWindowActionEvent args)
+ {
+ OnStructureMaking(uid, component.PlasmaCostWindow, component.ProductionLengthWindow, component, new ResinWindowDoAfterEvent());
+ }
+
+ private void OnNest(EntityUid uid, ResinSpinnerComponent component, AlienNestActionEvent args)
+ {
+ OnStructureMaking(uid, component.PlasmaCostNest, component.ProductionLengthNest, component, new AlienNestDoAfterEvent());
+ }
+
+ private void OnStructureMaking(EntityUid uid, float cost, float productionLength, ResinSpinnerComponent component, DoAfterEvent doAfterEvent)
+ {
+ if (TryComp(uid, out var plasmaComp)
+ && plasmaComp.Plasma < cost)
+ {
+ _popupSystem.PopupClient(Loc.GetString(component.PopupText), uid, uid);
+ return;
+ }
+
+ var doAfter = new DoAfterArgs(EntityManager, uid, productionLength, doAfterEvent, uid)
+ {
+ BlockDuplicate = true,
+ BreakOnDamage = true,
+ CancelDuplicate = true,
+ BreakOnUserMove = true
+ };
+
+ _doAfterSystem.TryStartDoAfter(doAfter);
+ }
+}
+
+public sealed partial class ResinWallActionEvent : InstantActionEvent { }
+
+public sealed partial class ResinWindowActionEvent : InstantActionEvent { }
+
+public sealed partial class AlienNestActionEvent : InstantActionEvent { }
+
+///
+/// Is relayed at the end of the making structure.
+///
+[Serializable, NetSerializable]
+public sealed partial class ResinWallDoAfterEvent : SimpleDoAfterEvent { }
+
+[Serializable, NetSerializable]
+public sealed partial class ResinWindowDoAfterEvent : SimpleDoAfterEvent { }
+
+[Serializable, NetSerializable]
+public sealed partial class AlienNestDoAfterEvent : SimpleDoAfterEvent { }
diff --git a/Content.Shared/Aliens/Systems/TailLashSystem.cs b/Content.Shared/Aliens/Systems/TailLashSystem.cs
new file mode 100644
index 00000000000..823206a38b7
--- /dev/null
+++ b/Content.Shared/Aliens/Systems/TailLashSystem.cs
@@ -0,0 +1,45 @@
+using Content.Shared.Actions;
+using Content.Shared.Aliens.Components;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Stunnable;
+using Robust.Shared.Audio.Systems;
+
+namespace Content.Shared.Aliens.Systems;
+
+///
+/// This handles...
+///
+public sealed class TailLashSystem : EntitySystem
+{
+ ///
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedStunSystem _stun = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+
+ SubscribeLocalEvent(OnLash);
+ }
+
+ private void OnComponentInit(EntityUid uid, TailLashComponent component, ComponentInit args)
+ {
+ _actions.AddAction(uid, ref component.TailLashActionEntity, component.TailLashAction, uid);
+ }
+
+ private void OnLash(EntityUid uid, TailLashComponent component, TailLashActionEvent args)
+ {
+ _audio.PlayPredicted(component.LashSound, uid, uid);
+ foreach (var entity in _lookup.GetEntitiesInRange(uid, component.LashRange))
+ {
+ if (HasComp(entity))
+ {
+ _stun.TryParalyze(entity, TimeSpan.FromSeconds(component.StunTime), true);
+ }
+ }
+ _actions.SetCooldown(component.TailLashActionEntity, TimeSpan.FromSeconds(component.Cooldown));
+ }
+}
diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs
index f25e1b03741..0f71361cd97 100644
--- a/Content.Shared/Buckle/Components/StrapComponent.cs
+++ b/Content.Shared/Buckle/Components/StrapComponent.cs
@@ -26,6 +26,14 @@ public sealed partial class StrapComponent : Component
[ViewVariables]
public EntityWhitelist? AllowedEntities;
+ ///
+ /// The amount of time that must pass for this entity to
+ /// be able to unbuckle after recently buckling.
+ ///
+ [DataField]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public TimeSpan Delay = TimeSpan.FromSeconds(0.25f);
+
///
/// The change in position to the strapped mob
///
diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs
index b58bdf83e49..5af7c84f33c 100644
--- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs
+++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs
@@ -399,6 +399,9 @@ public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force = fal
buckleComp.BuckledTo is not { } strapUid)
return false;
+ if (CompOrNull(strapUid) != null && Comp(strapUid).Delay > buckleComp.Delay)
+ buckleComp.Delay = Comp(strapUid).Delay;
+
if (!force)
{
var attemptEvent = new BuckleAttemptEvent(strapUid, buckleUid, userUid, false);
@@ -408,7 +411,11 @@ public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force = fal
return false;
if (_gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay)
+ {
+ _popup.PopupEntity(Loc.GetString("unbuckling-wait-message", ("delay", Math.Round((buckleComp.Delay - _gameTiming.CurTime + buckleComp.BuckleTime).TotalSeconds))), buckleUid, buckleUid);
return false;
+ }
+
if (!_interaction.InRangeUnobstructed(userUid, strapUid, buckleComp.Range, popup: true))
return false;
diff --git a/Content.Shared/Chat/ChatChannel.cs b/Content.Shared/Chat/ChatChannel.cs
index d87fcbc075e..71d542aff0c 100644
--- a/Content.Shared/Chat/ChatChannel.cs
+++ b/Content.Shared/Chat/ChatChannel.cs
@@ -90,10 +90,12 @@ public enum ChatChannel : ushort
///
Telepathic = 1 << 15,
+ XenoHivemind = 2 << 2,
+
///
/// Channels considered to be IC.
///
- IC = Local | Whisper | Radio | Dead | Emotes | Damage | Visual | Telepathic | Notifications, //Nyano - Summary: Adds telepathic as an 'IC' labelled chat..
+ IC = Local | Whisper | Radio | Dead | Emotes | Damage | Visual | Telepathic | Notifications | XenoHivemind, //Nyano - Summary: Adds telepathic as an 'IC' labelled chat..
AdminRelated = Admin | AdminAlert | AdminChat,
}
diff --git a/Content.Shared/Chat/ChatChannelExtensions.cs b/Content.Shared/Chat/ChatChannelExtensions.cs
index 9b707a53a0e..7dc57096513 100644
--- a/Content.Shared/Chat/ChatChannelExtensions.cs
+++ b/Content.Shared/Chat/ChatChannelExtensions.cs
@@ -15,6 +15,7 @@ public static Color TextColor(this ChatChannel channel)
ChatChannel.AdminAlert => Color.Red,
ChatChannel.AdminChat => Color.HotPink,
ChatChannel.Whisper => Color.DarkGray,
+ ChatChannel.XenoHivemind => Color.FromHex("#600a91"),
_ => Color.LightGray
};
}
diff --git a/Content.Shared/Chat/ChatSelectChannel.cs b/Content.Shared/Chat/ChatSelectChannel.cs
index 5104bbc3068..865620fe51a 100644
--- a/Content.Shared/Chat/ChatSelectChannel.cs
+++ b/Content.Shared/Chat/ChatSelectChannel.cs
@@ -52,10 +52,12 @@ public enum ChatSelectChannel : ushort
Admin = ChatChannel.AdminChat,
///
- /// Nyano - Summary:. Telepathic channel for all psionic entities.
+ /// Nyano - Summary:. Telepathic channel for all psionic entities.
///
Telepathic = ChatChannel.Telepathic,
+ XenoHivemind = ChatChannel.XenoHivemind,
+
Console = ChatChannel.Unspecified
}
}
diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs
index 8d14adcc24b..8128f137731 100644
--- a/Content.Shared/Chat/SharedChatSystem.cs
+++ b/Content.Shared/Chat/SharedChatSystem.cs
@@ -21,8 +21,9 @@ public abstract class SharedChatSystem : EntitySystem
public const char EmotesAltPrefix = '*';
public const char AdminPrefix = ']';
public const char WhisperPrefix = ',';
- public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix.
+ public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix.
public const char DefaultChannelKey = 'h';
+ public const char XenoHivemindPrefix = 'a';
[ValidatePrototypeId]
public const string CommonChannel = "Common";
diff --git a/Content.Shared/Devour/Components/DevourerComponent.cs b/Content.Shared/Devour/Components/DevourerComponent.cs
index fbeec28ca57..425be6aacd9 100644
--- a/Content.Shared/Devour/Components/DevourerComponent.cs
+++ b/Content.Shared/Devour/Components/DevourerComponent.cs
@@ -1,4 +1,5 @@
using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Mobs;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
@@ -59,6 +60,13 @@ public sealed partial class DevourerComponent : Component
}
};
+ [ViewVariables(VVAccess.ReadWrite), DataField("consumes")]
+ public HashSet Consumes = new()
+ {
+ MobState.Critical,
+ MobState.Dead
+ };
+
///
/// The chemical ID injected upon devouring
///
diff --git a/Content.Shared/Devour/SharedDevourSystem.cs b/Content.Shared/Devour/SharedDevourSystem.cs
index a2b788f3f38..f74ced741ae 100644
--- a/Content.Shared/Devour/SharedDevourSystem.cs
+++ b/Content.Shared/Devour/SharedDevourSystem.cs
@@ -1,3 +1,4 @@
+using System.Linq;
using Content.Shared.Actions;
using Content.Shared.Devour.Components;
using Content.Shared.DoAfter;
@@ -50,20 +51,16 @@ protected void OnDevourAction(EntityUid uid, DevourerComponent component, Devour
// Structure and mob devours handled differently.
if (TryComp(target, out MobStateComponent? targetState))
{
- switch (targetState.CurrentState)
+ if (component.Consumes.Contains(targetState.CurrentState))
{
- case MobState.Critical:
- case MobState.Dead:
-
- _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.DevourTime, new DevourDoAfterEvent(), uid, target: target, used: uid)
- {
- BreakOnTargetMove = true,
- BreakOnUserMove = true,
- });
- break;
- default:
- _popupSystem.PopupClient(Loc.GetString("devour-action-popup-message-fail-target-alive"), uid,uid);
- break;
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.DevourTime, new DevourDoAfterEvent(), uid, target: target, used: uid)
+ {
+ BreakOnUserMove = true,
+ });
+ }
+ else
+ {
+ _popupSystem.PopupClient(Loc.GetString("devour-action-popup-message-fail-target-alive"), uid,uid);
}
return;
@@ -76,7 +73,6 @@ protected void OnDevourAction(EntityUid uid, DevourerComponent component, Devour
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.StructureDevourTime, new DevourDoAfterEvent(), uid, target: target, used: uid)
{
- BreakOnTargetMove = true,
BreakOnUserMove = true,
});
}
diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs
index ee4a4e9023b..d80f9907504 100644
--- a/Content.Shared/Input/ContentKeyFunctions.cs
+++ b/Content.Shared/Input/ContentKeyFunctions.cs
@@ -18,6 +18,7 @@ public static class ContentKeyFunctions
public static readonly BoundKeyFunction FocusRadio = "FocusRadioWindow";
public static readonly BoundKeyFunction FocusLOOC = "FocusLOOCWindow";
public static readonly BoundKeyFunction FocusOOC = "FocusOOCWindow";
+ public static readonly BoundKeyFunction FocusXenoHivemindChat = "FocusXenoHivemindChatWindow";
public static readonly BoundKeyFunction FocusAdminChat = "FocusAdminChatWindow";
public static readonly BoundKeyFunction FocusDeadChat = "FocusDeadChatWindow";
public static readonly BoundKeyFunction FocusConsoleChat = "FocusConsoleChatWindow";
diff --git a/Content.Shared/Medical/SharedVomitActionSystem.cs b/Content.Shared/Medical/SharedVomitActionSystem.cs
new file mode 100644
index 00000000000..98c0044ac7a
--- /dev/null
+++ b/Content.Shared/Medical/SharedVomitActionSystem.cs
@@ -0,0 +1,33 @@
+using Content.Server.Medical.Components;
+using Content.Shared.Actions;
+using Robust.Shared.Containers;
+
+namespace Content.Shared.Medical;
+
+///
+/// This handles...
+///
+public abstract class SharedVomitActionSystem : EntitySystem
+{
+ ///
+
+ [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+ [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInit);
+ }
+
+ protected void OnInit(EntityUid uid, VomitActionComponent component, MapInitEvent args)
+ {
+ component.Stomach = ContainerSystem.EnsureContainer(uid, "stomach");
+
+ _actionsSystem.AddAction(uid, ref component.VomitActionEntity, component.VomitAction);
+ }
+
+
+}
+
+public sealed partial class VomitActionEvent : InstantActionEvent { }
diff --git a/Content.Shared/Medical/VomitActionComponent.cs b/Content.Shared/Medical/VomitActionComponent.cs
new file mode 100644
index 00000000000..d2370ae55b3
--- /dev/null
+++ b/Content.Shared/Medical/VomitActionComponent.cs
@@ -0,0 +1,26 @@
+using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Medical;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class VomitActionComponent : Component
+{
+ [DataField("vomitAction", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? VomitAction = "ActionVomit";
+
+ [DataField("vomitActionEntity")]
+ public EntityUid? VomitActionEntity;
+
+ [DataField("thirstAdded")]
+ public float ThirstAdded = 40f;
+
+ [DataField("hungerAdded")]
+ public float HungerAdded = 40f;
+
+ public Container Stomach = default!;
+}
diff --git a/Resources/Audio/Voice/Talk/alien.ogg b/Resources/Audio/Voice/Talk/alien.ogg
new file mode 100644
index 00000000000..c88ad43cebb
Binary files /dev/null and b/Resources/Audio/Voice/Talk/alien.ogg differ
diff --git a/Resources/Audio/Voice/Talk/alien_ask.ogg b/Resources/Audio/Voice/Talk/alien_ask.ogg
new file mode 100644
index 00000000000..ecc431fb9ab
Binary files /dev/null and b/Resources/Audio/Voice/Talk/alien_ask.ogg differ
diff --git a/Resources/Audio/Voice/Talk/alien_exclaim.ogg b/Resources/Audio/Voice/Talk/alien_exclaim.ogg
new file mode 100644
index 00000000000..cf1061c1d20
Binary files /dev/null and b/Resources/Audio/Voice/Talk/alien_exclaim.ogg differ
diff --git a/Resources/Locale/en-US/abilities/alien.ftl b/Resources/Locale/en-US/abilities/alien.ftl
new file mode 100644
index 00000000000..afc267c5446
--- /dev/null
+++ b/Resources/Locale/en-US/abilities/alien.ftl
@@ -0,0 +1,74 @@
+action-vomit-name = Vomit
+action-vomit-desc = Empty your stomach.
+
+action-make-acid-name = Make acid
+action-make-acid-desc = Make acid, instakilling non-protected hummanoids and corroding walls.
+
+action-create-weednode-name = Plant weednode
+action-create-weednode-desc = Plant weednode, that will slowly grow more weed around. Weed heals you and your plasma.
+
+action-create-resin-wall-name = Create wall
+action-create-resin-wall-desc = Create resin wall in front of yourself.
+
+action-create-resin-window-name = Create membrane
+action-create-resin-window-desc = Create resin membrane in front of yourself
+
+action-evolve-alien-drone = Evolve into drone
+action-evolve-alien-drone-desc = CHOOSE THIS IF YOU ARE FIRST IN YOUR HIVE. Evolve into drone, builder of the hive.
+
+action-evolve-alien-sentinel = Evolve into sentinel
+action-evolve-alien-sentinel-desc = Evolve into sentinel, guard and warrior of the hive.
+
+action-evolve-alien-praetorian = Evolve into praetorian
+action-evolve-alien-praetorian-desc = Evolve into praetorian, royal guard of queen.
+
+action-evolve-alien-hunter = Evolve into hunter
+action-evolve-alien-hunter-desc = Evolve into hunter. Hunt down targets and spread infestation.
+
+action-evolve-alien-queen = Evolve into queen
+action-evolve-alien-queen-desc = Evolve into queen, heart of the hive, wielding the ability to lay eggs.
+
+action-stalk-alien-hunter = Toggle stalking
+action-stalk-alien-hunter-desc = Toggle blending with the area.
+
+action-egg-alien = Lay egg
+action-egg-alien-desc = Lay egg in which facehugger will be born.
+
+action-promotion-alien = Royal larva
+action-promotion-alien-desc = Promote one of your children to be a praetorian.
+
+action-tail-lash = Tail lash
+action-tail-lash-desc = Stun nearby enemies with your tail.
+
+action-transfer-plasma-alien = Transfer plasma
+action-transfer-plasma-alien-desc = Transfer 50 plasma to nearby sister.
+
+alien-plasma-left = You have {$value} left for use.
+alien-create-structure-failed = You can't create structure here.
+alien-action-fail-plasma = You don't have enough plasma to make this.
+
+alien-acid-name = Corrosive acid
+alien-acid-desc = Acid, that corrodes walls and living beings.
+
+alien-node-name = Weednode
+alien-node-desc = It's strangely glowing
+
+alien-weed-name = Weed
+alien-weed-desc = ""
+
+action-larva-grow = Grow
+action-larva-grow-desc = Escape from your host and start growing.
+
+alien-create-structure-failed = You can't create it here.
+
+action-alien-jump = Leap
+action-alien-jump-desc = Leap onto your enemies stunning them.
+
+alien-evolution-fail = There is a royal xenomorph alreagy.
+
+alerts-promotion-fail = This daughter is already a royal xenomorph.
+
+alien-transfer-fail = You can't transfer plasma here now.
+
+action-create-alien-nest-name = Create nest
+action-create-alien-nest-desc = Create nest that holds your preys for a long time.
diff --git a/Resources/Locale/en-US/aliens/alien.ftl b/Resources/Locale/en-US/aliens/alien.ftl
new file mode 100644
index 00000000000..87adc706526
--- /dev/null
+++ b/Resources/Locale/en-US/aliens/alien.ftl
@@ -0,0 +1,43 @@
+alien-egg-name = Egg
+alien-egg-desc = A large mottled egg
+
+facehugger-name = Alien
+facehugger-desc = It has some sort of a tube at the end of its tail.
+
+mob-alien-larva-name = Alien larva
+mob-alien-larva-desc = Little and harmless alien
+
+mob-alien-drone-name = Alien drone
+mob-alien-drone-desc = They mostly come at night. Mostly.
+
+mob-alien-sentinel-name = Alien sentinel
+
+mob-alien-praetorian-name = Alien praetorian
+
+mob-alien-hunter-name = Alien hunter
+
+mob-alien-queen-name = Alien queen
+
+ghost-role-information-alien-larva-name = Alien larva
+ghost-role-information-alien-larva-description = Become an alien larva and spread the infestation.
+
+mob-alien-name = Alien
+ghost-role-mob-alien-description = Become a grown alien and spread the infestation.
+
+station-event-alien-infestation-anouncement = Unidentified lifesigns detected coming aboard the station. Secure any exterior access, including ducting and ventilation.
+
+hud-chatbox-select-channel-XenoHivemind = Hivemind
+
+ghost-role-information-alien-larva-inside-description = Become an alien larva that is going to burst out.
+
+alien-role-greeting = You are an alien larva. Help your hive to expand. You can contact your hive adding "a" to beginning of your message. If you are first alien - find place for a new hive and evolve into drone.
+alien-hunter-greeting = You are an alien hunter. Find facehuggers, throw them at your preys. Devour people and get them to your hive.
+alien-drone-greeting = You are an alien drone. Build your hive, evolve into praetorian, if you are first.
+alien-sentinel-greeting = You are an alien sentinel. Defend your hive, fight off intruders.
+alien-praetorian-greeting = You are an alien praetorian. Defend your queen. Help build new hives. Evolve into queen if there isn't one yet.
+alien-queen-greeting = You are an alien queen. Command your hive, lay eggs. STAY FUKKEN' ALIVE.
+alien-maid-greeting = You are an alien maid. Be lusty. Do most important job in your hive - seduce fellow spaceman.
+
+alerts-plasma-name = Plasma
+alerts-plasma-desc = Your body is syntesizing plasma, that you can use for your abilities
+
diff --git a/Resources/Locale/en-US/buckle/components/buckle-component.ftl b/Resources/Locale/en-US/buckle/components/buckle-component.ftl
index 32fbaa999ad..8c8af3d8354 100644
--- a/Resources/Locale/en-US/buckle/components/buckle-component.ftl
+++ b/Resources/Locale/en-US/buckle/components/buckle-component.ftl
@@ -5,3 +5,4 @@ buckle-component-cannot-buckle-message = You can't buckle yourself there!
buckle-component-other-cannot-buckle-message = You can't buckle {$owner} there!
buckle-component-cannot-fit-message = You can't fit there!
buckle-component-other-cannot-fit-message = {$owner} can't fit there!
+unbuckling-wait-message = You'll be able to unbuckle in {$delay} seconds.
diff --git a/Resources/Prototypes/Actions/aliens.yml b/Resources/Prototypes/Actions/aliens.yml
new file mode 100644
index 00000000000..901726324c7
--- /dev/null
+++ b/Resources/Prototypes/Actions/aliens.yml
@@ -0,0 +1,258 @@
+# Base actions
+- type: entity
+ id: ActionToggleLightingAlien
+ name: Toggle All Lighting
+ description: Toggle all light rendering to better observe dark areas.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite: Interface/Alien/screen_alien.rsi, state: nightvision0 }
+ priority: -1
+ clientExclusive: true
+ checkCanInteract: false
+ event: !type:ToggleLightingAlienActionEvent
+
+- type: entity
+ id: ActionVomit
+ name: action-vomit-name
+ description: action-vomit-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite : Fluids/vomit.rsi, state: vomit-0 }
+ checkCanInteract: false
+ priority: 0
+ event: !type:VomitActionEvent
+
+- type: entity
+ id: ActionMakeAcid
+ name: action-make-acid-name
+ description: action-make-acid-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: acid }
+ event: !type:AcidMakeActionEvent
+ priority: 1
+ useDelay: 1
+
+- type: entity
+ id: ActionAlienNode
+ name: action-create-weednode-name
+ description: action-create-weednode-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 2
+ useDelay: 10
+ icon: { sprite: Structures/weednode.rsi, state: full }
+ event: !type:WeednodeActionEvent
+
+- type: entity
+ id: ActionCombatModeToggleAlien
+ name: "[color=red]Combat Mode[/color]"
+ description: Enter combat mode
+ noSpawn: true
+ components:
+ - type: InstantAction
+ checkCanInteract: false
+ checkConsciousness: false
+ icon: { sprite: Interface/Alien/screen_alien.rsi, state: combat_off }
+ iconOn: { sprite: Interface/Alien/screen_alien.rsi, state: combat }
+ event: !type:ToggleCombatActionEvent
+ priority: -100
+
+# Drone
+
+- type: entity
+ id: ActionAlienDroneWall
+ name: action-create-resin-wall-name
+ description: action-create-resin-wall-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 3
+ useDelay: 1
+ icon: { sprite: Structures/Walls/resin.rsi, state: full }
+ event: !type:ResinWallActionEvent
+
+- type: entity
+ id: ActionWindowResin
+ name: action-create-resin-window-name
+ description: action-create-resin-window-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 4
+ useDelay: 1
+ icon: { sprite : Structures/Windows/resin_membrane.rsi, state: full }
+ event: !type:ResinWindowActionEvent
+
+- type: entity
+ id: ActionAlienNest
+ name: action-create-alien-nest-name
+ description: action-create-alien-nest-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 4
+ useDelay: 1
+ icon: { sprite : Structures/alien_nest.rsi, state: full }
+ event: !type:AlienNestActionEvent
+
+# Evolutions
+
+- type: entity
+ id: ActionEvolveDrone
+ name: action-evolve-alien-drone
+ description: action-evolve-alien-drone-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 9
+ useDelay: 5
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: aliend }
+ event: !type:AlienDroneEvolveActionEvent
+
+- type: entity
+ id: ActionEvolveSentinel
+ name: action-evolve-alien-sentinel
+ description: action-evolve-alien-sentinel-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 11
+ useDelay: 5
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: aliens }
+ event: !type:AlienSentinelEvolveActionEvent
+
+- type: entity
+ id: ActionEvolvePraetorian
+ name: action-evolve-alien-praetorian
+ description: action-evolve-alien-praetorian-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 10
+ useDelay: 0
+ icon: { sprite : Mobs/Aliens/Xenos/alienqueen.rsi, state: alienp }
+ event: !type:AlienPraetorianEvolveActionEvent
+
+- type: entity
+ id: ActionEvolveHunter
+ name: action-evolve-alien-hunter
+ description: action-evolve-alien-hunter-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 10
+ useDelay: 0
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: alienh }
+ event: !type:AlienHunterEvolveActionEvent
+
+- type: entity
+ id: ActionEvolveQueen
+ name: action-evolve-alien-queen
+ description: action-evolve-alien-queen-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 10
+ useDelay: 0
+ icon: { sprite : Mobs/Aliens/Xenos/alienqueen.rsi, state: alienq }
+ event: !type:AlienQueenEvolveActionEvent
+
+- type: entity
+ id: ActionLarvaGrow
+ name: action-larva-grow
+ description: action-larva-grow-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 10
+ useDelay: 0
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: larva0 }
+ event: !type:AlienLarvaGrowActionEvent
+
+# Sentinel
+
+- type: entity
+ id: ActionStalkAlien
+ name: action-stalk-alien-hunter
+ description: action-stalk-alien-hunter-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 0
+ useDelay: 0
+ icon: { sprite : Interface/Alien/screen_alien.rsi, state: walking }
+ event: !type:AlienStalkActionEvent
+
+# Hunter
+
+- type: entity
+ id: ActionJumpAlien
+ name: action-alien-jump
+ description: action-alien-jump-desc
+ noSpawn: true
+ components:
+ - type: WorldTargetAction
+ priority: 0
+ useDelay: 3
+ checkCanAccess: false
+ range: 10
+ icon: { sprite : Interface/Alien/screen_alien.rsi, state: leap_off }
+ iconOn: { sprite : Interface/Alien/screen_alien.rsi, state: leap_on }
+ event: !type:AlienJumpActionEvent
+
+# Queen
+
+- type: entity
+ id: ActionAlienEgg
+ name: action-egg-alien
+ description: action-egg-alien-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 0
+ useDelay: 1
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: egg }
+ event: !type:AlienEggActionEvent
+
+- type: entity
+ id: ActionAlienRoyalLarva
+ name: action-promotion-alien
+ description: action-promotion-alien-desc
+ noSpawn: true
+ components:
+ - type: EntityTargetAction
+ priority: 0
+ useDelay: 1
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: alien_medal }
+ iconOn: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: alien_medal_active }
+ event: !type:RoyalLarvaActionEvent
+
+- type: entity
+ id: ActionTailLash
+ name: action-tail-lash
+ description: action-tail-lash-desc
+ noSpawn: true
+ components:
+ - type: InstantAction
+ priority: 0
+ cooldown: 11
+ icon: { sprite : Mobs/Aliens/Xenos/alien.rsi, state: tail_lash }
+ event: !type:TailLashActionEvent
+
+- type: entity
+ id: ActionAlienTransferPlasma
+ name: action-transfer-plasma-alien
+ description: action-transfer-plasma-alien-desc
+ noSpawn: true
+ components:
+ - type: EntityTargetAction
+ priority: 0
+ useDelay: 1
+ icon: { sprite : Objects/Materials/Sheets/other.rsi, state: plasma }
+ iconOn: { sprite : Objects/Materials/Sheets/other.rsi, state: plasma_2 }
+ event: !type:TransferPlasmaActionEvent
diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml
index 2d1c9062e61..bfbe77b8244 100644
--- a/Resources/Prototypes/Alerts/alerts.yml
+++ b/Resources/Prototypes/Alerts/alerts.yml
@@ -5,6 +5,7 @@
id: BaseAlertOrder
order:
- category: Health
+ - category: Counter
- category: Stamina
- alertType: SuitPower
- category: Internals
@@ -64,6 +65,37 @@
name: alerts-low-pressure-name
description: alerts-low-pressure-desc
+- type: alert
+ id: PlasmaCounter
+ category: Counter
+ icons:
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display0
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display1
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display2
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display3
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display4
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display5
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display6
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display7
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display8
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display9
+ - sprite: /Textures/Interface/Alerts/plasma_counter.rsi
+ state: power_display10
+ minSeverity: 0
+ maxSeverity: 11
+ name: alerts-plasma-name
+ description: alerts-plasma-desc
+
- type: alert
id: HighPressure
category: Pressure
@@ -187,6 +219,43 @@
minSeverity: 0
maxSeverity: 4
+- type: alert
+ id: AlienHealth
+ category: Health
+ icons:
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health0
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health1
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health2
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health3
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health4
+ name: alerts-health-name
+ description: alerts-health-desc
+ minSeverity: 0
+ maxSeverity: 4
+
+- type: alert
+ id: AlienCrit
+ category: Health
+ icons:
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health6
+ name: alerts-crit-name
+ description: alerts-crit-desc
+
+- type: alert
+ id: AlienDead
+ category: Health
+ icons:
+ - sprite: /Textures/Interface/Alien/screen_alien.rsi
+ state: health7
+ name: alerts-dead-name
+ description: alerts-dead-desc
+
- type: alert
id: BorgHealth
category: Health
diff --git a/Resources/Prototypes/Body/Organs/Animal/xeno.yml b/Resources/Prototypes/Body/Organs/Animal/xeno.yml
new file mode 100644
index 00000000000..8f32e04eef4
--- /dev/null
+++ b/Resources/Prototypes/Body/Organs/Animal/xeno.yml
@@ -0,0 +1,80 @@
+- type: entity
+ id: OrganXenoAcidGland
+ parent: BaseAnimalOrgan
+ name: acid-gland
+ noSpawn: true
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Xeno/organs.rsi
+ state: acid_gland
+ - type: Organ
+
+- type: entity
+ id: OrganXenoEggsac
+ parent: BaseAnimalOrgan
+ name: eggsac
+ noSpawn: true
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Xeno/organs.rsi
+ state: eggsac
+ - type: Organ
+
+- type: entity
+ id: OrganXenoHivenode
+ parent: BaseAnimalOrgan
+ name: hivenode
+ noSpawn: true
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Xeno/organs.rsi
+ state: hivenode
+ - type: Organ
+
+- type: entity
+ id: OrganXenoPlasmaVessel
+ parent: BaseAnimalOrgan
+ name: plasma-vessel
+ noSpawn: true
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Xeno/organs.rsi
+ state: plasma_vessel
+ - type: Organ
+
+- type: entity
+ id: OrganXenoBrain
+ parent: BaseHumanOrganUnGibbable
+ name: brain
+ description: "The source of incredible, unending intelligence. Honk."
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Xeno/organs.rsi
+ state: brain-x
+ - type: Organ
+ - type: Input
+ context: "ghost"
+ - type: Brain
+ - type: InputMover
+ - type: Examiner
+ - type: BlockMovement
+ - type: BadFood
+ - type: Tag
+ tags:
+ - Meat
+
+- type: entity
+ id: TorsoXeno
+ name: "alien torso"
+ parent: [PartHuman, BaseTorso]
+ components:
+ - type: Sprite
+ sprite: Mobs/Species/Human/parts.rsi
+ state: "torso_m"
+ - type: Extractable
+ juiceSolution:
+ reagents:
+ - ReagentId: Fat
+ Quantity: 10
+ - ReagentId: Blood
+ Quantity: 20
diff --git a/Resources/Prototypes/Body/Prototypes/Animal/xeno.yml b/Resources/Prototypes/Body/Prototypes/Animal/xeno.yml
new file mode 100644
index 00000000000..13a1d58c8a4
--- /dev/null
+++ b/Resources/Prototypes/Body/Prototypes/Animal/xeno.yml
@@ -0,0 +1,51 @@
+- type: body
+ id: Xeno
+ name: "xeno"
+ root: torso
+ slots:
+ head:
+ part: HeadHuman
+ connections:
+ - torso
+ organs:
+ brain: OrganXenoBrain
+ eyes: OrganHumanEyes
+ torso:
+ part: TorsoXeno
+ connections:
+ - right_arm
+ - left_arm
+ - right_leg
+ - left_leg
+ organs:
+ heart: OrganHumanHeart
+ stomach: OrganAnimalStomach
+ liver: OrganHumanLiver
+ kidneys: OrganHumanKidneys
+ plasmaVessel: OrganXenoPlasmaVessel
+ acidGland: OrganXenoAcidGland
+ hivenode: OrganXenoHivenode
+ right_arm:
+ part: RightArmHuman
+ connections:
+ - right_hand
+ left_arm:
+ part: LeftArmHuman
+ connections:
+ - left_hand
+ right_hand:
+ part: RightHandHuman
+ left_hand:
+ part: LeftHandHuman
+ right_leg:
+ part: RightLegHuman
+ connections:
+ - right_foot
+ left_leg:
+ part: LeftLegHuman
+ connections:
+ - left_foot
+ right_foot:
+ part: RightFootHuman
+ left_foot:
+ part: LeftFootHuman
diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml
index 73b0ca6549c..42ebd2ace14 100644
--- a/Resources/Prototypes/DeltaV/GameRules/events.yml
+++ b/Resources/Prototypes/DeltaV/GameRules/events.yml
@@ -1,5 +1,5 @@
- type: entity
- id: XenoVents
+ id: AlienInfestation
parent: BaseGameRule
noSpawn: true
components:
@@ -13,22 +13,11 @@
duration: 60
- type: VentCrittersRule
entries:
- - id: MobXeno
- prob: 0.01
- - id: MobXenoRouny
- prob: 0.005
- - id: MobXenoDrone
- prob: 0.005
- - id: MobXenoSpitter
- prob: 0.005
- - id: MobXenoRunner
- prob: 0.005
- - id: MobXenoPraetorian
- prob: 0.005
- - id: MobXenoRavager
- prob: 0.005
- - id: MobXenoQueen
- prob: 0.005
+ - id: SpawnPointGhostAlienLarva
+ prob: 0.05
+ specialEntries:
+ - id: SpawnPointGhostAlienLarva
+ prob: 0.05
- type: entity
id: MothroachSpawn
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml
index 3da346cdd65..3a401f97dac 100644
--- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml
+++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml
@@ -153,3 +153,22 @@
- state: green
- sprite: Mobs/Species/Terminator/parts.rsi
state: full
+
+- type: entity
+ id: SpawnPointGhostAlienLarva
+ name: ghost role spawn point
+ suffix: alien larva
+ parent: MarkerBase
+ components:
+ - type: GhostRole
+ name: ghost-role-information-alien-larva-name
+ description: ghost-role-information-alien-larva-description
+ rules: ghost-role-information-xeno-rules
+ - type: GhostRoleMobSpawner
+ prototype: MobAlienLarvaGrowStageTwo
+ - type: Sprite
+ sprite: Markers/jobs.rsi
+ layers:
+ - state: green
+ - sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: larva1
diff --git a/Resources/Prototypes/Entities/Mobs/Player/alien_inventory_template.yml b/Resources/Prototypes/Entities/Mobs/Player/alien_inventory_template.yml
new file mode 100644
index 00000000000..cdf5c18721c
--- /dev/null
+++ b/Resources/Prototypes/Entities/Mobs/Player/alien_inventory_template.yml
@@ -0,0 +1,21 @@
+- type: inventoryTemplate
+ id: alien
+ slots:
+ - name: pocket1
+ slotTexture: "pocket"
+ slotFlags: POCKET
+ slotGroup: MainHotbar
+ stripTime: 3
+ uiWindowPos: 0,3
+ strippingWindowPos: 0,4
+ displayName: Pocket 1
+ stripHidden: true
+ - name: pocket2
+ slotTexture: "pocket"
+ slotFlags: POCKET
+ slotGroup: MainHotbar
+ stripTime: 3
+ uiWindowPos: 2,3
+ strippingWindowPos: 1,4
+ displayName: Pocket 2
+ stripHidden: true
diff --git a/Resources/Prototypes/Entities/Mobs/Player/aliens.yml b/Resources/Prototypes/Entities/Mobs/Player/aliens.yml
new file mode 100644
index 00000000000..804325a089a
--- /dev/null
+++ b/Resources/Prototypes/Entities/Mobs/Player/aliens.yml
@@ -0,0 +1,778 @@
+- type: entity
+ name: Alien larva
+ parent: SimpleSpaceMobBase
+ id: MobAlienLarva
+ description: Little and harmless alien
+ components:
+ - type: ShowInfectedIcons
+ - type: Body
+ prototype: Xeno
+ - type: GhostRole
+ makeSentient: true
+ allowSpeech: true
+ allowMovement: true
+ name: ghost-role-information-alien-larva-name
+ description: ghost-role-information-alien-larva-description
+ - type: GhostTakeoverAvailable
+ - type: Speech
+ speechSounds: Alien
+ speechVerb: SmallMob
+ - type: Vocal
+ sounds:
+ Male: UnisexReptilian
+ Female: UnisexReptilian
+ Unsexed: UnisexReptilian
+ - type: LizardAccent
+ - type: Sprite
+ drawdepth: SmallMobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: ["enum.DamageStateVisualLayers.Base", "movement"]
+ state: larva0
+ - type: SpriteMovement
+ movementLayers:
+ movement:
+ state: larva0
+ noMovementLayers:
+ movement:
+ state: larva0
+ - type: NpcFactionMember
+ factions:
+ - Xeno
+ - type: HTN
+ rootTask:
+ task: MouseCompound
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.2
+ density: 100
+ mask:
+ - SmallMobMask
+ layer:
+ - SmallMobLayer
+ - type: MobState
+ - type: Deathgasp
+ - type: MobStateActions
+ actions:
+ Critical:
+ - ActionCritSuccumb
+ - ActionCritFakeDeath
+ - ActionCritLastWords
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 25: Dead
+ stateAlertDict:
+ Alive: AlienHealth
+ Critical: AlienCrit
+ Dead: AlienDead
+ - type: MovementSpeedModifier
+ baseWalkSpeed : 5
+ baseSprintSpeed : 5
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: larva0
+ Critical:
+ Base: larva0_stun
+ Dead:
+ Base: larva0_dead
+ - type: Tag
+ tags:
+ - Trash
+ - VimPilot
+ - Meat
+ wilhelmProbability: 0.001
+ - type: CombatMode
+ combatToggleAction: ActionCombatModeToggleAlien
+ - type: MeleeWeapon
+ soundHit:
+ path: /Audio/Weapons/Xeno/alien_claw_flesh1.ogg
+ angle: 0
+ animation: WeaponArcBite
+ damage:
+ types:
+ Blunt: 2
+ - type: Bloodstream
+ bloodMaxVolume: 50
+ bloodReagent: FluorosulfuricAcid
+ - type: MobPrice
+ price: 50
+ - type: BadFood
+ - type: NonSpreaderZombie
+ - type: PreventSpiller
+ - type: PassiveDamage
+ allowedStates:
+ - Alive
+ - Critical
+ - Dead
+ - type: Alien
+ caste: larva
+ weedHeal:
+ groups:
+ Burn: -5
+ Toxin: -5
+ Airloss: -10
+ Brute: -5
+ - type: PlasmaVessel
+ maxPlasma: 30
+ - type: TimedPolymorph
+ polymorphPrototype: AlienEvolutionGrowStageTwo
+ polymorphTime: 50
+
+
+- type: entity
+ parent: MobAlienLarva # Larva that is inside of it's owner
+ id: MobAlienLarvaInside
+ components:
+ - type: TimedPolymorph
+ enabled: false
+ - type: InsideAlienLarva
+ evolutionCooldown: 5
+ - type: GhostRole
+ makeSentient: true
+ allowSpeech: true
+ allowMovement: true
+ name: ghost-role-information-alien-larva-name
+ description: ghost-role-information-alien-larva-inside-description
+
+- type: entity
+ parent: MobAlienLarva
+ id: MobAlienLarvaGrowStageTwo
+ components:
+ - type: Sprite
+ drawdepth: SmallMobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base", "movement" ]
+ state: larva1
+ - type: SpriteMovement
+ movementLayers:
+ movement:
+ state: larva1
+ noMovementLayers:
+ movement:
+ state: larva1
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: larva1
+ Critical:
+ Base: larva1_stun
+ Dead:
+ Base: larva1_dead
+ - type: TimedPolymorph
+ polymorphPrototype: AlienEvolutionGrowStageThree
+ polymorphTime: 50
+
+- type: entity
+ parent: MobAlienLarva
+ id: MobAlienLarvaGrowStageThree
+ components:
+ - type: Sprite
+ drawdepth: SmallMobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base", "movement" ]
+ state: larva2
+ - type: SpriteMovement
+ movementLayers:
+ movement:
+ state: larva2
+ noMovementLayers:
+ movement:
+ state: larva2
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: larva2
+ Critical:
+ Base: larva2_stun
+ Dead:
+ Base: larva2_dead
+ - type: TimedPolymorph
+ enabled: false
+ - type: AlienEvolution
+ evolutionCooldown: 50
+
+- type: entity
+ name: Alien drone
+ abstract: true
+ id: MobAlienBase
+ parent: SimpleSpaceMobBase
+ description: They mostly come at night. Mostly.
+ components:
+ - type: ShowInfectedIcons
+ - type: PlasmaTransfer
+ - type: Insulated
+ - type: CombatMode
+ combatToggleAction: ActionCombatModeToggleAlien
+ - type: InputMover
+ - type: MobMover
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 2
+ baseSprintSpeed: 5
+ - type: HTN
+ rootTask:
+ task: XenoCompound
+ blackboard:
+ NavClimb: !type:Bool
+ true
+ NavInteract: !type:Bool
+ true
+ NavPry: !type:Bool
+ true
+ NavSmash: !type:Bool
+ true
+ - type: Tool
+ speed: 1.5
+ qualities:
+ - Prying
+ - type: Prying
+ pryPowered: !type:Bool
+ true
+ force: !type:Bool
+ true
+ useSound:
+ path: /Audio/Items/crowbar.ogg
+ - type: Reactive
+ groups:
+ Flammable: [Touch]
+ Extinguish: [Touch]
+ - type: NpcFactionMember
+ factions:
+ - Xeno
+ - type: Hands
+ - type: Sprite
+ drawdepth: Mobs
+ offset: 0, 0.2
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: ["enum.DamageStateVisualLayers.Base"]
+ state: aliend
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: aliencuff
+ visible: false
+ - map: [ "clownedon" ] # Dynamically generated
+ sprite: "Effects/creampie.rsi"
+ state: "creampie_human"
+ visible: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.25
+ density: 1000
+ mask:
+ - MobMask
+ layer:
+ - MobLayer
+ - type: MobState
+ allowedStates:
+ - Alive
+ - Dead
+ - Critical
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 180: Critical
+ 280: Dead
+ stateAlertDict:
+ Alive: AlienHealth
+ Critical: AlienCrit
+ Dead: AlienDead
+ - type: SlowOnDamage
+ speedModifierThresholds:
+ 25: 0.5
+ - type: Stamina
+ critThreshold: 200
+ - type: Bloodstream
+ bloodReagent: FluorosulfuricAcid
+ bloodMaxVolume: 650
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 20
+ types:
+ Structural: 60
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: aliend
+ Critical:
+ Base: aliend_unconscious
+ Dead:
+ Base: aliend_dead
+ - type: Puller
+ - type: Butcherable
+ butcheringType: knife
+ spawned:
+ - id: FoodMeatXeno
+ amount: 5
+ - type: GhostRole
+ allowMovement: true
+ allowSpeech: true
+ makeSentient: true
+ name: mob-alien-name
+ description: ghost-role-mob-alien-description
+ rules: ghost-role-information-xeno-rules
+ - type: GhostTakeoverAvailable
+ - type: TypingIndicator
+ proto: alien
+ - type: Temperature
+ heatDamageThreshold: 360
+ coldDamageThreshold: -150
+ currentTemperature: 310.15
+ - type: Tag
+ tags:
+ - CannotSuicide
+ - DoorBumpOpener
+ - FootstepSound
+ - type: NoSlip
+ - type: Perishable #Ummmm the acid kills a lot of the bacteria or something
+ molsPerSecondPerUnitMass: 0.0005
+ - type: PassiveDamage
+ allowedStates:
+ - Alive
+ - Critical
+ - Dead
+ - type: Alien
+ caste: drone
+ weedHeal:
+ groups:
+ Burn: -5
+ Toxin: -5
+ Airloss: -10
+ Brute: -5
+ - type: Body
+ prototype: Xeno
+ - type: Inventory
+ templateId: alien
+ - type: Cuffable
+ - type: Ensnareable
+ sprite: Objects/Misc/ensnare.rsi
+ state: icon
+ - type: InventorySlots
+ - type: StatusEffects
+ allowed:
+ - Stun
+ - KnockedDown
+ - SlowedDown
+ - Stutter
+ - Electrocution
+ - ForcedSleep
+ - TemporaryBlindness
+ - Pacified
+ - StaminaModifier
+ - type: Devourer
+ shouldStoreDevoured: true
+ foodPreference: Humanoid
+ chemical: UncookedAnimalProteins
+ healRate: 5.0
+ whitelist:
+ components:
+ - MobState
+ consumes:
+ - Alive
+ - Critical
+ - Dead
+ - type: VomitAction
+ thirstAdded: 5.0
+ hungerAdded: 5.0
+ - type: PlasmaVessel
+ - type: Alerts
+ - type: Speech
+ speechSounds: Alien
+ speechVerb: SmallMob
+ - type: Vocal
+ sounds:
+ Male: UnisexReptilian
+ Female: UnisexReptilian
+ Unsexed: UnisexReptilian
+ - type: LizardAccent
+
+- type: entity
+ name: Alien drone
+ id: MobAlienDrone
+ parent: MobAlienBase
+ components:
+ - type: AcidMaker
+ action: ActionMakeAcid
+ productionLength: 0
+ entityProduced: AlienAcid
+ - type: ResinSpinner
+ - type: PlasmaVessel
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: PraetorianEvolution
+
+- type: entity
+ name: Alien sentinel
+ id: MobAlienSentinel
+ parent: MobAlienBase
+ components:
+ - type: Alien
+ caste: sentinel
+ - type: AlienStalk
+ - type: AcidMaker
+ action: ActionMakeAcid
+ entityProduced: AlienAcid
+ - type: Sprite
+ drawdepth: Mobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base" ]
+ state: aliens
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: aliencuff
+ visible: false
+ - map: [ "clownedon" ] # Dynamically generated
+ sprite: "Effects/creampie.rsi"
+ state: "creampie_human"
+ visible: false
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 250: Critical
+ 350: Dead
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 25
+ types:
+ Structural: 60
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: aliens
+ Critical:
+ Base: aliens_unconscious
+ Dead:
+ Base: aliens_dead
+ - type: PlasmaVessel
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: RechargeBasicEntityAmmo
+ rechargeCooldown: 0.75
+ - type: BasicEntityAmmoProvider
+ proto: BulletAcidSentinel
+ capacity: 1
+ count: 1
+ - type: Gun
+ fireRate: 0.25
+ useKey: false
+ selectedMode: FullAuto
+ availableModes:
+ - FullAuto
+ soundGunshot: /Audio/Weapons/Xeno/alien_spitacid.ogg
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 4
+ baseSprintSpeed: 5
+
+- type: entity
+ name: Alien praetorian
+ id: MobAlienPraetorian
+ parent: MobAlienBase
+ components:
+ - type: Alien
+ caste: praetorian
+ - type: AcidMaker
+ action: ActionMakeAcid
+ entityProduced: AlienAcid
+ plasmaCost: 100
+ - type: Sprite
+ drawdepth: Mobs
+ sprite: Mobs/Aliens/Xenos/alienqueen.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base" ]
+ state: alienp
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alienqueen.rsi
+ state: aliencuff_p
+ visible: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.4
+ density: 1000
+ mask:
+ - MobMask
+ layer:
+ - MobLayer
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 250: Critical
+ 350: Dead
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 30
+ types:
+ Structural: 80
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: alienp
+ Critical:
+ Base: alienp_unconscious
+ Dead:
+ Base: alienp_dead
+ - type: PlasmaVessel
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: RechargeBasicEntityAmmo
+ rechargeCooldown: 0.75
+ - type: BasicEntityAmmoProvider
+ proto: BulletAcidSentinel
+ capacity: 1
+ count: 1
+ - type: Gun
+ fireRate: 0.3
+ useKey: false
+ selectedMode: FullAuto
+ availableModes:
+ - FullAuto
+ soundGunshot: /Audio/Weapons/Xeno/alien_spitacid.ogg
+ - type: QueenEvolution
+ - type: ResinSpinner
+ - type: TailLash
+
+- type: entity
+ name: Alien hunter
+ id: MobAlienHunter
+ parent: MobAlienBase
+ components:
+ - type: Alien
+ caste: hunter
+ - type: Sprite
+ drawdepth: Mobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: [ "enum.JumpLayers.Jumping" ]
+ sprite: Mobs/Aliens/Xenos/alien_hunter_jump.rsi
+ state: icon
+ visible: false
+ - map: [ "enum.DamageStateVisualLayers.Base" ]
+ state: alienh
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: aliencuff
+ visible: false
+ - map: [ "clownedon" ] # Dynamically generated
+ sprite: "Effects/creampie.rsi"
+ state: "creampie_human"
+ visible: false
+ - type: GenericVisualizer
+ visuals:
+ enum.JumpVisuals.Jumping:
+ enum.JumpLayers.Jumping:
+ True: { visible: true }
+ False: { visible: false }
+ enum.DamageStateVisualLayers.Base:
+ True: { visible: false}
+ False: { visible: true}
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 205: Critical
+ 305: Dead
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 20
+ types:
+ Structural: 60
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: alienh
+ Critical:
+ Base: alienh_unconscious
+ Dead:
+ Base: alienh_dead
+ - type: PlasmaVessel
+ maxPlasma: 150
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: Devourer
+ devourTime: 2
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 4
+ baseSprintSpeed: 8
+ - type: JumpVisuals
+ baseState: alienh
+ - type: AlienJump
+ jumpSprite: Mobs/Aliens/Xenos/alien_hunter_jump.rsi
+
+- type: entity
+ name: Alien queen
+ id: MobAlienQueen
+ parent: MobAlienBase
+ components:
+ - type: Alien
+ caste: queen
+ - type: Sprite
+ drawdepth: Mobs
+ sprite: Mobs/Aliens/Xenos/alienqueen.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base" ]
+ state: alienq
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alienqueen.rsi
+ state: aliencuff_q
+ visible: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.6
+ density: 1000
+ mask:
+ - MobMask
+ layer:
+ - MobLayer
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 640: Critical
+ 740: Dead
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 30
+ types:
+ Structural: 300
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: alienq
+ Critical:
+ Base: alienq_unconscious
+ Dead:
+ Base: alienq_dead
+ - type: PlasmaVessel
+ maxPlasma: 500
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: ResinSpinner
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 1
+ baseSprintSpeed: 2
+ - type: AcidMaker
+ plasmaCost: 50
+ entityProduced: AlienAcid
+ action: ActionMakeAcid
+ - type: AlienQueen
+ action: ActionAlienRoyalLarva
+ - type: Speech
+ speechSounds: Alien
+ speechVerb: LargeMob
+ - type: TailLash
+
+- type: entity
+ name: Lusty alien maid
+ description: Don't ask it to lay eggs in you.
+ id: MobAlienMaid
+ parent: MobAlienBase
+ components:
+ - type: Alien
+ caste: maid
+ - type: PlasmaVessel
+ plasmaPerSecond: 5
+ plasmaModified: 40
+ - type: Sprite
+ drawdepth: Mobs
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ layers:
+ - map: [ "enum.DamageStateVisualLayers.Base" ]
+ state: maid
+ - map: [ "pocket1" ]
+ - map: [ "pocket2" ]
+ - map: [ "enum.HumanoidVisualLayers.Handcuffs" ]
+ color: "#ffffff"
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: aliencuff
+ visible: false
+ - map: [ "clownedon" ] # Dynamically generated
+ sprite: "Effects/creampie.rsi"
+ state: "creampie_human"
+ visible: false
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 208: Dead
+ - type: MeleeWeapon
+ altDisarm: true
+ angle: 0
+ soundHit:
+ collection: AlienClaw
+ animation: WeaponArcBite
+ damage:
+ groups:
+ Brute: 25
+ types:
+ Structural: 60
+ - type: DamageStateVisuals
+ rotate: true
+ states:
+ Alive:
+ Base: maid
+ Dead:
+ Base: maid_dead
+ - type: OwOAccent
diff --git a/Resources/Prototypes/Entities/Mobs/facehugger.yml b/Resources/Prototypes/Entities/Mobs/facehugger.yml
new file mode 100644
index 00000000000..11d2c9e03fb
--- /dev/null
+++ b/Resources/Prototypes/Entities/Mobs/facehugger.yml
@@ -0,0 +1,146 @@
+- type: entity
+ name: Alien
+ parent: BaseItem
+ id: Facehugger
+ description: It has some sort of a tube at the end of its tail. It seems to be active!
+ components:
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.2
+ density: 100
+ mask:
+ - SmallMobMask
+ layer:
+ - SmallMobLayer
+ - type: MobState
+ - type: Deathgasp
+ - type: MobStateActions
+ actions:
+ Critical:
+ - ActionCritSuccumb
+ - ActionCritFakeDeath
+ - ActionCritLastWords
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 25: Dead
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 5
+ baseSprintSpeed: 5
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: facehugger
+ Dead:
+ Base: facehugger_dead
+ - type: Tag
+ tags:
+ - AlienItem
+ - MonkeyWearable
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger
+ - type: Item
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger
+ size: Small
+ - type: StaticPrice
+ price: 1000
+ - type: Clothing
+ sprite: Clothing/Mask/facehugger.rsi
+ slots:
+ - Mask
+ - type: BreathMask
+ - type: Facehugger
+ range: 1
+ - type: Blindfold
+
+- type: entity
+ name: Alien
+ parent: BaseItem
+ id: FacehuggerInactive
+ description: It has some sort of a tube at the end of its tail. It doesn't seem active.
+ suffix: Inactive
+ components:
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger_impregnated
+ - type: Item
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger_impregnated
+ size: Small
+ - type: StaticPrice
+ price: 100
+ - type: Clothing
+ sprite: Clothing/Mask/facehugger.rsi
+ slots:
+ - Mask
+ - type: BreathMask
+ - type: Blindfold
+ - type: Tag
+ tags:
+ - AlienItem
+ - MonkeyWearable
+
+- type: entity
+ name: Lamarr
+ parent: BaseItem
+ id: FacehuggerLamarr
+ description: It has some sort of a tube at the end of its tail, but it doesn't seem, like it can use it.
+ components:
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.2
+ density: 100
+ mask:
+ - SmallMobMask
+ layer:
+ - SmallMobLayer
+ - type: MobState
+ - type: Deathgasp
+ - type: MobStateActions
+ actions:
+ Critical:
+ - ActionCritSuccumb
+ - ActionCritFakeDeath
+ - ActionCritLastWords
+ - type: MobThresholds
+ thresholds:
+ 0: Alive
+ 25: Dead
+ - type: MovementSpeedModifier
+ baseWalkSpeed: 5
+ baseSprintSpeed: 5
+ - type: DamageStateVisuals
+ states:
+ Alive:
+ Base: facehugger
+ Dead:
+ Base: facehugger_dead
+ - type: Tag
+ tags:
+ - AlienItem
+ - MonkeyWearable
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger
+ - type: Item
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: facehugger
+ size: Small
+ - type: StaticPrice
+ price: 1000
+ - type: Clothing
+ sprite: Clothing/Mask/facehugger.rsi
+ slots:
+ - Mask
+ - type: BreathMask
+ - type: Blindfold
diff --git a/Resources/Prototypes/Entities/Objects/Misc/alien_egg.yml b/Resources/Prototypes/Entities/Objects/Misc/alien_egg.yml
new file mode 100644
index 00000000000..93c03930f53
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Misc/alien_egg.yml
@@ -0,0 +1,205 @@
+- type: entity
+ parent: BaseStructureDynamic
+ id: AlienEggGrowing
+ name: Egg
+ description: A large mottled egg
+ components:
+ - type: Transform
+ noRot: true
+ - type: Icon
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_growing
+ - type: Sprite
+ noRot: true
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_growing
+ - type: InteractionOutline
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.4,-0.4,0.4,0.4"
+ density: 1000
+ mask:
+ - ItemMask
+ layer:
+ - SlipLayer
+ hard: false
+ - type: PlaceableSurface
+ isPlaceable: false # defaults to closed.
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 50
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: blood
+ - type: Appearance
+ - type: ItemSlots
+ - type: StaticPrice
+ price: 1000
+ - type: TimedPolymorph
+ polymorphTime: 240
+ polymorphPrototype: AlienEggGrowth
+
+- type: entity
+ parent: BaseStructureDynamic
+ id: AlienEgg
+ name: Egg
+ description: A large mottled egg
+ components:
+ - type: Transform
+ noRot: true
+ - type: Icon
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg
+ - type: Sprite
+ noRot: true
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg
+ - type: InteractionOutline
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.4,-0.4,0.4,0.4"
+ density: 1000
+ mask:
+ - ItemMask
+ layer:
+ - SlipLayer
+ hard: false
+ - type: PlaceableSurface
+ isPlaceable: false
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 50
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: blood
+ - type: Appearance
+ - type: ItemSlots
+ - type: StaticPrice
+ price: 1000
+ - type: AlienEggHatch
+ polymorphPrototype: AlienEggHatch
+
+- type: entity
+ parent: BaseStructureDynamic
+ id: AlienEggHatching
+ name: Egg
+ description: A large mottled egg
+ components:
+ - type: Transform
+ noRot: true
+ - type: Icon
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_opening
+ - type: Sprite
+ noRot: true
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_opening
+ - type: TimedDespawn
+ lifetime: 1.5
+ - type: SpawnOnDespawn
+ prototype: AlienEggOpened
+
+- type: entity
+ parent: BaseStructureDynamic
+ id: AlienEggOpened
+ name: Egg
+ description: A large mottled egg
+ components:
+ - type: Transform
+ noRot: true
+ - type: Icon
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_hatched
+ - type: Sprite
+ noRot: true
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg_hatched
+ - type: InteractionOutline
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.4,-0.4,0.4,0.4"
+ density: 1000
+ mask:
+ - ItemMask
+ layer:
+ - SlipLayer
+ hard: false
+ - type: PlaceableSurface
+ isPlaceable: false
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 50
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: blood
+ - type: Appearance
+ - type: ItemSlots
+ - type: StaticPrice
+ price: 1000
+ - type: ConditionalSpawner
+ prototypes:
+ - Facehugger
+
+- type: entity
+ id: AlienEggSpawner
+ name: alien egg spawner
+ parent: MarkerBase
+ components:
+ - type: Sprite
+ layers:
+ - state: red
+ - sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg
+ - type: RandomSpawner
+ prototypes:
+ - AlienEgg
+ chance: 1
+
+- type: entity
+ id: AlienEggSpawnerRandom
+ name: alien egg spawner
+ suffix: 20%
+ parent: MarkerBase
+ components:
+ - type: Sprite
+ layers:
+ - state: red
+ - sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: egg
+ - type: RandomSpawner
+ prototypes:
+ - AlienEgg
+ chance: 0.2
diff --git a/Resources/Prototypes/Entities/Objects/Misc/alien_weed.yml b/Resources/Prototypes/Entities/Objects/Misc/alien_weed.yml
new file mode 100644
index 00000000000..46c3bc9f83c
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Misc/alien_weed.yml
@@ -0,0 +1,88 @@
+- type: entity
+ name: Weed
+ description: Strange grey weeds.
+ parent: BaseStructure
+ id: AlienWeed
+ components:
+ - type: Sprite
+ sprite: Structures/resin_weeds.rsi
+ state: full
+ drawdepth: FloorTiles
+ - type: Icon
+ sprite: Structures/resin_weeds.rsi
+ state: full
+ - type: IconSmooth
+ key: full
+ base: resin-weeds
+ - type: Tag
+ tags: [ Carpet ]
+ - type: Physics
+ canCollide: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.5,-0.5,0.5,0.5"
+ layer:
+ - SlipLayer
+ mask:
+ - ItemMask
+ density: 1000
+ hard: false
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 15
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: PlasmaGainModifier
+
+- type: entity
+ name: Weed node
+ description: It's strangely glowing.
+ parent: BaseStructure
+ id: AlienWeednode
+ components:
+ - type: Sprite
+ sprite: Structures/weednode.rsi
+ state: full
+ drawdepth: FloorTiles
+ - type: Icon
+ sprite: Structures/weednode.rsi
+ state: full
+ - type: AreaSpawner
+ radius: 9
+ spawnPrototype: AlienWeed
+ intervalSeconds: 20
+ - type: Tag
+ tags: [ Carpet ]
+ - type: Physics
+ canCollide: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.5,-0.5,0.5,0.5"
+ layer:
+ - SlipLayer
+ mask:
+ - ItemMask
+ density: 1000
+ hard: false
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 15
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: PlasmaGainModifier
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
index 935e335c2a4..8ec27aa2720 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml
@@ -773,6 +773,23 @@
- type: Ammo
muzzleFlash: null
+- type: entity
+ id: BulletAcidSentinel
+ name: acid spit
+ parent: BaseBullet
+ noSpawn: true
+ components:
+ - type: Projectile
+ damage:
+ types:
+ Caustic: 33
+ - type: Sprite
+ sprite: Objects/Weapons/Guns/Projectiles/xeno_toxic.rsi
+ layers:
+ - state: xeno_toxic
+ - type: Ammo
+ muzzleFlash: null
+
- type: entity
id: BulletWaterShot
name: water
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/alien_acid.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/alien_acid.yml
new file mode 100644
index 00000000000..101d21928c9
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/alien_acid.yml
@@ -0,0 +1,97 @@
+- type: entity
+ parent: BaseItem
+ id: AlienAcid
+ name: alien-acid-name
+ description: alien-acid-desc
+ components:
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape: !type:PolygonShape
+ vertices:
+ - -0.20,0.10
+ - -0.10,0.20
+ - 0.20,-0.10
+ - 0.10,-0.20
+ density: 20
+ mask:
+ - ItemMask
+ restitution: 0.3
+ friction: 0.2
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: acid
+ - type: MeleeWeapon
+ wideAnimationRotation: -45
+ damage:
+ types:
+ Caustic: 100
+ angle: 0
+ animation: WeaponArcThrust
+ soundHit:
+ path: /Audio/Weapons/pierce.ogg
+ - type: Item
+ size: Tiny
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: acid
+ - type: Damageable
+ damageContainer: Inorganic
+ - type: Appearance
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 75
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - trigger:
+ !type:DamageTrigger
+ damage: 15
+ behaviors:
+ - !type:PlaySoundBehavior
+ sound:
+ collection: WoodDestroy
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: DamageOnHit
+ damage:
+ types:
+ Blunt: 100
+ - type: Unremoveable
+ - type: AlienAcid
+ - type: Tag
+ tags:
+ - AlienItem
+
+- type: entity
+ id: CorrosiveAcid
+ name: alien-acid-name
+ suffix: overlay
+ description: alien-acid-desc
+ components:
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: acid
+ - type: TimedSpawner
+ prototypes:
+ - CorrodedAcid
+ intervalSeconds: 30
+ minimumEntitiesSpawned: 1
+ maximumEntitiesSpawned: 1
+
+- type: entity
+ id: CorrodedAcid
+ name: corroded acid
+ suffix: overlay
+ description: alien-acid-desc
+ components:
+ - type: Sprite
+ sprite: Mobs/Aliens/Xenos/alien.rsi
+ state: acid
+ - type: EventHorizon
+ radius: 0.1
+ consumeTiles: false
+ canBreachContainment: true
+ - type: TimedDespawn
+ lifetime: 0.1
diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml
index 53d9a5224ef..3395a847f17 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml
@@ -1324,3 +1324,35 @@
- type: IconSmooth
key: cobblebricks
base: cobblebrick
+
+- type: entity
+ parent: BaseWall
+ id: WallResin
+ name: wall-resin-name
+ description: wall-resin-desc
+ components:
+ - type: MeleeSound
+ soundGroups:
+ Brute:
+ collection: blood
+ - type: Tag
+ tags:
+ - Wall
+ - type: Sprite
+ sprite: Structures/Walls/resin.rsi
+ - type: Icon
+ sprite: Structures/Walls/resin.rsi
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 100
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: gib
+ - type: IconSmooth
+ key: resinwall
+ base: resinwall
diff --git a/Resources/Prototypes/Entities/Structures/Windows/resin.yml b/Resources/Prototypes/Entities/Structures/Windows/resin.yml
new file mode 100644
index 00000000000..f90e92a3d44
--- /dev/null
+++ b/Resources/Prototypes/Entities/Structures/Windows/resin.yml
@@ -0,0 +1,74 @@
+- type: entity
+ id: WindowResin
+ parent: BaseStructure
+ name: resin-membrane-name
+ description: resin-membrane-desc
+ placement:
+ mode: SnapgridCenter
+ snap:
+ - Window
+ components:
+ - type: MeleeSound
+ soundGroups:
+ Brute:
+ collection: blood
+ - type: WallMount
+ arc: 360 # interact despite grilles
+ - type: Tag
+ tags:
+ - ForceFixRotations
+ - Window
+ - type: Sprite
+ drawdepth: WallTops
+ sprite: Structures/Windows/resin_membrane.rsi
+ - type: Icon
+ sprite: Structures/Windows/resin_membrane.rsi
+ state: full
+ - type: Physics
+ bodyType: Static
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb {}
+ mask:
+ - FullTileMask
+ layer:
+ - GlassLayer
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ damageModifierSet: Glass
+ - type: ExaminableDamage
+ messages: WindowMessages
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 150 #excess damage (nuke?). avoid computational cost of spawning entities.
+ behaviors:
+ - !type:PlaySoundBehavior
+ sound:
+ collection: gib
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - trigger:
+ !type:DamageTrigger
+ damage: 50
+ behaviors:
+ - !type:PlaySoundBehavior
+ sound:
+ collection: gib
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: Airtight
+ - type: IconSmooth
+ key: resin_membrane
+ base: resin_membrane
+ - type: InteractionPopup
+ interactSuccessString: comp-window-knock
+ messagePerceivedByOthers: comp-window-knock
+ interactSuccessSound:
+ path: /Audio/Effects/glass_knock.ogg
+ - type: Appearance
+ - type: StaticPrice
+ price: 100
diff --git a/Resources/Prototypes/Entities/Structures/alien_nest.yml b/Resources/Prototypes/Entities/Structures/alien_nest.yml
new file mode 100644
index 00000000000..a326fd3fc19
--- /dev/null
+++ b/Resources/Prototypes/Entities/Structures/alien_nest.yml
@@ -0,0 +1,47 @@
+- type: entity
+ name: alien-nest-name
+ description: alien-nest-desc
+ parent: BaseStructure
+ id: AlienNest
+ components:
+ - type: Sprite
+ sprite: Structures/alien_nest.rsi
+ state: full
+ drawdepth: FloorTiles
+ - type: Icon
+ sprite: Structures/alien_nest.rsi
+ state: full
+ - type: IconSmooth
+ key: full
+ base: alien_nest
+ - type: Tag
+ tags: [ Carpet ]
+ - type: Physics
+ canCollide: false
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.5,-0.5,0.5,0.5"
+ layer:
+ - SlipLayer
+ mask:
+ - ItemMask
+ density: 1000
+ hard: false
+ - type: Damageable
+ damageContainer: StructuralInorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 15
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: Strap
+ delay: 120
+ position: Down
+ rotation: -90
+
diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml
index b4249f8a3ea..20401c72161 100644
--- a/Resources/Prototypes/Polymorphs/polymorph.yml
+++ b/Resources/Prototypes/Polymorphs/polymorph.yml
@@ -164,3 +164,117 @@
revertOnDeath: true
revertOnCrit: true
duration: 20
+
+# Alien evolutions
+
+- type: polymorph
+ id: AlienEvolutionGrowStageTwo
+ configuration:
+ entity: MobAlienLarvaGrowStageTwo
+ forced: true
+ transferName: true
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienLarvaGrow
+ configuration:
+ entity: MobAlienLarva
+ forced: true
+ transferName: true
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionGrowStageThree
+ configuration:
+ entity: MobAlienLarvaGrowStageThree
+ forced: true
+ transferName: true
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionDrone
+ configuration:
+ entity: MobAlienDrone
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionSentinel
+ configuration:
+ entity: MobAlienSentinel
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionPraetorian
+ configuration:
+ entity: MobAlienPraetorian
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionHunter
+ configuration:
+ entity: MobAlienHunter
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEggGrowth
+ configuration:
+ entity: AlienEgg
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEggHatch
+ configuration:
+ entity: AlienEggHatching
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+- type: polymorph
+ id: AlienEvolutionQueen
+ configuration:
+ entity: MobAlienQueen
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
+
+# Deactivating facehugger
+
+- type: polymorph
+ id: FacehuggerToInactive
+ configuration:
+ entity: FacehuggerInactive
+ forced: true
+ transferName: false
+ revertOnDeath: false
+ revertOnCrit: false
+ allowRepeatedMorphs: true
diff --git a/Resources/Prototypes/StatusIcon/antag.yml b/Resources/Prototypes/StatusIcon/antag.yml
index 41bb0957416..77803a9178a 100644
--- a/Resources/Prototypes/StatusIcon/antag.yml
+++ b/Resources/Prototypes/StatusIcon/antag.yml
@@ -42,3 +42,53 @@
icon:
sprite: /Textures/Interface/Misc/job_icons.rsi
state: Syndicate
+
+# Infection stages
+
+- type: statusIcon
+ id: AlienInfectedIconStageZero
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected0
+
+- type: statusIcon
+ id: AlienInfectedIconStageOne
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected1
+
+- type: statusIcon
+ id: AlienInfectedIconStageTwo
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected2
+
+- type: statusIcon
+ id: AlienInfectedIconStageThree
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected3
+
+- type: statusIcon
+ id: AlienInfectedIconStageFour
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected4
+
+- type: statusIcon
+ id: AlienInfectedIconStageFive
+ priority: 0
+ locationPreference: Right
+ icon:
+ sprite: /Textures/Interface/Misc/infected.rsi
+ state: infected5
diff --git a/Resources/Prototypes/Voice/speech_sounds.yml b/Resources/Prototypes/Voice/speech_sounds.yml
index 2e7e7bf989a..0e95a7c118b 100644
--- a/Resources/Prototypes/Voice/speech_sounds.yml
+++ b/Resources/Prototypes/Voice/speech_sounds.yml
@@ -132,3 +132,12 @@
path: /Audio/Animals/dog_bark3.ogg
exclaimSound:
path: /Audio/Animals/dog_bark2.ogg
+
+- type: speechSounds
+ id: Alien
+ saySound:
+ path: /Audio/Voice/Talk/alien.ogg
+ askSound:
+ path: /Audio/Voice/Talk/alien_ask.ogg
+ exclaimSound:
+ path: /Audio/Voice/Talk/alien_exclaim.ogg
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index 2694cbeaf39..abddddea81f 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -10,6 +10,9 @@
- type: Tag
id: AirSensor
+- type: Tag
+ id: AlienItem
+
- type: Tag
id: Ambrosia
diff --git a/Resources/Textures/Clothing/Mask/facehugger.rsi/equipped-MASK.png b/Resources/Textures/Clothing/Mask/facehugger.rsi/equipped-MASK.png
new file mode 100644
index 00000000000..b9cb635ca75
Binary files /dev/null and b/Resources/Textures/Clothing/Mask/facehugger.rsi/equipped-MASK.png differ
diff --git a/Resources/Textures/Clothing/Mask/facehugger.rsi/meta.json b/Resources/Textures/Clothing/Mask/facehugger.rsi/meta.json
new file mode 100644
index 00000000000..b0555d7d958
--- /dev/null
+++ b/Resources/Textures/Clothing/Mask/facehugger.rsi/meta.json
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation on https://github.com/tgstation/tgstation/blob/master/icons/mob/clothing/mask.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "equipped-MASK",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/meta.json b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/meta.json
new file mode 100644
index 00000000000..263023a9a52
--- /dev/null
+++ b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/meta.json
@@ -0,0 +1,44 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Redacted by Kai5, take taken from tgstation on https://github.com/tgstation/tgstation/blob/master/icons/hud/screen_alien.dmin from",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "power_display0"
+ },
+ {
+ "name": "power_display1"
+ },
+ {
+ "name": "power_display2"
+ },
+ {
+ "name": "power_display3"
+ },
+ {
+ "name": "power_display4"
+ },
+ {
+ "name": "power_display5"
+ },
+ {
+ "name": "power_display6"
+ },
+ {
+ "name": "power_display7"
+ },
+ {
+ "name": "power_display8"
+ },
+ {
+ "name": "power_display9"
+ },
+ {
+ "name": "power_display10"
+ }
+ ]
+}
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display0.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display0.png
new file mode 100644
index 00000000000..2255be6f451
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display0.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display1.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display1.png
new file mode 100644
index 00000000000..6550bf5ddbf
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display1.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display10.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display10.png
new file mode 100644
index 00000000000..23ab4a8741a
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display10.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display2.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display2.png
new file mode 100644
index 00000000000..79dedf2b17e
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display2.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display3.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display3.png
new file mode 100644
index 00000000000..24fb35ec74e
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display3.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display4.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display4.png
new file mode 100644
index 00000000000..5494ec18777
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display4.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display5.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display5.png
new file mode 100644
index 00000000000..a4e9a2996c2
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display5.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display6.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display6.png
new file mode 100644
index 00000000000..74841d5cf96
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display6.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display7.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display7.png
new file mode 100644
index 00000000000..3e103c7d91d
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display7.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display8.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display8.png
new file mode 100644
index 00000000000..cdf7c434454
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display8.png differ
diff --git a/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display9.png b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display9.png
new file mode 100644
index 00000000000..30c7d682129
Binary files /dev/null and b/Resources/Textures/Interface/Alerts/plasma_counter.rsi/power_display9.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_drop.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_drop.png
new file mode 100644
index 00000000000..a03e210a602
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_drop.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_resist.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_resist.png
new file mode 100644
index 00000000000..f3e828417bc
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_resist.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest.png
new file mode 100644
index 00000000000..1de6aa14401
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest0.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest0.png
new file mode 100644
index 00000000000..7c64b742010
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_rest0.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_off.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_off.png
new file mode 100644
index 00000000000..6c94d216b23
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_off.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_on.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_on.png
new file mode 100644
index 00000000000..aeef61e5335
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/act_throw_on.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/chest.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/chest.png
new file mode 100644
index 00000000000..a4e1097061d
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/chest.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/combat.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/combat.png
new file mode 100644
index 00000000000..97e0b1bfe58
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/combat.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/combat_off.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/combat_off.png
new file mode 100644
index 00000000000..4473ffcd142
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/combat_off.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/disarm.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/disarm.png
new file mode 100644
index 00000000000..7ede9c55c12
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/disarm.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/eyes.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/eyes.png
new file mode 100644
index 00000000000..0ded91f9cfc
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/eyes.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_center.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_center.png
new file mode 100644
index 00000000000..c232babfb25
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_center.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_far.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_far.png
new file mode 100644
index 00000000000..ba037995177
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_far.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_med.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_med.png
new file mode 100644
index 00000000000..8bd46f40469
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_med.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_near.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_near.png
new file mode 100644
index 00000000000..8272426087e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/finder_near.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/grab.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/grab.png
new file mode 100644
index 00000000000..06b7cd0c745
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/grab.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/groin.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/groin.png
new file mode 100644
index 00000000000..a395e9f05c6
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/groin.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_l.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_l.png
new file mode 100644
index 00000000000..db6cdef758e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_l.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_r.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_r.png
new file mode 100644
index 00000000000..8975ad51f44
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/hand_r.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/harm.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/harm.png
new file mode 100644
index 00000000000..e7f035a09c5
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/harm.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/head.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/head.png
new file mode 100644
index 00000000000..b65ec5126ad
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/head.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health0.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health0.png
new file mode 100644
index 00000000000..a58d33d1e73
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health0.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health1.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health1.png
new file mode 100644
index 00000000000..2e8301d882f
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health1.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health2.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health2.png
new file mode 100644
index 00000000000..db21bb56bf6
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health2.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health3.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health3.png
new file mode 100644
index 00000000000..3b580b59d7b
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health3.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health4.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health4.png
new file mode 100644
index 00000000000..7fe82d3fc92
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health4.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health5.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health5.png
new file mode 100644
index 00000000000..833fc3a43f6
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health5.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health6.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health6.png
new file mode 100644
index 00000000000..bcb9f411304
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health6.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health7.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health7.png
new file mode 100644
index 00000000000..707c3494bec
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health7.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/health8.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/health8.png
new file mode 100644
index 00000000000..f8b4fc6a1a1
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/health8.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/help.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/help.png
new file mode 100644
index 00000000000..73db56bcfcf
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/help.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/l_arm.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/l_arm.png
new file mode 100644
index 00000000000..68a527594c1
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/l_arm.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/l_leg.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/l_leg.png
new file mode 100644
index 00000000000..def83c635fc
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/l_leg.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_off.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_off.png
new file mode 100644
index 00000000000..3ab1371b3ed
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_off.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_on.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_on.png
new file mode 100644
index 00000000000..a8a67fef2ae
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/leap_on.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/lhandactive.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/lhandactive.png
new file mode 100644
index 00000000000..8552376518e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/lhandactive.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/meta.json b/Resources/Textures/Interface/Alien/screen_alien.rsi/meta.json
new file mode 100644
index 00000000000..d075797db64
--- /dev/null
+++ b/Resources/Textures/Interface/Alien/screen_alien.rsi/meta.json
@@ -0,0 +1,197 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation on https://github.com/tgstation/tgstation/blob/master/icons/hud/screen_alien.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "suit"
+ },
+ {
+ "name": "pocket"
+ },
+ {
+ "name": "hand_r"
+ },
+ {
+ "name": "hand_l"
+ },
+ {
+ "name": "rhandactive"
+ },
+ {
+ "name": "lhandactive"
+ },
+ {
+ "name": "pull"
+ },
+ {
+ "name": "act_resist"
+ },
+ {
+ "name": "act_drop"
+ },
+ {
+ "name": "act_rest"
+ },
+ {
+ "name": "act_rest0"
+ },
+ {
+ "name": "act_throw_off"
+ },
+ {
+ "name": "act_throw_on"
+ },
+ {
+ "name": "swap_1"
+ },
+ {
+ "name": "swap_2"
+ },
+ {
+ "name": "harm"
+ },
+ {
+ "name": "help"
+ },
+ {
+ "name": "disarm"
+ },
+ {
+ "name": "grab"
+ },
+ {
+ "name": "walking"
+ },
+ {
+ "name": "running"
+ },
+ {
+ "name": "zone_sel"
+ },
+ {
+ "name": "leap_off"
+ },
+ {
+ "name": "leap_on"
+ },
+ {
+ "name": "template"
+ },
+ {
+ "name": "reserved"
+ },
+ {
+ "name": "template_frame"
+ },
+ {
+ "name": "health0"
+ },
+ {
+ "name": "health1"
+ },
+ {
+ "name": "health2"
+ },
+ {
+ "name": "health3"
+ },
+ {
+ "name": "health4"
+ },
+ {
+ "name": "health5"
+ },
+ {
+ "name": "health6",
+ "delays": [
+ [
+ 0.5,
+ 0.5
+ ]
+ ]
+ },
+ {
+ "name": "health7"
+ },
+ {
+ "name": "health8"
+ },
+ {
+ "name": "power_display"
+ },
+ {
+ "name": "chest"
+ },
+ {
+ "name": "groin"
+ },
+ {
+ "name": "r_arm"
+ },
+ {
+ "name": "l_arm"
+ },
+ {
+ "name": "r_leg"
+ },
+ {
+ "name": "l_leg"
+ },
+ {
+ "name": "eyes"
+ },
+ {
+ "name": "mouth"
+ },
+ {
+ "name": "head"
+ },
+ {
+ "name": "nightvision0"
+ },
+ {
+ "name": "nightvision1"
+ },
+ {
+ "name": "queen_finder"
+ },
+ {
+ "name": "finder_med",
+ "directions": 8
+ },
+ {
+ "name": "finder_near",
+ "directions": 8
+ },
+ {
+ "name": "finder_center",
+ "delays": [
+ [
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "finder_far",
+ "directions": 8
+ },
+ {
+ "name": "combat_off"
+ },
+ {
+ "name": "combat"
+ },
+ {
+ "name": "scroll_up"
+ },
+ {
+ "name": "scroll_down"
+ }
+ ]
+}
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/mouth.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/mouth.png
new file mode 100644
index 00000000000..5d6450f0e50
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/mouth.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision0.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision0.png
new file mode 100644
index 00000000000..06fa77f7150
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision0.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision1.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision1.png
new file mode 100644
index 00000000000..c2457ead6a6
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/nightvision1.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/pocket.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/pocket.png
new file mode 100644
index 00000000000..6f5e6ff683b
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/pocket.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/power_display.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/power_display.png
new file mode 100644
index 00000000000..0f71a023e8f
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/power_display.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/pull.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/pull.png
new file mode 100644
index 00000000000..547b71b3f3d
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/pull.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/queen_finder.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/queen_finder.png
new file mode 100644
index 00000000000..fe688a3a6b3
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/queen_finder.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/r_arm.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/r_arm.png
new file mode 100644
index 00000000000..262596c5654
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/r_arm.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/r_leg.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/r_leg.png
new file mode 100644
index 00000000000..f56a05a4f9c
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/r_leg.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/reserved.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/reserved.png
new file mode 100644
index 00000000000..2ffc795d4b9
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/reserved.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/rhandactive.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/rhandactive.png
new file mode 100644
index 00000000000..8552376518e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/rhandactive.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/running.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/running.png
new file mode 100644
index 00000000000..e9d8b6edbcb
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/running.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_down.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_down.png
new file mode 100644
index 00000000000..5385be4053e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_down.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_up.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_up.png
new file mode 100644
index 00000000000..336483f617f
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/scroll_up.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/suit.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/suit.png
new file mode 100644
index 00000000000..958b78f6f6e
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/suit.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_1.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_1.png
new file mode 100644
index 00000000000..c36e27beae6
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_1.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_2.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_2.png
new file mode 100644
index 00000000000..e519a6b9f59
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/swap_2.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/template.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/template.png
new file mode 100644
index 00000000000..ced0e918c89
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/template.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/template_frame.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/template_frame.png
new file mode 100644
index 00000000000..c4791470a60
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/template_frame.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/walking.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/walking.png
new file mode 100644
index 00000000000..7dae9747049
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/walking.png differ
diff --git a/Resources/Textures/Interface/Alien/screen_alien.rsi/zone_sel.png b/Resources/Textures/Interface/Alien/screen_alien.rsi/zone_sel.png
new file mode 100644
index 00000000000..0f5e16d7815
Binary files /dev/null and b/Resources/Textures/Interface/Alien/screen_alien.rsi/zone_sel.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected0.png b/Resources/Textures/Interface/Misc/infected.rsi/infected0.png
new file mode 100644
index 00000000000..3960ecc2a7b
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected0.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected1.png b/Resources/Textures/Interface/Misc/infected.rsi/infected1.png
new file mode 100644
index 00000000000..3960ecc2a7b
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected1.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected2.png b/Resources/Textures/Interface/Misc/infected.rsi/infected2.png
new file mode 100644
index 00000000000..530c30afe33
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected2.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected3.png b/Resources/Textures/Interface/Misc/infected.rsi/infected3.png
new file mode 100644
index 00000000000..8b4b1f3b44d
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected3.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected4.png b/Resources/Textures/Interface/Misc/infected.rsi/infected4.png
new file mode 100644
index 00000000000..866493beb89
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected4.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/infected5.png b/Resources/Textures/Interface/Misc/infected.rsi/infected5.png
new file mode 100644
index 00000000000..866493beb89
Binary files /dev/null and b/Resources/Textures/Interface/Misc/infected.rsi/infected5.png differ
diff --git a/Resources/Textures/Interface/Misc/infected.rsi/meta.json b/Resources/Textures/Interface/Misc/infected.rsi/meta.json
new file mode 100644
index 00000000000..c30eed24681
--- /dev/null
+++ b/Resources/Textures/Interface/Misc/infected.rsi/meta.json
@@ -0,0 +1,29 @@
+{
+ "version": 1,
+ "license": null,
+ "copyright": null,
+ "size": {
+ "x": 8,
+ "y": 9
+ },
+ "states": [
+ {
+ "name": "infected0"
+ },
+ {
+ "name": "infected1"
+ },
+ {
+ "name": "infected2"
+ },
+ {
+ "name": "infected3"
+ },
+ {
+ "name": "infected4"
+ },
+ {
+ "name": "infected5"
+ }
+ ]
+}
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Crawl.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Crawl.png
new file mode 100644
index 00000000000..631ee105530
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Crawl.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Back_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Back_Half.png
new file mode 100644
index 00000000000..659469fd448
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Back_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Front_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Front_Half.png
new file mode 100644
index 00000000000..ffad609b76d
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Drone_Front_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Back_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Back_Half.png
new file mode 100644
index 00000000000..659469fd448
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Back_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Front_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Front_Half.png
new file mode 100644
index 00000000000..9c0838856a4
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Front_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Stalking.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Stalking.png
new file mode 100644
index 00000000000..732b1798b07
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Hunter_Stalking.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Back_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Back_Half.png
new file mode 100644
index 00000000000..a001605c228
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Back_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Front_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Front_Half.png
new file mode 100644
index 00000000000..3752126759e
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Praetorian_Front_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Back_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Back_Half.png
new file mode 100644
index 00000000000..659469fd448
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Back_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Front_Half.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Front_Half.png
new file mode 100644
index 00000000000..b0315168bed
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Sentinel_Front_Half.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Stand.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Stand.png
new file mode 100644
index 00000000000..4b69b4603ff
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/Stand.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/acid.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/acid.png
new file mode 100644
index 00000000000..46053a7c1ae
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/acid.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal.png
new file mode 100644
index 00000000000..5f92be9f933
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal_active.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal_active.png
new file mode 100644
index 00000000000..862f6280eef
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alien_medal_active.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliencuff.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliencuff.png
new file mode 100644
index 00000000000..a4940bd1333
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliencuff.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend.png
new file mode 100644
index 00000000000..8e382949285
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_dead.png
new file mode 100644
index 00000000000..4571e1c06d0
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_husked.png
new file mode 100644
index 00000000000..73e36acfd21
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_pounce.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_pounce.png
new file mode 100644
index 00000000000..41f6ae0afb2
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_pounce.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_sleep.png
new file mode 100644
index 00000000000..a172ade2185
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_unconscious.png
new file mode 100644
index 00000000000..778bc0f11fa
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliend_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh.png
new file mode 100644
index 00000000000..29db838b5a5
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_dead.png
new file mode 100644
index 00000000000..79edd21d5d2
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_husked.png
new file mode 100644
index 00000000000..b733a990fbe
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_pounce.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_pounce.png
new file mode 100644
index 00000000000..1d2d1df7c5b
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_pounce.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_sleep.png
new file mode 100644
index 00000000000..f416b23394c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_unconscious.png
new file mode 100644
index 00000000000..a0e0aadadfa
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienh_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienother.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienother.png
new file mode 100644
index 00000000000..524096d55d1
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienother.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq.png
new file mode 100644
index 00000000000..4865a3c193c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_dead.png
new file mode 100644
index 00000000000..62bd50eb519
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_husked.png
new file mode 100644
index 00000000000..9b295cdfdec
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_sleep.png
new file mode 100644
index 00000000000..6d841082570
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_unconscious.png
new file mode 100644
index 00000000000..80a9fadabd2
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienq_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens.png
new file mode 100644
index 00000000000..d985b0180dd
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_dead.png
new file mode 100644
index 00000000000..5c7d62c547c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_husked.png
new file mode 100644
index 00000000000..fdc8aba4f15
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_pounce.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_pounce.png
new file mode 100644
index 00000000000..7a773b5637a
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_pounce.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_sleep.png
new file mode 100644
index 00000000000..0a8ae92a313
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_unconscious.png
new file mode 100644
index 00000000000..6de88942d0d
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/aliens_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit.png
new file mode 100644
index 00000000000..57055144dbb
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit_leap.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit_leap.png
new file mode 100644
index 00000000000..9e69d48f7bf
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/alienspit_leap.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_lie.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_lie.png
new file mode 100644
index 00000000000..a9a40359c14
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_lie.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_stand.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_stand.png
new file mode 100644
index 00000000000..d74ddb08e55
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/burst_stand.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_lie.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_lie.png
new file mode 100644
index 00000000000..38212e7b581
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_lie.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_stand.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_stand.png
new file mode 100644
index 00000000000..236eeefdbcc
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/bursted_stand.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/chitin.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/chitin.png
new file mode 100644
index 00000000000..e15a0cb59a1
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/chitin.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/claw.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/claw.png
new file mode 100644
index 00000000000..d49223cf498
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/claw.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg.png
new file mode 100644
index 00000000000..00f63624c75
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_growing.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_growing.png
new file mode 100644
index 00000000000..0a170d6def0
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_growing.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_hatched.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_hatched.png
new file mode 100644
index 00000000000..12543880fb1
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_hatched.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_opening.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_opening.png
new file mode 100644
index 00000000000..cb764baa2d6
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/egg_opening.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger.png
new file mode 100644
index 00000000000..361ee97a4f2
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_dead.png
new file mode 100644
index 00000000000..07e4240f1ec
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_impregnated.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_impregnated.png
new file mode 100644
index 00000000000..b5a321498bc
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_impregnated.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_inactive.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_inactive.png
new file mode 100644
index 00000000000..09d1f5d71e3
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_inactive.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_thrown.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_thrown.png
new file mode 100644
index 00000000000..7f109fac7be
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/facehugger_thrown.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected0.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected0.png
new file mode 100644
index 00000000000..479a784d569
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected0.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected1.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected1.png
new file mode 100644
index 00000000000..479a784d569
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected1.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected2.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected2.png
new file mode 100644
index 00000000000..aa27ce4696c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected2.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected3.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected3.png
new file mode 100644
index 00000000000..aa27ce4696c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected3.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected4.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected4.png
new file mode 100644
index 00000000000..453fc3d4f9a
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected4.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected5.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected5.png
new file mode 100644
index 00000000000..453fc3d4f9a
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected5.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected_old.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected_old.png
new file mode 100644
index 00000000000..3a6e790f392
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/infected_old.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0.png
new file mode 100644
index 00000000000..ff5587f5b5a
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_cuff.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_cuff.png
new file mode 100644
index 00000000000..5b3be2ce016
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_cuff.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_dead.png
new file mode 100644
index 00000000000..b88098bd832
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_sleep.png
new file mode 100644
index 00000000000..061222e85b5
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_stun.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_stun.png
new file mode 100644
index 00000000000..911eafe3fd8
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva0_stun.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1.png
new file mode 100644
index 00000000000..a02744e5c22
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_cuff.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_cuff.png
new file mode 100644
index 00000000000..7e12c7c912d
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_cuff.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_dead.png
new file mode 100644
index 00000000000..cb38c05490e
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_sleep.png
new file mode 100644
index 00000000000..11aeb22ef2e
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_stun.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_stun.png
new file mode 100644
index 00000000000..d19536271a4
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva1_stun.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2.png
new file mode 100644
index 00000000000..0a420c65024
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_cuff.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_cuff.png
new file mode 100644
index 00000000000..d00e8d839b2
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_cuff.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_dead.png
new file mode 100644
index 00000000000..0d51d0afd7a
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_sleep.png
new file mode 100644
index 00000000000..ff7726f68bb
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_stun.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_stun.png
new file mode 100644
index 00000000000..b6e1f487dda
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/larva2_stun.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid.png
new file mode 100644
index 00000000000..d3b21a3df1d
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid_dead.png
new file mode 100644
index 00000000000..0934e55d5e5
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/maid_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/meta.json
new file mode 100644
index 00000000000..1eefed76a14
--- /dev/null
+++ b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/meta.json
@@ -0,0 +1,625 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation: https://github.com/tgstation/tgstation/blob/master/icons/mob/nonhuman-player/alien.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "acid"
+ },
+ {
+ "name": "alienother"
+ },
+ {
+ "name": "infected_old"
+ },
+ {
+ "name": "infected0"
+ },
+ {
+ "name": "infected1"
+ },
+ {
+ "name": "infected2"
+ },
+ {
+ "name": "infected3"
+ },
+ {
+ "name": "infected4"
+ },
+ {
+ "name": "infected5"
+ },
+ {
+ "name": "facehugger",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "facehugger_inactive",
+ "directions": 4
+ },
+ {
+ "name": "facehugger_thrown",
+ "directions": 4
+ },
+ {
+ "name": "burst_stand",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "burst_lie",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "bursted_stand",
+ "directions": 4
+ },
+ {
+ "name": "bursted_lie"
+ },
+ {
+ "name": "Hunter_Stalking",
+ "directions": 4
+ },
+ {
+ "name": "Hunter_Front_Half",
+ "directions": 4
+ },
+ {
+ "name": "Hunter_Back_Half",
+ "directions": 4
+ },
+ {
+ "name": "Drone_Front_Half",
+ "directions": 4
+ },
+ {
+ "name": "Drone_Back_Half",
+ "directions": 4
+ },
+ {
+ "name": "Sentinel_Front_Half",
+ "directions": 4
+ },
+ {
+ "name": "Sentinel_Back_Half",
+ "directions": 4
+ },
+ {
+ "name": "Praetorian_Front_Half",
+ "directions": 4
+ },
+ {
+ "name": "Praetorian_Back_Half",
+ "directions": 4
+ },
+ {
+ "name": "Stand"
+ },
+ {
+ "name": "Crawl"
+ },
+ {
+ "name": "chitin"
+ },
+ {
+ "name": "claw"
+ },
+ {
+ "name": "nestoverlay"
+ },
+ {
+ "name": "egg_growing"
+ },
+ {
+ "name": "egg"
+ },
+ {
+ "name": "egg_opening",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "egg_hatched"
+ },
+ {
+ "name": "alienq",
+ "directions": 4
+ },
+ {
+ "name": "alienq_sleep"
+ },
+ {
+ "name": "alienq_unconscious"
+ },
+ {
+ "name": "alienq_dead"
+ },
+ {
+ "name": "alienq_husked"
+ },
+ {
+ "name": "alien_medal"
+ },
+ {
+ "name": "alien_medal_active"
+ },
+ {
+ "name": "alienh",
+ "directions": 4
+ },
+ {
+ "name": "aliend",
+ "directions": 4
+ },
+ {
+ "name": "aliens",
+ "directions": 4
+ },
+ {
+ "name": "alienh_pounce",
+ "directions": 4
+ },
+ {
+ "name": "aliend_pounce",
+ "directions": 4
+ },
+ {
+ "name": "aliens_pounce",
+ "directions": 4
+ },
+ {
+ "name": "alienh_sleep",
+ "directions": 4
+ },
+ {
+ "name": "aliend_sleep",
+ "directions": 4
+ },
+ {
+ "name": "aliens_sleep",
+ "directions": 4
+ },
+ {
+ "name": "alienh_unconscious"
+ },
+ {
+ "name": "aliend_unconscious"
+ },
+ {
+ "name": "aliens_unconscious"
+ },
+ {
+ "name": "aliens_dead"
+ },
+ {
+ "name": "alienh_dead"
+ },
+ {
+ "name": "aliend_dead"
+ },
+ {
+ "name": "alienh_husked"
+ },
+ {
+ "name": "aliend_husked"
+ },
+ {
+ "name": "aliens_husked"
+ },
+ {
+ "name": "larva0",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "larva0_sleep",
+ "delays": [
+ [
+ 1,
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "larva0_stun",
+ "directions": 4,
+ "delays": [
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ]
+ ]
+ },
+ {
+ "name": "larva0_cuff",
+ "directions": 4
+ },
+ {
+ "name": "larva0_dead"
+ },
+ {
+ "name": "larva1",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "larva1_sleep",
+ "delays": [
+ [
+ 1,
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "larva1_stun",
+ "directions": 4,
+ "delays": [
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ]
+ ]
+ },
+ {
+ "name": "larva1_cuff",
+ "directions": 4
+ },
+ {
+ "name": "larva1_dead"
+ },
+ {
+ "name": "larva2",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "larva2_sleep",
+ "delays": [
+ [
+ 1,
+ 1
+ ]
+ ]
+ },
+ {
+ "name": "larva2_stun",
+ "directions": 4,
+ "delays": [
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ],
+ [
+ 0.7,
+ 0.7
+ ]
+ ]
+ },
+ {
+ "name": "larva2_cuff",
+ "directions": 4
+ },
+ {
+ "name": "larva2_dead"
+ },
+ {
+ "name": "facehugger_dead"
+ },
+ {
+ "name": "facehugger_impregnated"
+ },
+ {
+ "name": "maid",
+ "directions": 4
+ },
+ {
+ "name": "maid_dead"
+ },
+ {
+ "name": "alienspit",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "alienspit_leap",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "aliencuff",
+ "directions": 4
+ },
+ {
+ "name": "tail_lash"
+ }
+ ]
+}
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/nestoverlay.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/nestoverlay.png
new file mode 100644
index 00000000000..74ad4c8a89c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/nestoverlay.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/tail_lash.png b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/tail_lash.png
new file mode 100644
index 00000000000..8dff74629d0
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien.rsi/tail_lash.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/icon.png b/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/icon.png
new file mode 100644
index 00000000000..25d3f75cc49
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/icon.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/meta.json
new file mode 100644
index 00000000000..6acf638d031
--- /dev/null
+++ b/Resources/Textures/Mobs/Aliens/Xenos/alien_hunter_jump.rsi/meta.json
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation: https://github.com/tgstation/tgstation/blob/master/icons/mob/nonhuman-player/alien.dmi",
+ "size": {
+ "x": 64,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_p.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_p.png
new file mode 100644
index 00000000000..5564f93d7d8
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_p.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_q.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_q.png
new file mode 100644
index 00000000000..c27318b36e5
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/aliencuff_q.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp.png
new file mode 100644
index 00000000000..823b45d579c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_dead.png
new file mode 100644
index 00000000000..196d4573301
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_husked.png
new file mode 100644
index 00000000000..bfda7d4d5ec
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_running.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_running.png
new file mode 100644
index 00000000000..823b45d579c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_running.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_sleep.png
new file mode 100644
index 00000000000..191bd40e2df
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_unconscious.png
new file mode 100644
index 00000000000..18cb133d35f
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienp_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq.png
new file mode 100644
index 00000000000..e26765dc0d8
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_dead.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_dead.png
new file mode 100644
index 00000000000..530e80ae14d
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_husked.png
new file mode 100644
index 00000000000..1c28e50d528
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_running.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_running.png
new file mode 100644
index 00000000000..e26765dc0d8
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_running.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_sleep.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_sleep.png
new file mode 100644
index 00000000000..faca73b689c
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_sleep.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_unconscious.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_unconscious.png
new file mode 100644
index 00000000000..7b847b99549
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienq_unconscious.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienqmaid_husked.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienqmaid_husked.png
new file mode 100644
index 00000000000..1e9c3fc1ff7
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienqmaid_husked.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_p.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_p.png
new file mode 100644
index 00000000000..5fae8c65cae
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_p.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_q.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_q.png
new file mode 100644
index 00000000000..efbdce2c26b
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/alienspit_q.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_l.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_l.png
new file mode 100644
index 00000000000..49ebb37a105
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_l.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_r.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_r.png
new file mode 100644
index 00000000000..d24d8fd8511
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactivep_r.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_l.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_l.png
new file mode 100644
index 00000000000..64f99c5cdfd
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_l.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_r.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_r.png
new file mode 100644
index 00000000000..9c507d849a3
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehugger_inactiveq_r.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_l.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_l.png
new file mode 100644
index 00000000000..49ebb37a105
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_l.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_r.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_r.png
new file mode 100644
index 00000000000..d24d8fd8511
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerp_r.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_l.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_l.png
new file mode 100644
index 00000000000..64f99c5cdfd
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_l.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_r.png b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_r.png
new file mode 100644
index 00000000000..9c507d849a3
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/facehuggerq_r.png differ
diff --git a/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/meta.json
new file mode 100644
index 00000000000..993dd5d0d60
--- /dev/null
+++ b/Resources/Textures/Mobs/Aliens/Xenos/alienqueen.rsi/meta.json
@@ -0,0 +1,170 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation on: https://github.com/tgstation/tgstation/blob/master/icons/mob/nonhuman-player/alienqueen.dmi",
+ "size": {
+ "x": 64,
+ "y": 64
+ },
+ "states": [
+ {
+ "name": "alienq",
+ "directions": 4
+ },
+ {
+ "name": "alienq_running",
+ "directions": 4
+ },
+ {
+ "name": "alienq_sleep"
+ },
+ {
+ "name": "alienq_unconscious"
+ },
+ {
+ "name": "alienq_dead"
+ },
+ {
+ "name": "alienq_husked"
+ },
+ {
+ "name": "alienp",
+ "directions": 4
+ },
+ {
+ "name": "alienp_running",
+ "directions": 4
+ },
+ {
+ "name": "alienp_sleep"
+ },
+ {
+ "name": "alienp_unconscious"
+ },
+ {
+ "name": "alienp_dead"
+ },
+ {
+ "name": "alienp_husked"
+ },
+ {
+ "name": "facehuggerq_r",
+ "directions": 4
+ },
+ {
+ "name": "facehuggerq_l",
+ "directions": 4
+ },
+ {
+ "name": "facehuggerp_r",
+ "directions": 4
+ },
+ {
+ "name": "facehuggerp_l",
+ "directions": 4
+ },
+ {
+ "name": "facehugger_inactiveq_r",
+ "directions": 4
+ },
+ {
+ "name": "facehugger_inactiveq_l",
+ "directions": 4
+ },
+ {
+ "name": "facehugger_inactivep_r",
+ "directions": 4
+ },
+ {
+ "name": "facehugger_inactivep_l",
+ "directions": 4
+ },
+ {
+ "name": "alienqmaid_husked"
+ },
+ {
+ "name": "alienspit_p",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "alienspit_q",
+ "directions": 4,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ],
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "aliencuff_p",
+ "directions": 4
+ },
+ {
+ "name": "aliencuff_q",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/acid_gland.png b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/acid_gland.png
new file mode 100644
index 00000000000..02e5548d974
Binary files /dev/null and b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/acid_gland.png differ
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/brain-x.png b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/brain-x.png
new file mode 100644
index 00000000000..bb5df36e512
Binary files /dev/null and b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/brain-x.png differ
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/eggsac.png b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/eggsac.png
new file mode 100644
index 00000000000..9712b476250
Binary files /dev/null and b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/eggsac.png differ
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/hivenode.png b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/hivenode.png
new file mode 100644
index 00000000000..308f0bc7685
Binary files /dev/null and b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/hivenode.png differ
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/meta.json b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/meta.json
new file mode 100644
index 00000000000..2789988eb75
--- /dev/null
+++ b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+ "version": 1,
+ "license": null,
+ "copyright": null,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "hivenode"
+ },
+ {
+ "name": "plasma_vessel"
+ },
+ {
+ "name": "acid_gland"
+ },
+ {
+ "name": "eggsac"
+ },
+ {
+ "name": "brain-x"
+ }
+ ]
+}
diff --git a/Resources/Textures/Mobs/Species/Xeno/organs.rsi/plasma_vessel.png b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/plasma_vessel.png
new file mode 100644
index 00000000000..2a1490c2508
Binary files /dev/null and b/Resources/Textures/Mobs/Species/Xeno/organs.rsi/plasma_vessel.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/full.png b/Resources/Textures/Structures/Walls/resin.rsi/full.png
new file mode 100644
index 00000000000..39497166714
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/full.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/meta.json b/Resources/Textures/Structures/Walls/resin.rsi/meta.json
new file mode 100644
index 00000000000..2cdd98533c2
--- /dev/null
+++ b/Resources/Textures/Structures/Walls/resin.rsi/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "",
+ "copyright": "",
+ "states": [
+ {
+ "name": "resinwall0",
+ "directions": 4
+ },
+ {
+ "name": "resinwall1",
+ "directions": 4
+ },
+ {
+ "name": "resinwall2",
+ "directions": 4
+ },
+ {
+ "name": "resinwall3",
+ "directions": 4
+ },
+ {
+ "name": "resinwall4",
+ "directions": 4
+ },
+ {
+ "name": "resinwall5",
+ "directions": 4
+ },
+ {
+ "name": "resinwall6",
+ "directions": 4
+ },
+ {
+ "name": "resinwall7",
+ "directions": 4
+ },
+ {
+ "name": "full",
+ "directions": 1
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall0.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall0.png
new file mode 100644
index 00000000000..9f219aa14eb
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall0.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall1.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall1.png
new file mode 100644
index 00000000000..54b6613679f
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall1.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall2.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall2.png
new file mode 100644
index 00000000000..9f219aa14eb
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall2.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall3.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall3.png
new file mode 100644
index 00000000000..54b6613679f
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall3.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall4.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall4.png
new file mode 100644
index 00000000000..9ab9dffeab6
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall4.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall5.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall5.png
new file mode 100644
index 00000000000..dd1a5daebe3
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall5.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall6.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall6.png
new file mode 100644
index 00000000000..9ab9dffeab6
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall6.png differ
diff --git a/Resources/Textures/Structures/Walls/resin.rsi/resinwall7.png b/Resources/Textures/Structures/Walls/resin.rsi/resinwall7.png
new file mode 100644
index 00000000000..dd1a5daebe3
Binary files /dev/null and b/Resources/Textures/Structures/Walls/resin.rsi/resinwall7.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/full.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/full.png
new file mode 100644
index 00000000000..c6501ceacdd
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/full.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/meta.json b/Resources/Textures/Structures/Windows/resin_membrane.rsi/meta.json
new file mode 100644
index 00000000000..fe1f5195edd
--- /dev/null
+++ b/Resources/Textures/Structures/Windows/resin_membrane.rsi/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "",
+ "copyright": "",
+ "states": [
+ {
+ "name": "resin_membrane0",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane1",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane2",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane3",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane4",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane5",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane6",
+ "directions": 4
+ },
+ {
+ "name": "resin_membrane7",
+ "directions": 4
+ },
+ {
+ "name": "full",
+ "directions": 1
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane0.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane0.png
new file mode 100644
index 00000000000..55591093492
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane0.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane1.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane1.png
new file mode 100644
index 00000000000..aedd5b68e42
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane1.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane2.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane2.png
new file mode 100644
index 00000000000..55591093492
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane2.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane3.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane3.png
new file mode 100644
index 00000000000..aedd5b68e42
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane3.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane4.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane4.png
new file mode 100644
index 00000000000..24613a3ff82
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane4.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane5.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane5.png
new file mode 100644
index 00000000000..92df698994f
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane5.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane6.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane6.png
new file mode 100644
index 00000000000..24613a3ff82
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane6.png differ
diff --git a/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane7.png b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane7.png
new file mode 100644
index 00000000000..92df698994f
Binary files /dev/null and b/Resources/Textures/Structures/Windows/resin_membrane.rsi/resin_membrane7.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest0.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest0.png
new file mode 100644
index 00000000000..f66f4f5953e
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest0.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest1.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest1.png
new file mode 100644
index 00000000000..8f5b1bf4453
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest1.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest2.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest2.png
new file mode 100644
index 00000000000..f66f4f5953e
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest2.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest3.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest3.png
new file mode 100644
index 00000000000..8f5b1bf4453
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest3.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest4.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest4.png
new file mode 100644
index 00000000000..293b94f8e30
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest4.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest5.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest5.png
new file mode 100644
index 00000000000..df351fc7b83
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest5.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest6.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest6.png
new file mode 100644
index 00000000000..293b94f8e30
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest6.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/alien_nest7.png b/Resources/Textures/Structures/alien_nest.rsi/alien_nest7.png
new file mode 100644
index 00000000000..df351fc7b83
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/alien_nest7.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/full.png b/Resources/Textures/Structures/alien_nest.rsi/full.png
new file mode 100644
index 00000000000..d814546feca
Binary files /dev/null and b/Resources/Textures/Structures/alien_nest.rsi/full.png differ
diff --git a/Resources/Textures/Structures/alien_nest.rsi/meta.json b/Resources/Textures/Structures/alien_nest.rsi/meta.json
new file mode 100644
index 00000000000..7f788762217
--- /dev/null
+++ b/Resources/Textures/Structures/alien_nest.rsi/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation on https://github.com/tgstation/tgstation/blob/master/icons/obj/smooth_structures/alien/nest.dmi",
+ "states": [
+ {
+ "name": "alien_nest0",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest1",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest2",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest3",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest4",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest5",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest6",
+ "directions": 4
+ },
+ {
+ "name": "alien_nest7",
+ "directions": 4
+ },
+ {
+ "name": "full",
+ "directions": 1
+ }
+ ]
+}
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/full.png b/Resources/Textures/Structures/resin_weeds.rsi/full.png
new file mode 100644
index 00000000000..ac07e2b5012
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/full.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/meta.json b/Resources/Textures/Structures/resin_weeds.rsi/meta.json
new file mode 100644
index 00000000000..6be2897d356
--- /dev/null
+++ b/Resources/Textures/Structures/resin_weeds.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/vgstation-coders/vgstation13/raw/99cc2ab62d65a3a7b554dc7b21ff5f57c835f973/icons/turf/walls.dmi", "states": [{"name": "resin-weeds0", "directions": 4}, {"name": "resin-weeds1", "directions": 4}, {"name": "resin-weeds2", "directions": 4}, {"name": "resin-weeds3", "directions": 4}, {"name": "resin-weeds4", "directions": 4}, {"name": "resin-weeds5", "directions": 4}, {"name": "resin-weeds6", "directions": 4}, {"name": "resin-weeds7", "directions": 4}, {"name": "full"}]}
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds0.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds0.png
new file mode 100644
index 00000000000..ebac83ba997
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds0.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds1.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds1.png
new file mode 100644
index 00000000000..d2c6702aaee
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds1.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds2.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds2.png
new file mode 100644
index 00000000000..ebac83ba997
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds2.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds3.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds3.png
new file mode 100644
index 00000000000..d2c6702aaee
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds3.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds4.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds4.png
new file mode 100644
index 00000000000..e13effee6a2
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds4.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds5.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds5.png
new file mode 100644
index 00000000000..b78a004d4c0
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds5.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds6.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds6.png
new file mode 100644
index 00000000000..e13effee6a2
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds6.png differ
diff --git a/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds7.png b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds7.png
new file mode 100644
index 00000000000..b78a004d4c0
Binary files /dev/null and b/Resources/Textures/Structures/resin_weeds.rsi/resin-weeds7.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/full.png b/Resources/Textures/Structures/weednode.rsi/full.png
new file mode 100644
index 00000000000..58bf43fbb26
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/full.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/meta.json b/Resources/Textures/Structures/weednode.rsi/meta.json
new file mode 100644
index 00000000000..62d84a37922
--- /dev/null
+++ b/Resources/Textures/Structures/weednode.rsi/meta.json
@@ -0,0 +1,15 @@
+{
+ "version": 1,
+ "size": {
+ "x": 40,
+ "y": 40
+ },
+ "license": "",
+ "copyright": "",
+ "states": [
+ {
+ "name": "full",
+ "directions": 1
+ }
+ ]
+}
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode0.png b/Resources/Textures/Structures/weednode.rsi/weednode0.png
new file mode 100644
index 00000000000..d3452111830
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode0.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode1.png b/Resources/Textures/Structures/weednode.rsi/weednode1.png
new file mode 100644
index 00000000000..4ea5287a12c
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode1.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode2.png b/Resources/Textures/Structures/weednode.rsi/weednode2.png
new file mode 100644
index 00000000000..d3452111830
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode2.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode3.png b/Resources/Textures/Structures/weednode.rsi/weednode3.png
new file mode 100644
index 00000000000..4ea5287a12c
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode3.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode4.png b/Resources/Textures/Structures/weednode.rsi/weednode4.png
new file mode 100644
index 00000000000..7c296e19052
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode4.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode5.png b/Resources/Textures/Structures/weednode.rsi/weednode5.png
new file mode 100644
index 00000000000..c2c011fb3d0
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode5.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode6.png b/Resources/Textures/Structures/weednode.rsi/weednode6.png
new file mode 100644
index 00000000000..7c296e19052
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode6.png differ
diff --git a/Resources/Textures/Structures/weednode.rsi/weednode7.png b/Resources/Textures/Structures/weednode.rsi/weednode7.png
new file mode 100644
index 00000000000..c2c011fb3d0
Binary files /dev/null and b/Resources/Textures/Structures/weednode.rsi/weednode7.png differ