using ProjectI.Combat; using UnityEngine; namespace ProjectI.Runs { /// Accepted foot/body volume, bounded sweep and solid-world visibility. Warps never create swept pickups. public static class CorePickupRules { public const float Radius = 2; public const float MaximumSweep = 12; private static readonly int WorldMask = ~LayerMask.GetMask("Players", "CombatTargets"); public static bool TryCandidate(Vector3 previous, Vector3 current, Vector3 core, bool continuous, out Vector3 bodyOrigin) { bodyOrigin = current + Vector3.up; if (!Finite(previous) || !Finite(current) || !Finite(core)) return false; Vector3 segment = current - previous; if (!continuous || segment.sqrMagnitude > MaximumSweep * MaximumSweep) previous = current; segment = current - previous; float horizontalSquared = segment.x * segment.x + segment.z * segment.z; float t = horizontalSquared > .0001f ? Mathf.Clamp01(((core.x - previous.x) * segment.x + (core.z - previous.z) * segment.z) / horizontalSquared) : 1; Vector3 foot = previous + segment * t; bodyOrigin = foot + Vector3.up; float vertical = core.y - foot.y; Vector3 delta = core - foot; delta.y = 0; return vertical >= -.25f && vertical <= 2.25f && delta.sqrMagnitude <= Radius * Radius; } public static bool IsVisible(Vector3 origin, Vector3 point, RaycastHit[] hits) { if (!Finite(origin) || !Finite(point) || hits == null || hits.Length == 0) return false; Vector3 delta = point - origin; if (delta.sqrMagnitude < .000001f) return true; int count = Physics.RaycastNonAlloc(origin, delta.normalized, hits, delta.magnitude, WorldMask, QueryTriggerInteraction.Ignore); if (count == hits.Length) return false; for (int i = 0; i < count; i++) if (hits[i].collider != null && hits[i].collider.GetComponentInParent() == null) return false; return true; } private static bool Finite(Vector3 v) => !float.IsNaN(v.x) && !float.IsInfinity(v.x) && !float.IsNaN(v.y) && !float.IsInfinity(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.z); } }