418 lines
14 KiB
C#
418 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using UnityEngine.InputSystem;
|
|
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BITFALL.Entities;
|
|
using BITFALL.Entities.Improvised;
|
|
using BITFALL.Entities.Inventory;
|
|
using BITFALL.Player.Equip;
|
|
using BITFALL.Player.Inventory;
|
|
using BITKit.Entities.Player;
|
|
using Cysharp.Threading.Tasks;
|
|
using JetBrains.Annotations;
|
|
using UnityEditor;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.InputSystem.Interactions;
|
|
using Debug = UnityEngine.Debug;
|
|
|
|
namespace BITFALL.Entities.Equipment
|
|
{
|
|
[CustomType(typeof(IPlayerEquipSelector))]
|
|
public class PlayerEquipSelector : EntityBehavior,IPlayerEquipSelector
|
|
{
|
|
[Header(Constant.Header.InternalVariables)]
|
|
private readonly Dictionary<int, IBasicItem> equips=new();
|
|
|
|
[Header(Constant.Header.Input)]
|
|
[SerializeField] private InputActionReference primaryAction;
|
|
[SerializeField] private InputActionReference secondaryAction;
|
|
[SerializeField] private InputActionReference tertiaryAction;
|
|
[SerializeField] private InputActionReference quaternaryAction;
|
|
[SerializeField] private InputActionReference holsterAction;
|
|
[SerializeField] private InputActionReference throwAction;
|
|
[SerializeField] private InputActionReference tacticsAction;
|
|
|
|
public event Func<IBasicItem, bool> TryEquipFactory;
|
|
public event Action<IDictionary<int, IBasicItem>> OnUpdateEquip;
|
|
|
|
[Inject]
|
|
private IEntityInventory _inventory;
|
|
[Inject(true)]
|
|
private IKnockdown _knockdown;
|
|
[Inject]
|
|
private IHealth _health;
|
|
|
|
private IBasicItem currentEquip;
|
|
[Inject(true)]
|
|
private IEntityEquipment _equipment;
|
|
[Inject(true)]
|
|
private ImprovisedServiceInterface _improvisedService;
|
|
[Inject]
|
|
private IEntityEquipmentContainer _equipmentContainer;
|
|
|
|
[Inject]
|
|
private IEquipService _equipService;
|
|
|
|
private readonly List<int> _blockList=new();
|
|
|
|
[Inject(true)] private InputActionGroup _inputActionGroup;
|
|
|
|
private readonly Optional<int> playerChoose = new ();
|
|
|
|
public override void OnAwake()
|
|
{
|
|
_health.OnSetAlive += OnSetAlive;
|
|
|
|
if (_knockdown is not null)
|
|
{
|
|
_knockdown.OnKnockdown += () =>
|
|
{
|
|
if (currentEquip is null) return;
|
|
if (currentEquip.GetAssetable().AllowUseWhileKnocked) return;
|
|
Equip(null);
|
|
};
|
|
_knockdown.OnRevive += () =>
|
|
{
|
|
if (playerChoose.Allow)
|
|
{
|
|
Equip(playerChoose.Value);
|
|
}
|
|
};
|
|
}
|
|
|
|
if (_inputActionGroup is not null)
|
|
{
|
|
if (primaryAction)
|
|
_inputActionGroup.RegisterCallback(primaryAction, OnPrimary);
|
|
if (secondaryAction)
|
|
_inputActionGroup.RegisterCallback(secondaryAction, OnSecondary);
|
|
if (tertiaryAction)
|
|
_inputActionGroup.RegisterCallback(tertiaryAction, OnTertiary);
|
|
if (quaternaryAction)
|
|
_inputActionGroup.RegisterCallback(quaternaryAction, OnQuaternary);
|
|
if (holsterAction)
|
|
_inputActionGroup.RegisterCallback(holsterAction, OnHolster);
|
|
if (throwAction)
|
|
_inputActionGroup.RegisterCallback(throwAction, Throw);
|
|
if (tacticsAction)
|
|
_inputActionGroup.RegisterCallback(tacticsAction, OnTactics);
|
|
}
|
|
|
|
if (_improvisedService is not null)
|
|
{
|
|
_improvisedService.OnEquipImprovisedItem += OnEquipImprovisedItem;
|
|
_improvisedService.OnUnEquipImprovisedItem += OnUnEquipImprovisedItem;
|
|
_improvisedService.OnTryEquipImprovisedItem += OnTryEquipImprovisedItem;
|
|
_improvisedService.OnTryUnEquipImprovisedItem += OnTryUnEquipImprovisedItem;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public override void OnStart()
|
|
{
|
|
base.OnStart();
|
|
_inventory.TryUseItemFactory += TryEquip;
|
|
_inventory.OnUsedItem += OnEquip;
|
|
_inventory.OnAdd += OnAdd;
|
|
_inventory.OnRemove += OnRemove;
|
|
}
|
|
|
|
public override void OnUpdate(float deltaTime)
|
|
{
|
|
base.OnUpdate(deltaTime);
|
|
if (_knockdown is not null)
|
|
{
|
|
_equipService.AllowEquip.SetDisableElements(1868448, _knockdown.IsPressured);
|
|
}
|
|
}
|
|
|
|
|
|
private bool OnTryUnEquipImprovisedItem(IBasicItem arg)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
private bool OnTryEquipImprovisedItem(IBasicItem arg)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
private void OnUnEquipImprovisedItem(IBasicItem obj)
|
|
{
|
|
Cancel();
|
|
}
|
|
|
|
private void OnEquipImprovisedItem(IBasicItem obj)
|
|
{
|
|
Equip(obj);
|
|
}
|
|
|
|
|
|
public void OnPrimary(InputAction.CallbackContext context)
|
|
{
|
|
if (context is not {interaction:PressInteraction ,performed:true}) return;
|
|
Equip(1);
|
|
playerChoose.SetValueThenAllow(1);
|
|
}
|
|
public void OnSecondary(InputAction.CallbackContext context)
|
|
{
|
|
if (context is not {interaction:PressInteraction ,performed:true}) return;
|
|
Equip(2);
|
|
playerChoose.SetValueThenAllow(2);
|
|
}
|
|
public void OnTertiary(InputAction.CallbackContext context)
|
|
{
|
|
if (context is not {interaction:PressInteraction ,performed:true}) return;
|
|
if (Equip(3) is false)
|
|
{
|
|
Equip(-1);
|
|
playerChoose.Clear();
|
|
}
|
|
else
|
|
{
|
|
playerChoose.SetValueThenAllow(3);
|
|
}
|
|
}
|
|
public void OnQuaternary(InputAction.CallbackContext context)
|
|
{
|
|
if (context is not {interaction:PressInteraction ,performed:true}) return;
|
|
Equip<EquipmentAsArmorPlate>();
|
|
}
|
|
public void OnHolster(InputAction.CallbackContext context)
|
|
{
|
|
if (context is not {interaction:PressInteraction ,performed:true}) return;
|
|
Equip(-1);
|
|
}
|
|
private void OnSetAlive(bool alive)
|
|
{
|
|
_equipService.AllowEquip.SetDisableElements(this,!alive);
|
|
if (alive)
|
|
{
|
|
if (playerChoose.Allow)
|
|
{
|
|
Equip(playerChoose.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Equip(-1);
|
|
if (Data.Get<bool>(BITConstant.Environment.sp_keepInventory)) return;
|
|
foreach (var x in equips.ToArray())
|
|
{
|
|
_inventory.Add(x.Value);
|
|
}
|
|
equips.Clear();
|
|
UpdateEquip();
|
|
}
|
|
}
|
|
private bool TryEquip(IBasicItem value)
|
|
{
|
|
if (_equipService.AllowEquip.Allow is false) return false;
|
|
switch (_knockdown)
|
|
{
|
|
case not null when _knockdown.IsKnockdown && value.GetAssetable().AllowUseWhileKnocked is false:
|
|
return false;
|
|
}
|
|
|
|
var asset = value.GetAssetable();
|
|
if (_equipment.IsSupportItem(value) is false) return false;
|
|
switch (asset)
|
|
{
|
|
case var _ when asset.TryGetProperty<EquipmentAsWeapon>(out _):
|
|
var index = 0;
|
|
if (equips.TryAdd(++index, value) || equips.TryAdd(++index,value))
|
|
{
|
|
_equipment.EntryEquip(value);
|
|
UpdateEquip();
|
|
_improvisedService?.TryUnEquipImprovised(out _);
|
|
currentEquip = value;
|
|
_inventory.UseItem(value);
|
|
playerChoose.SetValueThenAllow(index);
|
|
return true;
|
|
}
|
|
break;
|
|
case var _ when asset.TryGetProperty<EquipmentUseItem>(out _):
|
|
if (TryEquipFactory?.CastAsFunc().Any(x => x.Invoke(value)) is false) return false;
|
|
_equipment.EntryEquip(value);
|
|
_improvisedService?.TryUnEquipImprovised(out _);
|
|
currentEquip = value;
|
|
return true;
|
|
case var _ when asset.TryGetProperty<EquipmentAsSlot>(out var equipAsSlot):
|
|
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async void OnAdd(IBasicItem item)
|
|
{
|
|
if (_blockList.Contains(item.Id)) return;
|
|
|
|
if (_equipment.IsSupportItem(item) is false)
|
|
{
|
|
UpdateEquip();
|
|
}
|
|
|
|
if (currentEquip is not null && currentEquip.AddressablePath == item.AddressablePath)
|
|
{
|
|
if (equips.TryGetAny(x => x.Value.AddressablePath == item.AddressablePath, out var pair))
|
|
{
|
|
equips.Remove(pair.Key);
|
|
UpdateEquip();
|
|
}
|
|
|
|
currentEquip = null;
|
|
_equipment.EntryEquip((IBasicItem)null);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
await UniTask.NextFrame();
|
|
}
|
|
|
|
if (_equipment.IsSupportItem(item) && item.GetAssetable().TryGetProperty<EquipmentAsWeapon>(out _))
|
|
{
|
|
_inventory.TryUseItem(item);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
private void OnTactics(InputAction.CallbackContext obj)
|
|
{
|
|
|
|
switch(obj)
|
|
{
|
|
case {interaction:TapInteraction, performed: true}:
|
|
Equip<EquipmentAsTactics>();
|
|
break;
|
|
}
|
|
}
|
|
public void Throw(InputAction.CallbackContext context)
|
|
{
|
|
switch (context)
|
|
{
|
|
case { interaction: HoldInteraction, performed: true }:
|
|
if (currentEquip is null) return;
|
|
if (equips.TryGetAny(x => x.Value.AddressablePath == currentEquip.AddressablePath, out var pair))
|
|
{
|
|
if (_inventory.DropOrSpawn(currentEquip))
|
|
{
|
|
equips.Remove(pair.Key);
|
|
_equipment.EntryEquip((IBasicItem)null);
|
|
currentEquip = null;
|
|
UpdateEquip();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case { interaction: TapInteraction, performed: true }:
|
|
Equip<EquipmentAsThrow>();
|
|
break;
|
|
}
|
|
}
|
|
public void OnRemove(IBasicItem item)
|
|
{
|
|
_blockList.Add(item.Id);
|
|
if (_equipment.IsSupportItem(item) is false)
|
|
{
|
|
UpdateEquip();
|
|
}
|
|
}
|
|
private void OnEquip(IBasicItem obj)
|
|
{
|
|
_blockList.Add(obj.Id);
|
|
}
|
|
private void UpdateEquip()
|
|
{
|
|
OnUpdateEquip?.Invoke(new Dictionary<int, IBasicItem>(equips));
|
|
}
|
|
|
|
public IDictionary<int, IBasicItem> Equipped => new Dictionary<int, IBasicItem>(equips);
|
|
|
|
public bool TryDeEquip(IBasicItem item)
|
|
{
|
|
if (item is null) return false;
|
|
if (equips.Any(x => x.Value.AddressablePath == item.AddressablePath) is false) return false;
|
|
var index = equips.First(x=>x.Value.AddressablePath==item.AddressablePath).Key;
|
|
if (equips.TryRemove(index) is false) return false;
|
|
if (!_inventory.Add(item)) return false;
|
|
if (currentEquip?.AddressablePath == item.AddressablePath)
|
|
{
|
|
Equip(null);
|
|
playerChoose.Clear();
|
|
}
|
|
UpdateEquip();
|
|
return true;
|
|
}
|
|
|
|
public async void Cancel()
|
|
{
|
|
await UniTask.NextFrame();
|
|
if (playerChoose.Allow)
|
|
{
|
|
if (Equip(playerChoose.Value))
|
|
{
|
|
return;
|
|
};
|
|
//playerChoose.Clear();
|
|
}
|
|
Equip(null);
|
|
return;
|
|
}
|
|
|
|
private void Equip(IBasicItem item)
|
|
{
|
|
if (item is not null && _equipService.AllowEquip.Allow is false) return;
|
|
_equipment.EntryEquip(item);
|
|
currentEquip = item;
|
|
}
|
|
|
|
private bool Equip(int index)
|
|
{
|
|
|
|
if (index is not -1)
|
|
{
|
|
if (_equipService.AllowEquip.Allow is false) return false;
|
|
}
|
|
|
|
if (!equips.TryGetValue(index, out var x) && index is not -1) return false;
|
|
|
|
if (index is not -1 && _knockdown is not null && _knockdown.IsKnockdown)
|
|
{
|
|
if (x.GetAssetable().AllowUseWhileKnocked is false) return false;
|
|
}
|
|
|
|
currentEquip = x;
|
|
_improvisedService?.TryUnEquipImprovised(out _);
|
|
_equipment.EntryEquip(x);
|
|
return true;
|
|
}
|
|
|
|
private bool Equip<T>() where T : IEquipmentSlot
|
|
{
|
|
if (!_equipmentContainer.Equipment.TryGetAny(x => x.Key is T, out var item)) return false;
|
|
if (_knockdown is not null)
|
|
{
|
|
if(_knockdown.IsKnockdown && item.Value.GetAssetable().AllowUseWhileKnocked is false) return false;
|
|
}
|
|
_improvisedService.TryUnEquipImprovised(out _);
|
|
Equip(item.Value);
|
|
return true;
|
|
}
|
|
}
|
|
} |