using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using BITFALL.Entities.Equipment; using BITFALL.Entities.Inventory; using BITFALL.Items.Armor; using BITKit; using BITKit.Entities; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace BITFALL.Entities.Armor { [CustomType(typeof(IArmor))] public class EntityArmor : EntityBehavior,IArmor { [SerializeField] private Optional initialArmor; [SerializeField,HideInInspector] internal int currentArmor; private int _armor; public int Armor { get => _armor; set=>OnArmorChanged?.Invoke(currentArmor = _armor = value); } public int PlateCapacity { get; private set; } public bool TryGetCurrentArmor(out IBasicItem item) { item = _currentArmor; return _currentArmor is not null; } public IBasicItem[] Plates { get; set; } = Array.Empty(); private readonly List _plates = new(); public event Action OnArmorChanged; public event Action OnEquipArmor; public event Action OnUnEquipArmor; public event Action OnPlatesChanged; [Inject] private IHealth _health; [Inject(true)] private IPlayerEquipSelector _playerEquipSelector; [Inject(true)] private IEntityInventory _inventory; [Inject(true)] private IEntityEquipmentContainer _equipmentContainer; private IBasicItem _currentArmor; public override void OnAwake() { base.OnAwake(); _health.OnDamageFactory += OnDamageFactory; if (_inventory is not null) { _inventory.OnUsedItem += OnUsedItem; _inventory.AllowUseItemFactory += OnAllowUse; } if (_equipmentContainer is not null) { _equipmentContainer.OnEquip += OnEquip; _equipmentContainer.OnDeEquip += OnDeEquip; } if (_playerEquipSelector is not null) _playerEquipSelector.TryEquipFactory += OnTryEquip; } public override void OnStart() { base.OnStart(); if (initialArmor.Allow) { Armor = initialArmor.Value; } } private bool OnAllowUse(IBasicItem arg) { if (OnTryEquip(arg) is false) { throw new InGameException("无护甲或护甲已满"); } if (arg.TryGetProperty(out var nextPlate) is false) { return false; } if (Plates.Length==PlateCapacity && Plates .Select(x => x.GetOrCreateProperty()) .All(x => x.CurrentPoint >= nextPlate.CurrentPoint) ) { throw new InGameException("取消装备更低级的护甲"); } return true; } private bool OnTryEquip(IBasicItem arg) { if (arg is null) return true; if (arg.GetAssetable().TryGetProperty(out _)) { if (_currentArmor is null) { return false; } if (Armor == _currentArmor.GetAssetable().As().Capacity) { return false; } } return true; } private void OnDeEquip(IEquipmentSlot arg1, IBasicItem arg2) { if (arg1 is not EquipmentAsArmor) return; foreach (var x in Plates) { _inventory.DropOrSpawn(x); } Plates = Array.Empty(); _plates.Clear(); _currentArmor = null; OnUnEquipArmor?.Invoke(arg2); PlateCapacity = 0; OnPlatesChanged?.Invoke(Plates); OnArmorChanged?.Invoke(_armor = 0); } private void OnEquip(IEquipmentSlot arg1, IBasicItem arg2) { if (arg1 is not EquipmentAsArmor) return; _currentArmor = arg2; OnEquipArmor?.Invoke(arg2); PlateCapacity = arg2.GetAssetable().As().Capacity; OnPlatesChanged?.Invoke(Plates); } private void OnUsedItem(IBasicItem obj) { //if (_currentArmor?.GetAssetable() is not AssetableArmor assetableArmor) return; if (obj.TryGetProperty(out var newArmor) is false) return; if(_plates.Count==PlateCapacity) { var min = Plates.OrderBy(x => x.GetOrCreateProperty().CurrentPoint).First(); UninstallArmor(_plates.IndexOf(min)); } _plates.Add(obj); Plates = _plates.ToArray(); OnPlatesChanged?.Invoke(Plates); _armor += newArmor.CurrentPoint; OnArmorChanged?.Invoke(_armor); } private int OnDamageFactory(DamageMessage arg1, int damage) { if (_currentArmor is null && initialArmor.Allow is false) return damage; if (Armor is 0) return damage; for (var index = Plates.Length-1; index >=0 ; index--) { var x = Plates[index]; var plate = x.GetOrCreateProperty(); if (plate.CurrentPoint <= damage) { _plates.Remove(x); damage -= plate.CurrentPoint; } else { plate.CurrentPoint -= damage; damage = 0; x.TrySetProperty(plate); } if (damage <= 0) { break; } } Plates = _plates.ToArray(); OnPlatesChanged?.Invoke(Plates); return damage; } public void UninstallArmor(int index) { if(_plates.IndexInRange(index) is false) { throw new InGameException("护甲板索引超出范围"); } var plate = _plates[index]; if(_inventory.Add(plate) is false) { _inventory.DropOrSpawn(plate); } _plates.RemoveAt(index); Plates = _plates.ToArray(); OnPlatesChanged?.Invoke(Plates); } } }