Skip to content

Commit

Permalink
Step Trigger Minor Refactor (#884)
Browse files Browse the repository at this point in the history
# Description

I made this PR in response to a bug report from Floof, where it was
discovered that a "Minimum Size Felinid or Harpy" is instantaneously
killed by mouse traps. Which confused me, because Felinids and Harpies
are intended to be immune to floor traps like landmines, glass, and
mouse traps. Then I discovered that mouse traps overwrite the step
trigger cancellation, meaning that mouse traps will just completely
ignore a Felinid/Harpy canceling the step trigger. Additionally, to my
endless frustration, the Felinid/Harpy floor trap immunity is handled by
a Tag and not a Component, which isn't really acceptable in this day and
age.

I decided to take a little bit of a different approach to this problem,
first by doing the usual code cleanup to EE standards. Then by adding a
new StepTriggerImmuneComponent. This component acts as an early-exit for
the entire StepTriggerSystem, immediately at the initial entrypoint,
during the CanTrigger bool. This component is given to Felinids and
Harpies by default, representing their "Extremely low density bodies"
having too much surface area and not enough mass to trigger floor traps.
Effectively, they are now working as originally intended, by having
immunity to setting off landmines.

Because we have a trait point system, and this is coincidentally also a
trait requested by Nuclear14, I have gone ahead and created a Trait that
gives this component to anyone willing to pay the points for it.

# Changelog

:cl:
- fix: Felinids and Harpies will now correctly never set off floor
traps, such as landmines and mouse traps.
- add: Trap Avoider has been added as a new trait, allowing characters
to buy the innate ability to avoid floor traps. I would have named this
"Light Step", after the trait from Fallout that shares its name and
effect, but someone already gave that name to a different trait
entirely.

---------

Signed-off-by: VMSolidus <[email protected]>
Co-authored-by: DEATHB4DEFEAT <[email protected]>
  • Loading branch information
VMSolidus and DEATHB4DEFEAT committed Sep 9, 2024
1 parent 058650e commit d0c5110
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 68 deletions.
25 changes: 10 additions & 15 deletions Content.Server/Mousetrap/MousetrapSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
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;

Expand Down Expand Up @@ -44,15 +40,16 @@ private void OnStepTriggerAttempt(EntityUid uid, MousetrapComponent component, r

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;
}
if (!TryComp<PhysicsComponent>(args.Tripper, out var physics)
|| physics.Mass is 0)
return;

// 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 * MathF.Atan(physics.Mass - component.MassBalance) + 25 * MathF.PI;
args.Damage *= scaledDamage;
}

private void OnTrigger(EntityUid uid, MousetrapComponent component, TriggerEvent args)
Expand All @@ -64,9 +61,7 @@ private void OnTrigger(EntityUid uid, MousetrapComponent component, TriggerEvent
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Robust.Shared.GameStates;

namespace Content.Shared.StepTrigger.Components;

/// <summary>
/// This component marks an entity as being immune to all step triggers.
/// For example, a Felinid or Harpy being so low density, that they don't set off landmines.
/// </summary>
/// <remarks>
/// This is the "Earliest Possible Exit" method, and therefore isn't possible to un-cancel.
/// It will prevent ALL step trigger events from firing. Therefore there may sometimes be unintended consequences to this.
/// Consider using a subscription to StepTriggerAttemptEvent if you wish to be more selective.
/// </remarks>
[RegisterComponent, NetworkedComponent]
public sealed partial class StepTriggerImmuneComponent : Component { }
74 changes: 21 additions & 53 deletions Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,16 @@ public override void Update(float frameTime)
while (enumerator.MoveNext(out var uid, out var active, out var trigger, out var transform))
{
if (!Update(uid, trigger, transform, query))
{
continue;
}

RemCompDeferred(uid, active);
}
}

private bool Update(EntityUid uid, StepTriggerComponent component, TransformComponent transform, EntityQuery<PhysicsComponent> query)
{
if (!component.Active ||
component.Colliding.Count == 0)
{
if (!component.Active || component.Colliding.Count == 0)
return true;
}

if (component.Blacklist != null && TryComp<MapGridComponent>(transform.GridUid, out var grid))
{
Expand All @@ -67,17 +62,13 @@ private bool Update(EntityUid uid, StepTriggerComponent component, TransformComp
if (ent == uid)
continue;

if (component.Blacklist.IsValid(ent.Value, EntityManager) == true)
{
if (component.Blacklist.IsValid(ent.Value, EntityManager))
return false;
}
}
}

foreach (var otherUid in component.Colliding)
{
UpdateColliding(uid, component, transform, otherUid, query);
}

return false;
}
Expand All @@ -95,9 +86,8 @@ private void UpdateColliding(EntityUid uid, StepTriggerComponent component, Tran
if (!ourAabb.Intersects(otherAabb))
{
if (component.CurrentlySteppedOn.Remove(otherUid))
{
Dirty(uid, component);
}

return;
}

Expand All @@ -109,9 +99,7 @@ private void UpdateColliding(EntityUid uid, StepTriggerComponent component, Tran
|| component.CurrentlySteppedOn.Contains(otherUid)
|| ratio < component.IntersectRatio
|| !CanTrigger(uid, otherUid, component))
{
return;
}

if (component.StepOn)
{
Expand All @@ -130,7 +118,9 @@ private void UpdateColliding(EntityUid uid, StepTriggerComponent component, Tran

private bool CanTrigger(EntityUid uid, EntityUid otherUid, StepTriggerComponent component)
{
if (!component.Active || component.CurrentlySteppedOn.Contains(otherUid))
if (HasComp<StepTriggerImmuneComponent>(otherUid)
|| !component.Active
|| component.CurrentlySteppedOn.Contains(otherUid))
return false;

// Can't trigger if we don't ignore weightless entities
Expand All @@ -141,7 +131,6 @@ private bool CanTrigger(EntityUid uid, EntityUid otherUid, StepTriggerComponent
return false;

var msg = new StepTriggerAttemptEvent { Source = uid, Tripper = otherUid };

RaiseLocalEvent(uid, ref msg);

return msg.Continue && !msg.Cancelled;
Expand All @@ -151,18 +140,14 @@ private void OnStartCollide(EntityUid uid, StepTriggerComponent component, ref S
{
var otherUid = args.OtherEntity;

if (!args.OtherFixture.Hard)
return;

if (!CanTrigger(uid, otherUid, component))
if (!args.OtherFixture.Hard
|| !CanTrigger(uid, otherUid, component))
return;

EnsureComp<StepTriggerActiveComponent>(uid);

if (component.Colliding.Add(otherUid))
{
Dirty(uid, component);
}
}

private void OnEndCollide(EntityUid uid, StepTriggerComponent component, ref EndCollideEvent args)
Expand All @@ -182,29 +167,21 @@ private void OnEndCollide(EntityUid uid, StepTriggerComponent component, ref End
}

if (component.Colliding.Count == 0)
{
RemCompDeferred<StepTriggerActiveComponent>(uid);
}
}

private void TriggerHandleState(EntityUid uid, StepTriggerComponent component, ref AfterAutoHandleStateEvent args)
{
if (component.Colliding.Count > 0)
{
EnsureComp<StepTriggerActiveComponent>(uid);
}
else
{
RemCompDeferred<StepTriggerActiveComponent>(uid);
}
}

public void SetIntersectRatio(EntityUid uid, float ratio, StepTriggerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

if (MathHelper.CloseToPercent(component.IntersectRatio, ratio))
if (!Resolve(uid, ref component)
|| MathHelper.CloseToPercent(component.IntersectRatio, ratio))
return;

component.IntersectRatio = ratio;
Expand All @@ -213,10 +190,8 @@ public void SetIntersectRatio(EntityUid uid, float ratio, StepTriggerComponent?

public void SetRequiredTriggerSpeed(EntityUid uid, float speed, StepTriggerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

if (MathHelper.CloseToPercent(component.RequiredTriggeredSpeed, speed))
if (!Resolve(uid, ref component)
|| MathHelper.CloseToPercent(component.RequiredTriggeredSpeed, speed))
return;

component.RequiredTriggeredSpeed = speed;
Expand All @@ -225,37 +200,30 @@ public void SetRequiredTriggerSpeed(EntityUid uid, float speed, StepTriggerCompo

public void SetActive(EntityUid uid, bool active, StepTriggerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

if (active == component.Active)
if (!Resolve(uid, ref component)
|| active == component.Active)
return;

component.Active = active;
Dirty(uid, component);
}
}

/// <summary>
/// Raised at the beginning of a step trigger, and before entering the checks.
/// Allows for entities to end the steptrigger early via args.Cancelled.
/// </summary>
[ByRefEvent]
public struct StepTriggerAttemptEvent
{
public EntityUid Source;
public EntityUid Tripper;
public bool Continue;
/// <summary>
/// Set by systems which wish to cancel the step trigger event, regardless of event ordering.
/// </summary>
public bool Cancelled;
}
public record struct StepTriggerAttemptEvent(EntityUid Source, EntityUid Tripper, bool Continue, bool Cancelled);

/// <summary>
/// Raised when an entity stands on a steptrigger initially (assuming it has both on and off states).
/// Raised when an entity stands on a steptrigger initially (assuming it has both on and off states).
/// </summary>
[ByRefEvent]
public readonly record struct StepTriggeredOnEvent(EntityUid Source, EntityUid Tripper);

/// <summary>
/// Raised when an entity leaves a steptrigger if it has on and off states OR when an entity intersects a steptrigger.
/// 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);
5 changes: 5 additions & 0 deletions Resources/Locale/en-US/traits/traits.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ trait-description-NaturalTelepath =
drawbacks of Latent Psychic, except that you are guaranteed to start with full Telepathy. You may
still gain powers as normal for a Latent Psychic.
trait-name-TrapAvoider = Trap Avoider
trait-description-TrapAvoider =
You possess a preturnatural sense of traps, and will unconsciously avoid them. You will never trigger
floor traps, such as land mines, tripwires, mouse traps(If you're small enough), etc.
trait-name-AnomalousPositronics = Anomalous Positronics
trait-description-AnomalousPositronics =
Whether by intentional design from the manufacturer, black market modifications, or accidental omission,
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Entities/Mobs/Species/harpy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
understands:
- GalacticCommon
- SolCommon
- type: StepTriggerImmune

- type: entity
save: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
stealth: Subtle
stripTimeReduction: 0
stripTimeMultiplier: 0.667
- type: StepTriggerImmune

- type: entity
save: false
Expand Down
13 changes: 13 additions & 0 deletions Resources/Prototypes/Traits/skills.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,19 @@
traits:
- AnomalousPositronics

- type: trait
id: TrapAvoider
category: Physical
points: -3
components:
- type: StepTriggerImmune
requirements:
- !type:CharacterSpeciesRequirement
inverted: true
species:
- Felinid
- Harpy

- type: trait
id: AnomalousPositronics
category: Mental
Expand Down

0 comments on commit d0c5110

Please sign in to comment.