diff --git a/Content.Server/DeltaV/Ghost/Roles/Components/GhostRoleCharacterSpawnerComponent.cs b/Content.Server/DeltaV/Ghost/Roles/Components/GhostRoleCharacterSpawnerComponent.cs
new file mode 100644
index 00000000000..e2aaa94d948
--- /dev/null
+++ b/Content.Server/DeltaV/Ghost/Roles/Components/GhostRoleCharacterSpawnerComponent.cs
@@ -0,0 +1,22 @@
+namespace Content.Server.Ghost.Roles.Components
+{
+ ///
+ /// Allows a ghost to take this role, spawning their selected character.
+ ///
+ [RegisterComponent]
+ [Access(typeof(GhostRoleSystem))]
+ public sealed partial class GhostRoleCharacterSpawnerComponent : Component
+ {
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("deleteOnSpawn")]
+ public bool DeleteOnSpawn = true;
+
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("availableTakeovers")]
+ public int AvailableTakeovers = 1;
+
+ [ViewVariables]
+ public int CurrentTakeovers = 0;
+
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("outfitPrototype")]
+ public string OutfitPrototype = "PassengerGear";
+ }
+}
diff --git a/Content.Server/DeltaV/Ghost/Roles/GhostRoleSystem.Character.cs b/Content.Server/DeltaV/Ghost/Roles/GhostRoleSystem.Character.cs
new file mode 100644
index 00000000000..ced4ec802d8
--- /dev/null
+++ b/Content.Server/DeltaV/Ghost/Roles/GhostRoleSystem.Character.cs
@@ -0,0 +1,63 @@
+using Content.Server.Administration.Commands;
+using Content.Server.Ghost.Roles.Components;
+using Content.Server.Ghost.Roles.Events;
+using Content.Server.Preferences.Managers;
+using Content.Server.Station.Systems;
+using Content.Shared.Mind.Components;
+using Content.Shared.Preferences;
+using Content.Shared.Roles;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Ghost.Roles
+{
+ public sealed partial class GhostRoleSystem
+ {
+ [Dependency] private readonly IServerPreferencesManager _prefs = default!;
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+
+ private void OnSpawnerTakeCharacter( EntityUid uid, GhostRoleCharacterSpawnerComponent component,
+ ref TakeGhostRoleEvent args)
+ {
+ if (!TryComp(uid, out GhostRoleComponent? ghostRole) ||
+ ghostRole.Taken)
+ {
+ args.TookRole = false;
+ return;
+ }
+
+ var character = (HumanoidCharacterProfile) _prefs.GetPreferences(args.Player.UserId).SelectedCharacter;
+
+ var mob = _entityManager.System()
+ .SpawnPlayerMob(Transform(uid).Coordinates, null, character, null);
+ _transform.AttachToGridOrMap(mob);
+
+ string? outfit = null;
+ if (_prototypeManager.TryIndex(component.OutfitPrototype, out var outfitProto))
+ outfit = outfitProto.ID;
+
+ var spawnedEvent = new GhostRoleSpawnerUsedEvent(uid, mob);
+ RaiseLocalEvent(mob, spawnedEvent);
+
+ EnsureComp(mob);
+
+ GhostRoleInternalCreateMindAndTransfer(args.Player, uid, mob, ghostRole);
+
+ if (outfit != null)
+ SetOutfitCommand.SetOutfit(mob, outfit, _entityManager);
+
+ if (++component.CurrentTakeovers < component.AvailableTakeovers)
+ {
+ args.TookRole = true;
+ return;
+ }
+
+ ghostRole.Taken = true;
+
+ if (component.DeleteOnSpawn)
+ QueueDel(uid);
+
+ args.TookRole = true;
+ }
+ }
+}
diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs
index 98a62d39707..cb44b196d35 100644
--- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs
+++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs
@@ -27,7 +27,7 @@
namespace Content.Server.Ghost.Roles
{
[UsedImplicitly]
- public sealed class GhostRoleSystem : EntitySystem
+ public sealed partial class GhostRoleSystem : EntitySystem // Converted to partial to allow for DeltaV character ghost roles
{
[Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
@@ -62,6 +62,7 @@ public override void Initialize()
SubscribeLocalEvent(OnUnpaused);
SubscribeLocalEvent(OnSpawnerTakeRole);
SubscribeLocalEvent(OnTakeoverTakeRole);
+ SubscribeLocalEvent(OnSpawnerTakeCharacter); // DeltaV - Character ghost roles, see Content.Server/DeltaV/Ghost/Roles/GhostRoleSystem.Character.cs
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
}
diff --git a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml
new file mode 100644
index 00000000000..e1f06b82ec0
--- /dev/null
+++ b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml
@@ -0,0 +1,17 @@
+- type: entity
+ id: SpawnPointPlayerCharacter
+ name: ghost role spawn point
+ suffix: player character, DO NOT MAP
+ parent: MarkerBase
+ components:
+ - type: GhostRole
+ name: Roleplay Ghost Role
+ description: Placeholder
+ rules: Placeholder
+ - type: GhostRoleCharacterSpawner
+ - type: Sprite
+ sprite: Markers/jobs.rsi
+ layers:
+ - state: green
+ - sprite: Mobs/Species/Human/parts.rsi
+ state: full