Lavaland chasms (#19154)
This commit is contained in:
17
Content.Shared/Chasm/ChasmComponent.cs
Normal file
17
Content.Shared/Chasm/ChasmComponent.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Chasm;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a component that will cause entities to fall into them on a step trigger activation
|
||||
/// </summary>
|
||||
[NetworkedComponent, RegisterComponent, Access(typeof(ChasmSystem))]
|
||||
public sealed class ChasmComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Sound that should be played when an entity falls into the chasm
|
||||
/// </summary>
|
||||
[DataField("fallingSound")]
|
||||
public SoundSpecifier FallingSound = new SoundPathSpecifier("/Audio/Effects/falling.ogg");
|
||||
}
|
||||
37
Content.Shared/Chasm/ChasmFallingComponent.cs
Normal file
37
Content.Shared/Chasm/ChasmFallingComponent.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Numerics;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.Chasm;
|
||||
|
||||
/// <summary>
|
||||
/// Added to entities which have started falling into a chasm.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class ChasmFallingComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Time it should take for the falling animation (scaling down) to complete.
|
||||
/// </summary>
|
||||
[DataField("animationTime")]
|
||||
public TimeSpan AnimationTime = TimeSpan.FromSeconds(1.5f);
|
||||
|
||||
/// <summary>
|
||||
/// Time it should take in seconds for the entity to actually delete
|
||||
/// </summary>
|
||||
[DataField("deletionTime")]
|
||||
public TimeSpan DeletionTime = TimeSpan.FromSeconds(1.8f);
|
||||
|
||||
[DataField("nextDeletionTime", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextDeletionTime = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Original scale of the object so it can be restored if the component is removed in the middle of the animation
|
||||
/// </summary>
|
||||
public Vector2 OriginalScale = Vector2.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Scale that the animation should bring entities to.
|
||||
/// </summary>
|
||||
public Vector2 AnimationScale = new Vector2(0.01f, 0.01f);
|
||||
}
|
||||
78
Content.Shared/Chasm/ChasmSystem.cs
Normal file
78
Content.Shared/Chasm/ChasmSystem.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.StepTrigger.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Chasm;
|
||||
|
||||
/// <summary>
|
||||
/// Handles making entities fall into chasms when stepped on.
|
||||
/// </summary>
|
||||
public sealed class ChasmSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ChasmComponent, StepTriggeredEvent>(OnStepTriggered);
|
||||
SubscribeLocalEvent<ChasmComponent, StepTriggerAttemptEvent>(OnStepTriggerAttempt);
|
||||
SubscribeLocalEvent<ChasmFallingComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||
SubscribeLocalEvent<ChasmFallingComponent, UpdateCanMoveEvent>(OnUpdateCanMove);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
// don't predict queuedels on client
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var query = EntityQueryEnumerator<ChasmFallingComponent>();
|
||||
while (query.MoveNext(out var uid, out var chasm))
|
||||
{
|
||||
if (_timing.CurTime < chasm.NextDeletionTime)
|
||||
continue;
|
||||
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStepTriggered(EntityUid uid, ChasmComponent component, ref StepTriggeredEvent args)
|
||||
{
|
||||
// already doomed
|
||||
if (HasComp<ChasmFallingComponent>(args.Tripper))
|
||||
return;
|
||||
|
||||
var falling = AddComp<ChasmFallingComponent>(args.Tripper);
|
||||
|
||||
falling.NextDeletionTime = _timing.CurTime + falling.DeletionTime;
|
||||
_blocker.UpdateCanMove(args.Tripper);
|
||||
_audio.PlayPredicted(component.FallingSound, uid, args.Tripper);
|
||||
}
|
||||
|
||||
private void OnStepTriggerAttempt(EntityUid uid, ChasmComponent component, ref StepTriggerAttemptEvent args)
|
||||
{
|
||||
if (TryComp<PhysicsComponent>(args.Tripper, out var physics) && physics.BodyStatus == BodyStatus.InAir)
|
||||
return;
|
||||
|
||||
args.Continue = true;
|
||||
}
|
||||
|
||||
private void OnUnpaused(EntityUid uid, ChasmFallingComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextDeletionTime += args.PausedTime;
|
||||
}
|
||||
|
||||
private void OnUpdateCanMove(EntityUid uid, ChasmFallingComponent component, UpdateCanMoveEvent args)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
@@ -78,14 +78,15 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateColliding(EntityUid uid, StepTriggerComponent component, TransformComponent ownerTransform, EntityUid otherUid, EntityQuery<PhysicsComponent> query)
|
||||
private void UpdateColliding(EntityUid uid, StepTriggerComponent component, TransformComponent ownerXform, EntityUid otherUid, EntityQuery<PhysicsComponent> query)
|
||||
{
|
||||
if (!query.TryGetComponent(otherUid, out var otherPhysics))
|
||||
return;
|
||||
|
||||
var otherXform = Transform(otherUid);
|
||||
// TODO: This shouldn't be calculating based on world AABBs.
|
||||
var ourAabb = _entityLookup.GetWorldAABB(uid, ownerTransform);
|
||||
var otherAabb = _entityLookup.GetWorldAABB(otherUid);
|
||||
var ourAabb = _entityLookup.GetAABBNoContainer(uid, ownerXform.LocalPosition, ownerXform.LocalRotation);
|
||||
var otherAabb = _entityLookup.GetAABBNoContainer(otherUid, otherXform.LocalPosition, otherXform.LocalRotation);
|
||||
|
||||
if (!ourAabb.Intersects(otherAabb))
|
||||
{
|
||||
@@ -96,9 +97,13 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
// max 'area of enclosure' between the two aabbs
|
||||
// this is hard to explain
|
||||
var intersect = Box2.Area(otherAabb.Intersect(ourAabb));
|
||||
var ratio = Math.Max(intersect / Box2.Area(otherAabb), intersect / Box2.Area(ourAabb));
|
||||
if (otherPhysics.LinearVelocity.Length() < component.RequiredTriggerSpeed
|
||||
|| component.CurrentlySteppedOn.Contains(otherUid)
|
||||
|| otherAabb.IntersectPercentage(ourAabb) < component.IntersectRatio
|
||||
|| ratio < component.IntersectRatio
|
||||
|| !CanTrigger(uid, otherUid, component))
|
||||
{
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user