Files

143 lines
4.4 KiB
C#
Raw Permalink Normal View History

2026-06-04 21:37:43 +03:00
using System;
using System.Collections.Generic;
using OTG.Lab06.Characters;
using UnityEngine;
namespace OTG.Lab06.Abilities
{
public sealed class AbilityManager : MonoBehaviour
{
[SerializeField] private PlayerStats playerStats;
[SerializeField] private Transform castOrigin;
[SerializeField] private List<AbilityData> learnedAbilities = new List<AbilityData>();
private readonly List<AbilityRuntime> runtimes = new List<AbilityRuntime>();
public event Action<IReadOnlyList<AbilityRuntime>> AbilitiesChanged;
public event Action ResourcesChanged;
public IReadOnlyList<AbilityRuntime> Abilities => runtimes;
private void Awake()
{
if (playerStats == null)
{
playerStats = GetComponent<PlayerStats>();
}
if (castOrigin == null)
{
castOrigin = transform;
}
RebuildRuntime();
}
private void Update()
{
for (int i = 0; i < runtimes.Count; i++)
{
runtimes[i].Tick(Time.deltaTime);
}
HandleHotkeys();
AbilitiesChanged?.Invoke(runtimes);
}
public void SetLearnedAbilities(IEnumerable<AbilityData> abilities)
{
learnedAbilities.Clear();
learnedAbilities.AddRange(abilities);
RebuildRuntime();
}
public bool TryCast(int abilityIndex)
{
if (abilityIndex < 0 || abilityIndex >= runtimes.Count)
{
return false;
}
AbilityRuntime runtime = runtimes[abilityIndex];
AbilityData ability = runtime.Data;
if (ability == null || !runtime.IsReady || playerStats == null || !playerStats.SpendMana(ability.manaCost))
{
return false;
}
if (ability.effectPrefab == null)
{
Debug.LogWarning($"Ability '{ability.abilityName}' has no effect prefab.", ability);
playerStats.RestoreMana(ability.manaCost);
return false;
}
Quaternion rotation = Quaternion.LookRotation(GetCastForward(), Vector3.up);
GameObject effectObject = Instantiate(ability.effectPrefab, GetCastOrigin(), rotation);
AbilityEffect effect = effectObject.GetComponent<AbilityEffect>();
if (effect == null)
{
Debug.LogWarning($"Ability prefab '{ability.effectPrefab.name}' has no AbilityEffect component.", ability.effectPrefab);
Destroy(effectObject);
playerStats.RestoreMana(ability.manaCost);
return false;
}
var context = new AbilityCastContext(ability, transform, playerStats, GetCastOrigin(), GetCastForward());
effect.Activate(context);
runtime.StartCooldown();
ResourcesChanged?.Invoke();
AbilitiesChanged?.Invoke(runtimes);
return true;
}
private void RebuildRuntime()
{
runtimes.Clear();
foreach (AbilityData ability in learnedAbilities)
{
if (ability != null)
{
runtimes.Add(new AbilityRuntime(ability));
}
}
AbilitiesChanged?.Invoke(runtimes);
}
private void HandleHotkeys()
{
for (int i = 0; i < runtimes.Count && i < 9; i++)
{
if (Input.GetKeyDown((KeyCode)((int)KeyCode.Alpha1 + i)))
{
TryCast(i);
}
}
}
private Vector3 GetCastOrigin()
{
return castOrigin == null ? transform.position + Vector3.up : castOrigin.position;
}
private Vector3 GetCastForward()
{
if (Camera.main != null)
{
Vector3 cameraForward = Camera.main.transform.forward;
cameraForward.y = 0f;
if (cameraForward.sqrMagnitude > 0.01f)
{
return cameraForward.normalized;
}
}
Vector3 forward = transform.forward;
forward.y = 0f;
return forward.sqrMagnitude <= 0.01f ? Vector3.forward : forward.normalized;
}
}
}