public virtual HitReaction Hurt(HurtInfoBase hurtInfoBase)
        {
            HitReaction hr = new HitReaction();

            hr.reactionType = HitReactionType.Hit;
            OnHit?.Invoke(null, manager, hurtInfoBase.hitInfo);
            return(hr);
        }
        public override HitReaction Hurt(HurtInfoBase hurtInfoBase)
        {
            EntityPhysicsManager physicsManager = (EntityPhysicsManager)Controller.PhysicsManager;
            HurtInfo3D           hurtInfo       = (HurtInfo3D)hurtInfoBase;

            HitReaction hitReaction = new HitReaction();

            hitReaction.reactionType = HitReactionType.Hit;

            // Check if should hit grounded/aerial opponent.
            if (hurtInfo.hitInfo.groundOnly && !Controller.IsGrounded ||
                hurtInfo.hitInfo.airOnly && Controller.IsGrounded)
            {
                hitReaction.reactionType = HitReactionType.Avoided;
                return(hitReaction);
            }

            HitInfo hitInfo = (HitInfo)hurtInfo.hitInfo;

            // Got hit.
            LastHitBy = hurtInfo.hitInfo;
            SetHitStop(hurtInfo.hitInfo.hitstop);
            SetHitStun(hurtInfo.hitInfo.hitstun);
            ((EntityManager)manager).healthManager.Hurt(hitInfo.damageOnHit);

            // Convert forces the attacker-based forward direction.
            switch (hitInfo.forceType)
            {
            case HitboxForceType.SET:
                Vector3 baseForce = hitInfo.opponentForceDir * hitInfo.opponentForceMagnitude;
                Vector3 forces    = (hurtInfo.forward * baseForce.z + hurtInfo.right * baseForce.x);
                forces.y = baseForce.y;
                physicsManager.forceGravity.y = baseForce.y;
                forces.y = 0;
                physicsManager.forceMovement = forces;
                break;

            case HitboxForceType.PULL:
                Vector3 dir = transform.position - hurtInfo.center;
                if (!hitInfo.forceIncludeYForce)
                {
                    dir.y = 0;
                }
                Vector3 forceDir = Vector3.ClampMagnitude((dir) * hitInfo.opponentForceMagnitude, hitInfo.opponentMaxMagnitude);
                float   yForce   = forceDir.y;
                forceDir.y = 0;
                if (hitInfo.forceIncludeYForce)
                {
                    physicsManager.forceGravity.y = yForce;
                }
                physicsManager.forceMovement = forceDir;
                break;
            }

            if (physicsManager.forceGravity.y > 0)
            {
                Controller.IsGrounded = false;
            }

            // Change state to the correct one.
            if (Controller.IsGrounded && hitInfo.groundBounces)
            {
                Controller.StateManager.ChangeState((int)EntityStates.GROUND_BOUNCE);
            }
            else if (hitInfo.causesTumble)
            {
                Controller.StateManager.ChangeState((int)EntityStates.TUMBLE);
            }
            else
            {
                Controller.StateManager.ChangeState((int)(Controller.IsGrounded ? EntityStates.FLINCH : EntityStates.FLINCH_AIR));
            }

            return(hitReaction);
        }