first commit
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OTGIntegrated.Core;
|
||||
using OTGIntegrated.Player;
|
||||
using OTGIntegrated.Stats;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Abilities
|
||||
{
|
||||
public sealed class AbilityManager : MonoBehaviour
|
||||
{
|
||||
public List<AbilityData> learnedAbilities = new List<AbilityData>();
|
||||
public Transform castOrigin;
|
||||
|
||||
private readonly List<float> cooldownRemaining = new List<float>();
|
||||
private PlayerStats playerStats;
|
||||
private PlayerController playerController;
|
||||
|
||||
public event Action OnAbilitiesChanged;
|
||||
public IReadOnlyList<AbilityData> LearnedAbilities => learnedAbilities;
|
||||
|
||||
public void Initialize(PlayerStats stats)
|
||||
{
|
||||
playerStats = stats != null ? stats : GetComponent<PlayerStats>();
|
||||
playerController = GetComponent<PlayerController>();
|
||||
if (castOrigin == null)
|
||||
{
|
||||
castOrigin = transform;
|
||||
}
|
||||
|
||||
EnsureCooldownSlots();
|
||||
OnAbilitiesChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (playerStats == null)
|
||||
{
|
||||
playerStats = GetComponent<PlayerStats>();
|
||||
}
|
||||
|
||||
playerController = GetComponent<PlayerController>();
|
||||
EnsureCooldownSlots();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TickCooldowns();
|
||||
|
||||
if (playerController != null && !playerController.InputEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1)) TryUseAbility(0);
|
||||
if (Input.GetKeyDown(KeyCode.Alpha2)) TryUseAbility(1);
|
||||
if (Input.GetKeyDown(KeyCode.Alpha3)) TryUseAbility(2);
|
||||
}
|
||||
|
||||
public bool TryUseAbility(int index)
|
||||
{
|
||||
EnsureCooldownSlots();
|
||||
if (index < 0 || index >= learnedAbilities.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AbilityData ability = learnedAbilities[index];
|
||||
if (ability == null || playerStats == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cooldownRemaining[index] > 0f)
|
||||
{
|
||||
GameEvents.RaiseNotification("Способность на перезарядке");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!playerStats.SpendMana(ability.manaCost))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ability.effectPrefab == null)
|
||||
{
|
||||
playerStats.RestoreMana(ability.manaCost);
|
||||
Debug.LogWarning($"Ability has no effect prefab: {ability.displayName}", ability);
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 forward = GetCastForward();
|
||||
Vector3 origin = castOrigin != null ? castOrigin.position : transform.position + Vector3.up;
|
||||
GameObject effectObject = Instantiate(ability.effectPrefab, origin, Quaternion.LookRotation(forward, Vector3.up));
|
||||
AbilityEffect effect = effectObject.GetComponent<AbilityEffect>();
|
||||
if (effect == null)
|
||||
{
|
||||
playerStats.RestoreMana(ability.manaCost);
|
||||
Destroy(effectObject);
|
||||
Debug.LogWarning($"Ability effect prefab misses AbilityEffect: {ability.effectPrefab.name}", ability.effectPrefab);
|
||||
return false;
|
||||
}
|
||||
|
||||
effect.Activate(new AbilityContext(ability, transform, playerStats, origin, forward));
|
||||
cooldownRemaining[index] = GetEffectiveCooldown(ability);
|
||||
GameEvents.RaiseAbilityUsed(ability);
|
||||
GameEvents.RaiseNotification($"Способность: {ability.displayName}");
|
||||
OnAbilitiesChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public float GetCooldownRemaining(int index)
|
||||
{
|
||||
EnsureCooldownSlots();
|
||||
return index >= 0 && index < cooldownRemaining.Count ? cooldownRemaining[index] : 0f;
|
||||
}
|
||||
|
||||
public float GetCooldownNormalized(int index)
|
||||
{
|
||||
if (index < 0 || index >= learnedAbilities.Count || learnedAbilities[index] == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float cooldown = GetEffectiveCooldown(learnedAbilities[index]);
|
||||
return cooldown <= 0f ? 0f : Mathf.Clamp01(GetCooldownRemaining(index) / cooldown);
|
||||
}
|
||||
|
||||
private float GetEffectiveCooldown(AbilityData ability)
|
||||
{
|
||||
float reduction = playerStats != null ? playerStats.CooldownReduction : 0f;
|
||||
return Mathf.Max(0f, ability.cooldown * (1f - Mathf.Clamp(reduction, 0f, 0.9f)));
|
||||
}
|
||||
|
||||
private void TickCooldowns()
|
||||
{
|
||||
EnsureCooldownSlots();
|
||||
bool changed = false;
|
||||
for (int i = 0; i < cooldownRemaining.Count; i++)
|
||||
{
|
||||
if (cooldownRemaining[i] <= 0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cooldownRemaining[i] = Mathf.Max(0f, cooldownRemaining[i] - Time.deltaTime);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
OnAbilitiesChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCooldownSlots()
|
||||
{
|
||||
while (cooldownRemaining.Count < learnedAbilities.Count)
|
||||
{
|
||||
cooldownRemaining.Add(0f);
|
||||
}
|
||||
|
||||
while (cooldownRemaining.Count > learnedAbilities.Count)
|
||||
{
|
||||
cooldownRemaining.RemoveAt(cooldownRemaining.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 GetCastForward()
|
||||
{
|
||||
if (playerController != null)
|
||||
{
|
||||
return playerController.GetAimForward();
|
||||
}
|
||||
|
||||
Vector3 forward = transform.forward;
|
||||
forward.y = 0f;
|
||||
return forward.sqrMagnitude > 0.001f ? forward.normalized : Vector3.forward;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user