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 : "";
}