using System.Collections; using UnityEngine; public class Weapon : MonoBehaviour { [Header("Weapon Stats")] public string weaponName = "Assault Rifle"; public int damage = 25; public float fireRate = 0.12f; public float range = 100f; public int maxAmmo = 30; public int currentAmmo; public float reloadTime = 1.5f; [Header("Effects")] [SerializeField] private ParticleSystem muzzleFlash; [SerializeField] private GameObject impactEffectPrefab; [SerializeField] private Transform muzzlePoint; [Header("Ballistics & Projectile Support")] [SerializeField] private bool useProjectile = false; [SerializeField] private GameObject projectilePrefab; [SerializeField] private float projectileSpeed = 50f; [Header("Ammo Reserves")] [SerializeField] private bool infiniteReserve = true; [SerializeField] private int currentReserveAmmo = 90; [SerializeField] private int maxReserveAmmo = 180; [Header("Audio Effects (Optional)")] [SerializeField] private AudioSource audioSource; [SerializeField] private AudioClip fireSound; [SerializeField] private AudioClip reloadSound; [SerializeField] private AudioClip emptySound; private float nextFireTime; private bool isReloading; public bool IsReloading => isReloading; public bool InfiniteReserve => infiniteReserve; public int CurrentReserveAmmo => currentReserveAmmo; public int MaxReserveAmmo => maxReserveAmmo; private void Awake() { currentAmmo = maxAmmo; if (audioSource == null) { audioSource = GetComponent(); } } public bool CanShoot() => Time.time >= nextFireTime && !isReloading && currentAmmo > 0; public void Shoot(Camera playerCamera, LayerMask hitMask) { nextFireTime = Time.time + fireRate; currentAmmo--; if (muzzleFlash) muzzleFlash.Play(); PlaySound(fireSound); if (useProjectile && projectilePrefab != null) { FireProjectile(playerCamera); } else { FireHitscan(playerCamera, hitMask); } } private void FireHitscan(Camera playerCamera, LayerMask hitMask) { Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0)); if (Physics.Raycast(ray, out RaycastHit hit, range, hitMask)) { if (hit.collider.TryGetComponent(out var enemy)) { enemy.TakeDamage(damage); } if (impactEffectPrefab) { GameObject impact = Instantiate(impactEffectPrefab, hit.point, Quaternion.LookRotation(hit.normal)); Destroy(impact, 2.0f); } } } private void FireProjectile(Camera playerCamera) { Vector3 spawnPosition = muzzlePoint != null ? muzzlePoint.position : playerCamera.transform.position + playerCamera.transform.forward * 0.5f; // Calculate aim point by casting from crosshair Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0)); Vector3 targetPoint; if (Physics.Raycast(ray, out RaycastHit hit, range)) { targetPoint = hit.point; } else { targetPoint = ray.GetPoint(range); } Vector3 direction = (targetPoint - spawnPosition).normalized; Quaternion rotation = Quaternion.LookRotation(direction); GameObject projectileObj = Instantiate(projectilePrefab, spawnPosition, rotation); if (projectileObj.TryGetComponent(out var projectile)) { projectile.Initialize(damage, projectileSpeed, "Player"); } } public IEnumerator ReloadRoutine() { if (isReloading || currentAmmo == maxAmmo) yield break; if (!infiniteReserve && currentReserveAmmo <= 0) { PlaySound(emptySound); yield break; } isReloading = true; PlaySound(reloadSound); yield return new WaitForSeconds(reloadTime); int neededAmmo = maxAmmo - currentAmmo; if (infiniteReserve) { currentAmmo = maxAmmo; } else { int ammoToAdd = Mathf.Min(neededAmmo, currentReserveAmmo); currentAmmo += ammoToAdd; currentReserveAmmo -= ammoToAdd; } isReloading = false; } public void AddReserveAmmo(int amount) { currentReserveAmmo = Mathf.Clamp(currentReserveAmmo + amount, 0, maxReserveAmmo); } private void PlaySound(AudioClip clip) { if (clip != null && audioSource != null) { audioSource.PlayOneShot(clip); } } }