diff --git a/Content.Server/Dragon/DragonSystem.Rule.cs b/Content.Server/Dragon/DragonSystem.Rule.cs index f3c8035f7d..4a4f44e143 100644 --- a/Content.Server/Dragon/DragonSystem.Rule.cs +++ b/Content.Server/Dragon/DragonSystem.Rule.cs @@ -27,43 +27,25 @@ public sealed partial class DragonSystem return finished; } - protected override void Started(EntityUid uid, DragonRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) - { - base.Started(uid, component, gameRule, args); - - var eligible = EntityQuery().Select(x => x.Owner).ToList(); - - if (!eligible.Any()) - return; - - var station = _random.Pick(eligible); - - if (_station.GetLargestGrid(EntityManager.GetComponent(station)) is not { } grid) - return; - - Spawn("MobDragon", Transform(grid).MapPosition); - } - private void OnRiftRoundEnd(RoundEndTextAppendEvent args) { - var dragons = EntityQuery(true).ToList(); - - if (dragons.Count == 0) + if (EntityQuery().Count() == 0) return; args.AddLine(Loc.GetString("dragon-round-end-summary")); - foreach (var dragon in EntityQuery(true)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var dragon)) { var met = RiftsMet(dragon); - if (TryComp(dragon.Owner, out var actor)) + if (TryComp(uid, out var actor)) { - args.AddLine(Loc.GetString("dragon-round-end-dragon-player", ("name", dragon.Owner), ("count", met), ("player", actor.PlayerSession))); + args.AddLine(Loc.GetString("dragon-round-end-dragon-player", ("name", uid), ("count", met), ("player", actor.PlayerSession))); } else { - args.AddLine(Loc.GetString("dragon-round-end-dragon", ("name", dragon.Owner), ("count", met))); + args.AddLine(Loc.GetString("dragon-round-end-dragon", ("name", uid), ("count", met))); } } } diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 4c84f9b09c..de110fd694 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -1,304 +1,302 @@ -using System.Numerics; using Content.Server.Body.Systems; -using Content.Server.Popups; -using Content.Shared.Actions; -using Content.Shared.Chemistry.Components; -using Robust.Shared.Containers; -using Robust.Shared.Player; using Content.Server.Chat.Systems; using Content.Server.GameTicking; -using Content.Server.GameTicking.Rules; using Content.Server.NPC; +using Content.Server.NPC.Systems; +using Content.Server.Popups; +using Content.Server.Station.Systems; +using Content.Shared.Actions; +using Content.Shared.Chemistry.Components; using Content.Shared.Damage; +using Content.Shared.DoAfter; using Content.Shared.Dragon; using Content.Shared.Examine; +using Content.Shared.Humanoid; using Content.Shared.Maps; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; using Content.Shared.Movement.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Player; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Random; -using Content.Server.NPC.Systems; -using Content.Server.Station.Systems; -using Content.Shared.DoAfter; -using Content.Shared.Humanoid; -using Content.Shared.Mobs; -using Content.Shared.Mobs.Components; +using System.Numerics; -namespace Content.Server.Dragon +namespace Content.Server.Dragon; + +public sealed partial class DragonSystem : EntitySystem { - public sealed partial class DragonSystem : GameRuleSystem + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ITileDefinitionManager _tileDef = default!; + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly NPCSystem _npc = default!; + + /// + /// Minimum distance between 2 rifts allowed. + /// + private const int RiftRange = 15; + + /// + /// Radius of tiles + /// + private const int RiftTileRadius = 2; + + private const int RiftsAllowed = 3; + + public override void Initialize() { - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly ITileDefinitionManager _tileDef = default!; - [Dependency] private readonly ChatSystem _chat = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; - [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly StationSystem _station = default!; - [Dependency] private readonly NPCSystem _npc = default!; + base.Initialize(); - /// - /// Minimum distance between 2 rifts allowed. - /// - private const int RiftRange = 15; + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnDragonRift); + SubscribeLocalEvent(OnDragonMove); - /// - /// Radius of tiles - /// - private const int RiftTileRadius = 2; + SubscribeLocalEvent(OnMobStateChanged); - private const int RiftsAllowed = 3; + SubscribeLocalEvent(OnRiftShutdown); + SubscribeLocalEvent(OnRiftGetState); + SubscribeLocalEvent(OnAnchorChange); + SubscribeLocalEvent(OnRiftExamined); - public override void Initialize() + SubscribeLocalEvent(OnRiftRoundEnd); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var comp in EntityQuery()) { - base.Initialize(); - - SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnDragonRift); - SubscribeLocalEvent(OnDragonMove); - - SubscribeLocalEvent(OnMobStateChanged); - - SubscribeLocalEvent(OnRiftShutdown); - SubscribeLocalEvent(OnRiftGetState); - SubscribeLocalEvent(OnAnchorChange); - SubscribeLocalEvent(OnRiftExamined); - - SubscribeLocalEvent(OnRiftRoundEnd); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - foreach (var comp in EntityQuery()) + if (comp.WeakenedAccumulator > 0f) { - if (comp.WeakenedAccumulator > 0f) - { - comp.WeakenedAccumulator -= frameTime; + comp.WeakenedAccumulator -= frameTime; - // No longer weakened. - if (comp.WeakenedAccumulator < 0f) - { - comp.WeakenedAccumulator = 0f; - _movement.RefreshMovementSpeedModifiers(comp.Owner); - } + // No longer weakened. + if (comp.WeakenedAccumulator < 0f) + { + comp.WeakenedAccumulator = 0f; + _movement.RefreshMovementSpeedModifiers(comp.Owner); } + } - // At max rifts - if (comp.Rifts.Count >= RiftsAllowed) + // At max rifts + if (comp.Rifts.Count >= RiftsAllowed) + { + continue; + } + + // If there's an active rift don't accumulate. + if (comp.Rifts.Count > 0) + { + var lastRift = comp.Rifts[^1]; + + if (TryComp(lastRift, out var rift) && rift.State != DragonRiftState.Finished) { + comp.RiftAccumulator = 0f; continue; } - - // If there's an active rift don't accumulate. - if (comp.Rifts.Count > 0) - { - var lastRift = comp.Rifts[^1]; - - if (TryComp(lastRift, out var rift) && rift.State != DragonRiftState.Finished) - { - comp.RiftAccumulator = 0f; - continue; - } - } - - comp.RiftAccumulator += frameTime; - - // Delete it, naughty dragon! - if (comp.RiftAccumulator >= comp.RiftMaxAccumulator) - { - Roar(comp); - QueueDel(comp.Owner); - } } - foreach (var comp in EntityQuery()) + comp.RiftAccumulator += frameTime; + + // Delete it, naughty dragon! + if (comp.RiftAccumulator >= comp.RiftMaxAccumulator) { - if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator) - { - // TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up - // for now they just keep 3 rifts up. - - comp.Accumulator = comp.MaxAccumulator; - RemComp(comp.Owner); - comp.State = DragonRiftState.Finished; - Dirty(comp); - } - else if (comp.State != DragonRiftState.Finished) - { - comp.Accumulator += frameTime; - } - - comp.SpawnAccumulator += frameTime; - - if (comp.State < DragonRiftState.AlmostFinished && comp.Accumulator > comp.MaxAccumulator / 2f) - { - comp.State = DragonRiftState.AlmostFinished; - Dirty(comp); - var location = Transform(comp.Owner).LocalPosition; - - _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); - _audioSystem.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); - } - - if (comp.SpawnAccumulator > comp.SpawnCooldown) - { - comp.SpawnAccumulator -= comp.SpawnCooldown; - var ent = Spawn(comp.SpawnPrototype, Transform(comp.Owner).MapPosition); - _npc.SetBlackboard(ent, NPCBlackboard.FollowTarget, new EntityCoordinates(comp.Owner, Vector2.Zero)); - } + Roar(comp); + QueueDel(comp.Owner); } } - #region Rift - - private void OnRiftExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args) + foreach (var comp in EntityQuery()) { - args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100)))); - } - - private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args) - { - if (!args.Anchored && component.State == DragonRiftState.Charging) + if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator) { - QueueDel(uid); + // TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up + // for now they just keep 3 rifts up. + + comp.Accumulator = comp.MaxAccumulator; + RemComp(comp.Owner); + comp.State = DragonRiftState.Finished; + Dirty(comp); + } + else if (comp.State != DragonRiftState.Finished) + { + comp.Accumulator += frameTime; + } + + comp.SpawnAccumulator += frameTime; + + if (comp.State < DragonRiftState.AlmostFinished && comp.Accumulator > comp.MaxAccumulator / 2f) + { + comp.State = DragonRiftState.AlmostFinished; + Dirty(comp); + var location = Transform(comp.Owner).LocalPosition; + + _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); + _audioSystem.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); + } + + if (comp.SpawnAccumulator > comp.SpawnCooldown) + { + comp.SpawnAccumulator -= comp.SpawnCooldown; + var ent = Spawn(comp.SpawnPrototype, Transform(comp.Owner).MapPosition); + _npc.SetBlackboard(ent, NPCBlackboard.FollowTarget, new EntityCoordinates(comp.Owner, Vector2.Zero)); } } + } - private void OnRiftShutdown(EntityUid uid, DragonRiftComponent component, ComponentShutdown args) + #region Rift + + private void OnRiftExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100)))); + } + + private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args) + { + if (!args.Anchored && component.State == DragonRiftState.Charging) { - if (TryComp(component.Dragon, out var dragon) && !dragon.Weakened) + QueueDel(uid); + } + } + + private void OnRiftShutdown(EntityUid uid, DragonRiftComponent component, ComponentShutdown args) + { + if (TryComp(component.Dragon, out var dragon) && !dragon.Weakened) + { + foreach (var rift in dragon.Rifts) { - foreach (var rift in dragon.Rifts) - { - QueueDel(rift); - } - - dragon.Rifts.Clear(); - - // We can't predict the rift being destroyed anyway so no point adding weakened to shared. - dragon.WeakenedAccumulator = dragon.WeakenedDuration; - _movement.RefreshMovementSpeedModifiers(component.Dragon.Value); - _popupSystem.PopupEntity(Loc.GetString("carp-rift-destroyed"), component.Dragon.Value, component.Dragon.Value); + QueueDel(rift); } + + dragon.Rifts.Clear(); + + // We can't predict the rift being destroyed anyway so no point adding weakened to shared. + dragon.WeakenedAccumulator = dragon.WeakenedDuration; + _movement.RefreshMovementSpeedModifiers(component.Dragon.Value); + _popupSystem.PopupEntity(Loc.GetString("carp-rift-destroyed"), component.Dragon.Value, component.Dragon.Value); + } + } + + private void OnRiftGetState(EntityUid uid, DragonRiftComponent component, ref ComponentGetState args) + { + args.State = new DragonRiftComponentState() + { + State = component.State + }; + } + + private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args) + { + if (component.Weakened) + { + args.ModifySpeed(0.5f, 0.5f); + } + } + + private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args) + { + if (component.Weakened) + { + _popupSystem.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, uid); + return; } - private void OnRiftGetState(EntityUid uid, DragonRiftComponent component, ref ComponentGetState args) + if (component.Rifts.Count >= RiftsAllowed) { - args.State = new DragonRiftComponentState() - { - State = component.State - }; + _popupSystem.PopupEntity(Loc.GetString("carp-rift-max"), uid, uid); + return; } - private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args) + if (component.Rifts.Count > 0 && TryComp(component.Rifts[^1], out var rift) && rift.State != DragonRiftState.Finished) { - if (component.Weakened) - { - args.ModifySpeed(0.5f, 0.5f); - } + _popupSystem.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, uid); + return; } - private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args) + var xform = Transform(uid); + + // Have to be on a grid fam + if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) { - if (component.Weakened) + _popupSystem.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); + return; + } + + foreach (var (_, riftXform) in EntityQuery(true)) + { + if (riftXform.Coordinates.InRange(EntityManager, xform.Coordinates, RiftRange)) { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, uid); + _popupSystem.PopupEntity(Loc.GetString("carp-rift-proximity", ("proximity", RiftRange)), uid, uid); return; } - - if (component.Rifts.Count >= RiftsAllowed) - { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-max"), uid, uid); - return; - } - - if (component.Rifts.Count > 0 && TryComp(component.Rifts[^1], out var rift) && rift.State != DragonRiftState.Finished) - { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, uid); - return; - } - - var xform = Transform(uid); - - // Have to be on a grid fam - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) - { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); - return; - } - - foreach (var (_, riftXform) in EntityQuery(true)) - { - if (riftXform.Coordinates.InRange(EntityManager, xform.Coordinates, RiftRange)) - { - _popupSystem.PopupEntity(Loc.GetString("carp-rift-proximity", ("proximity", RiftRange)), uid, uid); - return; - } - } - - foreach (var tile in grid.GetTilesIntersecting(new Circle(xform.WorldPosition, RiftTileRadius), false)) - { - if (!tile.IsSpace(_tileDef)) - continue; - - _popupSystem.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid); - return; - } - - var carpUid = Spawn(component.RiftPrototype, xform.MapPosition); - component.Rifts.Add(carpUid); - Comp(carpUid).Dragon = uid; - _audioSystem.PlayPvs("/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg", carpUid); } - #endregion - - private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args) + foreach (var tile in grid.GetTilesIntersecting(new Circle(xform.WorldPosition, RiftTileRadius), false)) { + if (!tile.IsSpace(_tileDef)) + continue; + + _popupSystem.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid); + return; + } + + var carpUid = Spawn(component.RiftPrototype, xform.MapPosition); + component.Rifts.Add(carpUid); + Comp(carpUid).Dragon = uid; + _audioSystem.PlayPvs("/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg", carpUid); + } + + #endregion + + private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args) + { + foreach (var rift in component.Rifts) + { + QueueDel(rift); + } + } + + private void OnMobStateChanged(EntityUid uid, DragonComponent component, MobStateChangedEvent args) + { + //Empties the stomach upon death + //TODO: Do this when the dragon gets butchered instead + if (args.NewMobState == MobState.Dead) + { + if (component.SoundDeath != null) + _audioSystem.PlayPvs(component.SoundDeath, uid, component.SoundDeath.Params); + foreach (var rift in component.Rifts) { QueueDel(rift); } - } - private void OnMobStateChanged(EntityUid uid, DragonComponent component, MobStateChangedEvent args) - { - //Empties the stomach upon death - //TODO: Do this when the dragon gets butchered instead - if (args.NewMobState == MobState.Dead) - { - if (component.SoundDeath != null) - _audioSystem.PlayPvs(component.SoundDeath, uid, component.SoundDeath.Params); - - foreach (var rift in component.Rifts) - { - QueueDel(rift); - } - - component.Rifts.Clear(); - } - } - - private void Roar(DragonComponent component) - { - if (component.SoundRoar != null) - _audioSystem.Play(component.SoundRoar, Filter.Pvs(component.Owner, 4f, EntityManager), component.Owner, true, component.SoundRoar.Params); - } - - private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args) - { - if (component.SpawnRiftAction != null) - _actionsSystem.AddAction(uid, component.SpawnRiftAction, null); - - Roar(component); + component.Rifts.Clear(); } } + + private void Roar(DragonComponent component) + { + if (component.SoundRoar != null) + _audioSystem.Play(component.SoundRoar, Filter.Pvs(component.Owner, 4f, EntityManager), component.Owner, true, component.SoundRoar.Params); + } + + private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args) + { + if (component.SpawnRiftAction != null) + _actionsSystem.AddAction(uid, component.SpawnRiftAction, null); + + Roar(component); + } } + diff --git a/Content.Server/StationEvents/Components/RandomSpawnRuleComponent.cs b/Content.Server/StationEvents/Components/RandomSpawnRuleComponent.cs new file mode 100644 index 0000000000..7c8d8ab84c --- /dev/null +++ b/Content.Server/StationEvents/Components/RandomSpawnRuleComponent.cs @@ -0,0 +1,18 @@ +using Content.Server.StationEvents.Events; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.StationEvents.Components; + +/// +/// Spawns a single entity at a random tile on a station using TryGetRandomTile. +/// +[RegisterComponent, Access(typeof(RandomSpawnRule))] +public sealed class RandomSpawnRuleComponent : Component +{ + /// + /// The entity to be spawned. + /// + [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string Prototype = string.Empty; +} diff --git a/Content.Server/StationEvents/Components/RevenantSpawnRuleComponent.cs b/Content.Server/StationEvents/Components/RevenantSpawnRuleComponent.cs deleted file mode 100644 index d195eaad7c..0000000000 --- a/Content.Server/StationEvents/Components/RevenantSpawnRuleComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Server.StationEvents.Events; - -namespace Content.Server.StationEvents.Components; - -[RegisterComponent, Access(typeof(RevenantSpawnRule))] -public sealed class RevenantSpawnRuleComponent : Component -{ - [DataField("revenantPrototype")] - public string RevenantPrototype = "MobRevenant"; -} diff --git a/Content.Server/StationEvents/Events/RandomSpawnRule.cs b/Content.Server/StationEvents/Events/RandomSpawnRule.cs new file mode 100644 index 0000000000..c514acc623 --- /dev/null +++ b/Content.Server/StationEvents/Events/RandomSpawnRule.cs @@ -0,0 +1,18 @@ +using Content.Server.GameTicking.Rules.Components; +using Content.Server.StationEvents.Components; + +namespace Content.Server.StationEvents.Events; + +public sealed class RandomSpawnRule : StationEventSystem +{ + protected override void Started(EntityUid uid, RandomSpawnRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) + { + base.Started(uid, comp, gameRule, args); + + if (TryFindRandomTile(out _, out _, out _, out var coords)) + { + Sawmill.Info($"Spawning {comp.Prototype} at {coords}"); + Spawn(comp.Prototype, coords); + } + } +} diff --git a/Content.Server/StationEvents/Events/RevenantSpawnRule.cs b/Content.Server/StationEvents/Events/RevenantSpawnRule.cs deleted file mode 100644 index 6e99fb495e..0000000000 --- a/Content.Server/StationEvents/Events/RevenantSpawnRule.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Server.GameTicking.Rules.Components; -using Content.Server.StationEvents.Components; - -namespace Content.Server.StationEvents.Events; - -public sealed class RevenantSpawnRule : StationEventSystem -{ - protected override void Started(EntityUid uid, RevenantSpawnRuleComponent component, GameRuleComponent gameRule, - GameRuleStartedEvent args) - { - base.Started(uid, component, gameRule, args); - - if (TryFindRandomTile(out _, out _, out _, out var coords)) - { - Sawmill.Info($"Spawning revenant at {coords}"); - Spawn(component.RevenantPrototype, coords); - } - } -} diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index c60ef76cb7..6f16b4db60 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -93,3 +93,22 @@ - state: green - sprite: Structures/Wallmounts/signs.rsi state: radiation + +- type: entity + parent: MarkerBase + id: SpawnPointGhostDragon + noSpawn: true + name: ghost role spawn point + suffix: dragon + components: + - type: GhostRole + name: ghost-role-information-space-dragon-name + description: ghost-role-information-space-dragon-description + rules: ghost-role-component-default-rules + - type: GhostRoleMobSpawner + prototype: MobDragon + - type: Sprite + layers: + - state: green + - sprite: Mobs/Aliens/Carps/dragon.rsi + state: alive diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index d05099ffbe..38d5853d60 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -56,8 +56,8 @@ - type: BureaucraticErrorRule - type: entity - id: Dragon parent: BaseGameRule + id: Dragon noSpawn: true components: - type: StationEvent @@ -65,11 +65,12 @@ duration: 1 earliestStart: 45 minimumPlayers: 20 - - type: DragonRule + - type: RandomSpawnRule + prototype: SpawnPointGhostDragon - type: entity - id: RevenantSpawn parent: BaseGameRule + id: RevenantSpawn noSpawn: true components: - type: StationEvent @@ -77,7 +78,8 @@ duration: 1 earliestStart: 45 minimumPlayers: 20 - - type: RevenantSpawnRule + - type: RandomSpawnRule + prototype: MobRevenant - type: entity id: FalseAlarm