diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs
index 2f4117bc1e..a40b695885 100644
--- a/Content.Client/Entry/IgnoredComponents.cs
+++ b/Content.Client/Entry/IgnoredComponents.cs
@@ -173,6 +173,8 @@ namespace Content.Client.Entry
"ExaminableSolution",
"DrawableSolution",
"InjectableSolution",
+ "SalvageMobRestrictions",
+ "SalvageMobRestrictionsGrid",
"Barotrauma",
"GasVentPump",
"GasPassiveVent",
diff --git a/Content.Server/Salvage/SalvageMobRestrictionsComponent.cs b/Content.Server/Salvage/SalvageMobRestrictionsComponent.cs
new file mode 100644
index 0000000000..eabad86e5f
--- /dev/null
+++ b/Content.Server/Salvage/SalvageMobRestrictionsComponent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+using System;
+
+namespace Content.Server.Salvage;
+
+///
+/// This component exists as a sort of stateful marker for a
+/// killswitch meant to keep salvage mobs from doing stuff they
+/// really shouldn't (attacking station).
+/// The main thing is that adding this component ties the mob to
+/// whatever it's currently parented to.
+///
+[RegisterComponent]
+public sealed class SalvageMobRestrictionsComponent : Component
+{
+ [ViewVariables(VVAccess.ReadOnly)]
+ [DataField("linkedGridEntity")]
+ public EntityUid LinkedGridEntity = EntityUid.Invalid;
+}
+
diff --git a/Content.Server/Salvage/SalvageMobRestrictionsGridComponent.cs b/Content.Server/Salvage/SalvageMobRestrictionsGridComponent.cs
new file mode 100644
index 0000000000..6d7bf93ec0
--- /dev/null
+++ b/Content.Server/Salvage/SalvageMobRestrictionsGridComponent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+using System;
+
+namespace Content.Server.Salvage;
+
+///
+/// This component is attached to grids when a salvage mob is
+/// spawned on them.
+/// This attachment is done by SalvageMobRestrictionsSystem.
+/// *Simply put, when this component is removed, the mobs die.*
+/// *This applies even if the mobs are off-grid at the time.*
+///
+[RegisterComponent]
+public sealed class SalvageMobRestrictionsGridComponent : Component
+{
+ [ViewVariables(VVAccess.ReadOnly)]
+ [DataField("mobsToKill")]
+ public List MobsToKill = new();
+}
+
diff --git a/Content.Server/Salvage/SalvageMobRestrictionsSystem.cs b/Content.Server/Salvage/SalvageMobRestrictionsSystem.cs
new file mode 100644
index 0000000000..02fc0314cc
--- /dev/null
+++ b/Content.Server/Salvage/SalvageMobRestrictionsSystem.cs
@@ -0,0 +1,80 @@
+using Content.Shared.CCVar;
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.Damage;
+using Content.Shared.Damage;
+using Content.Server.Body.Components;
+using Robust.Server.Maps;
+using Robust.Shared.Configuration;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Log;
+using Robust.Shared.Map;
+using Robust.Shared.Maths;
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Content.Server.Salvage;
+
+public sealed class SalvageMobRestrictionsSystem : EntitySystem
+{
+ [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnRemove);
+ SubscribeLocalEvent(OnRemoveGrid);
+ }
+
+ private void OnInit(EntityUid uid, SalvageMobRestrictionsComponent component, ComponentInit args)
+ {
+ var gridUid = Transform(uid).ParentUid;
+ if (!EntityManager.EntityExists(gridUid))
+ {
+ // Give up, we were spawned improperly
+ return;
+ }
+ // When this code runs, the salvage magnet hasn't actually gotten ahold of the entity yet.
+ // So it therefore isn't in a position to do this.
+ if (!TryComp(gridUid, out SalvageMobRestrictionsGridComponent? rg))
+ {
+ rg = AddComp(gridUid);
+ }
+ rg!.MobsToKill.Add(uid);
+ component.LinkedGridEntity = gridUid;
+ }
+
+ private void OnRemove(EntityUid uid, SalvageMobRestrictionsComponent component, ComponentRemove args)
+ {
+ if (TryComp(component.LinkedGridEntity, out SalvageMobRestrictionsGridComponent? rg))
+ {
+ rg.MobsToKill.Remove(uid);
+ }
+ }
+
+ private void OnRemoveGrid(EntityUid uid, SalvageMobRestrictionsGridComponent component, ComponentRemove args)
+ {
+ foreach (EntityUid target in component.MobsToKill)
+ {
+ if (TryComp(target, out BodyComponent? body))
+ {
+ // Just because.
+ body.Gib();
+ }
+ else if (TryComp(target, out DamageableComponent? dc))
+ {
+ _damageableSystem.SetAllDamage(dc, 200);
+ }
+ }
+ }
+}
+
diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs
index b441de1c66..d315821795 100644
--- a/Content.Server/Salvage/SalvageSystem.cs
+++ b/Content.Server/Salvage/SalvageSystem.cs
@@ -189,8 +189,13 @@ namespace Content.Server.Salvage
{
if (player.AttachedEntity.HasValue)
{
- var playerTransform = EntityManager.GetComponent(player.AttachedEntity.Value);
- playerTransform.AttachParent(parentTransform);
+ var playerEntityUid = player.AttachedEntity.Value;
+ if (HasComp(playerEntityUid))
+ {
+ // Salvage mobs are NEVER immune (even if they're from a different salvage, they shouldn't be here)
+ continue;
+ }
+ Transform(playerEntityUid).AttachParent(parentTransform);
}
}
EntityManager.QueueDeleteEntity(salvage);
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/salvage.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/salvage.yml
index 3e415bf2d2..d0203be667 100644
--- a/Resources/Prototypes/Entities/Markers/Spawners/Random/salvage.yml
+++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/salvage.yml
@@ -1,3 +1,6 @@
+# NOTE! All mobs that come out of this should have Salvage rulesets.
+# These rulesets exist because Salvage mobs kept harassing the station and going out of control.
+
- type: entity
name: Salvage Material Crate Spawner
id: SalvageMaterialCrateSpawner
@@ -56,21 +59,21 @@
- texture: Mobs/Aliens/Carps/space.rsi/icon.png
- type: RandomSpawner
prototypes:
- - MobCarp
- - MobCarp
- - MobCarp
- - MobCarp
- - MobCarp
- - MobTick
- - MobTick
- - MobTick
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobTickSalvage
+ - MobTickSalvage
+ - MobTickSalvage
- PlushieCarp
- DehydratedSpaceCarp
chance: 0.25
offset: 0.2
- type: entity #I made this in case someone decided to make a terrifying space tick swarm for salvage. that someone may be me -EG404
- name: Space Tick Spawner
+ name: Salvage Space Tick Spawner
id: SpaceTickSpawner
parent: MarkerBase
suffix: 100
@@ -81,7 +84,7 @@
- texture: Mobs/Aliens/Xenos/spacetick.rsi/icon.png
- type: ConditionalSpawner
prototypes:
- - MobTick
+ - MobTickSalvage
- type: entity
id: SalvageMobSpawner75
@@ -90,14 +93,14 @@
components:
- type: RandomSpawner
prototypes:
- - MobCarp
- - MobCarp
- - MobCarp
- - MobCarp
- - MobCarp
- - MobTick
- - MobTick
- - MobTick
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobCarpSalvage
+ - MobTickSalvage
+ - MobTickSalvage
+ - MobTickSalvage
- PlushieCarp
- DehydratedSpaceCarp
chance: 0.75
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
index 1be269c2c0..4ade2dc49f 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
@@ -110,3 +110,15 @@
- Opaque
- type: GhostTakeoverAvailable
name: holocarp
+
+- type: entity
+ id: MobCarpSalvage
+ parent: MobCarp
+ suffix: "Salvage Ruleset"
+ components:
+ - type: GhostTakeoverAvailable
+ name: space carp on salvage wreck
+ description: |
+ Defend the loot inside the salvage wreck!
+ - type: SalvageMobRestrictions
+
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml
index 2228c823a5..7042b25c55 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml
@@ -77,7 +77,18 @@
makeSentient: true
name: space tick
description: |
- If you're a salvage spawn, defend the loot inside!
- Otherwise, wreak havoc on the station!
+ Wreak havoc on the station!
- type: ReplacementAccent
accent: genericAggressive
+
+- type: entity
+ id: MobTickSalvage
+ parent: MobTick
+ suffix: "Salvage Ruleset"
+ components:
+ - type: GhostTakeoverAvailable
+ name: space tick on salvage wreck
+ description: |
+ Defend the loot inside the salvage wreck!
+ - type: SalvageMobRestrictions
+