Trigger Refactor (#39034)
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared.Explosion;
|
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
[RegisterComponent, Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent {}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
public sealed partial class TriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
InitializeProximity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.HotPotato;
|
using Content.Shared.HotPotato;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.HotPotato;
|
namespace Content.Client.HotPotato;
|
||||||
@@ -10,6 +11,9 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
private readonly EntProtoId _hotPotatoEffectId = "HotPotatoEffect";
|
||||||
|
|
||||||
|
// TODO: particle system
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
@@ -23,7 +27,7 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
|||||||
if (_timing.CurTime < comp.TargetTime)
|
if (_timing.CurTime < comp.TargetTime)
|
||||||
continue;
|
continue;
|
||||||
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
|
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
|
||||||
Spawn("HotPotatoEffect", _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f)));
|
Spawn(_hotPotatoEffectId, _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
using Content.Client.Trigger.Systems;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
namespace Content.Client.Trigger;
|
namespace Content.Client.Trigger.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[Access(typeof(TimerTriggerVisualizerSystem))]
|
[Access(typeof(TimerTriggerVisualizerSystem))]
|
||||||
@@ -16,28 +17,27 @@ public sealed partial class TimerTriggerVisualsComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The RSI state used while the device has not been primed.
|
/// The RSI state used while the device has not been primed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("unprimedSprite")]
|
[DataField]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public string UnprimedSprite = "icon";
|
public string UnprimedSprite = "icon";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The RSI state used when the device is primed.
|
/// The RSI state used when the device is primed.
|
||||||
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("primingSprite")]
|
[DataField]
|
||||||
public string PrimingSprite = "primed";
|
public string PrimingSprite = "primed";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sound played when the device is primed.
|
/// The sound played when the device is primed.
|
||||||
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
/// Not VVWrite-able because it's only used at component init to construct the priming animation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("primingSound")]
|
[DataField, ViewVariables]
|
||||||
public SoundSpecifier? PrimingSound;
|
public SoundSpecifier? PrimingSound;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The actual priming animation.
|
/// The actual priming animation.
|
||||||
/// Constructed at component init from the sprite and sound.
|
/// Constructed at component init from the sprite and sound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
public Animation PrimingAnimation = default!;
|
public Animation PrimingAnimation = default!;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
using Content.Shared.Trigger;
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Triggers;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Animations;
|
using Robust.Shared.Animations;
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
public sealed partial class TriggerSystem
|
public sealed class ProximityTriggerAnimationSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
@@ -18,7 +19,7 @@ public sealed partial class TriggerSystem
|
|||||||
|
|
||||||
private const string AnimKey = "proximity";
|
private const string AnimKey = "proximity";
|
||||||
|
|
||||||
private static readonly Animation _flasherAnimation = new Animation
|
private static readonly Animation FlasherAnimation = new Animation
|
||||||
{
|
{
|
||||||
Length = TimeSpan.FromSeconds(0.6f),
|
Length = TimeSpan.FromSeconds(0.6f),
|
||||||
AnimationTracks = {
|
AnimationTracks = {
|
||||||
@@ -42,8 +43,10 @@ public sealed partial class TriggerSystem
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private void InitializeProximity()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
|
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
|
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
|
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
|
||||||
@@ -94,7 +97,7 @@ public sealed partial class TriggerSystem
|
|||||||
break;
|
break;
|
||||||
case ProximityTriggerVisuals.Active:
|
case ProximityTriggerVisuals.Active:
|
||||||
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
||||||
_player.Play((uid, player), _flasherAnimation, AnimKey);
|
_player.Play((uid, player), FlasherAnimation, AnimKey);
|
||||||
break;
|
break;
|
||||||
case ProximityTriggerVisuals.Off:
|
case ProximityTriggerVisuals.Off:
|
||||||
default:
|
default:
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem;
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
|
using Content.Client.Trigger.Components;
|
||||||
using Content.Shared.Trigger;
|
using Content.Shared.Trigger;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.Trigger;
|
namespace Content.Client.Trigger.Systems;
|
||||||
|
|
||||||
public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTriggerVisualsComponent>
|
public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTriggerVisualsComponent>
|
||||||
{
|
{
|
||||||
@@ -17,25 +16,26 @@ public sealed class TimerTriggerVisualizerSystem : VisualizerSystem<TimerTrigger
|
|||||||
SubscribeLocalEvent<TimerTriggerVisualsComponent, ComponentInit>(OnComponentInit);
|
SubscribeLocalEvent<TimerTriggerVisualsComponent, ComponentInit>(OnComponentInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, TimerTriggerVisualsComponent comp, ComponentInit args)
|
private void OnComponentInit(Entity<TimerTriggerVisualsComponent> ent, ref ComponentInit args)
|
||||||
{
|
{
|
||||||
comp.PrimingAnimation = new Animation
|
ent.Comp.PrimingAnimation = new Animation
|
||||||
{
|
{
|
||||||
Length = TimeSpan.MaxValue,
|
Length = TimeSpan.MaxValue,
|
||||||
AnimationTracks = {
|
AnimationTracks = {
|
||||||
new AnimationTrackSpriteFlick() {
|
new AnimationTrackSpriteFlick()
|
||||||
|
{
|
||||||
LayerKey = TriggerVisualLayers.Base,
|
LayerKey = TriggerVisualLayers.Base,
|
||||||
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.PrimingSprite, 0f) }
|
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.PrimingSprite, 0f) }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (comp.PrimingSound != null)
|
if (ent.Comp.PrimingSound != null)
|
||||||
{
|
{
|
||||||
comp.PrimingAnimation.AnimationTracks.Add(
|
ent.Comp.PrimingAnimation.AnimationTracks.Add(
|
||||||
new AnimationTrackPlaySound()
|
new AnimationTrackPlaySound()
|
||||||
{
|
{
|
||||||
KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(comp.PrimingSound), 0) }
|
KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(ent.Comp.PrimingSound), 0) }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.IntegrationTests.Tests.Interaction;
|
using Content.IntegrationTests.Tests.Interaction;
|
||||||
using Content.Server.Explosion.Components;
|
using Content.Shared.Trigger.Components;
|
||||||
using Content.Shared.Explosion.Components;
|
using Content.Shared.Trigger.Systems;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
@@ -25,19 +25,19 @@ public sealed class ModularGrenadeTests : InteractionTest
|
|||||||
await InteractUsing(Cable);
|
await InteractUsing(Cable);
|
||||||
|
|
||||||
// Insert & remove trigger
|
// Insert & remove trigger
|
||||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
AssertComp<TimerTriggerComponent>(false);
|
||||||
await InteractUsing(Trigger);
|
await InteractUsing(Trigger);
|
||||||
AssertComp<OnUseTimerTriggerComponent>();
|
AssertComp<TimerTriggerComponent>();
|
||||||
await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false);
|
await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false);
|
||||||
await InteractUsing(Pry);
|
await InteractUsing(Pry);
|
||||||
AssertComp<OnUseTimerTriggerComponent>(false);
|
AssertComp<TimerTriggerComponent>(false);
|
||||||
|
|
||||||
// Trigger was dropped to floor, not deleted.
|
// Trigger was dropped to floor, not deleted.
|
||||||
await FindEntity(Trigger, LookupFlags.Uncontained);
|
await FindEntity(Trigger, LookupFlags.Uncontained);
|
||||||
|
|
||||||
// Re-insert
|
// Re-insert
|
||||||
await InteractUsing(Trigger);
|
await InteractUsing(Trigger);
|
||||||
AssertComp<OnUseTimerTriggerComponent>();
|
AssertComp<TimerTriggerComponent>();
|
||||||
|
|
||||||
// Insert & remove payload.
|
// Insert & remove payload.
|
||||||
await InteractUsing(Payload);
|
await InteractUsing(Payload);
|
||||||
@@ -56,13 +56,14 @@ public sealed class ModularGrenadeTests : InteractionTest
|
|||||||
await Pickup();
|
await Pickup();
|
||||||
AssertComp<ActiveTimerTriggerComponent>(false);
|
AssertComp<ActiveTimerTriggerComponent>(false);
|
||||||
await UseInHand();
|
await UseInHand();
|
||||||
|
AssertComp<ActiveTimerTriggerComponent>(true);
|
||||||
|
|
||||||
// So uhhh grenades in hands don't destroy themselves when exploding. Maybe that will be fixed eventually.
|
// So uhhh grenades in hands don't destroy themselves when exploding. Maybe that will be fixed eventually.
|
||||||
await Drop();
|
await Drop();
|
||||||
|
|
||||||
// Wait until grenade explodes
|
// Wait until grenade explodes
|
||||||
var timer = Comp<ActiveTimerTriggerComponent>();
|
var triggerSys = SEntMan.System<TriggerSystem>();
|
||||||
while (timer.TimeRemaining >= 0)
|
while (Target != null && triggerSys.GetRemainingTime(SEntMan.GetEntity(Target.Value))?.TotalSeconds >= 0.0)
|
||||||
{
|
{
|
||||||
await RunTicks(10);
|
await RunTicks(10);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
using Content.Server.AlertLevel.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.AlertLevel;
|
|
||||||
/// <summary>
|
|
||||||
/// This component is for changing the alert level of the station when triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(AlertLevelChangeOnTriggerSystem))]
|
|
||||||
public sealed partial class AlertLevelChangeOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
///<summary>
|
|
||||||
///The alert level to change to when triggered.
|
|
||||||
///</summary>
|
|
||||||
[DataField]
|
|
||||||
public string Level = "blue";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Whether to play the sound when the alert level changes.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool PlaySound = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Whether to say the announcement when the alert level changes.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool Announce = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Force the alert change. This applies if the alert level is not selectable or not.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool Force = false;
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,13 @@ using Content.Server.Animals.Components;
|
|||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Radio;
|
using Content.Server.Radio;
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Server.Vocalization.Systems;
|
using Content.Server.Vocalization.Systems;
|
||||||
using Content.Shared.Animals.Components;
|
using Content.Shared.Animals.Components;
|
||||||
using Content.Shared.Animals.Systems;
|
using Content.Shared.Animals.Systems;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Content.Shared.Speech;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using Content.Shared.Dataset;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Chat;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes the entity speak when triggered. If the item has UseDelay component, the system will respect that cooldown.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class SpeakOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The identifier for the dataset prototype containing messages to be spoken by this entity.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public ProtoId<LocalizedDatasetPrototype> Pack = string.Empty;
|
|
||||||
}
|
|
||||||
@@ -67,6 +67,9 @@ public sealed class SuicideSystem : EntitySystem
|
|||||||
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag))
|
if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// TODO: fix this
|
||||||
|
// This is a handled event, but the result is never used
|
||||||
|
// It looks like TriggerOnMobstateChange is supposed to prevent you from suiciding
|
||||||
var suicideEvent = new SuicideEvent(victim);
|
var suicideEvent = new SuicideEvent(victim);
|
||||||
RaiseLocalEvent(victim, suicideEvent);
|
RaiseLocalEvent(victim, suicideEvent);
|
||||||
|
|
||||||
|
|||||||
@@ -60,11 +60,6 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||||
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
|
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
|
||||||
|
|
||||||
public const int VoiceRange = 10; // how far voice goes in world units
|
|
||||||
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
|
||||||
public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units
|
|
||||||
public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg";
|
|
||||||
|
|
||||||
private bool _loocEnabled = true;
|
private bool _loocEnabled = true;
|
||||||
private bool _deadLoocEnabled;
|
private bool _deadLoocEnabled;
|
||||||
private bool _critLoocEnabled;
|
private bool _critLoocEnabled;
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.Damage.Components;
|
|
||||||
|
|
||||||
namespace Content.Server.Damage.Systems;
|
|
||||||
|
|
||||||
// System for damage that occurs on specific trigger, towards the user..
|
|
||||||
public sealed class DamageUserOnTriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<DamageUserOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, DamageUserOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (args.User is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Handled |= OnDamageTrigger(uid, args.User.Value, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool OnDamageTrigger(EntityUid source, EntityUid target, DamageUserOnTriggerComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(source, ref component))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var damage = new DamageSpecifier(component.Damage);
|
|
||||||
var ev = new BeforeDamageUserOnTriggerEvent(damage, target);
|
|
||||||
RaiseLocalEvent(source, ev);
|
|
||||||
|
|
||||||
return _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: source) is not null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class BeforeDamageUserOnTriggerEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public DamageSpecifier Damage { get; set; }
|
|
||||||
public EntityUid Tripper { get; }
|
|
||||||
|
|
||||||
public BeforeDamageUserOnTriggerEvent(DamageSpecifier damage, EntityUid target)
|
|
||||||
{
|
|
||||||
Damage = damage;
|
|
||||||
Tripper = target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.Defusable.Components;
|
using Content.Server.Defusable.Components;
|
||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Explosion.EntitySystems;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Wires;
|
using Content.Server.Wires;
|
||||||
@@ -8,13 +7,13 @@ using Content.Shared.Construction.Components;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Defusable;
|
using Content.Shared.Defusable;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Trigger.Components;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Defusable.Systems;
|
namespace Content.Server.Defusable.Systems;
|
||||||
@@ -74,12 +73,13 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
||||||
}
|
}
|
||||||
else if (comp.Activated && TryComp<ActiveTimerTriggerComponent>(uid, out var activeComp))
|
else if (comp.Activated)
|
||||||
{
|
{
|
||||||
if (comp.DisplayTime)
|
var remaining = _trigger.GetRemainingTime(uid);
|
||||||
|
if (comp.DisplayTime && remaining != null)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
||||||
("time", MathF.Floor(activeComp.TimeRemaining))));
|
("time", Math.Floor(remaining.Value.TotalSeconds))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -139,16 +139,9 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
SetActivated(comp, true);
|
SetActivated(comp, true);
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid);
|
||||||
if (TryComp<OnUseTimerTriggerComponent>(uid, out var timerTrigger))
|
if (TryComp<TimerTriggerComponent>(uid, out var timerTrigger))
|
||||||
{
|
{
|
||||||
_trigger.HandleTimerTrigger(
|
_trigger.ActivateTimerTrigger((uid, timerTrigger));
|
||||||
uid,
|
|
||||||
user,
|
|
||||||
timerTrigger.Delay,
|
|
||||||
timerTrigger.BeepInterval,
|
|
||||||
timerTrigger.InitialBeepDelay,
|
|
||||||
timerTrigger.BeepSound
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RaiseLocalEvent(uid, new BombArmedEvent(uid));
|
RaiseLocalEvent(uid, new BombArmedEvent(uid));
|
||||||
@@ -188,7 +181,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
SetUsable(comp, false);
|
SetUsable(comp, false);
|
||||||
RemComp<ExplodeOnTriggerComponent>(uid);
|
RemComp<ExplodeOnTriggerComponent>(uid);
|
||||||
RemComp<OnUseTimerTriggerComponent>(uid);
|
RemComp<TimerTriggerComponent>(uid);
|
||||||
}
|
}
|
||||||
RemComp<ActiveTimerTriggerComponent>(uid);
|
RemComp<ActiveTimerTriggerComponent>(uid);
|
||||||
|
|
||||||
@@ -246,7 +239,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
if (comp is not { Activated: true, DelayWireUsed: false })
|
if (comp is not { Activated: true, DelayWireUsed: false })
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_trigger.TryDelay(wire.Owner, 30f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30));
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||||
comp.DelayWireUsed = true;
|
comp.DelayWireUsed = true;
|
||||||
}
|
}
|
||||||
@@ -268,7 +261,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
if (comp is { Activated: true, ProceedWireUsed: false })
|
if (comp is { Activated: true, ProceedWireUsed: false })
|
||||||
{
|
{
|
||||||
comp.ProceedWireUsed = true;
|
comp.ProceedWireUsed = true;
|
||||||
_trigger.TryDelay(wire.Owner, -15f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(-15));
|
||||||
}
|
}
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner);
|
||||||
@@ -298,7 +291,7 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
{
|
{
|
||||||
if (!comp.ActivatedWireUsed)
|
if (!comp.ActivatedWireUsed)
|
||||||
{
|
{
|
||||||
_trigger.TryDelay(wire.Owner, 30f);
|
_trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30));
|
||||||
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
_popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner);
|
||||||
comp.ActivatedWireUsed = true;
|
comp.ActivatedWireUsed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
@@ -14,15 +15,13 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Audio;
|
using Robust.Server.Audio;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using System.Linq;
|
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Destructible
|
namespace Content.Server.Destructible
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ public sealed partial class TimerStartBehavior : IThresholdBehavior
|
|||||||
{
|
{
|
||||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
system.TriggerSystem.StartTimer(owner, cause);
|
system.TriggerSystem.ActivateTimerTrigger(owner, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
namespace Content.Server.Destructible.Thresholds.Behaviors;
|
using Content.Shared.Trigger.Systems;
|
||||||
|
|
||||||
|
namespace Content.Server.Destructible.Thresholds.Behaviors;
|
||||||
|
|
||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public sealed partial class TriggerBehavior : IThresholdBehavior
|
public sealed partial class TriggerBehavior : IThresholdBehavior
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The trigger key to use when triggering.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string? KeyOut { get; set; } = TriggerSystem.DefaultTriggerKey;
|
||||||
|
|
||||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
system.TriggerSystem.Trigger(owner, cause);
|
system.TriggerSystem.Trigger(owner, cause, KeyOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
|
using Content.Server.DeviceNetwork;
|
||||||
|
using Content.Server.DeviceNetwork.Components;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.DeviceLinking.Events;
|
using Content.Shared.DeviceLinking.Events;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
using Content.Server.DeviceNetwork;
|
|
||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.DeviceLinking.Events;
|
using Content.Shared.DeviceLinking.Events;
|
||||||
using Content.Shared.DeviceNetwork;
|
using Content.Shared.DeviceNetwork;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
@@ -10,7 +9,6 @@ namespace Content.Server.DeviceLinking.Systems;
|
|||||||
public sealed class SignallerSystem : EntitySystem
|
public sealed class SignallerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly DeviceLinkSystem _link = default!;
|
[Dependency] private readonly DeviceLinkSystem _link = default!;
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -19,7 +17,6 @@ public sealed class SignallerSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<SignallerComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<SignallerComponent, ComponentInit>(OnInit);
|
||||||
SubscribeLocalEvent<SignallerComponent, UseInHandEvent>(OnUseInHand);
|
SubscribeLocalEvent<SignallerComponent, UseInHandEvent>(OnUseInHand);
|
||||||
SubscribeLocalEvent<SignallerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, SignallerComponent component, ComponentInit args)
|
private void OnInit(EntityUid uid, SignallerComponent component, ComponentInit args)
|
||||||
@@ -36,16 +33,4 @@ public sealed class SignallerSystem : EntitySystem
|
|||||||
_link.InvokePort(uid, component.Port);
|
_link.InvokePort(uid, component.Port);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, SignallerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp(uid, out UseDelayComponent? useDelay)
|
|
||||||
// if on cooldown, do nothing
|
|
||||||
// and set cooldown to prevent clocks
|
|
||||||
|| !_useDelay.TryResetDelay((uid, useDelay), true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_link.InvokePort(uid, component.Port);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||||
[Dependency] private readonly TurfSystem _turf = default!;
|
[Dependency] private readonly TurfSystem _turf = default!;
|
||||||
|
|
||||||
private static readonly ProtoId<StatusEffectPrototype> StatusEffectKey = "Electrocution";
|
private static readonly ProtoId<StatusEffectPrototype> StatusKeyIn = "Electrocution";
|
||||||
private static readonly ProtoId<DamageTypePrototype> DamageType = "Shock";
|
private static readonly ProtoId<DamageTypePrototype> DamageType = "Shock";
|
||||||
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
private static readonly ProtoId<TagPrototype> WindowTag = "Window";
|
||||||
|
|
||||||
@@ -386,12 +386,12 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Resolve(uid, ref statusEffects, false) ||
|
if (!Resolve(uid, ref statusEffects, false) ||
|
||||||
!_statusEffects.CanApplyEffect(uid, StatusEffectKey, statusEffects))
|
!_statusEffects.CanApplyEffect(uid, StatusKeyIn, statusEffects))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_statusEffects.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh, statusEffects))
|
if (!_statusEffects.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusKeyIn, time, refresh, statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var shouldStun = siemensCoefficient > 0.5f;
|
var shouldStun = siemensCoefficient > 0.5f;
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace Content.Server.Emp;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upon being triggered will EMP area around it.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[Access(typeof(EmpSystem))]
|
|
||||||
public sealed partial class EmpOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("range"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float Range = 1.0f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How much energy will be consumed per battery in range
|
|
||||||
/// </summary>
|
|
||||||
[DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float EnergyConsumption;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long it disables targets in seconds
|
|
||||||
/// </summary>
|
|
||||||
[DataField("disableDuration"), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float DisableDuration = 60f;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Radio;
|
using Content.Server.Radio;
|
||||||
using Content.Server.SurveillanceCamera;
|
using Content.Server.SurveillanceCamera;
|
||||||
@@ -20,7 +19,6 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, ExaminedEvent>(OnExamine);
|
SubscribeLocalEvent<EmpDisabledComponent, ExaminedEvent>(OnExamine);
|
||||||
SubscribeLocalEvent<EmpOnTriggerComponent, TriggerEvent>(HandleEmpTrigger);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, RadioSendAttemptEvent>(OnRadioSendAttempt);
|
SubscribeLocalEvent<EmpDisabledComponent, RadioSendAttemptEvent>(OnRadioSendAttempt);
|
||||||
SubscribeLocalEvent<EmpDisabledComponent, RadioReceiveAttemptEvent>(OnRadioReceiveAttempt);
|
SubscribeLocalEvent<EmpDisabledComponent, RadioReceiveAttemptEvent>(OnRadioReceiveAttempt);
|
||||||
@@ -28,14 +26,7 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
SubscribeLocalEvent<EmpDisabledComponent, SurveillanceCameraSetActiveAttemptEvent>(OnCameraSetActive);
|
SubscribeLocalEvent<EmpDisabledComponent, SurveillanceCameraSetActiveAttemptEvent>(OnCameraSetActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration)
|
||||||
/// Triggers an EMP pulse at the given location, by first raising an <see cref="EmpAttemptEvent"/>, then a raising <see cref="EmpPulseEvent"/> on all entities in range.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="coordinates">The location to trigger the EMP pulse at.</param>
|
|
||||||
/// <param name="range">The range of the EMP pulse.</param>
|
|
||||||
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse.</param>
|
|
||||||
/// <param name="duration">The duration of the EMP effects.</param>
|
|
||||||
public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration)
|
|
||||||
{
|
{
|
||||||
foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
|
foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
|
||||||
{
|
{
|
||||||
@@ -118,12 +109,6 @@ public sealed class EmpSystem : SharedEmpSystem
|
|||||||
args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine"));
|
args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args)
|
|
||||||
{
|
|
||||||
EmpPulse(_transform.GetMapCoordinates(uid), comp.Range, comp.EnergyConsumption, comp.DisableDuration);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args)
|
private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args)
|
||||||
{
|
{
|
||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class ActiveTriggerOnTimedCollideComponent : Component { }
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disallows starting the timer by hand, must be stuck or triggered by a system using <c>StartTimer</c>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class AutomatedTimerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will anchor the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class AnchorOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("removeOnTrigger")]
|
|
||||||
public bool RemoveOnTrigger = true;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will delete the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class DeleteOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gibs on trigger, self explanatory.
|
|
||||||
/// Also in case of an implant using this, gibs the implant user instead.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class GibOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Should gibbing also delete the owners items?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("deleteItems")]
|
|
||||||
public bool DeleteItems = false;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will play sound from the attached entity upon a <see cref="TriggerEvent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class SoundOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("removeOnTrigger")]
|
|
||||||
public bool RemoveOnTrigger = true;
|
|
||||||
|
|
||||||
[DataField("sound")]
|
|
||||||
public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Effects/Grenades/supermatter_start.ogg");
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components.OnTrigger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// After being triggered applies the specified components and runs triggers again.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
|
||||||
public sealed partial class TwoStageTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// How long it takes for the second stage to be triggered.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("triggerDelay")]
|
|
||||||
public TimeSpan TriggerDelay = TimeSpan.FromSeconds(10);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This list of components that will be added for the second trigger.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("components", required: true)]
|
|
||||||
public ComponentRegistry SecondStageComponents = new();
|
|
||||||
|
|
||||||
[DataField("nextTriggerTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan? NextTriggerTime;
|
|
||||||
|
|
||||||
[DataField("triggered")]
|
|
||||||
public bool Triggered = false;
|
|
||||||
|
|
||||||
[DataField("ComponentsIsLoaded")]
|
|
||||||
public bool ComponentsIsLoaded = false;
|
|
||||||
}
|
|
||||||
@@ -45,4 +45,10 @@ public sealed partial class ProjectileGrenadeComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public float MaxVelocity = 6f;
|
public float MaxVelocity = 6f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The trigger key that will activate the grenade.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public string TriggerKey = "timer";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A component that electrocutes an entity having this component when a trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
|
||||||
[Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class ShockOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The force of an electric shock when the trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public int Damage = 5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Duration of electric shock when the trigger is triggered.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public TimeSpan Duration = TimeSpan.FromSeconds(2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum delay between repeating triggers.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public TimeSpan Cooldown = TimeSpan.FromSeconds(4);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When can the trigger run again?
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan NextTrigger = TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Spawns a protoype when triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(TriggerSystem))]
|
|
||||||
public sealed partial class SpawnOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The prototype to spawn.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public EntProtoId Proto = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use MapCoordinates for spawning?
|
|
||||||
/// Set to true if you don't want the new entity parented to the spawner.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool mapCoords;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Content.Shared.DeviceLinking;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sends a trigger when signal is received.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TimerStartOnSignalComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("port", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
|
||||||
public string Port = "Timer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers on click.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnActivateComponent : Component { }
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers when colliding with another entity.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnCollideComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The fixture with which to collide.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public string FixtureID = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Doesn't trigger if the other colliding fixture is nonhard.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool IgnoreOtherNonHard = true;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Content.Shared.Mobs;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use where you want something to trigger on mobstate change
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnMobstateChangeComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// What state should trigger this?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("mobState", required: true)]
|
|
||||||
public List<MobState> MobState = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If true, prevents suicide attempts for the trigger to prevent cheese.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("preventSuicide")]
|
|
||||||
public bool PreventSuicide = false;
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Explosion;
|
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Physics;
|
|
||||||
using Robust.Shared.Physics.Collision.Shapes;
|
|
||||||
using Robust.Shared.Physics.Components;
|
|
||||||
using Robust.Shared.Physics.Dynamics;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raises a <see cref="TriggerEvent"/> whenever an entity collides with a fixture attached to the owner of this component.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, AutoGenerateComponentPause]
|
|
||||||
public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent
|
|
||||||
{
|
|
||||||
public const string FixtureID = "trigger-on-proximity-fixture";
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public readonly Dictionary<EntityUid, PhysicsComponent> Colliding = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What is the shape of the proximity fixture?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("shape")]
|
|
||||||
public IPhysShape Shape = new PhysShapeCircle(2f);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long the the proximity trigger animation plays for.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("animationDuration")]
|
|
||||||
public TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.6f);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the entity needs to be anchored for the proximity to work.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("requiresAnchored")]
|
|
||||||
public bool RequiresAnchored = true;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("enabled")]
|
|
||||||
public bool Enabled = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum delay between repeating triggers.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("cooldown")]
|
|
||||||
public TimeSpan Cooldown = TimeSpan.FromSeconds(5);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When can the trigger run again?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("nextTrigger", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan NextTrigger = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When will the visual state be updated again after activation?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("nextVisualUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))]
|
|
||||||
[AutoPausedField]
|
|
||||||
public TimeSpan NextVisualUpdate = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What speed should the other object be moving at to trigger the proximity fixture?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("triggerSpeed")]
|
|
||||||
public float TriggerSpeed = 3.5f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If this proximity is triggered should we continually repeat it?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("repeating")]
|
|
||||||
public bool Repeating = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What layer is the trigger fixture on?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("layer", customTypeSerializer: typeof(FlagSerializer<CollisionLayer>))]
|
|
||||||
public int Layer = (int) (CollisionGroup.MidImpassable | CollisionGroup.LowImpassable | CollisionGroup.HighImpassable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Content.Shared.DeviceLinking;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sends a trigger when signal is received.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnSignalComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("port", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
|
||||||
public string Port = "Trigger";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnSlipComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// calls the trigger when the object is initialized
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnSpawnComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is used for entities that want the more generic 'trigger' behavior after a step trigger occurs.
|
|
||||||
/// Not done by default, since it's not useful for everything and might cause weird behavior. But it is useful for a lot of stuff like mousetraps.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnStepTriggerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers when the entity is overlapped for the specified duration.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnTimedCollideComponent : Component
|
|
||||||
{
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("threshold")]
|
|
||||||
public float Threshold;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A collection of entities that are colliding with this, and their own unique accumulator.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public readonly Dictionary<EntityUid, float> Colliding = new();
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers on use in hand.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnUseComponent : Component { }
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sends a trigger when the keyphrase is heard
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerOnVoiceComponent : Component
|
|
||||||
{
|
|
||||||
public bool IsListening => IsRecording || !string.IsNullOrWhiteSpace(KeyPhrase);
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("keyPhrase")]
|
|
||||||
public string? KeyPhrase;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("listenRange")]
|
|
||||||
public int ListenRange { get; private set; } = 4;
|
|
||||||
|
|
||||||
[DataField("isRecording")]
|
|
||||||
public bool IsRecording = false;
|
|
||||||
|
|
||||||
[DataField("minLength")]
|
|
||||||
public int MinLength = 3;
|
|
||||||
|
|
||||||
[DataField("maxLength")]
|
|
||||||
public int MaxLength = 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers a gun when attempting to shoot while it's empty
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerWhenEmptyComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Content.Shared.Whitelist;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the user of a Trigger satisfies a whitelist and blacklist condition.
|
|
||||||
/// Cancels the trigger otherwise.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class TriggerWhitelistComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whitelist for what entites can cause this trigger.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public EntityWhitelist? Whitelist;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blacklist for what entites can cause this trigger.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public EntityWhitelist? Blacklist;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Explosion.Components;
|
using Content.Server.Explosion.Components;
|
||||||
using Content.Server.Weapons.Ranged.Systems;
|
using Content.Server.Weapons.Ranged.Systems;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -45,6 +46,9 @@ public sealed class ProjectileGrenadeSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnFragTrigger(Entity<ProjectileGrenadeComponent> entity, ref TriggerEvent args)
|
private void OnFragTrigger(Entity<ProjectileGrenadeComponent> entity, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
if (args.Key != entity.Comp.TriggerKey)
|
||||||
|
return;
|
||||||
|
|
||||||
FragmentIntoProjectiles(entity.Owner, entity.Comp);
|
FragmentIntoProjectiles(entity.Owner, entity.Comp);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
using Content.Server.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases a gas mixture to the atmosphere when triggered.
|
|
||||||
/// Can also release gas over a set timespan to prevent trolling people
|
|
||||||
/// with the instant-wall-of-pressure-inator.
|
|
||||||
/// </summary>
|
|
||||||
public sealed partial class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ReleaseGasOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shrimply sets the component to active when triggered, allowing it to release over time.
|
|
||||||
/// </summary>
|
|
||||||
private void OnTrigger(Entity<ReleaseGasOnTriggerComponent> ent, ref TriggerEvent args)
|
|
||||||
{
|
|
||||||
ent.Comp.Active = true;
|
|
||||||
ent.Comp.NextReleaseTime = _timing.CurTime;
|
|
||||||
ent.Comp.StartingTotalMoles = ent.Comp.Air.TotalMoles;
|
|
||||||
UpdateAppearance(ent.Owner, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
var query = EntityQueryEnumerator<ReleaseGasOnTriggerComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var comp))
|
|
||||||
{
|
|
||||||
if (!comp.Active || comp.NextReleaseTime > curTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var giverGasMix = comp.Air.Remove(comp.StartingTotalMoles * comp.RemoveFraction);
|
|
||||||
var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
|
|
||||||
|
|
||||||
if (environment == null)
|
|
||||||
{
|
|
||||||
UpdateAppearance(uid, false);
|
|
||||||
RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_atmosphereSystem.Merge(environment, giverGasMix);
|
|
||||||
comp.NextReleaseTime += comp.ReleaseInterval;
|
|
||||||
|
|
||||||
if (comp.PressureLimit != 0 && environment.Pressure >= comp.PressureLimit ||
|
|
||||||
comp.Air.TotalMoles <= 0)
|
|
||||||
{
|
|
||||||
UpdateAppearance(uid, false);
|
|
||||||
RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAppearance(Entity<AppearanceComponent?> entity, bool state)
|
|
||||||
{
|
|
||||||
if (!Resolve(entity, ref entity.Comp, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_appearance.SetData(entity, ReleaseGasOnTriggerVisuals.Key, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.RepulseAttract;
|
|
||||||
using Content.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
public sealed class RepulseAttractOnTriggerSystem : SharedRepulseAttractOnTriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly RepulseAttractSystem _repulse = default!;
|
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
|
||||||
[Dependency] private readonly UseDelaySystem _delay = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SharedRepulseAttractOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(Entity<SharedRepulseAttractOnTriggerComponent> ent, ref TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (_delay.IsDelayed(ent.Owner))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var position = _transform.GetMapCoordinates(ent);
|
|
||||||
_repulse.TryRepulseAttract(position, args.User, ent.Comp.Speed, ent.Comp.Range, ent.Comp.Whitelist, ent.Comp.CollisionMask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
using Content.Shared.Explosion.Components;
|
using Content.Shared.Explosion.Components;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
|
using Content.Shared.Trigger.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -15,6 +18,7 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||||
|
[Dependency] private readonly TriggerSystem _trigger = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -30,6 +34,9 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnScatteringTrigger(Entity<ScatteringGrenadeComponent> entity, ref TriggerEvent args)
|
private void OnScatteringTrigger(Entity<ScatteringGrenadeComponent> entity, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
if (args.Key != entity.Comp.TriggerKey)
|
||||||
|
return;
|
||||||
|
|
||||||
entity.Comp.IsTriggered = true;
|
entity.Comp.IsTriggered = true;
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
@@ -76,13 +83,12 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem
|
|||||||
|
|
||||||
_throwingSystem.TryThrow(contentUid, direction, component.Velocity);
|
_throwingSystem.TryThrow(contentUid, direction, component.Velocity);
|
||||||
|
|
||||||
if (component.TriggerContents)
|
if (component.TriggerContents && TryComp<TimerTriggerComponent>(contentUid, out var contentTimer))
|
||||||
{
|
{
|
||||||
additionalIntervalDelay += _random.NextFloat(component.IntervalBetweenTriggersMin, component.IntervalBetweenTriggersMax);
|
additionalIntervalDelay += _random.NextFloat(component.IntervalBetweenTriggersMin, component.IntervalBetweenTriggersMax);
|
||||||
var contentTimer = EnsureComp<ActiveTimerTriggerComponent>(contentUid);
|
|
||||||
contentTimer.TimeRemaining = component.DelayBeforeTriggerContents + additionalIntervalDelay;
|
_trigger.SetDelay((contentUid, contentTimer), TimeSpan.FromSeconds(component.DelayBeforeTriggerContents + additionalIntervalDelay));
|
||||||
var ev = new ActiveTimerTriggerEvent(contentUid, uid);
|
_trigger.ActivateTimerTrigger((contentUid, contentTimer));
|
||||||
RaiseLocalEvent(contentUid, ref ev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Fluids.EntitySystems;
|
|
||||||
using Content.Server.Spreader;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
|
||||||
using Content.Shared.Coordinates.Helpers;
|
|
||||||
using Content.Shared.Maps;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles creating smoke when <see cref="SmokeOnTriggerComponent"/> is triggered.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
|
||||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
|
||||||
[Dependency] private readonly SmokeSystem _smoke = default!;
|
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
|
||||||
[Dependency] private readonly SpreaderSystem _spreader = default!;
|
|
||||||
[Dependency] private readonly TurfSystem _turf = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SmokeOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, SmokeOnTriggerComponent comp, TriggerEvent args)
|
|
||||||
{
|
|
||||||
var xform = Transform(uid);
|
|
||||||
var mapCoords = _transform.GetMapCoordinates(uid, xform);
|
|
||||||
if (!_mapMan.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
|
|
||||||
!_map.TryGetTileRef(gridUid, grid, xform.Coordinates, out var tileRef) ||
|
|
||||||
tileRef.Tile.IsEmpty)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var coords = _map.MapToGrid(gridUid, mapCoords);
|
|
||||||
var ent = Spawn(comp.SmokePrototype, coords.SnapToGrid());
|
|
||||||
if (!TryComp<SmokeComponent>(ent, out var smoke))
|
|
||||||
{
|
|
||||||
Log.Error($"Smoke prototype {comp.SmokePrototype} was missing SmokeComponent");
|
|
||||||
Del(ent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_smoke.StartSmoke(ent, comp.Solution, comp.Duration, comp.SpreadAmount, smoke);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Interaction.Events;
|
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Sticky;
|
|
||||||
using Content.Shared.Verbs;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
public sealed partial class TriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
|
||||||
|
|
||||||
private void InitializeOnUse()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<OnUseTimerTriggerComponent, UseInHandEvent>(OnTimerUse);
|
|
||||||
SubscribeLocalEvent<OnUseTimerTriggerComponent, ExaminedEvent>(OnExamined);
|
|
||||||
SubscribeLocalEvent<OnUseTimerTriggerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAltVerbs);
|
|
||||||
SubscribeLocalEvent<OnUseTimerTriggerComponent, EntityStuckEvent>(OnStuck);
|
|
||||||
SubscribeLocalEvent<RandomTimerTriggerComponent, MapInitEvent>(OnRandomTimerTriggerMapInit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStuck(EntityUid uid, OnUseTimerTriggerComponent component, ref EntityStuckEvent args)
|
|
||||||
{
|
|
||||||
if (!component.StartOnStick)
|
|
||||||
return;
|
|
||||||
|
|
||||||
StartTimer((uid, component), args.User);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExamined(EntityUid uid, OnUseTimerTriggerComponent component, ExaminedEvent args)
|
|
||||||
{
|
|
||||||
if (args.IsInDetailsRange && component.Examinable)
|
|
||||||
args.PushText(Loc.GetString("examine-trigger-timer", ("time", component.Delay)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add an alt-click interaction that cycles through delays.
|
|
||||||
/// </summary>
|
|
||||||
private void OnGetAltVerbs(EntityUid uid, OnUseTimerTriggerComponent component, GetVerbsEvent<AlternativeVerb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanInteract || !args.CanAccess || args.Hands == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.UseVerbInstead)
|
|
||||||
{
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("verb-start-detonation"),
|
|
||||||
Act = () => StartTimer((uid, component), args.User),
|
|
||||||
Priority = 2
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.AllowToggleStartOnStick)
|
|
||||||
{
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("verb-toggle-start-on-stick"),
|
|
||||||
Act = () => ToggleStartOnStick(uid, args.User, component)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.DelayOptions == null || component.DelayOptions.Count == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Category = TimerOptions,
|
|
||||||
Text = Loc.GetString("verb-trigger-timer-cycle"),
|
|
||||||
Act = () => CycleDelay(component, args.User),
|
|
||||||
Priority = 1
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var option in component.DelayOptions)
|
|
||||||
{
|
|
||||||
if (MathHelper.CloseTo(option, component.Delay))
|
|
||||||
{
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Category = TimerOptions,
|
|
||||||
Text = Loc.GetString("verb-trigger-timer-set-current", ("time", option)),
|
|
||||||
Disabled = true,
|
|
||||||
Priority = (int) (-100 * option)
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Category = TimerOptions,
|
|
||||||
Text = Loc.GetString("verb-trigger-timer-set", ("time", option)),
|
|
||||||
Priority = (int) (-100 * option),
|
|
||||||
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
component.Delay = option;
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", option)), args.User, args.User);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRandomTimerTriggerMapInit(Entity<RandomTimerTriggerComponent> ent, ref MapInitEvent args)
|
|
||||||
{
|
|
||||||
var (_, comp) = ent;
|
|
||||||
|
|
||||||
if (!TryComp<OnUseTimerTriggerComponent>(ent, out var timerTriggerComp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
timerTriggerComp.Delay = _random.NextFloat(comp.Min, comp.Max);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CycleDelay(OnUseTimerTriggerComponent component, EntityUid user)
|
|
||||||
{
|
|
||||||
if (component.DelayOptions == null || component.DelayOptions.Count == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// This is somewhat inefficient, but its good enough. This is run rarely, and the lists should be short.
|
|
||||||
|
|
||||||
component.DelayOptions.Sort();
|
|
||||||
|
|
||||||
if (component.DelayOptions[^1] <= component.Delay)
|
|
||||||
{
|
|
||||||
component.Delay = component.DelayOptions[0];
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", component.Delay)), user, user);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var option in component.DelayOptions)
|
|
||||||
{
|
|
||||||
if (option > component.Delay)
|
|
||||||
{
|
|
||||||
component.Delay = option;
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", option)), user, user);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleStartOnStick(EntityUid grenade, EntityUid user, OnUseTimerTriggerComponent comp)
|
|
||||||
{
|
|
||||||
if (comp.StartOnStick)
|
|
||||||
{
|
|
||||||
comp.StartOnStick = false;
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-start-on-stick-off"), grenade, user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
comp.StartOnStick = true;
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-start-on-stick-on"), grenade, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || HasComp<AutomatedTimerComponent>(uid) || component.UseVerbInstead)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.DoPopup)
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("trigger-activated", ("device", uid)), args.User, args.User);
|
|
||||||
|
|
||||||
StartTimer((uid, component), args.User);
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VerbCategory TimerOptions = new("verb-categories-timer", "/Textures/Interface/VerbIcons/clock.svg.192dpi.png");
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Shared.Trigger;
|
|
||||||
using Robust.Shared.Physics.Components;
|
|
||||||
using Robust.Shared.Physics.Events;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
public sealed partial class TriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
|
|
||||||
private void InitializeProximity()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, StartCollideEvent>(OnProximityStartCollide);
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, EndCollideEvent>(OnProximityEndCollide);
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, MapInitEvent>(OnMapInit);
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentShutdown>(OnProximityShutdown);
|
|
||||||
// Shouldn't need re-anchoring.
|
|
||||||
SubscribeLocalEvent<TriggerOnProximityComponent, AnchorStateChangedEvent>(OnProximityAnchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProximityAnchor(EntityUid uid, TriggerOnProximityComponent component, ref AnchorStateChangedEvent args)
|
|
||||||
{
|
|
||||||
component.Enabled = !component.RequiresAnchored ||
|
|
||||||
args.Anchored;
|
|
||||||
|
|
||||||
SetProximityAppearance(uid, component);
|
|
||||||
|
|
||||||
if (!component.Enabled)
|
|
||||||
{
|
|
||||||
component.Colliding.Clear();
|
|
||||||
}
|
|
||||||
// Re-check for contacts as we cleared them.
|
|
||||||
else if (TryComp<PhysicsComponent>(uid, out var body))
|
|
||||||
{
|
|
||||||
_broadphase.RegenerateContacts((uid, body));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProximityShutdown(EntityUid uid, TriggerOnProximityComponent component, ComponentShutdown args)
|
|
||||||
{
|
|
||||||
component.Colliding.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, TriggerOnProximityComponent component, MapInitEvent args)
|
|
||||||
{
|
|
||||||
component.Enabled = !component.RequiresAnchored ||
|
|
||||||
Transform(uid).Anchored;
|
|
||||||
|
|
||||||
SetProximityAppearance(uid, component);
|
|
||||||
|
|
||||||
if (!TryComp<PhysicsComponent>(uid, out var body))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fixtures.TryCreateFixture(
|
|
||||||
uid,
|
|
||||||
component.Shape,
|
|
||||||
TriggerOnProximityComponent.FixtureID,
|
|
||||||
hard: false,
|
|
||||||
body: body,
|
|
||||||
collisionLayer: component.Layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProximityStartCollide(EntityUid uid, TriggerOnProximityComponent component, ref StartCollideEvent args)
|
|
||||||
{
|
|
||||||
if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component.Colliding[args.OtherEntity] = args.OtherBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnProximityEndCollide(EntityUid uid, TriggerOnProximityComponent component, ref EndCollideEvent args)
|
|
||||||
{
|
|
||||||
if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component.Colliding.Remove(args.OtherEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetProximityAppearance(EntityUid uid, TriggerOnProximityComponent component)
|
|
||||||
{
|
|
||||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
|
||||||
{
|
|
||||||
_appearance.SetData(uid, ProximityTriggerVisualState.State, component.Enabled ? ProximityTriggerVisuals.Inactive : ProximityTriggerVisuals.Off, appearance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Activate(EntityUid uid, EntityUid user, TriggerOnProximityComponent component)
|
|
||||||
{
|
|
||||||
DebugTools.Assert(component.Enabled);
|
|
||||||
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
|
|
||||||
if (!component.Repeating)
|
|
||||||
{
|
|
||||||
component.Enabled = false;
|
|
||||||
component.Colliding.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
component.NextTrigger = curTime + component.Cooldown;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Queue a visual update for when the animation is complete.
|
|
||||||
component.NextVisualUpdate = curTime + component.AnimationDuration;
|
|
||||||
|
|
||||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
|
||||||
{
|
|
||||||
_appearance.SetData(uid, ProximityTriggerVisualState.State, ProximityTriggerVisuals.Active, appearance);
|
|
||||||
}
|
|
||||||
|
|
||||||
Trigger(uid, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateProximity()
|
|
||||||
{
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<TriggerOnProximityComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var trigger))
|
|
||||||
{
|
|
||||||
if (curTime >= trigger.NextVisualUpdate)
|
|
||||||
{
|
|
||||||
// Update the visual state once the animation is done.
|
|
||||||
trigger.NextVisualUpdate = TimeSpan.MaxValue;
|
|
||||||
SetProximityAppearance(uid, trigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trigger.Enabled)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (curTime < trigger.NextTrigger)
|
|
||||||
// The trigger's on cooldown.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check for anything colliding and moving fast enough.
|
|
||||||
foreach (var (collidingUid, colliding) in trigger.Colliding)
|
|
||||||
{
|
|
||||||
if (Deleted(collidingUid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (colliding.LinearVelocity.Length() < trigger.TriggerSpeed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Trigger!
|
|
||||||
Activate(uid, collidingUid, trigger);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Content.Server.DeviceLinking.Systems;
|
|
||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Shared.DeviceLinking.Events;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems
|
|
||||||
{
|
|
||||||
public sealed partial class TriggerSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
|
|
||||||
private void InitializeSignal()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<TriggerOnSignalComponent,SignalReceivedEvent>(OnSignalReceived);
|
|
||||||
SubscribeLocalEvent<TriggerOnSignalComponent,ComponentInit>(OnInit);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<TimerStartOnSignalComponent,SignalReceivedEvent>(OnTimerSignalReceived);
|
|
||||||
SubscribeLocalEvent<TimerStartOnSignalComponent,ComponentInit>(OnTimerSignalInit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSignalReceived(EntityUid uid, TriggerOnSignalComponent component, ref SignalReceivedEvent args)
|
|
||||||
{
|
|
||||||
if (args.Port != component.Port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Trigger(uid, args.Trigger);
|
|
||||||
}
|
|
||||||
private void OnInit(EntityUid uid, TriggerOnSignalComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
_signalSystem.EnsureSinkPorts(uid, component.Port);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimerSignalReceived(EntityUid uid, TimerStartOnSignalComponent component, ref SignalReceivedEvent args)
|
|
||||||
{
|
|
||||||
if (args.Port != component.Port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
StartTimer(uid, args.Trigger);
|
|
||||||
}
|
|
||||||
private void OnTimerSignalInit(EntityUid uid, TimerStartOnSignalComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
_signalSystem.EnsureSinkPorts(uid, component.Port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Physics.Dynamics;
|
|
||||||
using Robust.Shared.Physics.Events;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
public sealed partial class TriggerSystem
|
|
||||||
{
|
|
||||||
private void InitializeTimedCollide()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<TriggerOnTimedCollideComponent, StartCollideEvent>(OnTimerCollide);
|
|
||||||
SubscribeLocalEvent<TriggerOnTimedCollideComponent, EndCollideEvent>(OnTimerEndCollide);
|
|
||||||
SubscribeLocalEvent<TriggerOnTimedCollideComponent, ComponentRemove>(OnComponentRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimerCollide(EntityUid uid, TriggerOnTimedCollideComponent component, ref StartCollideEvent args)
|
|
||||||
{
|
|
||||||
//Ensures the entity trigger will have an active component
|
|
||||||
EnsureComp<ActiveTriggerOnTimedCollideComponent>(uid);
|
|
||||||
var otherUID = args.OtherEntity;
|
|
||||||
if (component.Colliding.ContainsKey(otherUID))
|
|
||||||
return;
|
|
||||||
component.Colliding.Add(otherUID, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimerEndCollide(EntityUid uid, TriggerOnTimedCollideComponent component, ref EndCollideEvent args)
|
|
||||||
{
|
|
||||||
var otherUID = args.OtherEntity;
|
|
||||||
component.Colliding.Remove(otherUID);
|
|
||||||
|
|
||||||
if (component.Colliding.Count == 0 && HasComp<ActiveTriggerOnTimedCollideComponent>(uid))
|
|
||||||
RemComp<ActiveTriggerOnTimedCollideComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnComponentRemove(EntityUid uid, TriggerOnTimedCollideComponent component, ComponentRemove args)
|
|
||||||
{
|
|
||||||
if (HasComp<ActiveTriggerOnTimedCollideComponent>(uid))
|
|
||||||
RemComp<ActiveTriggerOnTimedCollideComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTimedCollide(float frameTime)
|
|
||||||
{
|
|
||||||
var query = EntityQueryEnumerator<ActiveTriggerOnTimedCollideComponent, TriggerOnTimedCollideComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out _, out var triggerOnTimedCollide))
|
|
||||||
{
|
|
||||||
foreach (var (collidingEntity, collidingTimer) in triggerOnTimedCollide.Colliding)
|
|
||||||
{
|
|
||||||
triggerOnTimedCollide.Colliding[collidingEntity] += frameTime;
|
|
||||||
if (collidingTimer > triggerOnTimedCollide.Threshold)
|
|
||||||
{
|
|
||||||
RaiseLocalEvent(uid, new TriggerEvent(uid, collidingEntity), true);
|
|
||||||
triggerOnTimedCollide.Colliding[collidingEntity] -= triggerOnTimedCollide.Threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Verbs;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems
|
|
||||||
{
|
|
||||||
public sealed partial class TriggerSystem
|
|
||||||
{
|
|
||||||
private void InitializeVoice()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<TriggerOnVoiceComponent, ComponentInit>(OnVoiceInit);
|
|
||||||
SubscribeLocalEvent<TriggerOnVoiceComponent, ExaminedEvent>(OnVoiceExamine);
|
|
||||||
SubscribeLocalEvent<TriggerOnVoiceComponent, GetVerbsEvent<AlternativeVerb>>(OnVoiceGetAltVerbs);
|
|
||||||
SubscribeLocalEvent<TriggerOnVoiceComponent, ListenEvent>(OnListen);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVoiceInit(EntityUid uid, TriggerOnVoiceComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
if (component.IsListening)
|
|
||||||
EnsureComp<ActiveListenerComponent>(uid).Range = component.ListenRange;
|
|
||||||
else
|
|
||||||
RemCompDeferred<ActiveListenerComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnListen(Entity<TriggerOnVoiceComponent> ent, ref ListenEvent args)
|
|
||||||
{
|
|
||||||
var component = ent.Comp;
|
|
||||||
var message = args.Message.Trim();
|
|
||||||
|
|
||||||
if (component.IsRecording)
|
|
||||||
{
|
|
||||||
var ev = new ListenAttemptEvent(args.Source);
|
|
||||||
RaiseLocalEvent(ent, ev);
|
|
||||||
|
|
||||||
if (ev.Cancelled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (message.Length >= component.MinLength && message.Length <= component.MaxLength)
|
|
||||||
FinishRecording(ent, args.Source, args.Message);
|
|
||||||
else if (message.Length > component.MaxLength)
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-record-failed-too-long"), ent);
|
|
||||||
else if (message.Length < component.MinLength)
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-record-failed-too-short"), ent);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(component.KeyPhrase) && message.IndexOf(component.KeyPhrase, StringComparison.InvariantCultureIgnoreCase) is var index and >= 0 )
|
|
||||||
{
|
|
||||||
_adminLogger.Add(LogType.Trigger, LogImpact.Medium,
|
|
||||||
$"A voice-trigger on {ToPrettyString(ent):entity} was triggered by {ToPrettyString(args.Source):speaker} speaking the key-phrase {component.KeyPhrase}.");
|
|
||||||
Trigger(ent, args.Source);
|
|
||||||
|
|
||||||
var messageWithoutPhrase = message.Remove(index, component.KeyPhrase.Length).Trim();
|
|
||||||
|
|
||||||
var voice = new VoiceTriggeredEvent(args.Source, message, messageWithoutPhrase);
|
|
||||||
RaiseLocalEvent(ent, ref voice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVoiceGetAltVerbs(Entity<TriggerOnVoiceComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanInteract || !args.CanAccess)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var component = ent.Comp;
|
|
||||||
|
|
||||||
var @event = args;
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString(component.IsRecording ? "verb-trigger-voice-stop" : "verb-trigger-voice-record"),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
if (component.IsRecording)
|
|
||||||
StopRecording(ent);
|
|
||||||
else
|
|
||||||
StartRecording(ent, @event.User);
|
|
||||||
},
|
|
||||||
Priority = 1
|
|
||||||
});
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(component.KeyPhrase))
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("verb-trigger-voice-clear"),
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
component.KeyPhrase = null;
|
|
||||||
component.IsRecording = false;
|
|
||||||
RemComp<ActiveListenerComponent>(ent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartRecording(Entity<TriggerOnVoiceComponent> ent, EntityUid user)
|
|
||||||
{
|
|
||||||
var component = ent.Comp;
|
|
||||||
component.IsRecording = true;
|
|
||||||
EnsureComp<ActiveListenerComponent>(ent).Range = component.ListenRange;
|
|
||||||
|
|
||||||
_adminLogger.Add(LogType.Trigger, LogImpact.Low,
|
|
||||||
$"A voice-trigger on {ToPrettyString(ent):entity} has started recording. User: {ToPrettyString(user):user}");
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-start-recording"), ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopRecording(Entity<TriggerOnVoiceComponent> ent)
|
|
||||||
{
|
|
||||||
var component = ent.Comp;
|
|
||||||
component.IsRecording = false;
|
|
||||||
if (string.IsNullOrWhiteSpace(component.KeyPhrase))
|
|
||||||
RemComp<ActiveListenerComponent>(ent);
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-stop-recording"), ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FinishRecording(Entity<TriggerOnVoiceComponent> ent, EntityUid source, string message)
|
|
||||||
{
|
|
||||||
var component = ent.Comp;
|
|
||||||
component.KeyPhrase = message;
|
|
||||||
component.IsRecording = false;
|
|
||||||
|
|
||||||
_adminLogger.Add(LogType.Trigger, LogImpact.Low,
|
|
||||||
$"A voice-trigger on {ToPrettyString(ent):entity} has recorded a new keyphrase: '{component.KeyPhrase}'. Recorded from {ToPrettyString(source):speaker}");
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-recorded", ("keyphrase", component.KeyPhrase!)), ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVoiceExamine(EntityUid uid, TriggerOnVoiceComponent component, ExaminedEvent args)
|
|
||||||
{
|
|
||||||
if (args.IsInDetailsRange)
|
|
||||||
{
|
|
||||||
args.PushText(string.IsNullOrWhiteSpace(component.KeyPhrase)
|
|
||||||
? Loc.GetString("trigger-voice-uninitialized")
|
|
||||||
: Loc.GetString("examine-trigger-voice", ("keyphrase", component.KeyPhrase)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when a voice trigger is activated, containing the message that triggered it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Source"> The EntityUid of the entity sending the message</param>
|
|
||||||
/// <param name="Message"> The contents of the message</param>
|
|
||||||
/// <param name="MessageWithoutPhrase"> The message without the phrase that triggered it.</param>
|
|
||||||
[ByRefEvent]
|
|
||||||
public readonly record struct VoiceTriggeredEvent(EntityUid Source, string Message, string MessageWithoutPhrase);
|
|
||||||
@@ -1,454 +0,0 @@
|
|||||||
using Content.Server.Administration.Logs;
|
|
||||||
using Content.Server.Body.Systems;
|
|
||||||
using Content.Server.Explosion.Components;
|
|
||||||
using Content.Shared.Flash;
|
|
||||||
using Content.Server.Electrocution;
|
|
||||||
using Content.Server.Pinpointer;
|
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
|
||||||
using Content.Shared.Flash.Components;
|
|
||||||
using Content.Server.Radio.EntitySystems;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
|
||||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
using Content.Shared.Implants.Components;
|
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Interaction.Events;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.Mobs;
|
|
||||||
using Content.Shared.Mobs.Components;
|
|
||||||
using Content.Shared.Payload.Components;
|
|
||||||
using Content.Shared.Radio;
|
|
||||||
using Content.Shared.Slippery;
|
|
||||||
using Content.Shared.StepTrigger.Systems;
|
|
||||||
using Content.Shared.Trigger;
|
|
||||||
using Content.Shared.Weapons.Ranged.Events;
|
|
||||||
using Content.Shared.Whitelist;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio.Systems;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.Physics.Events;
|
|
||||||
using Robust.Shared.Physics.Systems;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Raised whenever something is Triggered on the entity.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class TriggerEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
public EntityUid Triggered { get; }
|
|
||||||
public EntityUid? User { get; }
|
|
||||||
|
|
||||||
public TriggerEvent(EntityUid triggered, EntityUid? user = null)
|
|
||||||
{
|
|
||||||
Triggered = triggered;
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised before a trigger is activated.
|
|
||||||
/// </summary>
|
|
||||||
[ByRefEvent]
|
|
||||||
public record struct BeforeTriggerEvent(EntityUid Triggered, EntityUid? User, bool Cancelled = false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when timer trigger becomes active.
|
|
||||||
/// </summary>
|
|
||||||
[ByRefEvent]
|
|
||||||
public readonly record struct ActiveTimerTriggerEvent(EntityUid Triggered, EntityUid? User);
|
|
||||||
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed partial class TriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly ExplosionSystem _explosions = default!;
|
|
||||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
|
||||||
[Dependency] private readonly SharedFlashSystem _flashSystem = default!;
|
|
||||||
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
|
||||||
[Dependency] private readonly BodySystem _body = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
|
||||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
|
||||||
[Dependency] private readonly RadioSystem _radioSystem = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
|
||||||
[Dependency] private readonly ElectrocutionSystem _electrocution = default!;
|
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
InitializeProximity();
|
|
||||||
InitializeOnUse();
|
|
||||||
InitializeSignal();
|
|
||||||
InitializeTimedCollide();
|
|
||||||
InitializeVoice();
|
|
||||||
InitializeMobstate();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<TriggerOnSpawnComponent, MapInitEvent>(OnSpawnTriggered);
|
|
||||||
SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide);
|
|
||||||
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
|
|
||||||
SubscribeLocalEvent<TriggerOnUseComponent, UseInHandEvent>(OnUse);
|
|
||||||
SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger);
|
|
||||||
SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredOffEvent>(OnStepTriggered);
|
|
||||||
SubscribeLocalEvent<TriggerOnSlipComponent, SlipEvent>(OnSlipTriggered);
|
|
||||||
SubscribeLocalEvent<TriggerWhenEmptyComponent, OnEmptyGunShotEvent>(OnEmptyTriggered);
|
|
||||||
SubscribeLocalEvent<RepeatingTriggerComponent, MapInitEvent>(OnRepeatInit);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SpawnOnTriggerComponent, TriggerEvent>(OnSpawnTrigger);
|
|
||||||
SubscribeLocalEvent<DeleteOnTriggerComponent, TriggerEvent>(HandleDeleteTrigger);
|
|
||||||
SubscribeLocalEvent<ExplodeOnTriggerComponent, TriggerEvent>(HandleExplodeTrigger);
|
|
||||||
SubscribeLocalEvent<FlashOnTriggerComponent, TriggerEvent>(HandleFlashTrigger);
|
|
||||||
SubscribeLocalEvent<GibOnTriggerComponent, TriggerEvent>(HandleGibTrigger);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<AnchorOnTriggerComponent, TriggerEvent>(OnAnchorTrigger);
|
|
||||||
SubscribeLocalEvent<SoundOnTriggerComponent, TriggerEvent>(OnSoundTrigger);
|
|
||||||
SubscribeLocalEvent<ShockOnTriggerComponent, TriggerEvent>(HandleShockTrigger);
|
|
||||||
SubscribeLocalEvent<RattleComponent, TriggerEvent>(HandleRattleTrigger);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<TriggerWhitelistComponent, BeforeTriggerEvent>(HandleWhitelist);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleWhitelist(Entity<TriggerWhitelistComponent> ent, ref BeforeTriggerEvent args)
|
|
||||||
{
|
|
||||||
args.Cancelled = !_whitelist.CheckBoth(args.User, ent.Comp.Blacklist, ent.Comp.Whitelist);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSoundTrigger(EntityUid uid, SoundOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (component.RemoveOnTrigger) // if the component gets removed when it's triggered
|
|
||||||
{
|
|
||||||
var xform = Transform(uid);
|
|
||||||
_audio.PlayPvs(component.Sound, xform.Coordinates); // play the sound at its last known coordinates
|
|
||||||
}
|
|
||||||
else // if the component doesn't get removed when triggered
|
|
||||||
{
|
|
||||||
_audio.PlayPvs(component.Sound, uid); // have the sound follow the entity itself
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleShockTrigger(Entity<ShockOnTriggerComponent> shockOnTrigger, ref TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!_container.TryGetContainingContainer(shockOnTrigger.Owner, out var container))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var containerEnt = container.Owner;
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
|
|
||||||
if (curTime < shockOnTrigger.Comp.NextTrigger)
|
|
||||||
{
|
|
||||||
// The trigger's on cooldown.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_electrocution.TryDoElectrocution(containerEnt, null, shockOnTrigger.Comp.Damage, shockOnTrigger.Comp.Duration, true, ignoreInsulation: true);
|
|
||||||
shockOnTrigger.Comp.NextTrigger = curTime + shockOnTrigger.Comp.Cooldown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAnchorTrigger(EntityUid uid, AnchorOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
var xform = Transform(uid);
|
|
||||||
|
|
||||||
if (xform.Anchored)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_transformSystem.AnchorEntity(uid, xform);
|
|
||||||
|
|
||||||
if (component.RemoveOnTrigger)
|
|
||||||
RemCompDeferred<AnchorOnTriggerComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpawnTrigger(Entity<SpawnOnTriggerComponent> ent, ref TriggerEvent args)
|
|
||||||
{
|
|
||||||
var xform = Transform(ent);
|
|
||||||
|
|
||||||
if (ent.Comp.mapCoords)
|
|
||||||
{
|
|
||||||
var mapCoords = _transformSystem.GetMapCoordinates(ent, xform);
|
|
||||||
Spawn(ent.Comp.Proto, mapCoords);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var coords = xform.Coordinates;
|
|
||||||
if (!coords.IsValid(EntityManager))
|
|
||||||
return;
|
|
||||||
Spawn(ent.Comp.Proto, coords);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleExplodeTrigger(EntityUid uid, ExplodeOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
_explosions.TriggerExplosive(uid, user: args.User);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
_flashSystem.FlashArea(uid, args.User, component.Range, component.Duration, probability: component.Probability);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleDeleteTrigger(EntityUid uid, DeleteOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
QueueDel(uid);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleGibTrigger(EntityUid uid, GibOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp(uid, out TransformComponent? xform))
|
|
||||||
return;
|
|
||||||
if (component.DeleteItems)
|
|
||||||
{
|
|
||||||
var items = _inventory.GetHandOrInventoryEntities(xform.ParentUid);
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
Del(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_body.GibBody(xform.ParentUid, true);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void HandleRattleTrigger(EntityUid uid, RattleComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp<SubdermalImplantComponent>(uid, out var implanted))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (implanted.ImplantedEntity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Gets location of the implant
|
|
||||||
var posText = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString(uid));
|
|
||||||
var critMessage = Loc.GetString(component.CritMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText));
|
|
||||||
var deathMessage = Loc.GetString(component.DeathMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText));
|
|
||||||
|
|
||||||
if (!TryComp<MobStateComponent>(implanted.ImplantedEntity, out var mobstate))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Sends a message to the radio channel specified by the implant
|
|
||||||
if (mobstate.CurrentState == MobState.Critical)
|
|
||||||
_radioSystem.SendRadioMessage(uid, critMessage, _prototypeManager.Index<RadioChannelPrototype>(component.RadioChannel), uid);
|
|
||||||
if (mobstate.CurrentState == MobState.Dead)
|
|
||||||
_radioSystem.SendRadioMessage(uid, deathMessage, _prototypeManager.Index<RadioChannelPrototype>(component.RadioChannel), uid);
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTriggerCollide(EntityUid uid, TriggerOnCollideComponent component, ref StartCollideEvent args)
|
|
||||||
{
|
|
||||||
if (args.OurFixtureId == component.FixtureID && (!component.IgnoreOtherNonHard || args.OtherFixture.Hard))
|
|
||||||
Trigger(uid, args.OtherEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpawnTriggered(EntityUid uid, TriggerOnSpawnComponent component, MapInitEvent args)
|
|
||||||
{
|
|
||||||
Trigger(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActivate(EntityUid uid, TriggerOnActivateComponent component, ActivateInWorldEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || !args.Complex)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Trigger(uid, args.User);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUse(Entity<TriggerOnUseComponent> ent, ref UseInHandEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Trigger(ent.Owner, args.User);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnImplantTrigger(EntityUid uid, TriggerImplantActionComponent component, ActivateImplantEvent args)
|
|
||||||
{
|
|
||||||
args.Handled = Trigger(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStepTriggered(EntityUid uid, TriggerOnStepTriggerComponent component, ref StepTriggeredOffEvent args)
|
|
||||||
{
|
|
||||||
Trigger(uid, args.Tripper);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSlipTriggered(EntityUid uid, TriggerOnSlipComponent component, ref SlipEvent args)
|
|
||||||
{
|
|
||||||
Trigger(uid, args.Slipped);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEmptyTriggered(EntityUid uid, TriggerWhenEmptyComponent component, ref OnEmptyGunShotEvent args)
|
|
||||||
{
|
|
||||||
Trigger(uid, args.EmptyGun);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRepeatInit(Entity<RepeatingTriggerComponent> ent, ref MapInitEvent args)
|
|
||||||
{
|
|
||||||
ent.Comp.NextTrigger = _timing.CurTime + ent.Comp.Delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Trigger(EntityUid trigger, EntityUid? user = null)
|
|
||||||
{
|
|
||||||
var beforeTriggerEvent = new BeforeTriggerEvent(trigger, user);
|
|
||||||
RaiseLocalEvent(trigger, ref beforeTriggerEvent);
|
|
||||||
if (beforeTriggerEvent.Cancelled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var triggerEvent = new TriggerEvent(trigger, user);
|
|
||||||
EntityManager.EventBus.RaiseLocalEvent(trigger, triggerEvent, true);
|
|
||||||
return triggerEvent.Handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TryDelay(EntityUid uid, float amount, ActiveTimerTriggerComponent? comp = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref comp, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
comp.TimeRemaining += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start the timer for triggering the device.
|
|
||||||
/// </summary>
|
|
||||||
public void StartTimer(Entity<OnUseTimerTriggerComponent?> ent, EntityUid? user)
|
|
||||||
{
|
|
||||||
if (!Resolve(ent, ref ent.Comp, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var comp = ent.Comp;
|
|
||||||
HandleTimerTrigger(ent, user, comp.Delay, comp.BeepInterval, comp.InitialBeepDelay, comp.BeepSound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay, float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound)
|
|
||||||
{
|
|
||||||
if (delay <= 0)
|
|
||||||
{
|
|
||||||
RemComp<ActiveTimerTriggerComponent>(uid);
|
|
||||||
Trigger(uid, user);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasComp<ActiveTimerTriggerComponent>(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
// Check if entity is bomb/mod. grenade/etc
|
|
||||||
if (_container.TryGetContainer(uid, "payload", out BaseContainer? container) &&
|
|
||||||
container.ContainedEntities.Count > 0 &&
|
|
||||||
TryComp(container.ContainedEntities[0], out ChemicalPayloadComponent? chemicalPayloadComponent))
|
|
||||||
{
|
|
||||||
// If a beaker is missing, the entity won't explode, so no reason to log it
|
|
||||||
if (chemicalPayloadComponent?.BeakerSlotA.Item is not { } beakerA ||
|
|
||||||
chemicalPayloadComponent?.BeakerSlotB.Item is not { } beakerB ||
|
|
||||||
!TryComp(beakerA, out SolutionContainerManagerComponent? containerA) ||
|
|
||||||
!TryComp(beakerB, out SolutionContainerManagerComponent? containerB) ||
|
|
||||||
!TryComp(beakerA, out FitsInDispenserComponent? fitsA) ||
|
|
||||||
!TryComp(beakerB, out FitsInDispenserComponent? fitsB) ||
|
|
||||||
!_solutionContainerSystem.TryGetSolution((beakerA, containerA), fitsA.Solution, out _, out var solutionA) ||
|
|
||||||
!_solutionContainerSystem.TryGetSolution((beakerB, containerB), fitsB.Solution, out _, out var solutionB))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_adminLogger.Add(LogType.Trigger,
|
|
||||||
$"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains {SharedSolutionContainerSystem.ToPrettyString(solutionA)} in one beaker and {SharedSolutionContainerSystem.ToPrettyString(solutionB)} in the other.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_adminLogger.Add(LogType.Trigger,
|
|
||||||
$"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_adminLogger.Add(LogType.Trigger,
|
|
||||||
$"{delay} second timer trigger started on entity {ToPrettyString(uid):timer}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var active = AddComp<ActiveTimerTriggerComponent>(uid);
|
|
||||||
active.TimeRemaining = delay;
|
|
||||||
active.User = user;
|
|
||||||
active.BeepSound = beepSound;
|
|
||||||
active.BeepInterval = beepInterval;
|
|
||||||
active.TimeUntilBeep = initialBeepDelay == null ? active.BeepInterval : initialBeepDelay.Value;
|
|
||||||
|
|
||||||
var ev = new ActiveTimerTriggerEvent(uid, user);
|
|
||||||
RaiseLocalEvent(uid, ref ev);
|
|
||||||
|
|
||||||
if (TryComp<AppearanceComponent>(uid, out var appearance))
|
|
||||||
_appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Primed, appearance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
UpdateProximity();
|
|
||||||
UpdateTimer(frameTime);
|
|
||||||
UpdateTimedCollide(frameTime);
|
|
||||||
UpdateRepeat();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTimer(float frameTime)
|
|
||||||
{
|
|
||||||
HashSet<EntityUid> toRemove = new();
|
|
||||||
var query = EntityQueryEnumerator<ActiveTimerTriggerComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var timer))
|
|
||||||
{
|
|
||||||
timer.TimeRemaining -= frameTime;
|
|
||||||
timer.TimeUntilBeep -= frameTime;
|
|
||||||
|
|
||||||
if (timer.TimeRemaining <= 0)
|
|
||||||
{
|
|
||||||
Trigger(uid, timer.User);
|
|
||||||
toRemove.Add(uid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timer.BeepSound == null || timer.TimeUntilBeep > 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
timer.TimeUntilBeep += timer.BeepInterval;
|
|
||||||
_audio.PlayPvs(timer.BeepSound, uid, timer.BeepSound.Params);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var uid in toRemove)
|
|
||||||
{
|
|
||||||
RemComp<ActiveTimerTriggerComponent>(uid);
|
|
||||||
|
|
||||||
// In case this is a re-usable grenade, un-prime it.
|
|
||||||
if (TryComp<AppearanceComponent>(uid, out var appearance))
|
|
||||||
_appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateRepeat()
|
|
||||||
{
|
|
||||||
var now = _timing.CurTime;
|
|
||||||
var query = EntityQueryEnumerator<RepeatingTriggerComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var comp))
|
|
||||||
{
|
|
||||||
if (comp.NextTrigger > now)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
comp.NextTrigger = now + comp.Delay;
|
|
||||||
Trigger(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Serialization.Manager;
|
|
||||||
using Content.Server.Explosion.Components.OnTrigger;
|
|
||||||
|
|
||||||
namespace Content.Server.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
public sealed class TwoStageTriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
|
||||||
[Dependency] private readonly TriggerSystem _triggerSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<TwoStageTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, TwoStageTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (component.Triggered)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component.Triggered = true;
|
|
||||||
component.NextTriggerTime = _timing.CurTime + component.TriggerDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadComponents(EntityUid uid, TwoStageTriggerComponent component)
|
|
||||||
{
|
|
||||||
foreach (var (name, entry) in component.SecondStageComponents)
|
|
||||||
{
|
|
||||||
var comp = (Component) Factory.GetComponent(name);
|
|
||||||
var temp = (object)comp;
|
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c))
|
|
||||||
RemComp(uid, c);
|
|
||||||
|
|
||||||
_serializationManager.CopyTo(entry.Component, ref temp);
|
|
||||||
AddComp(uid, comp);
|
|
||||||
}
|
|
||||||
component.ComponentsIsLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
var enumerator = EntityQueryEnumerator<TwoStageTriggerComponent>();
|
|
||||||
while (enumerator.MoveNext(out var uid, out var component))
|
|
||||||
{
|
|
||||||
if (!component.Triggered)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!component.ComponentsIsLoaded)
|
|
||||||
LoadComponents(uid, component);
|
|
||||||
|
|
||||||
if (_timing.CurTime < component.NextTriggerTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
component.NextTriggerTime = null;
|
|
||||||
_triggerSystem.Trigger(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.GhostKick;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class GhostKickUserOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.GhostKick;
|
|
||||||
|
|
||||||
public sealed class GhostKickUserOnTriggerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly GhostKickManager _ghostKickManager = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<GhostKickUserOnTriggerComponent, TriggerEvent>(HandleMineTriggered);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleMineTriggered(EntityUid uid, GhostKickUserOnTriggerComponent userOnTriggerComponent, TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp(args.User, out ActorComponent? actor))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_ghostKickManager.DoDisconnect(
|
|
||||||
actor.PlayerSession.Channel,
|
|
||||||
"Tripped over a kick mine, crashed through the fourth wall");
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Server.Telephone;
|
using Content.Server.Telephone;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
@@ -12,6 +11,7 @@ using Content.Shared.Labels.Components;
|
|||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.Silicons.StationAi;
|
using Content.Shared.Silicons.StationAi;
|
||||||
using Content.Shared.Speech;
|
using Content.Shared.Speech;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Telephone;
|
using Content.Shared.Telephone;
|
||||||
using Content.Shared.UserInterface;
|
using Content.Shared.UserInterface;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
|
|||||||
@@ -1,61 +1,5 @@
|
|||||||
using Content.Server.Audio;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Damage.Systems;
|
|
||||||
using Content.Shared.Hands.Components;
|
|
||||||
using Content.Shared.Hands.EntitySystems;
|
|
||||||
using Content.Shared.HotPotato;
|
using Content.Shared.HotPotato;
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
|
||||||
|
|
||||||
namespace Content.Server.HotPotato;
|
namespace Content.Server.HotPotato;
|
||||||
|
|
||||||
public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
public sealed class HotPotatoSystem : SharedHotPotatoSystem;
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
|
||||||
[Dependency] private readonly AmbientSoundSystem _ambientSound = default!;
|
|
||||||
[Dependency] private readonly DamageOnHoldingSystem _damageOnHolding = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<HotPotatoComponent, ActiveTimerTriggerEvent>(OnActiveTimer);
|
|
||||||
SubscribeLocalEvent<HotPotatoComponent, MeleeHitEvent>(OnMeleeHit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActiveTimer(EntityUid uid, HotPotatoComponent comp, ref ActiveTimerTriggerEvent args)
|
|
||||||
{
|
|
||||||
EnsureComp<ActiveHotPotatoComponent>(uid);
|
|
||||||
comp.CanTransfer = false;
|
|
||||||
_ambientSound.SetAmbience(uid, true);
|
|
||||||
_damageOnHolding.SetEnabled(uid, true);
|
|
||||||
Dirty(uid, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMeleeHit(EntityUid uid, HotPotatoComponent comp, MeleeHitEvent args)
|
|
||||||
{
|
|
||||||
if (!HasComp<ActiveHotPotatoComponent>(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
comp.CanTransfer = true;
|
|
||||||
foreach (var hitEntity in args.HitEntities)
|
|
||||||
{
|
|
||||||
if (!TryComp<HandsComponent>(hitEntity, out var hands))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!_hands.IsHolding((hitEntity, hands), uid, out _) && _hands.TryForcePickupAnyHand(hitEntity, uid, handsComp: hands))
|
|
||||||
{
|
|
||||||
_popup.PopupEntity(Loc.GetString("hot-potato-passed",
|
|
||||||
("from", args.User), ("to", hitEntity)), uid, PopupType.Medium);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_popup.PopupEntity(Loc.GetString("hot-potato-failed",
|
|
||||||
("to", hitEntity)), uid, PopupType.Medium);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
comp.CanTransfer = false;
|
|
||||||
Dirty(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Server.IgnitionSource;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ignites for a certain length of time when triggered.
|
|
||||||
/// Requires <see cref="Shared.IgnitionSourceComponent"/> along with triggering components.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(IgniteOnTriggerSystem))]
|
|
||||||
public sealed partial class IgniteOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Once ignited, the time it will unignite at.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public TimeSpan IgnitedUntil = TimeSpan.Zero;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long the ignition source is active for after triggering.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public TimeSpan IgnitedTime = TimeSpan.FromSeconds(0.5);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sound to play when igniting.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public SoundSpecifier IgniteSound = new SoundCollectionSpecifier("WelderOn");
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Armable;
|
using Content.Shared.Armable;
|
||||||
using Content.Shared.Item.ItemToggle.Components;
|
using Content.Shared.Item.ItemToggle.Components;
|
||||||
using Content.Shared.LandMines;
|
using Content.Shared.LandMines;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.StepTrigger.Systems;
|
using Content.Shared.StepTrigger.Systems;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|
||||||
namespace Content.Server.LandMines;
|
namespace Content.Server.LandMines;
|
||||||
@@ -44,7 +44,8 @@ public sealed class LandMineSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void HandleStepOffTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOffEvent args)
|
private void HandleStepOffTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOffEvent args)
|
||||||
{
|
{
|
||||||
_trigger.Trigger(uid, args.Tripper);
|
// TODO: Adjust to the new trigger system
|
||||||
|
_trigger.Trigger(uid, args.Tripper, TriggerSystem.DefaultTriggerKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
using Content.Server.Damage.Systems;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Popups;
|
|
||||||
using Content.Shared.Interaction.Events;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.Mousetrap;
|
|
||||||
using Content.Shared.StepTrigger;
|
|
||||||
using Content.Shared.StepTrigger.Systems;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Physics.Components;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Mousetrap;
|
|
||||||
|
|
||||||
public sealed class MousetrapSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<MousetrapComponent, UseInHandEvent>(OnUseInHand);
|
|
||||||
SubscribeLocalEvent<MousetrapComponent, BeforeDamageUserOnTriggerEvent>(BeforeDamageOnTrigger);
|
|
||||||
SubscribeLocalEvent<MousetrapComponent, StepTriggerAttemptEvent>(OnStepTriggerAttempt);
|
|
||||||
SubscribeLocalEvent<MousetrapComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUseInHand(EntityUid uid, MousetrapComponent component, UseInHandEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component.IsActive = !component.IsActive;
|
|
||||||
_popupSystem.PopupEntity(component.IsActive
|
|
||||||
? Loc.GetString("mousetrap-on-activate")
|
|
||||||
: Loc.GetString("mousetrap-on-deactivate"),
|
|
||||||
uid,
|
|
||||||
args.User);
|
|
||||||
|
|
||||||
UpdateVisuals(uid);
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStepTriggerAttempt(EntityUid uid, MousetrapComponent component, ref StepTriggerAttemptEvent args)
|
|
||||||
{
|
|
||||||
args.Continue |= component.IsActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BeforeDamageOnTrigger(EntityUid uid, MousetrapComponent component, BeforeDamageUserOnTriggerEvent args)
|
|
||||||
{
|
|
||||||
if (TryComp(args.Tripper, out PhysicsComponent? physics) && physics.Mass != 0)
|
|
||||||
{
|
|
||||||
// The idea here is inverse,
|
|
||||||
// Small - big damage,
|
|
||||||
// Large - small damage
|
|
||||||
// yes i punched numbers into a calculator until the graph looked right
|
|
||||||
var scaledDamage = -50 * Math.Atan(physics.Mass - component.MassBalance) + (25 * Math.PI);
|
|
||||||
args.Damage *= scaledDamage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(EntityUid uid, MousetrapComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
component.IsActive = false;
|
|
||||||
UpdateVisuals(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateVisuals(EntityUid uid, MousetrapComponent? mousetrap = null, AppearanceComponent? appearance = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref mousetrap, ref appearance, false))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_appearance.SetData(uid, MousetrapVisuals.Visual,
|
|
||||||
mousetrap.IsActive ? MousetrapVisuals.Armed : MousetrapVisuals.Unarmed, appearance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Mind;
|
using Content.Server.Mind;
|
||||||
using Content.Server.Objectives.Components;
|
using Content.Server.Objectives.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
@@ -7,6 +6,7 @@ using Content.Shared.Ninja.Components;
|
|||||||
using Content.Shared.Ninja.Systems;
|
using Content.Shared.Ninja.Systems;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Sticky;
|
using Content.Shared.Sticky;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
|
||||||
namespace Content.Server.Ninja.Systems;
|
namespace Content.Server.Ninja.Systems;
|
||||||
|
|
||||||
@@ -80,6 +80,9 @@ public sealed class SpiderChargeSystem : SharedSpiderChargeSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args)
|
private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
if (args.Key != comp.TriggerKey)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!TryComp<SpaceNinjaComponent>(comp.Planter, out var ninja))
|
if (!TryComp<SpaceNinjaComponent>(comp.Planter, out var ninja))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Fluids.EntitySystems;
|
using Content.Server.Fluids.EntitySystems;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Explosion.Components;
|
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Nutrition;
|
using Content.Shared.Nutrition;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
using Content.Shared.Trigger.Components;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -77,15 +77,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
{
|
{
|
||||||
if (_itemSlots.TryEject(uid, itemSlot, user: null, out var item))
|
if (_itemSlots.TryEject(uid, itemSlot, user: null, out var item))
|
||||||
{
|
{
|
||||||
if (TryComp<OnUseTimerTriggerComponent>(item.Value, out var timerTrigger))
|
if (TryComp<TimerTriggerComponent>(item.Value, out var timerTrigger))
|
||||||
{
|
{
|
||||||
_trigger.HandleTimerTrigger(
|
_trigger.ActivateTimerTrigger((item.Value, timerTrigger));
|
||||||
item.Value,
|
|
||||||
null,
|
|
||||||
timerTrigger.Delay,
|
|
||||||
timerTrigger.BeepInterval,
|
|
||||||
timerTrigger.InitialBeepDelay,
|
|
||||||
timerTrigger.BeepSound);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Payload.Components;
|
using Content.Shared.Payload.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Serialization.Manager;
|
using Robust.Shared.Serialization.Manager;
|
||||||
@@ -54,18 +54,22 @@ public sealed class PayloadSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnCaseTriggered(EntityUid uid, PayloadCaseComponent component, TriggerEvent args)
|
private void OnCaseTriggered(EntityUid uid, PayloadCaseComponent component, TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
// TODO: Adjust to the new trigger system
|
||||||
|
|
||||||
if (!TryComp(uid, out ContainerManagerComponent? contMan))
|
if (!TryComp(uid, out ContainerManagerComponent? contMan))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Pass trigger event onto all contained payloads. Payload capacity configurable by construction graphs.
|
// Pass trigger event onto all contained payloads. Payload capacity configurable by construction graphs.
|
||||||
foreach (var ent in GetAllPayloads(uid, contMan))
|
foreach (var ent in GetAllPayloads(uid, contMan))
|
||||||
{
|
{
|
||||||
RaiseLocalEvent(ent, args, false);
|
RaiseLocalEvent(ent, ref args, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTriggerTriggered(EntityUid uid, PayloadTriggerComponent component, TriggerEvent args)
|
private void OnTriggerTriggered(EntityUid uid, PayloadTriggerComponent component, TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
// TODO: Adjust to the new trigger system
|
||||||
|
|
||||||
if (!component.Active)
|
if (!component.Active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -75,7 +79,7 @@ public sealed class PayloadSystem : EntitySystem
|
|||||||
// Ensure we don't enter a trigger-loop
|
// Ensure we don't enter a trigger-loop
|
||||||
DebugTools.Assert(!_tagSystem.HasTag(uid, PayloadTag));
|
DebugTools.Assert(!_tagSystem.HasTag(uid, PayloadTag));
|
||||||
|
|
||||||
RaiseLocalEvent(parent, args, false);
|
RaiseLocalEvent(parent, ref args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEntityInserted(EntityUid uid, PayloadCaseComponent _, EntInsertedIntoContainerMessage args)
|
private void OnEntityInserted(EntityUid uid, PayloadCaseComponent _, EntInsertedIntoContainerMessage args)
|
||||||
@@ -146,6 +150,7 @@ public sealed class PayloadSystem : EntitySystem
|
|||||||
|
|
||||||
private void HandleChemicalPayloadTrigger(Entity<ChemicalPayloadComponent> entity, ref TriggerEvent args)
|
private void HandleChemicalPayloadTrigger(Entity<ChemicalPayloadComponent> entity, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
// TODO: Adjust to the new trigger system
|
||||||
if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA
|
if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA
|
||||||
|| entity.Comp.BeakerSlotB.Item is not EntityUid beakerB
|
|| entity.Comp.BeakerSlotB.Item is not EntityUid beakerB
|
||||||
|| !TryComp(beakerA, out FitsInDispenserComponent? compA)
|
|| !TryComp(beakerA, out FitsInDispenserComponent? compA)
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
using Content.Shared.Polymorph;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Intended for use with the trigger system.
|
|
||||||
/// Polymorphs the user of the trigger.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class PolymorphOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Polymorph settings.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(required: true)]
|
|
||||||
public ProtoId<PolymorphPrototype> Polymorph;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Content.Shared.Polymorph;
|
|
||||||
using Content.Server.Polymorph.Components;
|
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Polymorph.Systems;
|
|
||||||
|
|
||||||
public sealed partial class PolymorphSystem
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Need to do this so we don't get a collection enumeration error in physics by polymorphing
|
|
||||||
/// an entity we're colliding with in case of TriggerOnCollide.
|
|
||||||
/// Also makes sure other trigger effects don't activate in nullspace after we have polymorphed.
|
|
||||||
/// </summary>
|
|
||||||
private Queue<(EntityUid Ent, ProtoId<PolymorphPrototype> Polymorph)> _queuedPolymorphUpdates = new();
|
|
||||||
|
|
||||||
private void InitializeTrigger()
|
|
||||||
{
|
|
||||||
SubscribeLocalEvent<PolymorphOnTriggerComponent, TriggerEvent>(OnTrigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTrigger(Entity<PolymorphOnTriggerComponent> ent, ref TriggerEvent args)
|
|
||||||
{
|
|
||||||
if (args.User == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_queuedPolymorphUpdates.Enqueue((args.User.Value, ent.Comp.Polymorph));
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateTrigger()
|
|
||||||
{
|
|
||||||
while (_queuedPolymorphUpdates.TryDequeue(out var data))
|
|
||||||
{
|
|
||||||
if (TerminatingOrDeleted(data.Item1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
PolymorphEntity(data.Item1, data.Item2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -58,7 +58,6 @@ public sealed partial class PolymorphSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
|
SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
|
||||||
|
|
||||||
InitializeMap();
|
InitializeMap();
|
||||||
InitializeTrigger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
@@ -85,8 +84,6 @@ public sealed partial class PolymorphSystem : EntitySystem
|
|||||||
Revert((uid, comp));
|
Revert((uid, comp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTrigger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentStartup(Entity<PolymorphableComponent> ent, ref ComponentStartup args)
|
private void OnComponentStartup(Entity<PolymorphableComponent> ent, ref ComponentStartup args)
|
||||||
|
|||||||
@@ -2,15 +2,14 @@ using System.Linq;
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Power.Components;
|
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Radio.Components;
|
using Content.Server.Radio.Components;
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Content.Shared.Radio;
|
using Content.Shared.Radio;
|
||||||
|
using Content.Shared.Speech;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Radio.Components;
|
using Content.Shared.Radio.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public sealed partial class BorgSystem
|
|||||||
|
|
||||||
var message = Loc.GetString(ent.Comp.DestroyingPopup, ("name", Name(ent)));
|
var message = Loc.GetString(ent.Comp.DestroyingPopup, ("name", Name(ent)));
|
||||||
Popup.PopupEntity(message, ent);
|
Popup.PopupEntity(message, ent);
|
||||||
_trigger.StartTimer(ent.Owner, user: null);
|
_trigger.ActivateTimerTrigger(ent.Owner);
|
||||||
|
|
||||||
// prevent a shitter borg running into people
|
// prevent a shitter borg running into people
|
||||||
RemComp<InputMoverComponent>(ent);
|
RemComp<InputMoverComponent>(ent);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Content.Server.Actions;
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Hands.Systems;
|
using Content.Server.Hands.Systems;
|
||||||
using Content.Server.PowerCell;
|
using Content.Server.PowerCell;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -25,6 +24,7 @@ using Content.Shared.Roles;
|
|||||||
using Content.Shared.Silicons.Borgs;
|
using Content.Shared.Silicons.Borgs;
|
||||||
using Content.Shared.Silicons.Borgs.Components;
|
using Content.Shared.Silicons.Borgs.Components;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.Sound.Components;
|
|
||||||
|
|
||||||
namespace Content.Server.Sound.Components
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whenever a <see cref="TriggerEvent"/> is run play a sound in PVS range.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class EmitSoundOnTriggerComponent : BaseEmitSoundComponent
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Server.Sound.Components;
|
|
||||||
using Content.Shared.UserInterface;
|
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Content.Shared.Sound.Components;
|
using Content.Shared.Sound.Components;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -38,16 +35,9 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
|
|
||||||
SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
|
SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args)
|
|
||||||
{
|
|
||||||
TryEmitSound(uid, component, args.User, false);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleSpamEmitSoundMapInit(Entity<SpamEmitSoundComponent> entity, ref MapInitEvent args)
|
private void HandleSpamEmitSoundMapInit(Entity<SpamEmitSoundComponent> entity, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
SpamEmitSoundReset(entity);
|
SpamEmitSoundReset(entity);
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using Content.Server.Chat.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.Speech.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This component is used to relay speech events to other systems.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class ActiveListenerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("range")]
|
|
||||||
public float Range = ChatSystem.VoiceRange;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Speech.Components;
|
using Content.Server.Speech.Components;
|
||||||
|
using Content.Shared.Speech;
|
||||||
|
|
||||||
namespace Content.Server.Speech.EntitySystems;
|
namespace Content.Server.Speech.EntitySystems;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Speech.Components;
|
using Content.Shared.Speech;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
|
|
||||||
namespace Content.Server.Speech.EntitySystems;
|
namespace Content.Server.Speech.EntitySystems;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Speech;
|
using Content.Shared.Speech;
|
||||||
using Content.Server.Speech.Components;
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using static Content.Server.Chat.Systems.ChatSystem;
|
using static Content.Server.Chat.Systems.ChatSystem;
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ using Content.Server.Administration.Logs;
|
|||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Speech.Components;
|
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Labels.Components;
|
using Content.Shared.Labels.Components;
|
||||||
@@ -13,6 +11,7 @@ using Content.Shared.Power;
|
|||||||
using Content.Shared.Silicons.StationAi;
|
using Content.Shared.Silicons.StationAi;
|
||||||
using Content.Shared.Silicons.Borgs.Components;
|
using Content.Shared.Silicons.Borgs.Components;
|
||||||
using Content.Shared.Speech;
|
using Content.Shared.Speech;
|
||||||
|
using Content.Shared.Speech.Components;
|
||||||
using Content.Shared.Telephone;
|
using Content.Shared.Telephone;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using Content.Server.AlertLevel;
|
using Content.Server.AlertLevel;
|
||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
|
|
||||||
namespace Content.Server.AlertLevel.Systems;
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
public sealed class AlertLevelChangeOnTriggerSystem : EntitySystem
|
public sealed class AlertLevelChangeOnTriggerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
@@ -18,10 +19,14 @@ public sealed class AlertLevelChangeOnTriggerSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnTrigger(Entity<AlertLevelChangeOnTriggerComponent> ent, ref TriggerEvent args)
|
private void OnTrigger(Entity<AlertLevelChangeOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
var stationUid = _station.GetOwningStation(ent.Owner);
|
var stationUid = _station.GetOwningStation(ent.Owner);
|
||||||
if (!stationUid.HasValue)
|
if (stationUid == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_alertLevelSystem.SetLevel(stationUid.Value, ent.Comp.Level, ent.Comp.PlaySound, ent.Comp.Announce, ent.Comp.Force);
|
_alertLevelSystem.SetLevel(stationUid.Value, ent.Comp.Level, ent.Comp.PlaySound, ent.Comp.Announce, ent.Comp.Force);
|
||||||
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Content.Server.GhostKick;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed class GhostKickUserOnTriggerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly GhostKickManager _ghostKickManager = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<GhostKickOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrigger(Entity<GhostKickOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp(target, out ActorComponent? actor))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ghostKickManager.DoDisconnect(
|
||||||
|
actor.PlayerSession.Channel,
|
||||||
|
Loc.GetString(ent.Comp.Reason));
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
|
||||||
using Content.Shared.IgnitionSource;
|
using Content.Shared.IgnitionSource;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Trigger;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.IgnitionSource;
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles igniting when triggered and stopping ignition after the delay.
|
/// Handles igniting when triggered and stopping ignition after the delay.
|
||||||
@@ -13,8 +12,6 @@ public sealed class IgniteOnTriggerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly SharedIgnitionSourceSystem _source = default!;
|
[Dependency] private readonly SharedIgnitionSourceSystem _source = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -23,6 +20,8 @@ public sealed class IgniteOnTriggerSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<IgniteOnTriggerComponent, TriggerEvent>(OnTrigger);
|
SubscribeLocalEvent<IgniteOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move this into ignition source component
|
||||||
|
// it already has an update loop
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
@@ -42,14 +41,18 @@ public sealed class IgniteOnTriggerSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnTrigger(Entity<IgniteOnTriggerComponent> ent, ref TriggerEvent args)
|
private void OnTrigger(Entity<IgniteOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
// prevent spamming sound and ignition
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
if (!TryComp(ent.Owner, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((ent.Owner, useDelay)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_source.SetIgnited(ent.Owner);
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
_audio.PlayPvs(ent.Comp.IgniteSound, ent);
|
|
||||||
|
|
||||||
_useDelay.TryResetDelay((ent.Owner, useDelay));
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_source.SetIgnited(target.Value);
|
||||||
ent.Comp.IgnitedUntil = _timing.CurTime + ent.Comp.IgnitedTime;
|
ent.Comp.IgnitedUntil = _timing.CurTime + ent.Comp.IgnitedTime;
|
||||||
|
Dirty(ent);
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
51
Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs
Normal file
51
Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Content.Server.Polymorph.Systems;
|
||||||
|
using Content.Shared.Polymorph;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed partial class PolymorphOnTriggerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly PolymorphSystem _polymorph = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Need to do this so we don't get a collection enumeration error in physics by polymorphing
|
||||||
|
/// an entity we're colliding with in case of TriggerOnCollide.
|
||||||
|
/// Also makes sure other trigger effects don't activate in nullspace after we have polymorphed.
|
||||||
|
/// </summary>
|
||||||
|
private Queue<(EntityUid Uid, ProtoId<PolymorphPrototype> Polymorph)> _queuedPolymorphUpdates = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PolymorphOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrigger(Entity<PolymorphOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_queuedPolymorphUpdates.Enqueue((target.Value, ent.Comp.Polymorph));
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frametime)
|
||||||
|
{
|
||||||
|
while (_queuedPolymorphUpdates.TryDequeue(out var data))
|
||||||
|
{
|
||||||
|
if (TerminatingOrDeleted(data.Uid))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_polymorph.PolymorphEntity(data.Uid, data.Polymorph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs
Normal file
49
Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using Content.Server.Radio.EntitySystems;
|
||||||
|
using Content.Server.Pinpointer;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed class RattleOnTriggerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly RadioSystem _radio = default!;
|
||||||
|
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<RattleOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrigger(Entity<RattleOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<MobStateComponent>(target.Value, out var mobstate))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
|
||||||
|
if (!ent.Comp.Messages.TryGetValue(mobstate.CurrentState, out var messageId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Gets the location of the user
|
||||||
|
var posText = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString(target.Value));
|
||||||
|
|
||||||
|
var message = Loc.GetString(messageId, ("user", target.Value), ("position", posText));
|
||||||
|
// Sends a message to the radio channel specified by the implant
|
||||||
|
_radio.SendRadioMessage(ent.Owner, message, _prototypeManager.Index(ent.Comp.RadioChannel), ent.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs
Normal file
48
Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Content.Shared.Trigger.Systems;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
|
public sealed class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var curTime = _timing.CurTime;
|
||||||
|
var query = EntityQueryEnumerator<ReleaseGasOnTriggerComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var uid, out var comp))
|
||||||
|
{
|
||||||
|
if (!comp.Active || comp.NextReleaseTime > curTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var giverGasMix = comp.Air.Remove(comp.StartingTotalMoles * comp.RemoveFraction);
|
||||||
|
var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
|
||||||
|
|
||||||
|
if (environment == null)
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, ReleaseGasOnTriggerVisuals.Key, false);
|
||||||
|
RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_atmosphereSystem.Merge(environment, giverGasMix);
|
||||||
|
comp.NextReleaseTime += comp.ReleaseInterval;
|
||||||
|
|
||||||
|
if (comp.PressureLimit != 0 && environment.Pressure >= comp.PressureLimit ||
|
||||||
|
comp.Air.TotalMoles <= 0)
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, ReleaseGasOnTriggerVisuals.Key, false);
|
||||||
|
RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs
Normal file
68
Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Content.Server.Fluids.EntitySystems;
|
||||||
|
using Content.Server.Spreader;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Coordinates.Helpers;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles creating smoke when <see cref="SmokeOnTriggerComponent"/> is triggered.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SmokeOnTriggerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IMapManager _mapMan = default!;
|
||||||
|
[Dependency] private readonly MapSystem _map = default!;
|
||||||
|
[Dependency] private readonly SmokeSystem _smoke = default!;
|
||||||
|
[Dependency] private readonly TransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly SpreaderSystem _spreader = default!;
|
||||||
|
[Dependency] private readonly TurfSystem _turf = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SmokeOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrigger(Entity<SmokeOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: move all of this into an API function in SmokeSystem
|
||||||
|
var xform = Transform(target.Value);
|
||||||
|
var mapCoords = _transform.GetMapCoordinates(target.Value, xform);
|
||||||
|
if (!_mapMan.TryFindGridAt(mapCoords, out var gridUid, out var gridComp) ||
|
||||||
|
!_map.TryGetTileRef(gridUid, gridComp, xform.Coordinates, out var tileRef) ||
|
||||||
|
tileRef.Tile.IsEmpty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_spreader.RequiresFloorToSpread(ent.Comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var coords = _map.MapToGrid(gridUid, mapCoords);
|
||||||
|
var smoke = Spawn(ent.Comp.SmokePrototype, coords.SnapToGrid());
|
||||||
|
if (!TryComp<SmokeComponent>(smoke, out var smokeComp))
|
||||||
|
{
|
||||||
|
Log.Error($"Smoke prototype {ent.Comp.SmokePrototype} was missing SmokeComponent");
|
||||||
|
Del(smoke);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_smoke.StartSmoke(smoke, ent.Comp.Solution, (float)ent.Comp.Duration.TotalSeconds, ent.Comp.SpreadAmount, smokeComp);
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using Content.Server.Explosion.EntitySystems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Trigger;
|
||||||
|
using Content.Shared.Trigger.Components.Effects;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Chat.Systems;
|
namespace Content.Server.Trigger.Systems;
|
||||||
|
|
||||||
public sealed class SpeakOnTriggerSystem : EntitySystem
|
public sealed class SpeakOnTriggerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly ChatSystem _chat = default!;
|
[Dependency] private readonly ChatSystem _chat = default!;
|
||||||
@@ -15,32 +15,34 @@ public sealed class SpeakOnTriggerSystem : EntitySystem
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<SpeakOnTriggerComponent, TriggerEvent>(OnTrigger);
|
SubscribeLocalEvent<SpeakOnTriggerComponent, TriggerEvent>(OnTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTrigger(Entity<SpeakOnTriggerComponent> ent, ref TriggerEvent args)
|
private void OnTrigger(Entity<SpeakOnTriggerComponent> ent, ref TriggerEvent args)
|
||||||
{
|
{
|
||||||
TrySpeak(ent);
|
if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key))
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TrySpeak(Entity<SpeakOnTriggerComponent> ent)
|
|
||||||
{
|
|
||||||
// If it doesn't have the use delay component, still send the message.
|
|
||||||
if (TryComp<UseDelayComponent>(ent.Owner, out var useDelay) && _useDelay.IsDelayed((ent.Owner, useDelay)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var target = ent.Comp.TargetUser ? args.User : ent.Owner;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string message;
|
||||||
|
if (ent.Comp.Text != null)
|
||||||
|
message = Loc.GetString(ent.Comp.Text);
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!_prototypeManager.TryIndex(ent.Comp.Pack, out var messagePack))
|
if (!_prototypeManager.TryIndex(ent.Comp.Pack, out var messagePack))
|
||||||
return;
|
return;
|
||||||
|
message = Loc.GetString(_random.Pick(messagePack.Values));
|
||||||
var message = Loc.GetString(_random.Pick(messagePack.Values));
|
}
|
||||||
// Chatcode moment: messages starting with "." are considered radio messages.
|
// Chatcode moment: messages starting with "." are considered radio messages.
|
||||||
// Prepending ">" forces the message to be spoken instead.
|
// Prepending ">" forces the message to be spoken instead.
|
||||||
// TODO chat refactor: remove this
|
// TODO chat refactor: remove this
|
||||||
message = '>' + message;
|
message = '>' + message;
|
||||||
_chat.TrySendInGameICMessage(ent.Owner, message, InGameICChatType.Speak, true);
|
_chat.TrySendInGameICMessage(target.Value, message, InGameICChatType.Speak, true);
|
||||||
|
args.Handled = true;
|
||||||
if (useDelay != null)
|
|
||||||
_useDelay.TryResetDelay((ent.Owner, useDelay));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Storage;
|
using Content.Shared.Storage;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
using Robust.Server.Containers;
|
using Robust.Server.Containers;
|
||||||
|
|
||||||
namespace Content.Server.VoiceTrigger;
|
namespace Content.Server.VoiceTrigger;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Content.Shared.Explosion.Components.OnTrigger;
|
using Content.Shared.Explosion.Components;
|
||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.Artifact.XAE.Components;
|
namespace Content.Server.Xenoarchaeology.Artifact.XAE.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activates 'trigger' for <see cref="ExplodeOnTriggerComponent"/>.
|
/// Activates <see cref="ExplosiveComponent"/> to explode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, Access(typeof(XAETriggerExplosivesSystem))]
|
[RegisterComponent, Access(typeof(XAETriggerExplosivesSystem))]
|
||||||
public sealed partial class XAETriggerExplosivesComponent : Component;
|
public sealed partial class XAETriggerExplosivesComponent : Component;
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ public abstract class SharedChatSystem : EntitySystem
|
|||||||
public const char WhisperPrefix = ',';
|
public const char WhisperPrefix = ',';
|
||||||
public const char DefaultChannelKey = 'h';
|
public const char DefaultChannelKey = 'h';
|
||||||
|
|
||||||
|
public const int VoiceRange = 10; // how far voice goes in world units
|
||||||
|
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
||||||
|
public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units
|
||||||
|
public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg";
|
||||||
|
|
||||||
public static readonly ProtoId<RadioChannelPrototype> CommonChannel = "Common";
|
public static readonly ProtoId<RadioChannelPrototype> CommonChannel = "Common";
|
||||||
|
|
||||||
public static readonly string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}";
|
public static readonly string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}";
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Content.Shared.Damage.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class DamageUserOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("ignoreResistances")] public bool IgnoreResistances;
|
|
||||||
|
|
||||||
[DataField("damage", required: true)]
|
|
||||||
public DamageSpecifier Damage = default!;
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Emp;
|
namespace Content.Shared.Emp;
|
||||||
@@ -7,4 +8,15 @@ public abstract class SharedEmpSystem : EntitySystem
|
|||||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||||
|
|
||||||
protected const string EmpDisabledEffectPrototype = "EffectEmpDisabled";
|
protected const string EmpDisabledEffectPrototype = "EffectEmpDisabled";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers an EMP pulse at the given location, by first raising an <see cref="EmpAttemptEvent"/>, then a raising <see cref="EmpPulseEvent"/> on all entities in range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="coordinates">The location to trigger the EMP pulse at.</param>
|
||||||
|
/// <param name="range">The range of the EMP pulse.</param>
|
||||||
|
/// <param name="energyConsumption">The amount of energy consumed by the EMP pulse.</param>
|
||||||
|
/// <param name="duration">The duration of the EMP effects.</param>
|
||||||
|
public virtual void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Shared.Explosion.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Component for tracking active trigger timers. A timers can activated by some other component, e.g. <see cref="OnUseTimerTriggerComponent"/>.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class ActiveTimerTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField] public float TimeRemaining;
|
|
||||||
|
|
||||||
[DataField] public EntityUid? User;
|
|
||||||
|
|
||||||
[DataField] public float BeepInterval;
|
|
||||||
|
|
||||||
[DataField] public float TimeUntilBeep;
|
|
||||||
|
|
||||||
[DataField] public SoundSpecifier? BeepSound;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Shared.Explosion.Components.OnTrigger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Explode using the entity's <see cref="ExplosiveComponent"/> if Triggered.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
|
||||||
public sealed partial class ExplodeOnTriggerComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Shared.Guidebook;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Shared.Explosion.Components
|
|
||||||
{
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
|
||||||
public sealed partial class OnUseTimerTriggerComponent : Component
|
|
||||||
{
|
|
||||||
[DataField] public float Delay = 1f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If not null, a user can use verbs to configure the delay to one of these options.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public List<float>? DelayOptions = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If not null, this timer will periodically play this sound while active.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public SoundSpecifier? BeepSound;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Time before beeping starts. Defaults to a single beep interval. If set to zero, will emit a beep immediately after use.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public float? InitialBeepDelay;
|
|
||||||
|
|
||||||
[DataField] public float BeepInterval = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the timer should instead be activated through a verb in the right-click menu
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public bool UseVerbInstead = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should timer be started when it was stuck to another entity.
|
|
||||||
/// Used for C4 charges and similar behaviour.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public bool StartOnStick;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Allows changing the start-on-stick quality.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("canToggleStartOnStick")] public bool AllowToggleStartOnStick;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether you can examine the item to see its timer or not.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public bool Examinable = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether or not to show the user a popup when starting the timer.
|
|
||||||
/// </summary>
|
|
||||||
[DataField] public bool DoPopup = true;
|
|
||||||
|
|
||||||
#region GuidebookData
|
|
||||||
|
|
||||||
[GuidebookData]
|
|
||||||
public float? ShortestDelayOption => DelayOptions?.Min();
|
|
||||||
|
|
||||||
[GuidebookData]
|
|
||||||
public float? LongestDelayOption => DelayOptions?.Max();
|
|
||||||
|
|
||||||
#endregion GuidebookData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user