Files
OTG_8/Assets/_Scripts/Talents/TalentManager.cs
T

269 lines
7.9 KiB
C#
Raw Normal View History

2026-06-04 23:22:13 +03:00
using System;
using System.Collections.Generic;
using OTGIntegrated.Core;
using OTGIntegrated.Stats;
using UnityEngine;
namespace OTGIntegrated.Talents
{
public sealed class TalentManager : MonoBehaviour
{
private const string TalentSourcePrefix = "Talent:";
public List<TalentData> allTalents = new List<TalentData>();
public int availableTalentPoints;
[SerializeField] private List<string> learnedTalentIds = new List<string>();
private PlayerStats playerStats;
private readonly Dictionary<string, TalentData> talentLookup = new Dictionary<string, TalentData>(StringComparer.Ordinal);
public event Action OnTalentStateChanged;
public IReadOnlyList<string> LearnedTalentIds => learnedTalentIds;
public void Initialize(PlayerStats stats)
{
playerStats = stats;
BuildLookup();
RebuildAllModifiers();
RaiseChanged();
}
private void Awake()
{
if (playerStats == null)
{
playerStats = GetComponent<PlayerStats>();
}
BuildLookup();
}
public bool IsLearned(TalentData talent)
{
return IsValidTalent(talent) && learnedTalentIds.Contains(talent.talentId);
}
public bool CanLearn(TalentData talent)
{
return IsValidTalent(talent) &&
!IsLearned(talent) &&
availableTalentPoints >= Mathf.Max(0, talent.cost) &&
ArePrerequisitesLearned(talent);
}
public bool ArePrerequisitesLearned(TalentData talent)
{
if (!IsValidTalent(talent))
{
return false;
}
if (talent.prerequisites == null || talent.prerequisites.Length == 0)
{
return true;
}
for (int i = 0; i < talent.prerequisites.Length; i++)
{
TalentData prerequisite = talent.prerequisites[i];
if (!IsValidTalent(prerequisite) || !IsLearned(prerequisite))
{
return false;
}
}
return true;
}
public bool LearnTalent(TalentData talent)
{
if (!IsValidTalent(talent))
{
GameEvents.RaiseNotification("Некорректный талант");
return false;
}
if (!CanLearn(talent))
{
GameEvents.RaiseNotification(GetBlockingReason(talent));
return false;
}
availableTalentPoints -= Mathf.Max(0, talent.cost);
learnedTalentIds.Add(talent.talentId);
ApplyTalentModifiers(talent);
GameEvents.RaiseTalentLearned(talent);
GameEvents.RaiseNotification($"Изучен талант: {talent.displayName}");
RaiseChanged();
return true;
}
public void AddTalentPoints(int amount)
{
if (amount <= 0)
{
return;
}
availableTalentPoints = Mathf.Max(0, availableTalentPoints + amount);
GameEvents.RaiseNotification(amount == 1 ? "Получено очко талантов" : $"Получено очков талантов: {amount}");
RaiseChanged();
}
public void SetTalentPoints(int points)
{
availableTalentPoints = Mathf.Max(0, points);
RaiseChanged();
}
public TalentData GetTalentById(string talentId)
{
BuildLookup();
if (string.IsNullOrWhiteSpace(talentId))
{
return null;
}
talentLookup.TryGetValue(talentId, out TalentData talent);
return talent;
}
public string GetBlockingReason(TalentData talent)
{
if (!IsValidTalent(talent))
{
return "Некорректные данные таланта";
}
if (IsLearned(talent))
{
return "Талант уже изучен";
}
if (!ArePrerequisitesLearned(talent))
{
return GetMissingPrerequisiteText(talent);
}
if (availableTalentPoints < Mathf.Max(0, talent.cost))
{
return "Недостаточно очков талантов";
}
return "Доступно";
}
public void LoadProgress(int points, List<string> learnedIds)
{
BuildLookup();
availableTalentPoints = Mathf.Max(0, points);
learnedTalentIds.Clear();
if (learnedIds != null)
{
for (int i = 0; i < learnedIds.Count; i++)
{
string id = learnedIds[i];
if (!string.IsNullOrWhiteSpace(id) && talentLookup.ContainsKey(id) && !learnedTalentIds.Contains(id))
{
learnedTalentIds.Add(id);
}
}
}
RebuildAllModifiers();
RaiseChanged();
}
public void ResetTalents()
{
learnedTalentIds.Clear();
availableTalentPoints = 0;
RebuildAllModifiers();
RaiseChanged();
}
public void RebuildAllModifiers()
{
if (playerStats == null)
{
return;
}
playerStats.RemoveModifiersBySourcePrefix(TalentSourcePrefix);
for (int i = 0; i < allTalents.Count; i++)
{
TalentData talent = allTalents[i];
if (IsLearned(talent))
{
ApplyTalentModifiers(talent);
}
}
playerStats.RecalculateStats();
}
private void ApplyTalentModifiers(TalentData talent)
{
if (!IsValidTalent(talent) || playerStats == null || talent.modifiers == null)
{
return;
}
string sourceId = TalentSourcePrefix + talent.talentId;
playerStats.RemoveModifiersBySource(sourceId);
for (int i = 0; i < talent.modifiers.Length; i++)
{
StatModifier modifier = talent.modifiers[i];
modifier.sourceId = sourceId;
playerStats.AddModifier(modifier);
}
}
private void BuildLookup()
{
talentLookup.Clear();
for (int i = 0; i < allTalents.Count; i++)
{
TalentData talent = allTalents[i];
if (IsValidTalent(talent))
{
talentLookup[talent.talentId] = talent;
}
}
}
private bool IsValidTalent(TalentData talent)
{
return talent != null && !string.IsNullOrWhiteSpace(talent.talentId);
}
private string GetMissingPrerequisiteText(TalentData talent)
{
if (talent.prerequisites == null)
{
return "Требования не выполнены";
}
for (int i = 0; i < talent.prerequisites.Length; i++)
{
TalentData prerequisite = talent.prerequisites[i];
if (!IsValidTalent(prerequisite) || !IsLearned(prerequisite))
{
return prerequisite != null ? $"Требуется: {prerequisite.displayName}" : "Требуется другой талант";
}
}
return "Требования не выполнены";
}
private void RaiseChanged()
{
GameEvents.RaiseTalentPointChanged(availableTalentPoints);
OnTalentStateChanged?.Invoke();
}
}
}