using UnityEngine; namespace ProjectI.Combat { public static class CombatAuthorityRules { public const float ReviveRange = 3f; public const double ReviveSeconds = 3; public static bool IsValidAim(Vector3 direction) { return IsFinite(direction) && Mathf.Abs(direction.sqrMagnitude - 1f) <= 0.01f; } public static bool CanRevive(ulong source, ulong target, bool sourceAlive, bool targetDowned, Vector3 sourcePosition, Vector3 targetPosition) { return source != target && sourceAlive && targetDowned && IsFinite(sourcePosition) && IsFinite(targetPosition) && (sourcePosition - targetPosition).sqrMagnitude <= ReviveRange * ReviveRange; } public static bool IsReviveInputFresh(double now, double lastInput) { return IsFinite(now) && IsFinite(lastInput) && now >= lastInput && now - lastInput <= 0.5; } internal static bool IsFinite(double value) { return !double.IsNaN(value) && !double.IsInfinity(value); } private static bool IsFinite(Vector3 value) { return IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z); } } public sealed class ReviveTracker { public float Progress { get; private set; } private bool active; private ulong currentTarget; private double startedAt; private double previousTime; private double work; public bool Tick(ulong target, bool eligible, double now,double rate=1) { if (!eligible || !CombatAuthorityRules.IsFinite(now)) { Reset(); return false; } if (!active || currentTarget != target || now < previousTime) { active = true; currentTarget = target; startedAt = now; work=0;previousTime=now; } if(!CombatAuthorityRules.IsFinite(rate)||rate<1)rate=1; work+=System.Math.Max(0,now-previousTime)*rate; previousTime = now; Progress = Mathf.Clamp01((float)(work / CombatAuthorityRules.ReviveSeconds)); return Progress >= 1f; } public void Reset() { active = false; Progress = 0;work=0; } public void SetHolding(bool holding) { if (!holding) Reset(); } } }