diff --git a/Content.Server/ADT/Abilities/XenoQeen/XenoQeenSystem.cs b/Content.Server/ADT/Abilities/XenoQeen/XenoQeenSystem.cs deleted file mode 100644 index fb4f41abde3..00000000000 --- a/Content.Server/ADT/Abilities/XenoQeen/XenoQeenSystem.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Content.Server.Popups; -using Content.Shared.Actions; -using Content.Shared.Actions.Events; -using Content.Shared.Coordinates.Helpers; -using Content.Shared.Maps; -using Content.Shared.Physics; -using Robust.Shared.Containers; -using Robust.Shared.Map; - -namespace Content.Server.Abilities.XenoQeen -{ - public sealed class XenoQeenSystem : EntitySystem - { - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly TurfSystem _turf = default!; - [Dependency] private readonly IMapManager _mapMan = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnCreateTurret); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - } - private void OnComponentInit(EntityUid uid, XenoQeenComponent component, ComponentInit args) - { - _actionsSystem.AddAction(uid, ref component.XenoTurretActionEntity, component.XenoTurretAction, uid); - } - private void OnCreateTurret(EntityUid uid, XenoQeenComponent component, InvisibleWallActionEvent args) - { - if (!component.Enabled) - return; - - if (_container.IsEntityOrParentInContainer(uid)) - return; - - var xform = Transform(uid); - // Get the tile in front of the Qeen - var offsetValue = xform.LocalRotation.ToWorldVec(); - var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan); - var tile = coords.GetTileRef(EntityManager, _mapMan); - if (tile == null) - return; - - // Check if the tile is blocked by a wall or mob, and don't create the wall if so - if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable | CollisionGroup.Opaque)) - { - _popupSystem.PopupEntity(Loc.GetString("create-turret-failed"), uid, uid); - return; - } - - _popupSystem.PopupEntity(Loc.GetString("create-turret"), uid); - // Make sure we set the invisible wall to despawn properly - Spawn(component.XenoTurret, _turf.GetTileCenter(tile.Value)); - // Handle args so cooldown works - args.Handled = true; - } - - } -} diff --git a/Content.Server/ADT/Abilities/XenoQeen/XenoQeenComponent.cs b/Content.Server/ADT/Abilities/XenoQueen/XenoQueenComponent.cs similarity index 58% rename from Content.Server/ADT/Abilities/XenoQeen/XenoQeenComponent.cs rename to Content.Server/ADT/Abilities/XenoQueen/XenoQueenComponent.cs index 1e4b46a9c18..e2d015d0a19 100644 --- a/Content.Server/ADT/Abilities/XenoQeen/XenoQeenComponent.cs +++ b/Content.Server/ADT/Abilities/XenoQueen/XenoQueenComponent.cs @@ -1,13 +1,13 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Abilities.XenoQeen +namespace Content.Server.Abilities.XenoQueen { /// /// Lets its owner entity use mime powers, like placing invisible walls. /// [RegisterComponent] - public sealed partial class XenoQeenComponent : Component + public sealed partial class XenoQueenComponent : Component { /// /// Whether this component is active or not. @@ -25,5 +25,27 @@ public sealed partial class XenoQeenComponent : Component public string? XenoTurretAction = "ActionXenoQeenTurret"; [DataField("xenoTurretActionEntity")] public EntityUid? XenoTurretActionEntity; + + // Призывы + [DataField] + public EntityUid? ActionSpawnXenoBurrower; + + [DataField] + public EntityUid? ActionSpawnXenoDrone; + + [DataField] + public EntityUid? ActionSpawnXenoRunner; + + [DataField] + public EntityUid? ActionSpawnXenoSpitter; + + [DataField] + public EntityUid? ActionSpawnXenoPraetorian; + + [DataField] + public EntityUid? ActionSpawnXenoRavager; + + [DataField] + public EntityUid? ActionSpawnXenoQueen; } } diff --git a/Content.Server/ADT/Abilities/XenoQueen/XenoQueenSystem.cs b/Content.Server/ADT/Abilities/XenoQueen/XenoQueenSystem.cs new file mode 100644 index 00000000000..5bab86c3e57 --- /dev/null +++ b/Content.Server/ADT/Abilities/XenoQueen/XenoQueenSystem.cs @@ -0,0 +1,143 @@ +using Content.Server.Popups; +using Content.Shared.Actions; +using Content.Shared.Actions.Events; +using Content.Shared.Maps; +using Content.Shared.Coordinates.Helpers; +using Content.Shared.Magic.Events; +using Content.Shared.Physics; +using Robust.Shared.Containers; +using Robust.Shared.Spawners; +using Robust.Shared.Map; +using Robust.Shared.Random; +using System.Numerics; +using Content.Shared.Storage; +using Robust.Shared.Network; +using Content.Shared.Magic; + +namespace Content.Server.Abilities.XenoQueen +{ + public sealed class XenoQueenSystem : EntitySystem + { + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly TurfSystem _turf = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IMapManager _mapMan = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnCreateTurret); + SubscribeLocalEvent (OnWorldSpawn); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + } + private void OnComponentInit(EntityUid uid, XenoQueenComponent component, ComponentInit args) + { + _actionsSystem.AddAction(uid, ref component.XenoTurretActionEntity, component.XenoTurretAction, uid); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoBurrower, "ActionSpawnMobXenoBurrower"); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoDrone, "ActionSpawnMobXenoDrone"); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoRunner, "ActionSpawnMobXenoRunner"); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoSpitter, "ActionSpawnMobXenoSpitter"); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoPraetorian, "ActionSpawnMobXenoPraetorian"); + _actionsSystem.AddAction(uid, ref component.ActionSpawnXenoRavager, "ActionSpawnMobXenoRavager"); + //_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoQueen, "ActionSpawnMobXenoQueen"); + } + private void OnCreateTurret(EntityUid uid, XenoQueenComponent component, InvisibleWallActionEvent args) + { + if (!component.Enabled) + return; + + if (_container.IsEntityOrParentInContainer(uid)) + return; + + var xform = Transform(uid); + // Get the tile in front of the Qeen + var offsetValue = xform.LocalRotation.ToWorldVec(); + var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan); + var tile = coords.GetTileRef(EntityManager, _mapMan); + if (tile == null) + return; + + // Check if the tile is blocked by a wall or mob, and don't create the wall if so + if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable | CollisionGroup.Opaque)) + { + _popupSystem.PopupEntity(Loc.GetString("create-turret-failed"), uid, uid); + return; + } + + _popupSystem.PopupEntity(Loc.GetString("create-turret"), uid); + // Make sure we set the invisible wall to despawn properly + Spawn(component.XenoTurret, _turf.GetTileCenter(tile.Value)); + // Handle args so cooldown works + args.Handled = true; + } + // Spawn Tipo + private void OnWorldSpawn(SpawnXenoQueenEvent args) + { + if (args.Handled || !PassesSpellPrerequisites(args.Action, args.Performer)) + return; + + var targetMapCoords = args.Target; + + WorldSpawnSpellHelper(args.Prototypes, targetMapCoords, args.Performer, args.Lifetime, args.Offset); + Speak(args); + args.Handled = true; + } + // Help + private void WorldSpawnSpellHelper(List entityEntries, EntityCoordinates entityCoords, EntityUid performer, float? lifetime, Vector2 offsetVector2) + { + var getProtos = EntitySpawnCollection.GetSpawns(entityEntries, _random); + + var offsetCoords = entityCoords; + foreach (var proto in getProtos) + { + SpawnSpellHelper(proto, offsetCoords, performer, lifetime); + offsetCoords = offsetCoords.Offset(offsetVector2); + } + } + // Help 2 + private void SpawnSpellHelper(string? proto, EntityCoordinates position, EntityUid performer, float? lifetime = null, bool preventCollide = false) + { + if (!_net.IsServer) + return; + + var ent = Spawn(proto, position.SnapToGrid(EntityManager, _mapManager)); + + if (lifetime != null) + { + var comp = EnsureComp(ent); + comp.Lifetime = lifetime.Value; + } + + if (preventCollide) + { + var comp = EnsureComp(ent); + comp.Uid = performer; + } + } + // + private bool PassesSpellPrerequisites(EntityUid spell, EntityUid performer) + { + var ev = new BeforeCastSpellEvent(performer); + RaiseLocalEvent(spell, ref ev); + return !ev.Cancelled; + } + // + private void Speak(BaseActionEvent args) + { + if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech)) + return; + + var ev = new SpeakSpellEvent(args.Performer, speak.Speech); + RaiseLocalEvent(ref ev); + } + } +} diff --git a/Content.Server/ADT/Events/SpawnXenoQueenEvent.cs b/Content.Server/ADT/Events/SpawnXenoQueenEvent.cs new file mode 100644 index 00000000000..20cffc60c68 --- /dev/null +++ b/Content.Server/ADT/Events/SpawnXenoQueenEvent.cs @@ -0,0 +1,37 @@ +using System.Numerics; +using Content.Shared.Actions; +using Content.Shared.Storage; + +namespace Content.Shared.Magic.Events; + +// TODO: This class needs combining with InstantSpawnSpellEvent + +public sealed partial class SpawnXenoQueenEvent : WorldTargetActionEvent, ISpeakSpell +{ + /// + /// The list of prototypes this spell will spawn + /// + [DataField] + public List Prototypes = new(); + + // TODO: This offset is liable for deprecation. + // TODO: Target tile via code instead? + /// + /// The offset the prototypes will spawn in on relative to the one prior. + /// Set to 0,0 to have them spawn on the same tile. + /// + [DataField] + public Vector2 Offset; + + /// + /// Lifetime to set for the entities to self delete + /// + [DataField] + public float? Lifetime; + + [DataField] + public string? Speech { get; private set; } + + [DataField] + public int? Cost { get; private set; } +} diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQeen.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQueen.ftl similarity index 76% rename from Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQeen.ftl rename to Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQueen.ftl index afd5c9c194b..2dac4bb55cb 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQeen.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQueen.ftl @@ -9,8 +9,10 @@ ent-ActionSpawnMobXenoPraetorian = Призвать Преторианеца ent-ActionSpawnMobXenoDrone = Просто Дрон. Кому он нужен? .desc = Родите рабочего, Дрон. ent-ActionSpawnMobXenoRavager = Призвать Разрушителя - .desc = Родите смерть во плоти! + .desc = Родите [color=red]смерть[/color] во плоти! ent-ActionSpawnMobXenoRunner = Призвать Бегуна .desc = Родите самую быструю личинку! ent-ActionSpawnMobXenoBurrower = Призвать рабочего - .desc = Стандартный ксено. \ No newline at end of file + .desc = Стандартный ксено. +ent-ActionSpawnMobXenoQueen = Призвать [color=violet]Королеву[/color]. + .desc = [color=red]Новое потомство! Новое поколенеи! Эволюция![/color] \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Actions/XenoQeen.yml b/Resources/Prototypes/ADT/Actions/XenoQueen.yml similarity index 87% rename from Resources/Prototypes/ADT/Actions/XenoQeen.yml rename to Resources/Prototypes/ADT/Actions/XenoQueen.yml index 897149e35c6..877f37c6d3f 100644 --- a/Resources/Prototypes/ADT/Actions/XenoQeen.yml +++ b/Resources/Prototypes/ADT/Actions/XenoQueen.yml @@ -13,6 +13,26 @@ event: !type:InvisibleWallActionEvent # Я не смог сделать отдельный ивент для спавнта турели. Он не видел прототип ивента. +- type: entity + id: ActionSpawnMobXenoQueen + name: Spawn Queen + description: New offspring! + categories: [ HideSpawnMenu ] + components: + - type: WorldTargetAction + useDelay: 1200 + range: 4 + itemIconStyle: BigAction + icon: + sprite: Mobs/Aliens/Xenos/queen.rsi + state: crit + event: !type:WorldSpawnSpellEvent + prototypes: + - id: MobXenoQueen + amount: 1 + offset: 0, 1 + speech: "Ааааааа! Ррррр!" + - type: entity id: ActionSpawnMobXenoBurrower name: Spawn Burrower @@ -26,12 +46,13 @@ icon: sprite: Mobs/Aliens/Xenos/burrower.rsi state: crit - event: !type:WorldSpawnSpellEvent + event: !type:SpawnXenoQueenEvent prototypes: - id: MobXeno amount: 1 offset: 0, 1 speech: "Фаьюп" + cost: 10 - type: entity id: ActionSpawnMobXenoSpitter diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index 00f4c8273cb..6665a05ef31 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -78,6 +78,10 @@ damage: groups: Brute: 6 + # Start ADT: Xeno Buff + - type: StaminaDamageOnHit + damage: 10 + # End ADT - type: DamageStateVisuals rotate: true states: @@ -157,6 +161,8 @@ damage: groups: Brute: 8 + - type: StaminaDamageOnHit + damage: 12 # ADT End - type: Fixtures fixtures: @@ -197,6 +203,10 @@ damage: groups: Brute: 5 # ADT Tweak + # Start ADT: Xeno Buff + - type: StaminaDamageOnHit + damage: 15 + # End ADT - type: MovementSpeedModifier baseSprintSpeed: 4 - type: Fixtures @@ -221,15 +231,7 @@ id: MobXenoQueen components: # ADT Start: Xeno buff - - type: XenoQeen # ADT Tweak: Способность спавнта турелей - - type: ActionGrant - actions: - - ActionSpawnMobXenoBurrower # Призыв обычного - - ActionSpawnMobXenoDrone # Призыв Дрона - - ActionSpawnMobXenoRunner # Призыв бегуна - - ActionSpawnMobXenoSpitter # Призыв Плевальщиков - - ActionSpawnMobXenoPraetorian # Призыв Преторианеца - - ActionSpawnMobXenoRavager # Призыв Разрушителя + - type: XenoQueen # ADT Tweak: Способности королевы #ADT End - type: Sprite drawdepth: Mobs @@ -250,6 +252,10 @@ damage: groups: Brute: 20 # ADT Tweak + # Start ADT: Xeno Buff + - type: StaminaDamageOnHit + damage: 35 + # End ADT - type: Fixtures fixtures: fix1: @@ -294,6 +300,10 @@ - type: SlowOnDamage speedModifierThresholds: 50: 0.7 + # Start ADT: Xeno Buff + - type: StaminaDamageOnHit + damage: 60 + # End ADT - type: Fixtures fixtures: fix1: @@ -334,6 +344,10 @@ damage: groups: Brute: 5 + # Start ADT: Xeno Buff + - type: StaminaDamageOnHit + damage: 5 + # End ADT - type: Fixtures fixtures: fix1: diff --git a/Resources/Prototypes/Entities/Mobs/Player/ShuttleRoles/settings.yml b/Resources/Prototypes/Entities/Mobs/Player/ShuttleRoles/settings.yml index 7e68d7c61dc..51381fb0030 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/ShuttleRoles/settings.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/ShuttleRoles/settings.yml @@ -397,6 +397,7 @@ parent: VisitorCivilian components: - type: BibleUser + - type: Chaplain - type: GhostRole name: job-name-chaplain - type: Loadout