using System; using System.Collections; using System.Collections.Generic; using BITFALL.Entities.Inventory; using BITFALL.Hotkey; using BITFALL.Items; using BITFALL.Player.Medical; 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 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; [Inject(true)] private IPlayerMedical _playerMedical; 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; switch (_playerMedical) { case not null when _playerMedical.GetAllWounds().Count is 0: break; case not null when _playerMedical.GetAllWounds().Count>0: default: knockedHealth-=_isPressured?1:2; if (knockedHealth < 0) { _health.HealthPoint =-1; } break; } } private void OnPressureAction(InputAction.CallbackContext obj) { if (IsKnockdown is false) return; switch (obj) { case {interaction:PressInteraction,performed:true}: _isPressured.AddElement(this); break; case {interaction:PressInteraction,canceled:true}: _isPressured.RemoveElement(this); break; } } private bool TryUseItem(IBasicItem arg) { if (IsKnockdown is false) return false; if (arg is not null && arg.GetAssetable().TryGetProperty(out _)) { _inventory.UseItem(arg); return true; } return false; } private void OnUseItem(IBasicItem arg) { if (IsKnockdown is false || arg.GetAssetable().TryGetProperty(out _) is false) return; IsKnockdown = false; OnRevive?.Invoke(); _isPressured.RemoveElement(this); if (onReviveAnimation is not null) { UnityEntity.Invoke(Constant.Animation.Play,onReviveAnimation.Value); } if (debug) { BIT4Log.Log("玩家已自救"); } } private void OnSetAlive(bool obj) { IsKnockdown = false; } private int OnDamageFactory(DamageMessage arg, int currentDamage) { if (Data.Get(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("玩家被击倒"); } 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; } } }