diff --git a/SecretAPI/Enums/RoomSafetyFailReason.cs b/SecretAPI/Enums/RoomSafetyFailReason.cs
new file mode 100644
index 0000000..a5cc293
--- /dev/null
+++ b/SecretAPI/Enums/RoomSafetyFailReason.cs
@@ -0,0 +1,44 @@
+namespace SecretAPI.Enums
+{
+ using System;
+ using MapGeneration;
+ using SecretAPI.Extensions;
+ using UnityEngine;
+
+ ///
+ /// Reasons why should fail.
+ ///
+ [Flags]
+ public enum RoomSafetyFailReason
+ {
+ ///
+ /// No fail.
+ ///
+ None = 0,
+
+ ///
+ /// Room safety check will fail if warhead has gone off and room is not part of .
+ ///
+ Warhead = 1,
+
+ ///
+ /// Room safety check will fail if decontamination has gone off and room is part of .
+ ///
+ Decontamination = 2,
+
+ ///
+ /// Room safety check will fail if room has .
+ ///
+ Tesla = 4,
+
+ ///
+ /// Room safety check will fail if the listed room fails a check.
+ ///
+ MissingFloor = 8,
+
+ ///
+ /// Room safety check will fail if the listed room is part of .
+ ///
+ KnownBad = 16,
+ }
+}
\ No newline at end of file
diff --git a/SecretAPI/Extensions/RoomExtensions.cs b/SecretAPI/Extensions/RoomExtensions.cs
index 41629af..ab87169 100644
--- a/SecretAPI/Extensions/RoomExtensions.cs
+++ b/SecretAPI/Extensions/RoomExtensions.cs
@@ -1,8 +1,12 @@
namespace SecretAPI.Extensions
{
using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
using LabApi.Features.Wrappers;
using MapGeneration;
+ using PlayerRoles.FirstPersonControl;
+ using PlayerRoles.PlayableScps.Scp106;
+ using SecretAPI.Enums;
using UnityEngine;
///
@@ -10,9 +14,13 @@
///
public static class RoomExtensions
{
- private static readonly List KnownUnsafeRooms =
+ private const float RaycastDistance = 2;
+
+ ///
+ /// Gets a list of that will be denied by .
+ ///
+ public static List KnownUnsafeRooms { get; } =
[
- RoomName.HczTesla, // Instant death
RoomName.EzEvacShelter, // Stuck permanently
RoomName.EzCollapsedTunnel, // Stuck permanently
RoomName.HczWaysideIncinerator, // Death
@@ -23,19 +31,67 @@ public static class RoomExtensions
/// Gets whether a room is safe to teleport to. Will consider decontamination, warhead, teslas and void rooms.
///
/// The room to check.
+ /// Reasons why the safety check should fail.
/// Whether the room is safe to teleport to.
- public static bool IsSafeToTeleport(this Room room)
+ public static bool IsSafeToTeleport(this Room room, RoomSafetyFailReason failReasons)
{
- if (Warhead.IsDetonated && room.Zone != FacilityZone.Surface)
+ if (failReasons.HasFlag(RoomSafetyFailReason.Warhead) && Warhead.IsDetonated && room.Zone != FacilityZone.Surface)
return false;
- if (Decontamination.IsDecontaminating && room.Zone == FacilityZone.LightContainment)
+ if (failReasons.HasFlag(RoomSafetyFailReason.Decontamination) && Decontamination.IsDecontaminating && room.Zone == FacilityZone.LightContainment)
+ return false;
+
+ if (failReasons.HasFlag(RoomSafetyFailReason.Tesla) && room.Name == RoomName.HczTesla)
return false;
if (KnownUnsafeRooms.Contains(room.Name))
return false;
- return Physics.Raycast(room.Position, Vector3.down, out _, 2);
+ if (failReasons.HasFlag(RoomSafetyFailReason.MissingFloor) && !Physics.Raycast(room.Position, Vector3.down, out _, RaycastDistance, FpcStateProcessor.Mask))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Tries to get a location to teleport a to.
+ ///
+ /// The player to attempt to get a teleport position from.
+ /// The position found if any, otherwise null.
+ /// If set to anything other than will only attempt to find in that zone.
+ /// The default radius allowed nea the found spot.
+ /// Whether a valid teleport position was correctly found.
+ public static bool TryGetTeleportLocation(this Player player, [NotNullWhen(true)] out Vector3? position, FacilityZone zone = FacilityZone.None, float defaultRadius = Scp106PocketExitFinder.RaycastRange)
+ {
+ position = null;
+ return player.RoleBase is IFpcRole fpc && TryGetTeleportLocation(fpc, out position, zone);
+ }
+
+ ///
+ /// Tries to get a location to teleport a to.
+ ///
+ /// The to attempt to get a teleport position from.
+ /// The position found if any, otherwise null.
+ /// If set to anything other than will only attempt to find in that zone.
+ /// The default radius allowed nea the found spot.
+ /// Whether a valid teleport position was correctly found.
+ public static bool TryGetTeleportLocation(this IFpcRole fpc, [NotNullWhen(true)] out Vector3? position, FacilityZone zone = FacilityZone.None, float defaultRadius = Scp106PocketExitFinder.RaycastRange)
+ {
+ position = null;
+
+ IEnumerable poses = zone == FacilityZone.None
+ ? SafeLocationFinder.GetLocations(null, null)
+ : Scp106PocketExitFinder.GetPosesForZone(zone);
+
+ if (!poses.TryGetRandomValue(out Pose pose))
+ return false;
+
+ float radius = defaultRadius;
+ if (Room.TryGetRoomAtPosition(pose.position, out Room? room))
+ radius = Scp106PocketExitFinder.GetRaycastRange(room.Zone);
+
+ position = SafeLocationFinder.GetSafePosition(pose.position, pose.forward, radius, fpc.FpcModule.CharController);
+ return true;
}
}
}
\ No newline at end of file