152 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			152 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using Fusion; | ||
|  | using UnityEngine; | ||
|  | 
 | ||
|  | namespace TPSBR | ||
|  | { | ||
|  | 	public enum EHitAction | ||
|  | 	{ | ||
|  | 		None, | ||
|  | 		Damage, | ||
|  | 		Heal, | ||
|  | 		Shield, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public struct HitData | ||
|  | 	{ | ||
|  | 		public EHitAction     Action; | ||
|  | 		public float          Amount; | ||
|  | 		public bool           IsCritical; | ||
|  | 		public bool           IsFatal; | ||
|  | 		public Vector3        Position; | ||
|  | 		public Vector3        Normal; | ||
|  | 		public Vector3        Direction; | ||
|  | 		public PlayerRef      InstigatorRef; | ||
|  | 		public IHitInstigator Instigator; | ||
|  | 		public IHitTarget     Target; | ||
|  | 		public EHitType       HitType; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public enum EHitType | ||
|  | 	{ | ||
|  | 		None, | ||
|  | 		Pistol, | ||
|  | 		Rifle, | ||
|  | 		Grenade, | ||
|  | 		Suicide, | ||
|  | 		Heal, | ||
|  | 		SMG, | ||
|  | 		Shotgun, | ||
|  | 		Sniper, | ||
|  | 		ShrinkingArea, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public interface IHitTarget | ||
|  | 	{ | ||
|  | 		Transform HitPivot { get; } | ||
|  | 		void ProcessHit(ref HitData hit); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public interface IHitInstigator | ||
|  | 	{ | ||
|  | 		void HitPerformed(HitData hit); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public static class HitUtility | ||
|  | 	{ | ||
|  | 		// PUBLIC METHODS | ||
|  | 
 | ||
|  | 		public static bool ProcessHit(PlayerRef instigatorRef, Vector3 direction, LagCompensatedHit hit, float baseDamage, EHitType hitType, out HitData processedHit) | ||
|  | 		{ | ||
|  | 			processedHit = default; | ||
|  | 
 | ||
|  | 			IHitTarget target = hit.Hitbox != null ? hit.Hitbox.Root.GetComponent<IHitTarget>() : null; | ||
|  | 			if (target == null) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			processedHit.Action        = EHitAction.Damage; | ||
|  | 			processedHit.Amount        = baseDamage; | ||
|  | 			processedHit.Position      = hit.Point; | ||
|  | 			processedHit.Normal        = hit.Normal; | ||
|  | 			processedHit.Direction     = direction; | ||
|  | 			processedHit.Target        = target; | ||
|  | 			processedHit.InstigatorRef = instigatorRef; | ||
|  | 			processedHit.HitType       = hitType; | ||
|  | 
 | ||
|  | 			if (hit.Hitbox is BodyPart bodyPart) | ||
|  | 			{ | ||
|  | 				processedHit.Amount = baseDamage * bodyPart.DamageMultiplier; | ||
|  | 				processedHit.IsCritical = bodyPart.IsCritical; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			return ProcessHit(ref processedHit); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		public static bool ProcessHit(NetworkObject instigator, Vector3 direction, LagCompensatedHit hit, float baseDamage, EHitType hitType, out HitData processedHit) | ||
|  | 		{ | ||
|  | 			processedHit = default; | ||
|  | 
 | ||
|  | 			if (instigator == null) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			IHitTarget target = hit.Hitbox != null ? hit.Hitbox.Root.GetComponent<IHitTarget>() : null; | ||
|  | 			if (target == null) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			if (hit.Hitbox.Root.gameObject == instigator.gameObject) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			processedHit.Action        = EHitAction.Damage; | ||
|  | 			processedHit.Amount        = baseDamage; | ||
|  | 			processedHit.Position      = hit.Point; | ||
|  | 			processedHit.Normal        = hit.Normal; | ||
|  | 			processedHit.Direction     = direction; | ||
|  | 			processedHit.Target        = target; | ||
|  | 			processedHit.InstigatorRef = instigator.InputAuthority; | ||
|  | 			processedHit.Instigator    = instigator.GetComponent<IHitInstigator>(); | ||
|  | 			processedHit.HitType       = hitType; | ||
|  | 
 | ||
|  | 			if (hit.Hitbox is BodyPart bodyPart) | ||
|  | 			{ | ||
|  | 				processedHit.Amount = baseDamage * bodyPart.DamageMultiplier; | ||
|  | 				processedHit.IsCritical = bodyPart.IsCritical; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			return ProcessHit(ref processedHit); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		public static bool ProcessHit(NetworkBehaviour instigator, Collider collider, float damage, EHitType hitType, out HitData processedHit) | ||
|  | 		{ | ||
|  | 			processedHit = new HitData(); | ||
|  | 
 | ||
|  | 			var target = collider.GetComponentInParent<IHitTarget>(); | ||
|  | 			if (target == null) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			processedHit.Action        = EHitAction.Damage; | ||
|  | 			processedHit.Amount        = damage; | ||
|  | 			processedHit.InstigatorRef = instigator.Object.InputAuthority; | ||
|  | 			processedHit.Instigator    = instigator.GetComponent<IHitInstigator>(); | ||
|  | 			processedHit.Position      = collider.transform.position; | ||
|  | 			processedHit.Normal        = (instigator.transform.position - collider.transform.position).normalized; | ||
|  | 			processedHit.Direction     = -processedHit.Normal; | ||
|  | 			processedHit.Target        = target; | ||
|  | 			processedHit.HitType       = hitType; | ||
|  | 
 | ||
|  | 			return ProcessHit(ref processedHit); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		public static bool ProcessHit(ref HitData hitData) | ||
|  | 		{ | ||
|  | 			hitData.Target.ProcessHit(ref hitData); | ||
|  | 
 | ||
|  | 			// For local debug targets we show hit feedback immediately | ||
|  | 			if (hitData.Instigator != null && hitData.Target is Health == false) | ||
|  | 			{ | ||
|  | 				hitData.Instigator.HitPerformed(hitData); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			return true; | ||
|  | 		} | ||
|  | 	} | ||
|  | } |