213 lines
5.1 KiB
C#
213 lines
5.1 KiB
C#
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<int> 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<IBasicItem>();
|
|
private readonly List<IBasicItem> _plates = new();
|
|
public event Action<int> OnArmorChanged;
|
|
public event Action<IBasicItem> OnEquipArmor;
|
|
public event Action<IBasicItem> OnUnEquipArmor;
|
|
public event Action<IBasicItem[]> 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("<color=yellow>无护甲或护甲已满</color>");
|
|
}
|
|
|
|
if (arg.TryGetProperty<AsArmor>(out var nextPlate) is false)
|
|
{
|
|
return false;
|
|
}
|
|
if (Plates.Length==PlateCapacity &&
|
|
Plates
|
|
.Select(x => x.GetOrCreateProperty<AsArmor>())
|
|
.All(x => x.CurrentPoint >= nextPlate.CurrentPoint)
|
|
)
|
|
{
|
|
throw new InGameException("<color=yellow>取消装备更低级的护甲</color>");
|
|
}
|
|
return true;
|
|
}
|
|
private bool OnTryEquip(IBasicItem arg)
|
|
{
|
|
if (arg is null) return true;
|
|
if (arg.GetAssetable().TryGetProperty<AsArmor>(out _))
|
|
{
|
|
if (_currentArmor is null)
|
|
{
|
|
return false;
|
|
}
|
|
if (Armor == _currentArmor.GetAssetable().As<ScriptableArmor>().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<IBasicItem>();
|
|
_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<ScriptableArmor>().Capacity;
|
|
OnPlatesChanged?.Invoke(Plates);
|
|
}
|
|
|
|
private void OnUsedItem(IBasicItem obj)
|
|
{
|
|
//if (_currentArmor?.GetAssetable() is not AssetableArmor assetableArmor) return;
|
|
if (obj.TryGetProperty<AsArmor>(out var newArmor) is false) return;
|
|
if(_plates.Count==PlateCapacity)
|
|
{
|
|
var min = Plates.OrderBy(x => x.GetOrCreateProperty<AsArmor>().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<AsArmor>();
|
|
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);
|
|
}
|
|
}
|
|
}
|