143 lines
4.4 KiB
C#
143 lines
4.4 KiB
C#
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|