[DataField("requiredSlipSpeed")] private float _requiredSlipSpeed = 6;
[DataField("paralyzeTime")] private float _paralyzeTime = 1;
+ /// <summary>
+ /// <see cref="SlipperyComponent.SuperSlippery"/>
+ /// </summary>
+ [DataField("superSlippery")] private bool _superSlippery;
+
public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
{
- if (reactVolume < 5) return FixedPoint2.Zero;
+ if (reactVolume < 5)
+ return FixedPoint2.Zero;
var entityManager = IoCManager.Resolve<IEntityManager>();
var slippery = entityManager.EnsureComponent<SlipperyComponent>(puddleUid);
slippery.LaunchForwardsMultiplier = _launchForwardsMultiplier;
slippery.ParalyzeTime = _paralyzeTime;
- entityManager.Dirty(slippery);
+ slippery.SuperSlippery = _superSlippery;
+ entityManager.Dirty(puddleUid, slippery);
var step = entityManager.EnsureComponent<StepTriggerComponent>(puddleUid);
entityManager.EntitySysManager.GetEntitySystem<StepTriggerSystem>().SetRequiredTriggerSpeed(puddleUid, _requiredSlipSpeed, step);
{
// Reactive entities have a chance to get a touch reaction from slipping on a puddle
// (i.e. it is implied they fell face first onto it or something)
- if (!HasComp<ReactiveComponent>(args.Slipped))
+ if (!HasComp<ReactiveComponent>(args.Slipped) || HasComp<SlidingComponent>(args.Slipped))
return;
// Eventually probably have some system of 'body coverage' to tweak the probability but for now just 0.5
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Slippery;
+
+/// <summary>
+/// Applies continuous movement to the attached entity when colliding with super slipper entities.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class SlidingComponent : Component
+{
+ /// <summary>
+ /// A list of SuperSlippery entities the entity with this component is colliding with.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public HashSet<EntityUid> CollidingEntities = new ();
+
+ /// <summary>
+ /// The friction modifier that will be applied to any friction calculations.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float FrictionModifier;
+}
--- /dev/null
+using Content.Shared.Movement.Events;
+using Content.Shared.Standing;
+using Content.Shared.Stunnable;
+using Robust.Shared.Physics.Events;
+
+namespace Content.Shared.Slippery;
+
+public sealed class SlidingSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<SlidingComponent, TileFrictionEvent>(OnSlideAttempt);
+ SubscribeLocalEvent<SlidingComponent, StoodEvent>(OnStand);
+ SubscribeLocalEvent<SlidingComponent, StartCollideEvent>(OnStartCollide);
+ SubscribeLocalEvent<SlidingComponent, EndCollideEvent>(OnEndCollide);
+ }
+
+ /// <summary>
+ /// Modify the friction by the frictionModifier stored on the component.
+ /// </summary>
+ private void OnSlideAttempt(EntityUid uid, SlidingComponent component, ref TileFrictionEvent args)
+ {
+ args.Modifier = component.FrictionModifier;
+ }
+
+ /// <summary>
+ /// Remove the component when the entity stands up again.
+ /// </summary>
+ private void OnStand(EntityUid uid, SlidingComponent component, ref StoodEvent args)
+ {
+ RemComp<SlidingComponent>(uid);
+ }
+
+ /// <summary>
+ /// Sets friction to 0 if colliding with a SuperSlippery Entity.
+ /// </summary>
+ private void OnStartCollide(EntityUid uid, SlidingComponent component, ref StartCollideEvent args)
+ {
+ if (!TryComp<SlipperyComponent>(args.OtherEntity, out var slippery) || !slippery.SuperSlippery)
+ return;
+
+ component.CollidingEntities.Add(args.OtherEntity);
+ component.FrictionModifier = 0;
+ Dirty(uid, component);
+ }
+
+ /// <summary>
+ /// Set friction to normal when ending collision with a SuperSlippery entity.
+ /// </summary>
+ private void OnEndCollide(EntityUid uid, SlidingComponent component, ref EndCollideEvent args)
+ {
+ if (!component.CollidingEntities.Remove(args.OtherEntity))
+ return;
+
+ if (component.CollidingEntities.Count == 0)
+ component.FrictionModifier = SharedStunSystem.KnockDownModifier;
+
+ Dirty(uid, component);
+ }
+
+}
/// <summary>
/// How many seconds the mob will be paralyzed for.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
[DataField, AutoNetworkedField]
[Access(Other = AccessPermissions.ReadWrite)]
public float ParalyzeTime = 3f;
/// <summary>
/// The entity's speed will be multiplied by this to slip it forwards.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
[DataField, AutoNetworkedField]
[Access(Other = AccessPermissions.ReadWrite)]
public float LaunchForwardsMultiplier = 1f;
+
+ /// <summary>
+ /// If this is true, any slipping entity loses its friction until
+ /// it's not colliding with any SuperSlippery entities anymore.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ [Access(Other = AccessPermissions.ReadWrite)]
+ public bool SuperSlippery;
}
}
using Content.Shared.StepTrigger.Systems;
using Content.Shared.Stunnable;
using JetBrains.Annotations;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Physics.Components;
private void TrySlip(EntityUid uid, SlipperyComponent component, EntityUid other)
{
- if (HasComp<KnockedDownComponent>(other))
+ if (HasComp<KnockedDownComponent>(other) && !component.SuperSlippery)
return;
var attemptEv = new SlipAttemptEvent();
var ev = new SlipEvent(other);
RaiseLocalEvent(uid, ref ev);
- if (TryComp(other, out PhysicsComponent? physics))
+ if (TryComp(other, out PhysicsComponent? physics) && !HasComp<SlidingComponent>(other))
+ {
_physics.SetLinearVelocity(other, physics.LinearVelocity * component.LaunchForwardsMultiplier, body: physics);
+ if (component.SuperSlippery)
+ EnsureComp<SlidingComponent>(other);
+ }
+
var playSound = !_statusEffects.HasStatusEffect(other, "KnockedDown");
_stun.TryParalyze(other, TimeSpan.FromSeconds(component.ParalyzeTime), true);
paralyzeTime: 3
launchForwardsMultiplier: 2
requiredSlipSpeed: 1
+ superSlippery: true
- type: reagent
id: SpaceGlue
footstepSound:
collection: FootstepSticky
params:
- volume: 6
\ No newline at end of file
+ volume: 6