using System; using System.Linq; using Cirno.Scripts.Resources; using Cirno.Scripts.Utils; using Godot; using Godot.Collections; namespace Cirno.Scripts.Components.Actors; public partial class PlayerWeaponProvider : Node2D { [Export] public PackedScene WeaponTemplate { get; private set; } public Array EquippedWeapons { get; set; } = []; private int _currentWeaponIndex = 0; private int CurrentWeaponIndex { get => Math.Clamp(_currentWeaponIndex, 0, EquippedWeapons.Count -1); set { if (value > EquippedWeapons.Count) { _currentWeaponIndex = 0; } if (value < 0) { _currentWeaponIndex = EquippedWeapons.Count - 1; } _currentWeaponIndex = value; } } private InventoryManager _inventoryManager; public Weapon EquippedWeapon { get; set; } private CharacterBody2D _parent; public void Init(CharacterBody2D parent) { _parent = parent; _inventoryManager = this.GetInventoryManager(); _inventoryManager.WeaponEquip += this.OnInventoryWeaponEquipped; _inventoryManager.ItemAdded += OnInventoryWeaponAdded; } private void OnInventoryWeaponEquipped(string itemKey) { Equip(itemKey, true); } private void OnInventoryWeaponAdded(LootItem item, int amount) { if (item.Item is not ItemTypes.Weapon) return; Equip(item, false); } private void EquipStartupWeapon() { if (EquippedWeapon is not null) return; if (!string.IsNullOrWhiteSpace(GlobalState.Session.EquippedWeaponId)) { // equip it Equip(GlobalState.Session.EquippedWeaponId, false); } else { // Try to equip whatever is first var weaponData = InventoryManager.Instance.Items.FirstOrDefault(x => x.Item.Item is ItemTypes.Weapon); if (weaponData is null) return; Equip(weaponData.Item.ItemKey, false); } } // This is a soft equip public void AddWeapon(Weapon weapon) { EquippedWeapons.Add(weapon); } // Triggered by event in inventorymanager private void EquipWeapon(Weapon weapon) { EquippedWeapon = weapon; CurrentWeaponIndex = EquippedWeapons.IndexOf(weapon); GlobalState.Session.EquippedWeaponId = weapon.WeaponData.ItemKey; } public void NextWeapon() { CurrentWeaponIndex += 1; Equip(EquippedWeapons[CurrentWeaponIndex], true); } public void PreviousWeapon() { CurrentWeaponIndex -= 1; Equip(EquippedWeapons[CurrentWeaponIndex], true); } public void Shoot(Vector2 direction) { if (EquippedWeapon == null) return; EquippedWeapon.ShootDirection = direction; EquippedWeapon.Shoot(); } // Remastered method private LootItem GetItemFromInventory(string itemKey) { return InventoryManager.Instance.Items.FirstOrDefault(x => x.Item.ItemKey == itemKey)?.Item; } private Weapon GetWeaponFromLocal(string itemKey) { return EquippedWeapons.FirstOrDefault(x => x.WeaponData.ItemKey == itemKey); } // Remastered method private Weapon SpawnWeapon(string itemKey) { return SpawnWeapon(GetItemFromInventory(itemKey)); } // Remastered method private Weapon SpawnWeapon(LootItem startingItem) { if (WeaponTemplate == null) { GD.Print("Could not spawn weapon because template is null"); return null; } // Check if it's not spawned already var maybeExistingWeapon = GetWeaponFromLocal(startingItem.ItemKey); if (maybeExistingWeapon is not null) return maybeExistingWeapon; var weapon = this.CreateSibling(WeaponTemplate); weapon.WeaponData = startingItem.WeaponData; this.AddWeapon(weapon); return weapon; } public Weapon Equip(LootItem item, bool force) { var maybeExistingWeapon = GetWeaponFromLocal(item.ItemKey); if (maybeExistingWeapon is not null) return Equip(maybeExistingWeapon, force); // Spawn if not present var spawnedWeapon = SpawnWeapon(item); return Equip(spawnedWeapon, force); } public Weapon Equip(string itemKey, bool force) { // Check in local inventory first var maybeExistingWeapon = GetWeaponFromLocal(itemKey); if (maybeExistingWeapon is not null) return Equip(maybeExistingWeapon, force); // Spawn if not present var spawnedWeapon = SpawnWeapon(itemKey); return Equip(spawnedWeapon, force); } public Weapon Equip(Weapon weapon, bool force) { // When we get here we already have a spawned weapon and it's in the list // Always equip it if there's nothing equipped if (this.EquippedWeapon is null) { this.EquipWeapon(weapon); return weapon; } // If it's a soft equip check for priority if (!force && this.EquippedWeapon.WeaponData.Priority < weapon.WeaponData.Priority) { this.EquipWeapon(weapon); return weapon; } EquipWeapon(weapon); return weapon; } }