diff --git a/Content.Client/_CP14/MagicVision/CP14ClientMagicVisionSystem.cs b/Content.Client/_CP14/MagicVision/CP14ClientMagicVisionSystem.cs index 7d840f09b4..5aa3a38bc7 100644 --- a/Content.Client/_CP14/MagicVision/CP14ClientMagicVisionSystem.cs +++ b/Content.Client/_CP14/MagicVision/CP14ClientMagicVisionSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared._CP14.MagicVision; using Content.Shared.Examine; +using Content.Shared.StatusEffectNew; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; @@ -9,6 +10,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client._CP14.MagicVision; @@ -21,6 +23,8 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly IOverlayManager _overlayMan = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly StatusEffectsSystem _status = default!; + private CP14MagicVisionOverlay? _overlay; private CP14MagicVisionNoirOverlay? _overlay2; @@ -36,71 +40,39 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem SubscribeLocalEvent(OnHandleStateMarker); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent>(OnPlayerAttached); + SubscribeLocalEvent>(OnPlayerDetached); + + SubscribeLocalEvent(OnStatusEffectApplied); + SubscribeLocalEvent(OnStatusEffectRemoved); - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentShutdown); } - private void OnComponentShutdown(Entity ent, ref ComponentShutdown args) + private void OnPlayerAttached(Entity ent, ref StatusEffectRelayedEvent args) { - if (_player.LocalEntity != ent) - return; - if (_overlay != null) - { - _overlayMan.RemoveOverlay(_overlay); - _overlay = null; - } - if (_overlay2 != null) - { - _overlayMan.RemoveOverlay(_overlay2); - _overlay2 = null; - } - - _audio.PlayGlobal(_endSound, ent); + ApplyOverlay(ent); } - - private void OnComponentInit(Entity ent, ref ComponentInit args) + private void OnStatusEffectApplied(Entity ent, ref StatusEffectAppliedEvent args) { - if (_player.LocalEntity != ent) + //Prevents it from beeing applied twice + if (_timing.IsFirstTimePredicted == true) return; - _overlay = new CP14MagicVisionOverlay(); - _overlayMan.AddOverlay(_overlay); - _overlay.StartOverlay = _timing.CurTime; - - _overlay2 = new CP14MagicVisionNoirOverlay(); - _overlayMan.AddOverlay(_overlay2); - - _audio.PlayGlobal(_startSound, ent); + ApplyOverlay(ent); } - private void OnPlayerAttached(Entity ent, ref LocalPlayerAttachedEvent args) + private void OnPlayerDetached(Entity ent, ref StatusEffectRelayedEvent args) { - _overlay = new CP14MagicVisionOverlay(); - _overlayMan.AddOverlay(_overlay); - _overlay.StartOverlay = _timing.CurTime; - - _overlay2 = new CP14MagicVisionNoirOverlay(); - _overlayMan.AddOverlay(_overlay2); - - _audio.PlayGlobal(_startSound, ent); + RemoveOverlay(ent); } - private void OnPlayerDetached(Entity ent, ref LocalPlayerDetachedEvent args) + private void OnStatusEffectRemoved(Entity ent, ref StatusEffectRemovedEvent args) { - if (_overlay != null) - { - _overlayMan.RemoveOverlay(_overlay); - _overlay = null; - } - if (_overlay2 != null) - { - _overlayMan.RemoveOverlay(_overlay2); - _overlay2 = null; - } - _audio.PlayGlobal(_endSound, ent); + //Prevents it from beeing removed twice + if (_timing.IsFirstTimePredicted == true) + return; + + RemoveOverlay(ent); } protected override void OnExamined(Entity ent, ref ExaminedEvent args) @@ -156,4 +128,36 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem var alpha = 1 - progress; _sprite.SetColor(ent.Owner, Color.White.WithAlpha((float)alpha)); } + + private void ApplyOverlay(Entity ent) + { + _overlay = new CP14MagicVisionOverlay(); + _overlayMan.AddOverlay(_overlay); + _overlay.StartOverlay = _timing.CurTime; + + _overlay2 = new CP14MagicVisionNoirOverlay(); + _overlayMan.AddOverlay(_overlay2); + + _audio.PlayGlobal(_startSound, ent); + } + + private void RemoveOverlay(Entity ent) + { + // Check if it is the last Magic Vision Status Effect + if (_status.HasEffectComp(_player.LocalEntity)) + return; + + if (_overlay != null) + { + _overlayMan.RemoveOverlay(_overlay); + _overlay = null; + } + if (_overlay2 != null) + { + _overlayMan.RemoveOverlay(_overlay2); + _overlay2 = null; + } + + _audio.PlayGlobal(_endSound, ent); + } } diff --git a/Content.Client/_CP14/MagicVision/CP14MagicVisionOverlay.cs b/Content.Client/_CP14/MagicVision/CP14MagicVisionOverlay.cs index 68f7690b9b..0eefb3c4de 100644 --- a/Content.Client/_CP14/MagicVision/CP14MagicVisionOverlay.cs +++ b/Content.Client/_CP14/MagicVision/CP14MagicVisionOverlay.cs @@ -44,9 +44,6 @@ public sealed class CP14MagicVisionOverlay : Overlay if (playerEntity == null) return; - if (!_entityManager.HasComponent(playerEntity)) - return; - var curTime = _timing.CurTime; var timeLeft = (float)(curTime - StartOverlay).TotalSeconds; diff --git a/Content.Server/_CP14/MagicVision/CP14MagicVisionSystem.cs b/Content.Server/_CP14/MagicVision/CP14MagicVisionSystem.cs index 4511765154..208576a13d 100644 --- a/Content.Server/_CP14/MagicVision/CP14MagicVisionSystem.cs +++ b/Content.Server/_CP14/MagicVision/CP14MagicVisionSystem.cs @@ -1,6 +1,6 @@ using Content.Shared._CP14.MagicVision; -using Content.Shared.Eye; using Robust.Shared.Timing; +using Content.Shared.StatusEffectNew; namespace Content.Server._CP14.MagicVision; @@ -13,26 +13,19 @@ public sealed class CP14MagicVisionSystem : CP14SharedMagicVisionSystem { base.Initialize(); - SubscribeLocalEvent(OnMagicVisionToggle); - SubscribeLocalEvent(OnGetVisMask); + SubscribeLocalEvent>(OnGetVisMask); + + SubscribeLocalEvent(OnApplied); + SubscribeLocalEvent(OnRemoved); } - private void OnGetVisMask(Entity ent, ref GetVisMaskEvent args) + private void OnGetVisMask(Entity ent, ref StatusEffectRelayedEvent args) { - args.VisibilityMask |= (int)VisibilityFlags.CP14MagicVision; - } + var appliedMask = (int)CP14MagicVisionStatusEffectComponent.VisibilityMask; + var newArgs = args.Args; - private void OnMagicVisionToggle(Entity ent, ref CP14MagicVisionToggleActionEvent args) - { - if (!HasComp(ent)) - { - AddComp(ent); - } - else - { - RemComp(ent); - } - _eye.RefreshVisibilityMask(ent.Owner); + newArgs.VisibilityMask |= appliedMask; + args = args with { Args = newArgs }; } public override void Update(float frameTime) @@ -51,4 +44,14 @@ public sealed class CP14MagicVisionSystem : CP14SharedMagicVisionSystem QueueDel(uid); } } + + private void OnApplied(Entity ent, ref StatusEffectAppliedEvent args) + { + _eye.RefreshVisibilityMask(args.Target); + } + + private void OnRemoved(Entity ent, ref StatusEffectRemovedEvent args) + { + _eye.RefreshVisibilityMask(args.Target); + } } diff --git a/Content.Server/_CP14/StatusEffect/CP14EntityEffectsStatusEffectSystem.cs b/Content.Server/_CP14/StatusEffect/CP14EntityEffectsStatusEffectSystem.cs new file mode 100644 index 0000000000..daa32713ac --- /dev/null +++ b/Content.Server/_CP14/StatusEffect/CP14EntityEffectsStatusEffectSystem.cs @@ -0,0 +1,38 @@ +using Content.Shared._CP14.StatusEffect; +using Content.Shared.StatusEffectNew; +using Content.Shared.StatusEffectNew.Components; +using Robust.Shared.Timing; + +namespace Content.Server._CP14.StatusEffect; + +public sealed partial class CP14EntityEffectsStatusEffectSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityManager _entityManager = default!; + + public override void Update(float frameTime) + { + base.Update(frameTime); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var entityEffect, out var statusEffect)) + { + if (entityEffect.NextUpdateTime > _timing.CurTime) + continue; + + if (statusEffect.AppliedTo is not EntityUid targetUid) + continue; + + entityEffect.NextUpdateTime = _timing.CurTime + entityEffect.Frequency; + foreach (var effect in entityEffect.Effects) + { + //Apply Effect on target + effect.Effect(new(targetUid, _entityManager)); + } + } + } + + public override void Initialize() + { + base.Initialize(); + } +} diff --git a/Content.Server/_CP14/StatusEffect/Components/CP14EntityEffectsStatusEffectComponent.cs b/Content.Server/_CP14/StatusEffect/Components/CP14EntityEffectsStatusEffectComponent.cs new file mode 100644 index 0000000000..2027483606 --- /dev/null +++ b/Content.Server/_CP14/StatusEffect/Components/CP14EntityEffectsStatusEffectComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.EntityEffects; + +namespace Content.Server._CP14.StatusEffect; + +/// +/// Applies Entity Effects at a given frequency +/// +[RegisterComponent, AutoGenerateComponentState, Access(typeof(CP14EntityEffectsStatusEffectSystem))] + +public sealed partial class CP14EntityEffectsStatusEffectComponent : Component +{ + /// + /// List of Effects that will be applied + /// + [DataField] + public List Effects = []; + + /// + /// How often objects will try to apply . In Seconds. + /// + [DataField] + public TimeSpan Frequency = TimeSpan.FromSeconds(5); + + /// + /// The time of the next Effect trigger + /// + [DataField] + public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero; +} diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs index 1f977c141e..94c225054a 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs @@ -7,6 +7,7 @@ using Content.Shared.Speech; using Content.Shared.StatusEffectNew.Components; using Content.Shared.Stunnable; using Robust.Shared.Player; +using Content.Shared.Mobs; namespace Content.Shared.StatusEffectNew; @@ -16,6 +17,8 @@ public sealed partial class StatusEffectsSystem { //CP14 Zone SubscribeLocalEvent(RelayStatusEffectEvent); + SubscribeLocalEvent(RefRelayStatusEffectEvent); + SubscribeLocalEvent(RefRelayStatusEffectEvent); //CP14 Zone end SubscribeLocalEvent(RelayStatusEffectEvent); diff --git a/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellToggleStatusEffect.cs b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellToggleStatusEffect.cs new file mode 100644 index 0000000000..1f2ecbaa24 --- /dev/null +++ b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellToggleStatusEffect.cs @@ -0,0 +1,24 @@ +using Content.Shared.StatusEffectNew; +using Robust.Shared.Prototypes; + +namespace Content.Shared._CP14.MagicSpell.Spells; + +public sealed partial class CP14SpellToggleStatusEffect : CP14SpellEffect +{ + [DataField(required: true)] + public EntProtoId StatusEffect = default; + + public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args) + { + if (args.Target is null) + return; + + var effectSys = entManager.System(); + + if (!effectSys.HasStatusEffect(args.Target.Value, StatusEffect)) + effectSys.TrySetStatusEffectDuration(args.Target.Value, StatusEffect); + else + effectSys.TryRemoveStatusEffect(args.Target.Value, StatusEffect); + + } +} diff --git a/Content.Shared/_CP14/MagicVision/CP14SharedMagicVisionSystem.cs b/Content.Shared/_CP14/MagicVision/CP14SharedMagicVisionSystem.cs index 3e15d27d17..b998ad5c0b 100644 --- a/Content.Shared/_CP14/MagicVision/CP14SharedMagicVisionSystem.cs +++ b/Content.Shared/_CP14/MagicVision/CP14SharedMagicVisionSystem.cs @@ -4,6 +4,7 @@ using Content.Shared._CP14.AuraDNA; using Content.Shared._CP14.MagicVision.Components; using Content.Shared.Actions; using Content.Shared.Examine; +using Content.Shared.Mobs; using Content.Shared.StatusEffectNew; using Robust.Shared.Map; using Robust.Shared.Network; @@ -27,6 +28,15 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent>(OnMobStateChange); + } + + private void OnMobStateChange(Entity ent, ref StatusEffectRelayedEvent args) + { + if (args.Args.NewMobState == MobState.Alive) return; + + //Removes MagicVisionStatusEffect entity when MobState is Crit,Dead or Invalid + TryQueueDel(ent); } protected virtual void OnExamined(Entity ent, ref ExaminedEvent args) @@ -148,7 +158,3 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem Dirty(ent, markerComp); } } - -public sealed partial class CP14MagicVisionToggleActionEvent : InstantActionEvent -{ -} diff --git a/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionComponent.cs b/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionComponent.cs deleted file mode 100644 index 08a7cac7b4..0000000000 --- a/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._CP14.MagicVision; - -/// -/// Allows to see magic vision trace entities -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class CP14MagicVisionComponent : Component -{ -} diff --git a/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionStatusEffectComponent.cs b/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionStatusEffectComponent.cs new file mode 100644 index 0000000000..6232171459 --- /dev/null +++ b/Content.Shared/_CP14/MagicVision/Components/CP14MagicVisionStatusEffectComponent.cs @@ -0,0 +1,17 @@ +using Content.Shared.Eye; +using Robust.Shared.GameStates; + +namespace Content.Shared._CP14.MagicVision; + +/// +/// Allows to see magic vision trace entities +/// Use only in conjunction with , on the status effect entity. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class CP14MagicVisionStatusEffectComponent : Component +{ + /// + /// VisionMask to see Magic Vision layer + /// + public const VisibilityFlags VisibilityMask = VisibilityFlags.CP14MagicVision; +} diff --git a/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_vision.yml b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_vision.yml index 20e80d8515..c06545d815 100644 --- a/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_vision.yml +++ b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_vision.yml @@ -5,16 +5,20 @@ description: You focus on magical flows to track recent events and scan the aura imprints of other living beings. components: - type: Action - useDelay: 5 + useDelay: 0.5 itemIconStyle: BigAction checkCanInteract: false + checkConsciousness: true sound: !type:SoundPathSpecifier path: /Audio/Magic/rumble.ogg icon: sprite: _CP14/Actions/Spells/meta.rsi state: magic_vision - type: InstantAction - event: !type:CP14MagicVisionToggleActionEvent + event: !type:CP14InstantModularEffectEvent + effects: + - !type:CP14SpellToggleStatusEffect + statusEffect: CP14MetaMagicVisionSpellStatusEffect - type: entity id: CP14ManaVisionPointer @@ -51,4 +55,4 @@ color: "#42a4f5" - type: Clickable - type: Visibility - layer: 16 #magic vision only \ No newline at end of file + layer: 16 #magic vision only diff --git a/Resources/Prototypes/_CP14/Entities/StatusEffects/magic_vision.yml b/Resources/Prototypes/_CP14/Entities/StatusEffects/magic_vision.yml new file mode 100644 index 0000000000..0a4b5dbdff --- /dev/null +++ b/Resources/Prototypes/_CP14/Entities/StatusEffects/magic_vision.yml @@ -0,0 +1,18 @@ +- type: entity + id: CP14MagicVisionStatusEffect + parent: MobStatusEffectBase + name: Magical vision + components: + - type: StatusEffect + - type: CP14MagicVisionStatusEffect + +- type: entity + id: CP14MetaMagicVisionSpellStatusEffect + parent: CP14MagicVisionStatusEffect + name: Magical vision spell + components: + - type: CP14EntityEffectsStatusEffect + effects: + - !type:CP14ManaChange + manaDelta: -5 + safe: false