RiftMayhem/Assets/Scripts/AbilitySystem/Base/CastingStateController.cs

134 lines
4.1 KiB
C#

using Kryz.CharacterStats.Examples;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
public class CastingStateController : MonoBehaviour
{
public bool isCasting;
public PlayerMovement playerMovement;
public LayerMask movementMask;
private MovementSpeedModifierEffectInstance movementSpeedModifier;
private Camera cam;
private Ray ray;
private RaycastHit hit;
private ProjectileSpawnLocationController projectileSpawnLocationController;
private CharacterStats stats;
public UnityEvent<BaseAbility> OnAbilityQueued = new UnityEvent<BaseAbility>();
private void Awake()
{
cam = Camera.main;
movementSpeedModifier = playerMovement.GetComponent<MovementSpeedModifierEffectInstance>();
stats = playerMovement.GetComponent<CharacterStats>();
projectileSpawnLocationController = transform.root.GetComponentInChildren<ProjectileSpawnLocationController>();
}
/// <summary>
/// Calculate current attack interval based on base speed and modifiers
/// </summary>
private float GetCurrentAttackInterval()
{
float totalAttackSpeed = GameConstants.CharacterStatsBalancing.BaseAttacksPerSecond * (1f + (MathHelpers.NormalizePercentage(stats.GetStat("attackspeed").Value) / 100f));
float interval = 1f / totalAttackSpeed;
return Mathf.Max(interval, GameConstants.CharacterStatsBalancing.FastestAttacksPerSecond);
}
/// <summary>
/// Get current attacks per second
/// </summary>
public float GetCurrentAttacksPerSecond()
{
return 1f / GetCurrentAttackInterval();
}
public void RequestAbilityCast(BaseAbility ability, Action abilityExecution)
{
if (isCasting) return;
if (!ability.castableWhileMoving)
{
movementSpeedModifier.ToggleCastPenalty(true);
}
OnAbilityQueued.Invoke(ability);
StartCoroutine(Casting(ability, abilityExecution));
}
public void RequestAbilityChannel(BaseAbility channeledAbility, Action abilityChannelExecution)
{
if (isCasting) return;
if (!channeledAbility.castableWhileMoving)
{
movementSpeedModifier.ToggleCastPenalty(true);
}
OnAbilityQueued.Invoke(channeledAbility);
StartCoroutine(Channeling(channeledAbility, abilityChannelExecution));
}
private IEnumerator Casting(BaseAbility ability, Action abilityExecution)
{
isCasting = true;
// Use player attack speed instead of ability cast time
float castTime = GetCurrentAttackInterval();
CastBarHandler.Instance.ShowCastBar(ability, abilityExecution, castTime);
playerMovement.InstantFaceCast(projectileSpawnLocationController.GetLookat());
// Wait for the calculated attack interval
yield return new WaitForSeconds(castTime);
if (!GameConstants.Animation.IsAnimationEventBasedAbility(ability.animationType))
{
abilityExecution.Invoke();
}
isCasting = false;
if (!ability.castableWhileMoving)
{
movementSpeedModifier.ToggleCastPenalty(false);
}
}
private IEnumerator Channeling(BaseAbility channeledAbility, Action abilityChannelExecution)
{
isCasting = true;
// For channeled abilities, you might want different behavior
// This maintains the original channeling logic
CastBarHandler.Instance.ShowChannelingBar(channeledAbility, abilityChannelExecution);
playerMovement.InstantFaceCast(projectileSpawnLocationController.GetLookat());
abilityChannelExecution.Invoke();
if (!channeledAbility.castableWhileMoving)
{
movementSpeedModifier.ToggleCastPenalty(true);
}
yield return null;
}
public void ResetChannelingCast()
{
isCasting = false;
movementSpeedModifier.ToggleCastPenalty(false);
}
public void ResetCastingOnMeleeAnimationEvent()
{
isCasting = false;
movementSpeedModifier.ToggleCastPenalty(false);
StopAllCoroutines();
}
}