diff --git a/Content.Server/Bible/BibleSystem.cs b/Content.Server/Bible/BibleSystem.cs index e64aad7581..9ebf45b895 100644 --- a/Content.Server/Bible/BibleSystem.cs +++ b/Content.Server/Bible/BibleSystem.cs @@ -10,6 +10,8 @@ using Content.Server.Cooldown; using Content.Server.Bible.Components; using Content.Server.MobState; using Content.Server.Popups; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Ghost.Roles.Events; using Content.Shared.IdentityManagement; using Content.Shared.Popups; using Robust.Shared.Random; @@ -39,6 +41,7 @@ namespace Content.Server.Bible SubscribeLocalEvent(GetSummonAction); SubscribeLocalEvent(OnSummon); SubscribeLocalEvent(OnFamiliarDeath); + SubscribeLocalEvent(OnSpawned); } private readonly Queue _addQueue = new(); @@ -194,6 +197,17 @@ namespace Content.Server.Bible } } + /// + /// When the familiar spawns, set its source to the bible. + /// + private void OnSpawned(EntityUid uid, FamiliarComponent component, GhostRoleSpawnerUsedEvent args) + { + if (!TryComp(Transform(args.Spawner).ParentUid, out var summonable)) + return; + + component.Source = summonable.Owner; + summonable.Summon = uid; + } private void AttemptSummon(SummonableComponent component, EntityUid user, TransformComponent? position) { @@ -212,12 +226,11 @@ namespace Content.Server.Bible var familiar = EntityManager.SpawnEntity(component.SpecialItemPrototype, position.Coordinates); component.Summon = familiar; - // We only want to add the familiar component to mobs - if (HasComp(familiar)) + // If this is going to use a ghost role mob spawner, attach it to the bible. + if (HasComp(familiar)) { - // Make this Summon the familiar's source - var familiarComp = EnsureComp(familiar); - familiarComp.Source = component.Owner; + _popupSystem.PopupEntity(Loc.GetString("bible-summon-requested"), user, Filter.Pvs(user), PopupType.Medium); + Transform(familiar).AttachParent(component.Owner); } component.AlreadySummoned = true; _actionsSystem.RemoveAction(user, component.SummonAction); diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs index e9ac30c353..43c317fd34 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using Robust.Server.Player; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Content.Server.Ghost.Roles.Events; namespace Content.Server.Ghost.Roles.Components { @@ -38,6 +39,11 @@ namespace Content.Server.Ghost.Roles.Components throw new NullReferenceException("Prototype string cannot be null or empty!"); var mob = _entMan.SpawnEntity(Prototype, _entMan.GetComponent(Owner).Coordinates); + var xform = _entMan.GetComponent(mob); + xform.AttachToGridOrMap(); + + var spawnedEvent = new GhostRoleSpawnerUsedEvent(Owner, mob); + _entMan.EventBus.RaiseLocalEvent(mob, spawnedEvent, false); if (MakeSentient) MakeSentientCommand.MakeSentient(mob, _entMan); @@ -53,7 +59,7 @@ namespace Content.Server.Ghost.Roles.Components Taken = true; if (_deleteOnSpawn) - _entMan.DeleteEntity(Owner); + _entMan.QueueDeleteEntity(Owner); return true; } diff --git a/Content.Server/Ghost/Roles/Events/GhostRoleSpawnerUsedEvent.cs b/Content.Server/Ghost/Roles/Events/GhostRoleSpawnerUsedEvent.cs new file mode 100644 index 0000000000..8a9c0267e9 --- /dev/null +++ b/Content.Server/Ghost/Roles/Events/GhostRoleSpawnerUsedEvent.cs @@ -0,0 +1,25 @@ +namespace Content.Server.Ghost.Roles.Events +{ + /// + /// Raised on a spawned entity after they use a ghost role mob spawner. + /// + public sealed class GhostRoleSpawnerUsedEvent : EntityEventArgs + { + /// + /// The entity that spawned this. + /// + public EntityUid Spawner; + + /// + /// The entity spawned. + /// + public EntityUid Spawned; + + public GhostRoleSpawnerUsedEvent(EntityUid spawner, EntityUid spawned) + { + Spawner = spawner; + + Spawned = spawned; + } + } +} diff --git a/Resources/Locale/en-US/chapel/bible.ftl b/Resources/Locale/en-US/chapel/bible.ftl index d96471525e..d9287cf635 100644 --- a/Resources/Locale/en-US/chapel/bible.ftl +++ b/Resources/Locale/en-US/chapel/bible.ftl @@ -5,6 +5,7 @@ bible-heal-fail-others = {CAPITALIZE(THE($user))} hits {THE($target)} with {THE( bible-sizzle = The book sizzles in your hands! bible-summon-verb = Summon familiar bible-summon-verb-desc = Summon a familiar that will aid you and gain humanlike intelligence once inhabited by a soul. +bible-summon-requested = Your familiar will arrive once a willing soul comes forth. bible-summon-respawn-ready = {CAPITALIZE(THE($book))} surges with ethereal power. {CAPITALIZE(POSS-ADJ($book))} resident is home again. necro-heal-success-self = You hit {THE($target)} with {THE($bible)}, and {POSS-ADJ($target)} flesh warps as it melts! necro-heal-success-others = {CAPITALIZE(THE($user))} hits {THE($target)} with {THE($bible)}, and {POSS-ADJ($target)} flesh warps as it melts! diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index beb998cd10..d655022da7 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -14,3 +14,38 @@ layers: - state: green - texture: Mobs/Animals/regalrat.rsi/icon.png + +- type: entity + id: SpawnPointGhostRemilia + name: ghost role spawn point + suffix: Remilia + parent: MarkerBase + components: + - type: GhostRoleMobSpawner + prototype: MobBatRemilia + name: Remilia, the chaplain's familiar + description: Obey your master. Eat fruit. + rules: You are an intelligent fruit bat. Follow the chaplain around. Don't cause any trouble unless the chaplain tells you to. + - type: Sprite + sprite: Markers/jobs.rsi + layers: + - state: green + - texture: Mobs/Animals/bat.rsi/bat.png + +- type: entity + id: SpawnPointGhostCerberus + name: ghost role spawn point + suffix: cerberus + parent: MarkerBase + components: + - type: GhostRoleMobSpawner + prototype: MobCorgiCerberus + name: Cerberus, Evil Familiar + description: Obey your master. Spread chaos. + rules: You are an intelligent, demonic dog. Try to help the chaplain and any of his flock. As an antagonist, you're otherwise unrestrained. + - type: Sprite + sprite: Markers/jobs.rsi + layers: + - state: green + - texture: Mobs/Pets/corgi.rsi/narsian.png + diff --git a/Resources/Prototypes/Entities/Mobs/Player/familiars.yml b/Resources/Prototypes/Entities/Mobs/Player/familiars.yml index 845c7e3260..8aa218ba8e 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/familiars.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/familiars.yml @@ -22,6 +22,7 @@ - type: Mind showExamineInfo: true - type: Alerts + - type: Familiar - type: entity name: Cerberus @@ -71,3 +72,4 @@ - Chapel - type: Mind showExamineInfo: true + - type: Familiar diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml index 9f0ddce24d..88d61369e0 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml @@ -17,7 +17,7 @@ groups: Burn: 30 - type: Summonable - specialItem: MobBatRemilia + specialItem: SpawnPointGhostRemilia - type: ItemCooldown - type: Sprite netsync: false @@ -58,7 +58,7 @@ healSound: "/Audio/Effects/lightburn.ogg" cooldownTime: 1.3 - type: Summonable - specialItem: MobCorgiCerberus + specialItem: SpawnPointGhostCerberus respawnTime: 300 - type: Sprite netsync: false