using System; using System.Collections.Generic; using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Physics; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Shared.GameObjects.Components.Movement { public abstract class SharedSlipperyComponent : Component, ICollideBehavior { #pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager; #pragma warning restore 649 public sealed override string Name => "Slippery"; /// /// The list of entities that have been slipped by this component, /// and which have not stopped colliding with its owner yet. /// protected readonly List _slipped = new List(); /// /// How many seconds the mob will be paralyzed for. /// [ViewVariables(VVAccess.ReadWrite)] private float ParalyzeTime { get; set; } = 3f; /// /// Percentage of shape intersection for a slip to occur. /// [ViewVariables(VVAccess.ReadWrite)] private float IntersectPercentage { get; set; } = 0.3f; /// /// Entities will only be slipped if their speed exceeds this limit. /// [ViewVariables(VVAccess.ReadWrite)] private float RequiredSlipSpeed { get; set; } = 0f; private bool TrySlip(IEntity entity) { if (ContainerHelpers.IsInContainer(Owner) || _slipped.Contains(entity.Uid) || !entity.TryGetComponent(out SharedStunnableComponent stun) || !entity.TryGetComponent(out ICollidableComponent otherBody) || !entity.TryGetComponent(out IPhysicsComponent otherPhysics) || !Owner.TryGetComponent(out ICollidableComponent body)) { return false; } if (otherPhysics.LinearVelocity.Length < RequiredSlipSpeed || stun.KnockedDown) { return false; } var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB); if (percentage < IntersectPercentage) { return false; } if (!EffectBlockerSystem.CanSlip(entity)) { return false; } if (entity.TryGetComponent(out ICollidableComponent collidable)) { var controller = collidable.EnsureController(); controller.LinearVelocity = collidable.LinearVelocity; } stun.Paralyze(5); _slipped.Add(entity.Uid); OnSlip(); return true; } protected virtual void OnSlip() { } public void CollideWith(IEntity collidedWith) { TrySlip(collidedWith); } public void Update() { foreach (var uid in _slipped.ToArray()) { if (!uid.IsValid() || !_entityManager.EntityExists(uid)) { continue; } var entity = _entityManager.GetEntity(uid); var collidable = Owner.GetComponent(); var otherCollidable = entity.GetComponent(); if (!collidable.WorldAABB.Intersects(otherCollidable.WorldAABB)) { _slipped.Remove(uid); } } } public override void Initialize() { base.Initialize(); var collidable = Owner.GetComponent(); collidable.Hard = false; var shape = collidable.PhysicsShapes[0]; shape.CollisionLayer |= (int) CollisionGroup.SmallImpassable; shape.CollisionMask = (int)CollisionGroup.None; } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(this, x => ParalyzeTime, "paralyzeTime", 3f); serializer.DataField(this, x => IntersectPercentage, "intersectPercentage", 0.3f); serializer.DataField(this, x => RequiredSlipSpeed, "requiredSlipSpeed", 0f); } } }