Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / item / package / Holster.cs
using System;
using System.Collections.Generic;
using Godot;

/// <summary>
/// 角色身上的武器袋, 存储角色携带的武器
/// </summary>
public class Holster
{
    /// <summary>
    /// 归属者
    /// </summary>
    public Role Master { get; }

    /// <summary>
    /// 当前使用的武器对象
    /// </summary>
    public Weapon ActiveWeapon { get; private set; }

    /// <summary>
    /// 当前使用的武器的索引
    /// </summary>
    public int ActiveIndex { get; private set; } = 0;

    /// <summary>
    /// 武器袋容量
    /// </summary>
    public int Capacity { get; private set; } = 0;

    /// <summary>
    /// 武器插槽
    /// </summary>
    public Weapon[] Weapons { get; private set;  }

    public Holster(Role master)
    {
        Master = master;
        //默认容量4
        SetCapacity(4);
    }

    /// <summary>
    /// 修改武器袋容量
    /// </summary>
    public void SetCapacity(int capacity)
    {
        if (capacity < 0)
        {
            capacity = 0;
        }

        if (capacity == Capacity)
        {
            return;
        }

        if (Weapons == null)
        {
            Weapons = new Weapon[capacity];
        }
        else if (Weapons.Length > capacity) //删减格子
        {
            var newArray = new Weapon[capacity];
            for (var i = 0; i < Weapons.Length; i++)
            {
                if (i < capacity)
                {
                    newArray[i] = Weapons[i];
                }
                else
                {
                    Master.ThrowWeapon(i);
                }
            }

            Weapons = newArray;
        }
        else //添加格子
        {
            var newArray = new Weapon[capacity];
            for (var i = 0; i < Weapons.Length; i++)
            {
                newArray[i] = Weapons[i];
            }
            Weapons = newArray;
        }
        Capacity = capacity;
        
    }

    /// <summary>
    /// 返回当前武器袋是否是空的
    /// </summary>
    public bool IsEmpty()
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            if (Weapons[i] != null)
            {
                return false;
            }
        }

        return true;
    }
    
    /// <summary>
    /// 返回当前武器袋是否还有空位
    /// </summary>
    public bool HasVacancy()
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            if (Weapons[i] == null)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 根据索引获取武器
    /// </summary>
    public Weapon GetWeapon(int index)
    {
        if (index < 0 || index >= Weapons.Length)
        {
            return null;
        }
        return Weapons[index];
    }

    /// <summary>
    /// 根据武器id查找武器袋中该武器所在的位置, 如果没有, 则返回 -1
    /// </summary>
    /// <param name="id">武器id</param>
    public int FindWeapon(string id)
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            var item = Weapons[i];
            if (item != null && item.ItemId == id)
            {
                return i;
            }
        }
        return -1;
    }

    /// <summary>
    /// 通过回调函数查询武器在武器袋中的位置, 如果没有, 则返回 -1
    /// </summary>
    public int FindWeapon(Func<Weapon, int, bool> handler)
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            var item = Weapons[i];
            if (item != null && handler(item, i))
            {
                return i;
            }
        }
        return -1;
    }

    /// <summary>
    /// 遍历所有武器
    /// </summary>
    public void ForEach(Action<Weapon, int> handler)
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            var item = Weapons[i];
            if (item != null)
            {
                handler(item, i);
            }
        }
    }

    /// <summary>
    /// 从武器袋中移除所有武器, 并返回
    /// </summary>
    public Weapon[] GetAndClearWeapon()
    {
        var weapons = new List<Weapon>();
        for (var i = 0; i < Weapons.Length; i++)
        {
            var weapon = Weapons[i];
            if (weapon != null)
            {
                weapon.GetParent().RemoveChild(weapon);
                weapon.RemoveAt();
                weapons.Add(weapon);
                Weapons[i] = null;
            }
        }

        return weapons.ToArray();
    }

    /// <summary>
    /// 返回是否能放入武器
    /// </summary>
    /// <param name="weapon">武器对象</param>
    public bool CanPickupWeapon(Weapon weapon)
    {
        for (var i = 0; i < Weapons.Length; i++)
        {
            var item = Weapons[i];
            if (item == null)
            {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 拾起武器, 存入武器袋中, 返回存放在武器袋的位置, 如果容不下这把武器, 则会返回 -1
    /// </summary>
    /// <param name="weapon">武器对象</param>
    /// <param name="exchange">是否立即切换到该武器, 默认 true </param>
    public int PickupWeapon(Weapon weapon, bool exchange = true)
    {
        //已经被拾起了
        if (weapon.Master != null)
        {
            return -1;
        }
        for (var i = 0; i < Weapons.Length; i++)
        {
            var item = Weapons[i];
            if (item == null)
            {
                weapon.Pickup();
                Weapons[i] = weapon;
                weapon.PickUpWeapon(Master);
                if (exchange)
                {
                    ExchangeByIndex(i);
                }

                return i;
            }
        }
        return -1;
    }

    /// <summary>
    /// 移除指定位置的武器, 并返回这个武器对象, 如果移除正在使用的这把武器, 则会自动切换到上一把武器
    /// </summary>
    /// <param name="index">所在武器袋的位置索引</param>
    public Weapon RemoveWeapon(int index)
    {
        if (index < 0 || index >= Weapons.Length)
        {
            return null;
        }
        var weapon = Weapons[index];
        if (weapon == null)
        {
            return null;
        }
        weapon.GetParent().RemoveChild(weapon);
        Weapons[index] = null;

        //如果是当前手持的武器, 就需要调用切换武器操作
        if (index == ActiveIndex)
        {
            //没有其他武器了
            if (ExchangePrev() == index)
            {
                ActiveIndex = 0;
                ActiveWeapon = null;
            }
        }
        weapon.RemoveAt();
        return weapon;
    }

    /// <summary>
    /// 切换到上一个武器
    /// </summary>
    public int ExchangePrev()
    {
        var index = ActiveIndex - 1;
        do
        {
            if (index < 0)
            {
                index = Weapons.Length - 1;
            }
            if (ExchangeByIndex(index))
            {
                return index;
            }
        } while (index-- != ActiveIndex);
        return -1;
    }

    /// <summary>
    /// 切换到下一个武器, 
    /// </summary>
    public int ExchangeNext()
    {
        var index = ActiveIndex + 1;
        do
        {
            if (index >= Weapons.Length)
            {
                index = 0;
            }
            if (ExchangeByIndex(index))
            {
                return index;
            }
        }
        while (index++ != ActiveIndex);
        return -1;
    }

    /// <summary>
    /// 切换到指定索引的武器
    /// </summary>
    public bool ExchangeByIndex(int index)
    {
        if (index == ActiveIndex && ActiveWeapon != null) return true;
        if (index < 0 || index > Weapons.Length) return false;
        var weapon = Weapons[index];
        if (weapon == null) return false;

        //将上一把武器放到背后
        if (ActiveWeapon != null)
        {
            var tempParent = ActiveWeapon.GetParentOrNull<Node2D>();
            if (tempParent != null)
            {
                tempParent.RemoveChild(ActiveWeapon);
                Master.BackMountPoint.AddChild(ActiveWeapon);
                Master.OnPutBackMount(ActiveWeapon, ActiveIndex);
                ActiveWeapon.Conceal();
            }
        }

        //更改父节点
        var parent = weapon.GetParentOrNull<Node>();
        if (parent == null)
        {
            Master.MountPoint.AddChild(weapon);
        }
        else if (parent != Master.MountPoint)
        {
            parent.RemoveChild(weapon);
            Master.MountPoint.AddChild(weapon);
        }

        weapon.Position = Vector2.Zero;
        weapon.Scale = Vector2.One;
        weapon.RotationDegrees = 0;
        weapon.Visible = true;
        ActiveWeapon = weapon;
        ActiveIndex = index;
        ActiveWeapon.Active();
        return true;
    }
}