using System.Collections.Generic; using UnityEngine; /// /// Attach to the Player GameObject. /// Manages all instantiated weapon instances and switching between them. /// Also registers any weapon already in the scene (e.g. the starting gun). /// public class WeaponManager : MonoBehaviour { [Header("References")] [Tooltip("The transform weapons are parented to — usually the Camera or a WeaponHolder child.")] public Transform weaponHolder; [Header("Weapon Position")] [Tooltip("Local position offset applied to all equipped weapons.")] public Vector3 weaponPositionOffset = new Vector3(0.2f, -0.25f, 0.45f); [Tooltip("Local euler rotation offset applied to all equipped weapons.")] public Vector3 weaponRotationOffset = new Vector3(0f, 0f, 0f); [Tooltip("Scale applied to all equipped weapons.")] public Vector3 weaponScale = new Vector3(1f, 1f, 1f); [Header("Switching")] public bool allowScrollSwitch = true; public bool allowNumberKeys = true; // ─── internal slot ─────────────────────────────────────────────── public class WeaponSlot { public string itemName; public GameObject instance; // the live GO in weaponHolder public ItemDefinition definition; // may be null for the starting gun } public List slots = new List(); public int activeIndex { get; private set; } = -1; // ───────────────────────────────────────────────────────────────── void Start() { // Auto-find weapon holder if not set if (weaponHolder == null) { Camera cam = GetComponentInChildren(); weaponHolder = cam != null ? cam.transform : transform; } // Register any SimpleGun already present as children of the holder SimpleGun[] existing = weaponHolder.GetComponentsInChildren(true); foreach (SimpleGun gun in existing) { RegisterExistingGun(gun.gameObject); } } private Inventory _inventory; void Update() { if (slots.Count == 0) return; // Live-update active weapon transform so Inspector tweaks take effect immediately if (activeIndex >= 0 && activeIndex < slots.Count) { var vm = slots[activeIndex].instance.GetComponent(); if (vm != null) vm.Apply(); else { Transform t = slots[activeIndex].instance.transform; t.localPosition = weaponPositionOffset; t.localRotation = Quaternion.Euler(weaponRotationOffset); t.localScale = weaponScale; } } // Don't switch weapons while the inventory UI is open if (_inventory == null) _inventory = GetComponent(); if (_inventory != null && _inventory.IsOpen) return; // Scroll wheel if (allowScrollSwitch) { float scroll = Input.GetAxis("Mouse ScrollWheel"); if (scroll > 0f) CycleWeapon(1); if (scroll < 0f) CycleWeapon(-1); } // Number keys 1–9 if (allowNumberKeys) { for (int i = 0; i < Mathf.Min(slots.Count, 9); i++) { if (Input.GetKeyDown(KeyCode.Alpha1 + i)) EquipByIndex(i); } } } // ─── Public API ────────────────────────────────────────────────── /// Register a weapon that already exists in the scene (starting gun). public void RegisterExistingGun(GameObject gunGO, ItemDefinition def = null) { string name = def != null ? def.itemName : gunGO.name; // Don't double-register if (slots.Exists(s => s.instance == gunGO)) return; slots.Add(new WeaponSlot { itemName = name, instance = gunGO, definition = def }); int idx = slots.Count - 1; // Always start inactive — player must pick up / equip from inventory gunGO.SetActive(false); Debug.Log($"[WeaponManager] Registered existing weapon: {name} at slot {idx} (inactive)"); } /// Add a new weapon from a definition (called by Inventory on first equip). public int AddWeapon(ItemDefinition def) { if (def == null || def.weaponPrefab == null) { Debug.LogWarning("[WeaponManager] AddWeapon: definition or prefab is null."); return -1; } // Already registered? int existing = slots.FindIndex(s => s.definition == def); if (existing >= 0) return existing; GameObject instance = Instantiate(def.weaponPrefab, weaponHolder); var vm = instance.GetComponent(); if (vm != null) vm.Apply(); else { instance.transform.localPosition = weaponPositionOffset; instance.transform.localRotation = Quaternion.Euler(weaponRotationOffset); instance.transform.localScale = weaponScale; } instance.SetActive(false); // Strip colliders so they don't mess with the CharacterController foreach (Collider col in instance.GetComponentsInChildren()) if (!(col is CharacterController)) Destroy(col); slots.Add(new WeaponSlot { itemName = def.itemName, instance = instance, definition = def }); int newIdx = slots.Count - 1; Debug.Log($"[WeaponManager] Added weapon: {def.itemName} at slot {newIdx}"); return newIdx; } /// Equip weapon by slot index. public void EquipByIndex(int index) { if (index < 0 || index >= slots.Count) return; // Deactivate current if (activeIndex >= 0 && activeIndex < slots.Count) slots[activeIndex].instance.SetActive(false); activeIndex = index; slots[activeIndex].instance.SetActive(true); Debug.Log($"[WeaponManager] Equipped: {slots[activeIndex].itemName}"); } /// Equip weapon by item name. public void EquipByName(string name) { int idx = slots.FindIndex(s => s.itemName == name); if (idx >= 0) EquipByIndex(idx); else Debug.LogWarning($"[WeaponManager] No slot found for: {name}"); } /// Cycle forward (+1) or backward (-1). public void CycleWeapon(int dir) { if (slots.Count == 0) return; int next = (activeIndex + dir + slots.Count) % slots.Count; EquipByIndex(next); } /// Deactivate the current weapon without switching to another. public void Unequip() { if (activeIndex >= 0 && activeIndex < slots.Count) slots[activeIndex].instance.SetActive(false); activeIndex = -1; Debug.Log("[WeaponManager] Unequipped all weapons."); } public string ActiveWeaponName => (activeIndex >= 0 && activeIndex < slots.Count) ? slots[activeIndex].itemName : ""; }