Landmine stepoff (#22962)

* make landmine work on stepping off

* update methods naming

* made both step modes possible

* updated stepoff event raise to not interfere with game physics internals

* added comments

* figuring out how audiosystem works

* added beep sound effect, updated how stepoff trigger works to make it more consistent

* updated source in attributions.yml

* made stepoff working every time

* introduced suggested changes

* updated janitor's WetSignMine to have audio

* made cleaner events and bashing my head at OnEndCollide event raise

* inverted conditional where applicable

* review

---------

Co-authored-by: Yurii Kis <yurii.kis@smartteksas.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
KISS
2024-03-24 07:33:45 +02:00
committed by GitHub
parent f96cf360e9
commit 54dd273f66
13 changed files with 97 additions and 49 deletions

View File

@@ -25,7 +25,7 @@ public sealed partial class EnsnareableSystem
{ {
SubscribeLocalEvent<EnsnaringComponent, ComponentRemove>(OnComponentRemove); SubscribeLocalEvent<EnsnaringComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<EnsnaringComponent, StepTriggerAttemptEvent>(AttemptStepTrigger); SubscribeLocalEvent<EnsnaringComponent, StepTriggerAttemptEvent>(AttemptStepTrigger);
SubscribeLocalEvent<EnsnaringComponent, StepTriggeredEvent>(OnStepTrigger); SubscribeLocalEvent<EnsnaringComponent, StepTriggeredOffEvent>(OnStepTrigger);
SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit); SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit);
SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow); SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
} }
@@ -49,7 +49,7 @@ public sealed partial class EnsnareableSystem
args.Continue = true; args.Continue = true;
} }
private void OnStepTrigger(EntityUid uid, EnsnaringComponent component, ref StepTriggeredEvent args) private void OnStepTrigger(EntityUid uid, EnsnaringComponent component, ref StepTriggeredOffEvent args)
{ {
TryEnsnare(args.Tripper, uid, component); TryEnsnare(args.Tripper, uid, component);
} }

View File

@@ -88,7 +88,7 @@ namespace Content.Server.Explosion.EntitySystems
SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide); SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide);
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate); SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger); SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger);
SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredEvent>(OnStepTriggered); SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredOffEvent>(OnStepTriggered);
SubscribeLocalEvent<TriggerOnSlipComponent, SlipEvent>(OnSlipTriggered); SubscribeLocalEvent<TriggerOnSlipComponent, SlipEvent>(OnSlipTriggered);
SubscribeLocalEvent<TriggerWhenEmptyComponent, OnEmptyGunShotEvent>(OnEmptyTriggered); SubscribeLocalEvent<TriggerWhenEmptyComponent, OnEmptyGunShotEvent>(OnEmptyTriggered);
@@ -228,7 +228,7 @@ namespace Content.Server.Explosion.EntitySystems
args.Handled = Trigger(uid); args.Handled = Trigger(uid);
} }
private void OnStepTriggered(EntityUid uid, TriggerOnStepTriggerComponent component, ref StepTriggeredEvent args) private void OnStepTriggered(EntityUid uid, TriggerOnStepTriggerComponent component, ref StepTriggeredOffEvent args)
{ {
Trigger(uid, args.Tripper); Trigger(uid, args.Tripper);
} }

View File

@@ -1,6 +1,13 @@
namespace Content.Server.LandMines; using Robust.Shared.Audio;
namespace Content.Server.LandMines;
[RegisterComponent] [RegisterComponent]
public sealed partial class LandMineComponent : Component public sealed partial class LandMineComponent : Component
{ {
/// <summary>
/// Trigger sound effect when stepping onto landmine
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? Sound;
} }

View File

@@ -1,43 +1,43 @@
using Content.Server.Explosion.EntitySystems; using Content.Server.Explosion.EntitySystems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.StepTrigger;
using Content.Shared.StepTrigger.Systems; using Content.Shared.StepTrigger.Systems;
using Robust.Shared.Player; using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
namespace Content.Server.LandMines; namespace Content.Server.LandMines;
public sealed class LandMineSystem : EntitySystem public sealed class LandMineSystem : EntitySystem
{ {
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly TriggerSystem _trigger = default!; [Dependency] private readonly TriggerSystem _trigger = default!;
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<LandMineComponent, StepTriggeredEvent>(HandleTriggered); SubscribeLocalEvent<LandMineComponent, StepTriggeredOnEvent>(HandleStepOnTriggered);
SubscribeLocalEvent<LandMineComponent, StepTriggerAttemptEvent>(HandleTriggerAttempt); SubscribeLocalEvent<LandMineComponent, StepTriggeredOffEvent>(HandleStepOffTriggered);
SubscribeLocalEvent<LandMineComponent, StepTriggerAttemptEvent>(HandleStepTriggerAttempt);
} }
private static void HandleTriggerAttempt( private void HandleStepOnTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOnEvent args)
EntityUid uid, {
LandMineComponent component, _popupSystem.PopupCoordinates(
ref StepTriggerAttemptEvent args) Loc.GetString("land-mine-triggered", ("mine", uid)),
Transform(uid).Coordinates,
args.Tripper,
PopupType.LargeCaution);
_audioSystem.PlayPvs(component.Sound, uid);
}
private void HandleStepOffTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOffEvent args)
{
_trigger.Trigger(uid, args.Tripper);
}
private static void HandleStepTriggerAttempt(EntityUid uid, LandMineComponent component, ref StepTriggerAttemptEvent args)
{ {
args.Continue = true; args.Continue = true;
} }
private void HandleTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredEvent args)
{
// This doesn't use TriggerOnStepTrigger since we don't want to display the popup if nothing happens
// and I didn't feel like making an `AfterTrigger` event
if (_trigger.Trigger(uid, args.Tripper))
{
_popupSystem.PopupCoordinates(
Loc.GetString("land-mine-triggered", ("mine", uid)),
Transform(uid).Coordinates,
args.Tripper,
PopupType.LargeCaution);
}
}
} }

View File

@@ -11,7 +11,7 @@ public sealed class LavaSystem : EntitySystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<LavaComponent, StepTriggeredEvent>(OnLavaStepTriggered); SubscribeLocalEvent<LavaComponent, StepTriggeredOffEvent>(OnLavaStepTriggered);
SubscribeLocalEvent<LavaComponent, StepTriggerAttemptEvent>(OnLavaStepTriggerAttempt); SubscribeLocalEvent<LavaComponent, StepTriggerAttemptEvent>(OnLavaStepTriggerAttempt);
} }
@@ -23,7 +23,7 @@ public sealed class LavaSystem : EntitySystem
args.Continue = true; args.Continue = true;
} }
private void OnLavaStepTriggered(EntityUid uid, LavaComponent component, ref StepTriggeredEvent args) private void OnLavaStepTriggered(EntityUid uid, LavaComponent component, ref StepTriggeredOffEvent args)
{ {
var otherUid = args.Tripper; var otherUid = args.Tripper;

View File

@@ -24,7 +24,7 @@ public sealed class ChasmSystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<ChasmComponent, StepTriggeredEvent>(OnStepTriggered); SubscribeLocalEvent<ChasmComponent, StepTriggeredOffEvent>(OnStepTriggered);
SubscribeLocalEvent<ChasmComponent, StepTriggerAttemptEvent>(OnStepTriggerAttempt); SubscribeLocalEvent<ChasmComponent, StepTriggerAttemptEvent>(OnStepTriggerAttempt);
SubscribeLocalEvent<ChasmFallingComponent, UpdateCanMoveEvent>(OnUpdateCanMove); SubscribeLocalEvent<ChasmFallingComponent, UpdateCanMoveEvent>(OnUpdateCanMove);
} }
@@ -47,7 +47,7 @@ public sealed class ChasmSystem : EntitySystem
} }
} }
private void OnStepTriggered(EntityUid uid, ChasmComponent component, ref StepTriggeredEvent args) private void OnStepTriggered(EntityUid uid, ChasmComponent component, ref StepTriggeredOffEvent args)
{ {
// already doomed // already doomed
if (HasComp<ChasmFallingComponent>(args.Tripper)) if (HasComp<ChasmFallingComponent>(args.Tripper))

View File

@@ -31,14 +31,14 @@ public sealed class SlipperySystem : EntitySystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<SlipperyComponent, StepTriggerAttemptEvent>(HandleAttemptCollide); SubscribeLocalEvent<SlipperyComponent, StepTriggerAttemptEvent>(HandleAttemptCollide);
SubscribeLocalEvent<SlipperyComponent, StepTriggeredEvent>(HandleStepTrigger); SubscribeLocalEvent<SlipperyComponent, StepTriggeredOffEvent>(HandleStepTrigger);
SubscribeLocalEvent<NoSlipComponent, SlipAttemptEvent>(OnNoSlipAttempt); SubscribeLocalEvent<NoSlipComponent, SlipAttemptEvent>(OnNoSlipAttempt);
SubscribeLocalEvent<ThrownItemComponent, SlipCausingAttemptEvent>(OnThrownSlipAttempt); SubscribeLocalEvent<ThrownItemComponent, SlipCausingAttemptEvent>(OnThrownSlipAttempt);
// as long as slip-resistant mice are never added, this should be fine (otherwise a mouse-hat will transfer it's power to the wearer). // as long as slip-resistant mice are never added, this should be fine (otherwise a mouse-hat will transfer it's power to the wearer).
SubscribeLocalEvent<NoSlipComponent, InventoryRelayedEvent<SlipAttemptEvent>>((e, c, ev) => OnNoSlipAttempt(e, c, ev.Args)); SubscribeLocalEvent<NoSlipComponent, InventoryRelayedEvent<SlipAttemptEvent>>((e, c, ev) => OnNoSlipAttempt(e, c, ev.Args));
} }
private void HandleStepTrigger(EntityUid uid, SlipperyComponent component, ref StepTriggeredEvent args) private void HandleStepTrigger(EntityUid uid, SlipperyComponent component, ref StepTriggeredOffEvent args)
{ {
TrySlip(uid, component, args.Tripper); TrySlip(uid, component, args.Tripper);
} }

View File

@@ -49,8 +49,14 @@ public sealed partial class StepTriggerComponent : Component
/// If this is true, steptrigger will still occur on entities that are in air / weightless. They do not /// If this is true, steptrigger will still occur on entities that are in air / weightless. They do not
/// by default. /// by default.
/// </summary> /// </summary>
[DataField] [DataField, AutoNetworkedField]
public bool IgnoreWeightless; public bool IgnoreWeightless;
/// <summary>
/// Does this have separate "StepOn" and "StepOff" triggers.
/// </summary>
[DataField, AutoNetworkedField]
public bool StepOn = false;
} }
[RegisterComponent] [RegisterComponent]

View File

@@ -11,6 +11,7 @@ public sealed class StepTriggerSystem : EntitySystem
{ {
[Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly SharedGravitySystem _gravity = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -40,7 +41,9 @@ public sealed class StepTriggerSystem : EntitySystem
while (enumerator.MoveNext(out var uid, out var active, out var trigger, out var transform)) while (enumerator.MoveNext(out var uid, out var active, out var trigger, out var transform))
{ {
if (!Update(uid, trigger, transform, query)) if (!Update(uid, trigger, transform, query))
{
continue; continue;
}
RemCompDeferred(uid, active); RemCompDeferred(uid, active);
} }
@@ -56,7 +59,8 @@ public sealed class StepTriggerSystem : EntitySystem
if (component.Blacklist != null && TryComp<MapGridComponent>(transform.GridUid, out var grid)) if (component.Blacklist != null && TryComp<MapGridComponent>(transform.GridUid, out var grid))
{ {
var anch = grid.GetAnchoredEntitiesEnumerator(grid.LocalToTile(transform.Coordinates)); var positon = _map.LocalToTile(uid, grid, transform.Coordinates);
var anch = _map.GetAnchoredEntitiesEnumerator(uid, grid, positon);
while (anch.MoveNext(out var ent)) while (anch.MoveNext(out var ent))
{ {
@@ -109,8 +113,16 @@ public sealed class StepTriggerSystem : EntitySystem
return; return;
} }
var ev = new StepTriggeredEvent { Source = uid, Tripper = otherUid }; if (component.StepOn)
RaiseLocalEvent(uid, ref ev, true); {
var evStep = new StepTriggeredOnEvent(uid, otherUid);
RaiseLocalEvent(uid, ref evStep);
}
else
{
var evStep = new StepTriggeredOffEvent(uid, otherUid);
RaiseLocalEvent(uid, ref evStep);
}
component.CurrentlySteppedOn.Add(otherUid); component.CurrentlySteppedOn.Add(otherUid);
Dirty(uid, component); Dirty(uid, component);
@@ -130,7 +142,7 @@ public sealed class StepTriggerSystem : EntitySystem
var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid }; var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid };
RaiseLocalEvent(uid, ref msg, true); RaiseLocalEvent(uid, ref msg);
return msg.Continue && !msg.Cancelled; return msg.Continue && !msg.Cancelled;
} }
@@ -163,6 +175,12 @@ public sealed class StepTriggerSystem : EntitySystem
component.CurrentlySteppedOn.Remove(otherUid); component.CurrentlySteppedOn.Remove(otherUid);
Dirty(uid, component); Dirty(uid, component);
if (component.StepOn)
{
var evStepOff = new StepTriggeredOffEvent(uid, otherUid);
RaiseLocalEvent(uid, ref evStepOff);
}
if (component.Colliding.Count == 0) if (component.Colliding.Count == 0)
{ {
RemCompDeferred<StepTriggerActiveComponent>(uid); RemCompDeferred<StepTriggerActiveComponent>(uid);
@@ -230,9 +248,14 @@ public struct StepTriggerAttemptEvent
public bool Cancelled; public bool Cancelled;
} }
/// <summary>
/// Raised when an entity stands on a steptrigger initially (assuming it has both on and off states).
/// </summary>
[ByRefEvent] [ByRefEvent]
public struct StepTriggeredEvent public readonly record struct StepTriggeredOnEvent(EntityUid Source, EntityUid Tripper);
{
public EntityUid Source; /// <summary>
public EntityUid Tripper; /// Raised when an entity leaves a steptrigger if it has on and off states OR when an entity intersects a steptrigger.
} /// </summary>
[ByRefEvent]
public readonly record struct StepTriggeredOffEvent(EntityUid Source, EntityUid Tripper);

View File

@@ -221,3 +221,8 @@
copyright: TGStation at 3df5d3b42bfb6b3b5adba1067ab41f83816255bb copyright: TGStation at 3df5d3b42bfb6b3b5adba1067ab41f83816255bb
license: CC-BY-SA-3.0 license: CC-BY-SA-3.0
source: https://github.com/tgstation/tgstation/blob/3df5d3b42bfb6b3b5adba1067ab41f83816255bb/sound/misc/server-ready.ogg source: https://github.com/tgstation/tgstation/blob/3df5d3b42bfb6b3b5adba1067ab41f83816255bb/sound/misc/server-ready.ogg
- files: [beep_landmine.ogg]
copyright: '"beep_landmine.ogg" by kaktuscsc of Discord for SS14'
license: "CC-BY-SA-3.0"
source: https://github.com/YuriyKiss/space-station-14/commit/971a135a9c83aed46e967aac9302ab5b35562b5f

Binary file not shown.

View File

@@ -35,9 +35,13 @@
- !type:DoActsBehavior - !type:DoActsBehavior
acts: [ "Destruction" ] acts: [ "Destruction" ]
- type: LandMine - type: LandMine
- type: TriggerOnStepTrigger sound:
path: /Audio/Effects/beep_landmine.ogg
params:
maxDistance: 10
- type: StepTrigger - type: StepTrigger
requiredTriggeredSpeed: 0 requiredTriggeredSpeed: 0
stepOn: true
- type: entity - type: entity
name: kick mine name: kick mine
@@ -57,7 +61,6 @@
- type: Construction - type: Construction
graph: ModularMineGraph graph: ModularMineGraph
node: emptyCase node: emptyCase
- type: LandMine
- type: entity - type: entity
name: explosive mine name: explosive mine
@@ -71,4 +74,3 @@
intensitySlope: 3 intensitySlope: 3
totalIntensity: 120 # about a ~4 tile radius totalIntensity: 120 # about a ~4 tile radius
canCreateVacuum: false canCreateVacuum: false
- type: DeleteOnTrigger

View File

@@ -230,6 +230,7 @@
- type: StepTrigger - type: StepTrigger
intersectRatio: 0.2 intersectRatio: 0.2
requiredTriggeredSpeed: 0 requiredTriggeredSpeed: 0
stepOn: true
- type: CollisionWake - type: CollisionWake
enabled: false enabled: false
- type: Physics - type: Physics
@@ -251,6 +252,10 @@
mask: mask:
- ItemMask - ItemMask
- type: LandMine - type: LandMine
sound:
path: /Audio/Effects/beep_landmine.ogg
params:
maxDistance: 10
- type: ExplodeOnTrigger - type: ExplodeOnTrigger
- type: Explosive - type: Explosive
explosionType: HardBomb # normally Default and max 5 total 60 explosionType: HardBomb # normally Default and max 5 total 60