BITFALL/Assets/Artists/Scripts/Entities/Knockdown/EntityKnockdown.cs

210 lines
5.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using BITFALL.Entities.Inventory;
using BITFALL.Hotkey;
using BITFALL.Items;
using BITKit;
using BITKit.Entities;
using Cysharp.Threading.Tasks;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
namespace BITFALL.Entities
{
[CustomType(typeof(IKnockdown))]
public sealed class EntityKnockdown :EntityBehavior,IKnockdown,IHotkeyProvider
{
[SerializeField] private bool debug;
[SerializeField,ReadOnly] private int knockedHealth;
[SerializeField] private int initialKnockedHealth;
[SerializeField] private Optional<float> invincibilityTimes;
[SerializeField] private InputActionReference pressureAction;
[SerializeReference,SubclassSelector] private ITicker ticker;
[SerializeReference,SubclassSelector] private IReference onKnockdownAnimation;
[SerializeReference,SubclassSelector] private IReference onReviveAnimation;
[Inject(true)] private InputActionGroup _inputActionGroup;
public int KnockedHealth=>knockedHealth;
public int InitialKnockedHealth
{
get => initialKnockedHealth;
set => initialKnockedHealth = value;
}
public event Action OnKnockdown;
public event Action OnRevive;
public bool IsKnockdown { get;private set; }
public bool IsPressured => _isPressured;
private readonly IntervalUpdate invincibilityInterval = new();
[Inject]
private IHealth _health;
[Inject]
private IEntityInventory _inventory;
[Inject(true)] private IHotkeyCollection _hotkeyCollection;
private readonly ValidHandle _isPressured=new();
public override void OnStart()
{
_health.OnDamageFactory += OnDamageFactory;
_health.OnSetAlive += OnSetAlive;
_inventory.TryUseItemFactory+=TryUseItem;
_inventory.OnUsedItem += OnUseItem;
_inputActionGroup?.RegisterCallback(pressureAction, OnPressureAction);
ticker?.Add(OnTick);
destroyCancellationToken.Register(() =>
{
ticker?.Remove(OnTick);
});
if (_hotkeyCollection is not null)
{
OnRevive += () => { _hotkeyCollection.UnRegister(this); };
OnKnockdown += () => { _hotkeyCollection.Register(this); };
_health.OnSetAlive += (x) => { _hotkeyCollection.UnRegister(this); };
}
}
private void OnTick(float obj)
{
if (IsKnockdown is false || _health.HealthPoint<0) return;
knockedHealth-=_isPressured?1:2;
if (knockedHealth < 0)
{
_health.HealthPoint =-1;
}
}
private void OnPressureAction(InputAction.CallbackContext obj)
{
if (IsKnockdown is false) return;
switch (obj)
{
case {interaction:PressInteraction,performed:true}:
_isPressured.AddElement("123");
break;
case {interaction:PressInteraction,canceled:true}:
_isPressured.RemoveElement("123");
break;
}
}
private bool TryUseItem(IBasicItem arg)
{
if (IsKnockdown is false) return false;
if (arg is not null && arg.GetAssetable().TryGetProperty<PlayerReviveItem>(out _))
{
_inventory.UseItem(arg);
return true;
}
return false;
}
private void OnUseItem(IBasicItem arg)
{
if (IsKnockdown is false ||
arg.GetAssetable().TryGetProperty<PlayerReviveItem>(out _) is false) return;
IsKnockdown = false;
OnRevive?.Invoke();
if (onReviveAnimation is not null)
{
UnityEntity.Invoke(Constant.Animation.Play,onReviveAnimation.Value);
}
if (debug)
{
BIT4Log.Log<IKnockdown>("玩家已自救");
}
}
private void OnSetAlive(bool obj)
{
IsKnockdown = false;
}
private int OnDamageFactory(DamageMessage arg, int currentDamage)
{
if (Data.Get<bool>(BITConstant.Environment.sp_knockdown_disabled)) return currentDamage;
if (IsKnockdown && invincibilityTimes.Allow && invincibilityInterval.AllowUpdateWithoutReset is false)
{
return 0;
}
if (currentDamage > _health.MaxHealthPoint + initialKnockedHealth) return currentDamage;
switch (IsKnockdown)
{
case false when _health.HealthPoint - currentDamage >= 0:
return currentDamage;
case true when currentDamage>knockedHealth:
return currentDamage;
case true when KnockedHealth >= 0:
knockedHealth -= currentDamage;
return 0;
}
IsKnockdown = true;
knockedHealth = initialKnockedHealth;
if (invincibilityTimes.Allow)
{
invincibilityInterval.Interval = invincibilityTimes.Value;
invincibilityInterval.Reset();
}
OnKnockdown?.Invoke();
_health.HealthPoint = 0;
if (debug)
{
BIT4Log.Log<IKnockdown>("玩家被击倒");
}
if(onKnockdownAnimation is not null)
UnityEntity.Invoke(Constant.Animation.Play,onKnockdownAnimation.Value);
return 0;
}
public string Name => "放弃止血";
public string Description => "放弃止血,你将迷失在无人区";
object IHotkeyProvider.Data => null;
public bool Enabled => true;
public Action OnPerform => Lost;
public float HoldDuration => 2;
private void Lost()
{
if (IsKnockdown is false) return;
_health.HealthPoint =-1;
}
}
}