using System; using System.Collections; using System.Collections.Generic; using Animancer; using BITFALL.Combat; using BITFALL.Player.Movement; using BITKit; using BITKit.Entities; using BITKit.StateMachine; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Interactions; namespace BITFALL.Entities.Equipment.Melee { [Serializable] public sealed class Empty:PlayerMeleeControllerState{} [Serializable] public sealed class Draw:PlayerMeleeControllerState { [SerializeField] private AnimationClip drawClip; public override void OnStateEntry(IState old) { base.OnStateEntry(old); var state = my.animancerComponent.Play(drawClip); state.Events.OnEnd = () => { state.Events.OnEnd = null; my.TransitionState(); }; } } [Serializable] public sealed class Idle:PlayerMeleeControllerState { [SerializeField] private AnimationClip idleClip; [SerializeField] private AnimationClip runClip; public override void OnStateEntry(IState old) { base.OnStateEntry(old); my.inputActionGroup.RegisterCallback(my.attackAction, OnAttack); my.inputActionGroup.EnsureCreated(my.blockAction); if (my.inputActionGroup.GetAction(my.attackAction).IsPressed()) { my.TransitionState(); return; } my.animancerComponent.Play(idleClip,0.2f); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); my.inputActionGroup.UnRegisterCallback(my.attackAction, OnAttack); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); switch (my.inputActionGroup.GetAction(my.blockAction)) { case var x when x.IsPressed(): my.TransitionState(); return; } if (my._movement.CurrentState is IPlayerRunState) { my.animancerComponent.Play(runClip,0.2f); } else { my.animancerComponent.Play(idleClip,0.2f); } } private void OnAttack(InputAction.CallbackContext obj) { if (BITAppForUnity.AllowCursor) return; switch (obj) { case {interaction: PressInteraction,performed:true}: my.TransitionState(); return; } } } [Serializable] public sealed class Attack:PlayerMeleeControllerState { [SerializeField] private AnimationClip[] attackClip; private AnimancerState state; private bool keepAttacking; public override void OnStateEntry(IState old) { base.OnStateEntry(old); AttackInternal(); my.inputActionGroup.RegisterCallback(my.attackAction, OnAttack); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this,true)); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); my.inputActionGroup.UnRegisterCallback(my.attackAction, OnAttack); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this,false)); keepAttacking = false; } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (state.NormalizedTime > 0.5f && keepAttacking) AttackInternal(); } private void OnEnd() { state.Events.OnEnd = null; my.TransitionState(); } private void OnAttack(InputAction.CallbackContext obj) { if (BITAppForUnity.AllowCursor) return; switch (obj) { case { interaction: HoldInteraction, started: true }: if (state is not null) state.Events.OnEnd = null; my.TransitionState(); return; case { interaction: TapInteraction, performed: true } when state.NormalizedTime > 0.5f: switch (state.NormalizedTime) { case > 0.5f: AttackInternal(); return; case > 0.16f: keepAttacking = true; return; } return; } } private void AttackInternal() { keepAttacking = false; if (state is not null) { state.Events.OnEnd = null; state.Stop(); } state?.Stop(); state = my.animancerComponent.Play(attackClip.Random()); state.Events.OnEnd = OnEnd; state.Speed = my._playerMovement.Stamina > 0 ? 1 : 0.5f; } } [Serializable] public sealed class Charging : PlayerMeleeControllerState { [SerializeField] private AnimationClip chargingClip; private AnimancerState state; public override void OnStateEntry(IState old) { base.OnStateEntry(old); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this, true)); state = my.animancerComponent.Play(chargingClip,0.2f); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this, false)); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (my.inputActionGroup.GetAction(my.attackAction).IsPressed()) return; if (state.NormalizedTime >= 0.9f) { my.TransitionState(); } else { my.TransitionState(); } } } [Serializable] public sealed class HeavyAttack:PlayerMeleeControllerState { [SerializeField] private AnimationClip heavyAttack; public override void OnStateEntry(IState old) { base.OnStateEntry(old); var state = my.animancerComponent.Play(heavyAttack); state.Events.OnEnd = () => { state.Events.OnEnd = null; my.TransitionState(); }; state.Speed = my._playerMovement.Stamina > 0 ? 1 : 0.5f; } } [Serializable] public sealed class Blocking : PlayerMeleeControllerState { [SerializeField] private AnimationClip blockClip; [SerializeField] private AnimationClip blockedClip; [SerializeField] private AnimationClip breakBlockClip; public bool AllowBlockStun => _interval.AllowUpdateWithoutReset is false; private readonly IntervalUpdate _interval = new(0.32f); public override void OnStateEntry(IState old) { base.OnStateEntry(old); my.animancerComponent.Layers[1].IsAdditive = true; _interval.Reset(); my.animancerComponent.Play(blockClip,0.2f); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this,true)); my._health.OnDamageFactory += OnDamageFactory; } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); my._movement.ExecuteCommand(new PlayerPauseRunCommand(this,false)); my._health.OnDamageFactory += OnDamageFactory; } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if(my.inputActionGroup.GetAction(my.blockAction).IsPressed() is false) my.TransitionState(); } private int OnDamageFactory(DamageMessage arg1, int arg2) { if (arg1.DamageType is not MeleeDamageMessage) return arg2; my.animancerComponent.Layers[1].Stop(); if (my._playerMovement.Stamina < my.melee.BlockStaminaCost) { my.animancerComponent.Layers[1].Play(breakBlockClip); my._playerMovement.Stamina = 0; return arg1.Damage/2; } my._playerMovement.Stamina -= my.melee.BlockStaminaCost; my.animancerComponent.Layers[1].Play(breakBlockClip); if (!AllowBlockStun) return 0; if (arg1.Initiator.TryGetComponent(out var combat)) { combat.HitStun(); } return 0; } } }