diff --git a/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs b/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs index d4eaad38826..b91062b60b4 100644 --- a/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs +++ b/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs @@ -1,5 +1,7 @@ +using System.ComponentModel.Design; using System.Linq; using Content.Client.Light.Components; +using Content.Shared.Trigger.Components.Effects; using Robust.Client.GameObjects; using Robust.Client.Animations; using Robust.Shared.Random; @@ -36,6 +38,10 @@ public sealed class LightBehaviorSystem : EntitySystem container.LightBehaviour.UpdatePlaybackValues(container.Animation); _player.Play(uid, container.Animation, container.FullKey); } + else + { + StopLightBehaviour((uid, component), container.LightBehaviour.ID, resetToOriginalSettings: true); + } } private void OnLightStartup(Entity entity, ref ComponentStartup args) @@ -53,7 +59,7 @@ public sealed class LightBehaviorSystem : EntitySystem { if (container.LightBehaviour.Enabled) { - StartLightBehaviour(entity, container.LightBehaviour.ID); + StartLightBehaviour((entity, entity), container.LightBehaviour.ID); } } } @@ -82,12 +88,13 @@ public sealed class LightBehaviorSystem : EntitySystem /// If specified light behaviours are already animating, calling this does nothing. /// Multiple light behaviours can have the same ID. /// - public void StartLightBehaviour(Entity entity, string id = "") + public void StartLightBehaviour(Entity entity, string id = "") { - if (!TryComp(entity, out AnimationPlayerComponent? animation)) - { + if (!Resolve(entity, ref entity.Comp)) + return; + + if (!TryComp(entity, out AnimationPlayerComponent? animation)) return; - } foreach (var container in entity.Comp.Animations) { @@ -95,7 +102,7 @@ public sealed class LightBehaviorSystem : EntitySystem { if (!_player.HasRunningAnimation(entity, animation, LightBehaviourComponent.KeyPrefix + container.Key)) { - CopyLightSettings(entity, container.LightBehaviour.Property); + CopyLightSettings((entity, entity.Comp), container.LightBehaviour.Property); container.LightBehaviour.UpdatePlaybackValues(container.Animation); _player.Play(entity, container.Animation, LightBehaviourComponent.KeyPrefix + container.Key); } @@ -118,11 +125,9 @@ public sealed class LightBehaviorSystem : EntitySystem return; } - var comp = entity.Comp; - var toRemove = new List(); - foreach (var container in comp.Animations) + foreach (var container in entity.Comp.Animations) { if (container.LightBehaviour.ID == id || id == string.Empty) { @@ -140,18 +145,24 @@ public sealed class LightBehaviorSystem : EntitySystem foreach (var container in toRemove) { - comp.Animations.Remove(container); + entity.Comp.Animations.Remove(container); } - if (resetToOriginalSettings && TryComp(entity, out PointLightComponent? light)) + if (resetToOriginalSettings) + ResetToOriginalSettings(entity); + + entity.Comp.OriginalPropertyValues.Clear(); + } + + private void ResetToOriginalSettings(Entity entity) + { + if (!Resolve(entity, ref entity.Comp2)) + return; + + foreach (var (property, value) in entity.Comp1.OriginalPropertyValues) { - foreach (var (property, value) in comp.OriginalPropertyValues) - { - AnimationHelper.SetAnimatableProperty(light, property, value); - } + AnimationHelper.SetAnimatableProperty(entity.Comp2, property, value); } - - comp.OriginalPropertyValues.Clear(); } /// @@ -194,7 +205,7 @@ public sealed class LightBehaviorSystem : EntitySystem if (playImmediately) { - StartLightBehaviour(entity, behaviour.ID); + StartLightBehaviour((entity, entity), behaviour.ID); } } } diff --git a/Content.Client/Trigger/Systems/LightBehaviorOnTriggerSystem.cs b/Content.Client/Trigger/Systems/LightBehaviorOnTriggerSystem.cs new file mode 100644 index 00000000000..01e530067e8 --- /dev/null +++ b/Content.Client/Trigger/Systems/LightBehaviorOnTriggerSystem.cs @@ -0,0 +1,21 @@ +using Content.Client.Light.EntitySystems; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Timing; + +namespace Content.Client.Trigger.Systems; + +/// +/// This handles... +/// +public sealed class LightBehaviorOnTriggerSystem : XOnTriggerSystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly LightBehaviorSystem _light = default!; + + protected override void OnTrigger(Entity ent, EntityUid target, ref TriggerEvent args) + { + if (_timing.IsFirstTimePredicted) + _light.StartLightBehaviour(target, ent.Comp.Behavior); + } +} diff --git a/Content.Server/Radio/EntitySystems/JammerSystem.cs b/Content.Server/Radio/EntitySystems/JammerSystem.cs index dead85f51fa..e39fc23831c 100644 --- a/Content.Server/Radio/EntitySystems/JammerSystem.cs +++ b/Content.Server/Radio/EntitySystems/JammerSystem.cs @@ -19,100 +19,23 @@ public sealed class JammerSystem : SharedJammerSystem { base.Initialize(); - SubscribeLocalEvent(OnActivate); - SubscribeLocalEvent(OnPowerCellChanged); SubscribeLocalEvent(OnRadioSendAttempt); - } - - // TODO: Very important: Make this charge rate based instead of updating every single tick - // See BatteryComponent - public override void Update(float frameTime) - { - var query = EntityQueryEnumerator(); - - while (query.MoveNext(out var uid, out var _, out var jam)) - { - - if (_powerCell.TryGetBatteryFromSlot(uid, out var battery)) - { - if (!_battery.TryUseCharge(battery.Value.AsNullable(), GetCurrentWattage((uid, jam)) * frameTime)) - { - ChangeLEDState(uid, false); - RemComp(uid); - RemComp(uid); - } - else - { - var chargeFraction = _battery.GetChargeLevel(battery.Value.AsNullable()); - var chargeLevel = chargeFraction switch - { - > 0.50f => RadioJammerChargeLevel.High, - < 0.15f => RadioJammerChargeLevel.Low, - _ => RadioJammerChargeLevel.Medium, - }; - ChangeChargeLevel(uid, chargeLevel); - } - - } - - } - } - - private void OnActivate(Entity ent, ref ActivateInWorldEvent args) - { - if (args.Handled || !args.Complex) - return; - - var activated = !HasComp(ent) && - _powerCell.TryGetBatteryFromSlot(ent.Owner, out var battery) && - _battery.GetCharge(battery.Value.AsNullable()) > GetCurrentWattage(ent); - if (activated) - { - ChangeLEDState(ent.Owner, true); - EnsureComp(ent); - EnsureComp(ent, out var jammingComp); - _jammer.SetRange((ent, jammingComp), GetCurrentRange(ent)); - _jammer.AddJammableNetwork((ent, jammingComp), DeviceNetworkComponent.DeviceNetIdDefaults.Wireless.ToString()); - - // Add excluded frequencies using the system method - if (ent.Comp.FrequenciesExcluded != null) - { - foreach (var freq in ent.Comp.FrequenciesExcluded) - { - _jammer.AddExcludedFrequency((ent, jammingComp), (uint)freq); - } - } - } - else - { - ChangeLEDState(ent.Owner, false); - RemCompDeferred(ent); - RemCompDeferred(ent); - } - var state = Loc.GetString(activated ? "radio-jammer-component-on-state" : "radio-jammer-component-off-state"); - var message = Loc.GetString("radio-jammer-component-on-use", ("state", state)); - Popup.PopupEntity(message, args.User, args.User); - args.Handled = true; - } - - private void OnPowerCellChanged(Entity ent, ref PowerCellChangedEvent args) - { - if (args.Ejected) - { - ChangeLEDState(ent.Owner, false); - RemCompDeferred(ent); - } + SubscribeLocalEvent(OnRadioReceiveAttempt); } private void OnRadioSendAttempt(ref RadioSendAttemptEvent args) { - if (ShouldCancelSend(args.RadioSource, args.Channel.Frequency)) - { + if (ShouldCancel(args.RadioSource, args.Channel.Frequency)) args.Cancelled = true; - } } - private bool ShouldCancelSend(EntityUid sourceUid, int frequency) + private void OnRadioReceiveAttempt(ref RadioReceiveAttemptEvent args) + { + if (ShouldCancel(args.RadioReceiver, args.Channel.Frequency)) + args.Cancelled = true; + } + + private bool ShouldCancel(EntityUid sourceUid, int frequency) { var source = Transform(sourceUid).Coordinates; var query = EntityQueryEnumerator(); @@ -120,7 +43,7 @@ public sealed class JammerSystem : SharedJammerSystem while (query.MoveNext(out var uid, out _, out var jam, out var transform)) { // Check if this jammer excludes the frequency - if (jam.FrequenciesExcluded != null && jam.FrequenciesExcluded.Contains(frequency)) + if (jam.FrequenciesExcluded.Contains(frequency)) continue; if (_transform.InRange(source, transform.Coordinates, GetCurrentRange((uid, jam)))) diff --git a/Content.Shared/PowerCell/PowerCellSystem.Draw.cs b/Content.Shared/PowerCell/PowerCellSystem.Draw.cs index 8790ec941c3..73e0d5dcd09 100644 --- a/Content.Shared/PowerCell/PowerCellSystem.Draw.cs +++ b/Content.Shared/PowerCell/PowerCellSystem.Draw.cs @@ -11,11 +11,11 @@ public sealed partial class PowerCellSystem [PublicAPI] public void SetDrawEnabled(Entity ent, bool enabled) { - if (!Resolve(ent, ref ent.Comp, false) || ent.Comp.Enabled == enabled) - return; - - ent.Comp.Enabled = enabled; - Dirty(ent, ent.Comp); + if (Resolve(ent, ref ent.Comp, false) && ent.Comp.Enabled != enabled) + { + ent.Comp.Enabled = enabled; + Dirty(ent, ent.Comp); + } if (TryGetBatteryFromSlot(ent.Owner, out var battery)) _battery.RefreshChargeRate(battery.Value.AsNullable()); diff --git a/Content.Shared/PowerCell/ToggleCellDrawSystem.cs b/Content.Shared/PowerCell/ToggleCellDrawSystem.cs index 9c50a8aa601..c4d78ff52e8 100644 --- a/Content.Shared/PowerCell/ToggleCellDrawSystem.cs +++ b/Content.Shared/PowerCell/ToggleCellDrawSystem.cs @@ -36,9 +36,7 @@ public sealed class ToggleCellDrawSystem : EntitySystem private void OnToggled(Entity ent, ref ItemToggledEvent args) { - var uid = ent.Owner; - var draw = Comp(uid); - _cell.SetDrawEnabled((uid, draw), args.Activated); + _cell.SetDrawEnabled(ent.Owner, args.Activated); } private void OnEmpty(Entity ent, ref PowerCellSlotEmptyEvent args) diff --git a/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs index 67af4cc900a..5fd10094668 100644 --- a/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs +++ b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs @@ -1,25 +1,67 @@ +using Content.Shared.DeviceNetwork.Components; using Content.Shared.Popups; using Content.Shared.Verbs; using Content.Shared.Examine; using Content.Shared.Radio.Components; using Content.Shared.DeviceNetwork.Systems; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Power; namespace Content.Shared.Radio.EntitySystems; public abstract class SharedJammerSystem : EntitySystem { + [Dependency] private readonly ItemToggleSystem _itemToggle = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedDeviceNetworkJammerSystem _jammer = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnItemToggle); + SubscribeLocalEvent(OnRefreshChargeRate); SubscribeLocalEvent>(OnGetVerb); SubscribeLocalEvent(OnExamine); } + private void OnItemToggle(Entity entity, ref ItemToggledEvent args) + { + if (args.Activated) + { + EnsureComp(entity); + EnsureComp(entity, out var jammingComp); + _jammer.SetRange((entity, jammingComp), GetCurrentRange(entity)); + _jammer.AddJammableNetwork((entity, jammingComp), DeviceNetworkComponent.DeviceNetIdDefaults.Wireless.ToString()); + + // Add excluded frequencies using the system method + foreach (var freq in entity.Comp.FrequenciesExcluded) + { + _jammer.AddExcludedFrequency((entity, jammingComp), (uint)freq); + } + } + else + { + RemCompDeferred(entity); + RemCompDeferred(entity); + } + + if (args.User == null) + return; + + var state = Loc.GetString(args.Activated ? "radio-jammer-component-on-state" : "radio-jammer-component-off-state"); + var message = Loc.GetString("radio-jammer-component-on-use", ("state", state)); + _popup.PopupPredicted(message, args.User.Value, args.User.Value); + } + + private void OnRefreshChargeRate(Entity entity, ref RefreshChargeRateEvent args) + { + if (_itemToggle.IsActivated(entity.Owner)) + args.NewChargeRate -= GetCurrentWattage(entity); + } + private void OnGetVerb(Entity entity, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) @@ -47,7 +89,7 @@ public abstract class SharedJammerSystem : EntitySystem // The range should be updated when it turns on again! _jammer.TrySetRange(entity.Owner, GetCurrentRange(entity)); - Popup.PopupClient(Loc.GetString(setting.Message), user, user); + _popup.PopupClient(Loc.GetString(setting.Message), user, user); }, Text = Loc.GetString(setting.Name), }; @@ -58,37 +100,26 @@ public abstract class SharedJammerSystem : EntitySystem private void OnExamine(Entity ent, ref ExaminedEvent args) { - if (args.IsInDetailsRange) - { - var powerIndicator = HasComp(ent) - ? Loc.GetString("radio-jammer-component-examine-on-state") - : Loc.GetString("radio-jammer-component-examine-off-state"); - args.PushMarkup(powerIndicator); + if (!args.IsInDetailsRange) + return; - var powerLevel = Loc.GetString(ent.Comp.Settings[ent.Comp.SelectedPowerLevel].Name); - var switchIndicator = Loc.GetString("radio-jammer-component-switch-setting", ("powerLevel", powerLevel)); - args.PushMarkup(switchIndicator); - } + var powerIndicator = _itemToggle.IsActivated(ent.Owner) + ? Loc.GetString("radio-jammer-component-examine-on-state") + : Loc.GetString("radio-jammer-component-examine-off-state"); + args.PushMarkup(powerIndicator); + + var powerLevel = Loc.GetString(ent.Comp.Settings[ent.Comp.SelectedPowerLevel].Name); + var switchIndicator = Loc.GetString("radio-jammer-component-switch-setting", ("powerLevel", powerLevel)); + args.PushMarkup(switchIndicator); } - public float GetCurrentWattage(Entity jammer) + private float GetCurrentWattage(Entity jammer) { return jammer.Comp.Settings[jammer.Comp.SelectedPowerLevel].Wattage; } - public float GetCurrentRange(Entity jammer) + protected float GetCurrentRange(Entity jammer) { return jammer.Comp.Settings[jammer.Comp.SelectedPowerLevel].Range; } - - protected void ChangeLEDState(Entity ent, bool isLEDOn) - { - _appearance.SetData(ent, RadioJammerVisuals.LEDOn, isLEDOn, ent.Comp); - } - - protected void ChangeChargeLevel(Entity ent, RadioJammerChargeLevel chargeLevel) - { - _appearance.SetData(ent, RadioJammerVisuals.ChargeLevel, chargeLevel, ent.Comp); - } - } diff --git a/Content.Shared/Trigger/Components/Effects/LightBehaviorOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/LightBehaviorOnTriggerComponent.cs new file mode 100644 index 00000000000..b31bff78419 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/LightBehaviorOnTriggerComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Plays a light behavior on the target when this trigger is activated, of note is that the entity needs a PointLightComponent +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class LightBehaviorOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The light behavior we're triggering. + /// + [DataField(required: true)] + public string Behavior = string.Empty; +} diff --git a/Content.Shared/Trigger/Components/Effects/ScramOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/ScramOnTriggerComponent.cs index bacf0f69e8b..ecdb2c7da5b 100644 --- a/Content.Shared/Trigger/Components/Effects/ScramOnTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/Effects/ScramOnTriggerComponent.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -12,10 +13,10 @@ namespace Content.Shared.Trigger.Components.Effects; public sealed partial class ScramOnTriggerComponent : BaseXOnTriggerComponent { /// - /// Up to how far to teleport the entity. + /// Up to how far to teleport the entity. Represented with X as Min Radius, and Y as Max Radius /// [DataField, AutoNetworkedField] - public float TeleportRadius = 100f; + public Vector2 TeleportRadius = new (10f, 15f); /// /// the sound to play when teleporting. diff --git a/Content.Shared/Trigger/Systems/ScramOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/ScramOnTriggerSystem.cs index cd79eed13bf..32666f1be88 100644 --- a/Content.Shared/Trigger/Systems/ScramOnTriggerSystem.cs +++ b/Content.Shared/Trigger/Systems/ScramOnTriggerSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Maps; using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Systems; @@ -50,7 +51,7 @@ public sealed class ScramOnTriggerSystem : XOnTriggerSystem /// Trends towards the outer radius. Compensates for small grids. - private EntityCoordinates? SelectRandomTileInRange(EntityUid uid, float radius, int tries = 40, PhysicsComponent? physicsComponent = null) + private EntityCoordinates? SelectRandomTileInRange(EntityUid uid, Vector2 radius, int tries = 40, PhysicsComponent? physicsComponent = null) { var userCoords = Transform(uid).Coordinates; EntityCoordinates? targetCoords = null; @@ -68,7 +69,7 @@ public sealed class ScramOnTriggerSystem : XOnTriggerSystem