cirnogodot/Scripts/Components/Actors/PlayerWeaponProvider.cs

287 lines
7.8 KiB
C#
Raw Normal View History

using System;
using System.Linq;
2025-05-06 10:25:11 +02:00
using Cirno.Scripts.Components.FSM.Player;
2025-02-28 18:50:42 +01:00
using Cirno.Scripts.Resources;
2025-05-02 15:49:25 +02:00
using Cirno.Scripts.Utils;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.Components.Actors;
public partial class PlayerWeaponProvider : Node2D
{
2025-05-06 10:25:11 +02:00
[Export] public PlayerStorageModule StorageModule { get; set; }
2025-02-28 18:50:42 +01:00
[Export] public PackedScene WeaponTemplate { get; private set; }
2025-05-06 10:53:49 +02:00
[Export] public double WeaponSwitchCooldown { get; private set; } = 0.5d;
2025-05-06 15:07:22 +02:00
[Export] public Marker2D WeaponRightOffset { get; private set; } // local offset when facing right
[Export] public Marker2D WeaponLeftOffset { get; private set; } // local offset when facing left
2025-04-09 23:24:55 +02:00
public Array<Weapon> EquippedWeapons { get; set; } = [];
2025-05-02 15:49:25 +02:00
private int _currentWeaponIndex = 0;
2025-05-06 10:53:49 +02:00
private double _switchCooldown = 0d;
private bool _switching = false;
2025-05-02 15:49:25 +02:00
private int CurrentWeaponIndex
{
get => Math.Clamp(_currentWeaponIndex, 0, EquippedWeapons.Count -1);
2025-05-02 15:49:25 +02:00
set
{
2025-05-06 10:53:49 +02:00
if (value > EquippedWeapons.Count - 1)
2025-05-02 15:49:25 +02:00
{
_currentWeaponIndex = 0;
2025-05-06 10:53:49 +02:00
return;
2025-05-02 15:49:25 +02:00
}
2025-05-02 15:49:25 +02:00
if (value < 0)
{
_currentWeaponIndex = EquippedWeapons.Count - 1;
2025-05-06 10:53:49 +02:00
return;
2025-05-02 15:49:25 +02:00
}
_currentWeaponIndex = value;
}
}
2025-05-02 15:49:25 +02:00
private InventoryManager _inventoryManager;
2025-05-02 15:49:25 +02:00
public Weapon EquippedWeapon { get; set; }
2025-02-28 19:59:36 +01:00
2025-05-02 15:49:25 +02:00
private CharacterBody2D _parent;
2025-02-28 19:59:36 +01:00
public void Init(CharacterBody2D parent)
{
_parent = parent;
_inventoryManager = this.GetInventoryManager();
2025-02-28 18:50:42 +01:00
2025-05-02 15:49:25 +02:00
_inventoryManager.WeaponEquip += this.OnInventoryWeaponEquipped;
2025-02-28 18:50:42 +01:00
2025-05-02 15:49:25 +02:00
_inventoryManager.ItemAdded += OnInventoryWeaponAdded;
2025-05-02 15:51:40 +02:00
EquipStartupWeapon();
}
2025-05-06 10:53:49 +02:00
public void Update(double delta)
{
2025-05-06 15:07:22 +02:00
RotateWeapon();
2025-05-06 10:53:49 +02:00
if (!_switching) return;
_switchCooldown += delta;
if (_switchCooldown >= WeaponSwitchCooldown)
{
_switching = false;
_switchCooldown = 0d;
}
}
2025-05-06 15:07:22 +02:00
private void RotateWeapon()
{
if (EquippedWeapon is null) return;
EquippedWeapon.RotateWeapon(StorageModule.FacingDirection, WeaponLeftOffset.Position, WeaponRightOffset.Position);
// EquippedWeapon.SetRotation(angle + Mathf.Pi / 2.0f);
//
//
//
// EquippedWeapon.FlipH = facingLeft;
//
// // 3. Position on correct side (assuming EquippedWeapon is a child of the Player node)
// EquippedWeapon.Position = facingLeft ? WeaponLeftOffset : WeaponRightOffset;
}
2025-05-06 10:53:49 +02:00
2025-05-02 15:49:25 +02:00
private void OnInventoryWeaponEquipped(string itemKey)
{
2025-05-02 15:49:25 +02:00
Equip(itemKey, true);
}
2025-05-02 15:49:25 +02:00
private void OnInventoryWeaponAdded(LootItem item, int amount)
{
2025-05-02 15:49:25 +02:00
if (item.Item is not ItemTypes.Weapon) return;
Equip(item, false);
}
2025-05-02 15:49:25 +02:00
private void EquipStartupWeapon()
{
if (EquippedWeapon is not null) return;
if (!string.IsNullOrWhiteSpace(GlobalState.Session.EquippedWeaponId))
2025-03-13 14:20:30 +01:00
{
2025-05-02 15:49:25 +02:00
// 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
2025-05-02 15:49:25 +02:00
private void EquipWeapon(Weapon weapon)
{
2025-05-06 10:53:49 +02:00
if (EquippedWeapon == weapon)
{
return;
}
// Need to start cooldown
EquippedWeapon?.Hide();
EquippedWeapon = weapon;
CurrentWeaponIndex = EquippedWeapons.IndexOf(weapon);
2025-05-02 15:49:25 +02:00
GlobalState.Session.EquippedWeaponId = weapon.WeaponData.ItemKey;
2025-05-06 10:53:49 +02:00
EquippedWeapon.Show();
_switching = true;
_switchCooldown = 0d;
2025-05-08 11:07:23 +02:00
InventoryManager.Instance.UpdateEquippedWeapon(weapon.WeaponData.ItemKey);
}
public void NextWeapon()
{
CurrentWeaponIndex += 1;
2025-05-02 15:49:25 +02:00
Equip(EquippedWeapons[CurrentWeaponIndex], true);
}
public void PreviousWeapon()
{
CurrentWeaponIndex -= 1;
2025-05-02 15:49:25 +02:00
Equip(EquippedWeapons[CurrentWeaponIndex], true);
}
public void Shoot(Vector2 direction)
{
if (EquippedWeapon == null) return;
2025-05-06 10:53:49 +02:00
if (_switching) return;
2025-04-08 17:59:20 +02:00
EquippedWeapon.ShootDirection = direction;
EquippedWeapon.Shoot();
}
2025-05-07 21:50:00 +02:00
public void Reload()
{
if (EquippedWeapon == null) return;
if (_switching) return;
EquippedWeapon.Reload();
}
2025-05-02 15:49:25 +02:00
// 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)
2025-02-28 18:50:42 +01:00
{
2025-05-02 16:20:54 +02:00
if (startingItem is null)
{
2025-05-02 18:12:33 +02:00
GD.Print($"Could not spawn weapon was not in the inventory.");
2025-05-02 16:20:54 +02:00
return null;
}
2025-02-28 18:50:42 +01:00
if (WeaponTemplate == null)
{
GD.Print("Could not spawn weapon because template is null");
2025-05-02 15:49:25 +02:00
return null;
2025-02-28 18:50:42 +01:00
}
2025-05-02 15:49:25 +02:00
// Check if it's not spawned already
var maybeExistingWeapon = GetWeaponFromLocal(startingItem.ItemKey);
if (maybeExistingWeapon is not null) return maybeExistingWeapon;
2025-02-28 18:50:42 +01:00
var weapon = this.CreateSibling<Weapon>(WeaponTemplate);
weapon.WeaponData = startingItem.WeaponData;
2025-05-06 10:25:11 +02:00
2025-05-06 15:07:22 +02:00
weapon.Sprite.Texture = startingItem.InventorySprite;
2025-05-02 15:49:25 +02:00
2025-02-28 18:50:42 +01:00
this.AddWeapon(weapon);
2025-05-02 15:49:25 +02:00
return weapon;
}
2025-02-28 18:50:42 +01:00
2025-05-02 15:49:25 +02:00
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);
if (spawnedWeapon is null)
{
GD.Print($"Tried to spawn weapon {itemKey} but failed because it was null.");
return null;
};
2025-05-02 15:49:25 +02:00
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
if (weapon is null)
{
return null;
}
2025-05-02 15:49:25 +02:00
// Always equip it if there's nothing equipped
if (this.EquippedWeapon is null)
2025-02-28 18:50:42 +01:00
{
this.EquipWeapon(weapon);
2025-05-02 15:49:25 +02:00
return weapon;
2025-02-28 18:50:42 +01:00
}
2025-05-02 15:49:25 +02:00
// 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;
}
}