using static UnityEngine.Random; namespace RaycastPro { using System; using System.Collections; using UnityEngine; using UnityEngine.Events; #if UNITY_EDITOR using UnityEditor; #endif public abstract class BaseCaster : RaycastCore { /// /// Allow to manuel Casting. /// /// Bullet Array Index public abstract void Cast(int _bulletIndex); [Tooltip("Automatically instantiate into this object.")] public Transform poolManager; [SerializeField] public UnityEvent onRate; [SerializeField] public UnityEvent onReload; [Tooltip("When turn on, gun auto reload on enable or end of shooting.")] public bool autoReload = true; public abstract void Reload(); #region Update protected void Update() { if (autoUpdate != UpdateMode.Normal) return; OnCast(); } protected void LateUpdate() { if (autoUpdate != UpdateMode.Late) return; OnCast(); } protected void FixedUpdate() { if (autoUpdate != UpdateMode.Fixed) return; OnCast(); } #endregion protected static void CopyBullet(T to, T from) { var fields = to.GetType().GetFields(); foreach (var field in fields) { if (field.IsStatic) continue; field.SetValue(to, field.GetValue(from)); } var props = to.GetType().GetProperties(); foreach (var prop in props) { if (!prop.CanWrite || !prop.CanWrite || prop.Name == "name") continue; prop.SetValue(to, prop.GetValue(from, null), null); } } [Serializable] public class Ammo { [Tooltip("When activate, the cost of shooting will be zero.")] [SerializeField] public bool infiniteAmmo = true; [Tooltip("The total number of bullets out of the magazine")] [SerializeField] public int amount = 12; [Tooltip("The Capacity of each magazine that will enter the reload time when it runs out.")] [SerializeField] public int magazineCapacity = 6; [Tooltip("The number of bullets in the current magazine.")] [SerializeField] public int magazineAmount = 6; [Tooltip("Interruption time until the magazine is filled")] [SerializeField] public float reloadTime = 2f; [Tooltip("The firing pause time between each shot")] [SerializeField] public float rateTime = .1f; [Tooltip("Randomness")] [SerializeField] public float randomness = 0f; [Tooltip("Chance to miss shooting when cast, 0-1 : 0-100%")] [SerializeField] public float missRate = 0f; /// /// Total amount of Gun bullets". /// public int Total => amount + magazineAmount; [SerializeField] internal bool inRate; [SerializeField] internal bool inReload; public bool IsReloading => inReload; public bool IsInRate => inRate; public int MagazineAmount { get => magazineAmount; set => magazineAmount = Mathf.Clamp(value, 0, magazineCapacity); } public int MagazineCapacity { get => magazineCapacity; set => magazineCapacity = Mathf.Max(0, value); } public int Amount { get => amount; set => amount = Mathf.Max(0, value); } public bool Use(BaseCaster _caster, int _amount = 1) { if (inRate) return false; if (inReload) return false; if (magazineAmount < _amount) { if (_caster.autoReload) { _caster.StartCoroutine(IReload()); _caster.onReload?.Invoke(); } return false; } if (value > missRate) { magazineAmount -= _amount; _inRateC = _caster.StartCoroutine(IRate()); _caster.onRate?.Invoke(); } return true; } private Coroutine _inRateC; /// /// Change to Ienumerator /// internal IEnumerator IRate() { inRate = true; yield return new WaitForSeconds(Range(rateTime - randomness, randomness + randomness)); inRate = false; } public float currentReloadTime { get; private set; } = 0f; internal IEnumerator IReload() { inReload = true; currentReloadTime = 0f; while (currentReloadTime <= reloadTime) { currentReloadTime += Time.deltaTime; yield return new WaitForSeconds(Time.deltaTime); } currentReloadTime = 0f; if (infiniteAmmo) // Bill { magazineAmount = magazineCapacity; } else { var needed = magazineCapacity - magazineAmount; var possible = Mathf.Min(amount, needed); magazineAmount += possible; amount -= possible; } inReload = false; } #if UNITY_EDITOR internal void EditorPanel(SerializedProperty serializedProperty) { BeginHorizontal(); EditorGUILayout.PropertyField(serializedProperty.FindPropertyRelative(nameof(amount))); MiniField(serializedProperty.FindPropertyRelative(nameof(infiniteAmmo)), "I".ToContent("Infinite Ammo")); EndHorizontal(); var mCapProp = serializedProperty.FindPropertyRelative(nameof(magazineCapacity)); PropertyMaxIntField(mCapProp, "Magazine Capacity".ToContent()); PropertySliderField(serializedProperty.FindPropertyRelative(nameof(magazineAmount)), 0, mCapProp.intValue, "Magazine Amount".ToContent(), i => {}); PropertyMaxField(serializedProperty.FindPropertyRelative(nameof(reloadTime))); PropertyMaxField(serializedProperty.FindPropertyRelative(nameof(rateTime))); PropertyMaxField(serializedProperty.FindPropertyRelative(nameof(randomness))); PropertySliderField(serializedProperty.FindPropertyRelative(nameof(missRate)), 0, 1, "Miss Rate".ToContent()); } #endif } } }