Refactor InRangeUnobstructed and add extension methods (#1925)
* Sort out InRangeUnobstructed and add extension methods * Rename client RangeChecks to RangeExtensions * Add container extension methods and test * Add missing component methods Component to container Grid coordinates to container Map coordinates to container Local player to container * Actually use the field * Merge fixes * Add popup argument to local player extension methods * Reduce code repetition for client range extensions
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Physics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -18,98 +21,516 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
public class SharedInteractionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPhysicsManager _physicsManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
public const float InteractionRange = 2;
|
||||
public const float InteractionRangeSquared = InteractionRange * InteractionRange;
|
||||
|
||||
public delegate bool Ignored(IEntity entity);
|
||||
|
||||
/// <summary>
|
||||
/// Traces a ray from coords to otherCoords and returns the length
|
||||
/// of the vector between coords and the ray's first hit.
|
||||
/// </summary>
|
||||
/// <param name="coords">Set of coordinates to use.</param>
|
||||
/// <param name="otherCoords">Other set of coordinates to use.</param>
|
||||
/// <param name="origin">Set of coordinates to use.</param>
|
||||
/// <param name="other">Other set of coordinates to use.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="predicate">A predicate to check whether to ignore an entity or not. If it returns true, it will be ignored.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <returns>Length of resulting ray.</returns>
|
||||
public float UnobstructedRayLength(MapCoordinates coords, MapCoordinates otherCoords,
|
||||
int collisionMask = (int) CollisionGroup.Impassable, Func<IEntity, bool> predicate = null)
|
||||
public float UnobstructedDistance(
|
||||
MapCoordinates origin,
|
||||
MapCoordinates other,
|
||||
int collisionMask = (int) CollisionGroup.Impassable,
|
||||
Ignored predicate = null)
|
||||
{
|
||||
var dir = otherCoords.Position - coords.Position;
|
||||
var dir = other.Position - origin.Position;
|
||||
|
||||
if (dir.LengthSquared.Equals(0f)) return 0f;
|
||||
|
||||
var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, returnOnFirstHit: false).ToList();
|
||||
predicate ??= _ => false;
|
||||
var ray = new CollisionRay(origin.Position, dir.Normalized, collisionMask);
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
|
||||
|
||||
if (rayResults.Count == 0) return dir.Length;
|
||||
return (rayResults[0].HitPos - coords.Position).Length;
|
||||
return (rayResults[0].HitPos - origin.Position).Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces a ray from coords to otherCoords and returns the length
|
||||
/// of the vector between coords and the ray's first hit.
|
||||
/// </summary>
|
||||
/// <param name="coords">Set of coordinates to use.</param>
|
||||
/// <param name="otherCoords">Other set of coordinates to use.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="ignoredEnt">the entity to be ignored when checking for collisions.</param>
|
||||
/// <param name="origin">Set of coordinates to use.</param>
|
||||
/// <param name="other">Other set of coordinates to use.</param>
|
||||
/// <param name="collisionMask">The mask to check for collisions</param>
|
||||
/// <param name="ignoredEnt">
|
||||
/// The entity to be ignored when checking for collisions.
|
||||
/// </param>
|
||||
/// <returns>Length of resulting ray.</returns>
|
||||
public float UnobstructedRayLength(MapCoordinates coords, MapCoordinates otherCoords,
|
||||
int collisionMask = (int) CollisionGroup.Impassable, IEntity ignoredEnt = null) =>
|
||||
UnobstructedRayLength(coords, otherCoords, collisionMask,
|
||||
ignoredEnt == null ? null : (Func<IEntity, bool>) (entity => ignoredEnt == entity));
|
||||
public float UnobstructedDistance(
|
||||
MapCoordinates origin,
|
||||
MapCoordinates other,
|
||||
int collisionMask = (int) CollisionGroup.Impassable,
|
||||
IEntity ignoredEnt = null)
|
||||
{
|
||||
var predicate = ignoredEnt == null
|
||||
? null
|
||||
: (Ignored) (e => e == ignoredEnt);
|
||||
|
||||
return UnobstructedDistance(origin, other, collisionMask, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that these coordinates are within a certain distance without any
|
||||
/// entity that matches the collision mask obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the two sets of coordinates..
|
||||
/// this method will only check if nothing obstructs the two sets
|
||||
/// of coordinates.
|
||||
/// </summary>
|
||||
/// <param name="coords">Set of coordinates to use.</param>
|
||||
/// <param name="otherCoords">Other set of coordinates to use.</param>
|
||||
/// <param name="range">maximum distance between the two sets of coordinates.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="predicate">A predicate to check whether to ignore an entity or not. If it returns true, it will be ignored.</param>
|
||||
/// <param name="ignoreInsideBlocker">if true and the coordinates are inside the obstruction, ignores the obstruction and
|
||||
/// considers the interaction unobstructed. Therefore, setting this to true makes this check more permissive, such
|
||||
/// as allowing an interaction to occur inside something impassable (like a wall). The default, false,
|
||||
/// makes the check more restrictive.</param>
|
||||
/// <returns>True if the two points are within a given range without being obstructed.</returns>
|
||||
public bool InRangeUnobstructed(MapCoordinates coords, MapCoordinates otherCoords, float range = InteractionRange,
|
||||
int collisionMask = (int)CollisionGroup.Impassable, Func<IEntity, bool> predicate = null, bool ignoreInsideBlocker = false)
|
||||
/// <param name="origin">Set of coordinates to use.</param>
|
||||
/// <param name="other">Other set of coordinates to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two sets of coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
MapCoordinates origin,
|
||||
MapCoordinates other,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false)
|
||||
{
|
||||
if (!coords.InRange(otherCoords, range))
|
||||
return false;
|
||||
if (!origin.InRange(other, range)) return false;
|
||||
|
||||
var dir = otherCoords.Position - coords.Position;
|
||||
var dir = other.Position - origin.Position;
|
||||
|
||||
if (dir.LengthSquared.Equals(0f)) return true;
|
||||
if (range > 0f && !(dir.LengthSquared <= range * range)) return false;
|
||||
|
||||
var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, returnOnFirstHit: false).ToList();
|
||||
return rayResults.Count == 0 || (ignoreInsideBlocker && rayResults.Count > 0 && (rayResults[0].HitPos - otherCoords.Position).Length < 1f);
|
||||
predicate ??= _ => false;
|
||||
|
||||
var ray = new CollisionRay(origin.Position, dir.Normalized, (int) collisionMask);
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
|
||||
|
||||
if (rayResults.Count == 0) return true;
|
||||
|
||||
if (!ignoreInsideBlocker) return false;
|
||||
|
||||
if (rayResults.Count <= 0) return false;
|
||||
|
||||
return (rayResults[0].HitPos - other.Position).Length < 1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that these coordinates are within a certain distance without any
|
||||
/// Checks that two entities are within a certain distance without any
|
||||
/// entity that matches the collision mask obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the two sets of coordinates..
|
||||
/// this method will only check if nothing obstructs the two entities.
|
||||
/// </summary>
|
||||
/// <param name="coords">Set of coordinates to use.</param>
|
||||
/// <param name="otherCoords">Other set of coordinates to use.</param>
|
||||
/// <param name="range">maximum distance between the two sets of coordinates.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="ignoredEnt">the entity to be ignored when checking for collisions.</param>
|
||||
/// <param name="ignoreInsideBlocker">if true and the coordinates are inside the obstruction, ignores the obstruction and
|
||||
/// considers the interaction unobstructed. Therefore, setting this to true makes this check more permissive, such
|
||||
/// as allowing an interaction to occur inside something impassable (like a wall). The default, false,
|
||||
/// makes the check more restrictive.</param>
|
||||
/// <returns>True if the two points are within a given range without being obstructed.</returns>
|
||||
public bool InRangeUnobstructed(MapCoordinates coords, MapCoordinates otherCoords, float range = InteractionRange,
|
||||
int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null, bool ignoreInsideBlocker = false) =>
|
||||
InRangeUnobstructed(coords, otherCoords, range, collisionMask,
|
||||
ignoredEnt == null ? null : (Func<IEntity, bool>)(entity => ignoredEnt == entity), ignoreInsideBlocker);
|
||||
/// <param name="origin">The first entity to use.</param>
|
||||
/// <param name="other">Other entity to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entities.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the origin entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
IEntity origin,
|
||||
IEntity other,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var originPosition = origin.Transform.MapPosition;
|
||||
var otherPosition = other.Transform.MapPosition;
|
||||
predicate ??= e => e == origin || e == other;
|
||||
|
||||
var inRange = InRangeUnobstructed(originPosition, otherPosition, range, collisionMask, predicate, ignoreInsideBlocker);
|
||||
|
||||
if (!inRange && popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
origin.PopupMessage(origin, message);
|
||||
}
|
||||
|
||||
return inRange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that an entity and a component are within a certain
|
||||
/// distance without any entity that matches the collision mask
|
||||
/// obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="origin">The entity to use.</param>
|
||||
/// <param name="other">The component to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the entity and component.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the origin entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
IEntity origin,
|
||||
IComponent other,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var originPosition = origin.Transform.MapPosition;
|
||||
var otherPosition = other.Owner.Transform.MapPosition;
|
||||
predicate ??= e => e == origin || e == other.Owner;
|
||||
|
||||
var inRange = InRangeUnobstructed(originPosition, otherPosition, range, collisionMask, predicate, ignoreInsideBlocker);
|
||||
|
||||
if (!inRange && popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
origin.PopupMessage(origin, message);
|
||||
}
|
||||
|
||||
return inRange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that an entity and a set of grid coordinates are within a certain
|
||||
/// distance without any entity that matches the collision mask
|
||||
/// obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="origin">The entity to use.</param>
|
||||
/// <param name="other">The grid coordinates to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entity and set of grid coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the origin entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
IEntity origin,
|
||||
GridCoordinates other,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var originPosition = origin.Transform.MapPosition;
|
||||
var otherPosition = other.ToMap(_mapManager);
|
||||
predicate ??= e => e == origin;
|
||||
|
||||
var inRange = InRangeUnobstructed(originPosition, otherPosition, range, collisionMask, predicate, ignoreInsideBlocker);
|
||||
|
||||
if (!inRange && popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
origin.PopupMessage(origin, message);
|
||||
}
|
||||
|
||||
return inRange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that an entity and a set of map coordinates are within a certain
|
||||
/// distance without any entity that matches the collision mask
|
||||
/// obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="origin">The entity to use.</param>
|
||||
/// <param name="other">The map coordinates to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entity and set of map coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the origin entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
IEntity origin,
|
||||
MapCoordinates other,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var originPosition = origin.Transform.MapPosition;
|
||||
predicate ??= e => e == origin;
|
||||
|
||||
var inRange = InRangeUnobstructed(originPosition, other, range, collisionMask, predicate, ignoreInsideBlocker);
|
||||
|
||||
if (!inRange && popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
origin.PopupMessage(origin, message);
|
||||
}
|
||||
|
||||
return inRange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the user and target of a
|
||||
/// <see cref="ITargetedInteractEventArgs"/> are within a certain
|
||||
/// distance without any entity that matches the collision mask
|
||||
/// obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="args">The event args to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entity and set of map coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and both the user and target are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the user entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
ITargetedInteractEventArgs args,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var origin = args.User;
|
||||
var other = args.Target;
|
||||
|
||||
return InRangeUnobstructed(origin, other, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the user of a <see cref="DragDropEventArgs"/> is within a
|
||||
/// certain distance of the target and dropped entities without any entity
|
||||
/// that matches the collision mask obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="args">The event args to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entity and set of map coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and both the user and target are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the user entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
DragDropEventArgs args,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var user = args.User;
|
||||
var dropped = args.Dropped;
|
||||
var target = args.Target;
|
||||
|
||||
if (!InRangeUnobstructed(user, target, range, collisionMask, predicate, ignoreInsideBlocker))
|
||||
{
|
||||
if (popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
target.PopupMessage(user, message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InRangeUnobstructed(user, dropped, range, collisionMask, predicate, ignoreInsideBlocker))
|
||||
{
|
||||
if (popup)
|
||||
{
|
||||
var message = Loc.GetString("You can't reach there!");
|
||||
dropped.PopupMessage(user, message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the user and target of a
|
||||
/// <see cref="AfterInteractEventArgs"/> are within a certain distance
|
||||
/// without any entity that matches the collision mask obstructing them.
|
||||
/// If the <paramref name="range"/> is zero or negative,
|
||||
/// this method will only check if nothing obstructs the entity and component.
|
||||
/// </summary>
|
||||
/// <param name="args">The event args to use.</param>
|
||||
/// <param name="range">
|
||||
/// Maximum distance between the two entity and set of map coordinates.
|
||||
/// </param>
|
||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
||||
/// <param name="predicate">
|
||||
/// A predicate to check whether to ignore an entity or not.
|
||||
/// If it returns true, it will be ignored.
|
||||
/// </param>
|
||||
/// <param name="ignoreInsideBlocker">
|
||||
/// If true and both the user and target are inside
|
||||
/// the obstruction, ignores the obstruction and considers the interaction
|
||||
/// unobstructed.
|
||||
/// Therefore, setting this to true makes this check more permissive,
|
||||
/// such as allowing an interaction to occur inside something impassable
|
||||
/// (like a wall). The default, false, makes the check more restrictive.
|
||||
/// </param>
|
||||
/// <param name="popup">
|
||||
/// Whether or not to popup a feedback message on the user entity for
|
||||
/// it to see.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the two points are within a given range without being obstructed.
|
||||
/// </returns>
|
||||
public bool InRangeUnobstructed(
|
||||
AfterInteractEventArgs args,
|
||||
float range = InteractionRange,
|
||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||
Ignored predicate = null,
|
||||
bool ignoreInsideBlocker = false,
|
||||
bool popup = false)
|
||||
{
|
||||
var user = args.User;
|
||||
var target = args.Target;
|
||||
predicate ??= e => e == user;
|
||||
|
||||
MapCoordinates otherPosition;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
otherPosition = args.ClickLocation.ToMap(_mapManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
otherPosition = target.Transform.MapPosition;
|
||||
predicate += e => e == target;
|
||||
}
|
||||
|
||||
return InRangeUnobstructed(user, otherPosition, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user