212 lines
6.0 KiB
C#
212 lines
6.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using YachtDice.Modifiers.Definition;
|
|
|
|
namespace YachtDice.Modifiers.Runtime
|
|
{
|
|
public class ModifierRegistry
|
|
{
|
|
private readonly List<ModifierInstance> _instances = new();
|
|
private readonly List<ModifierInstance> _activeCache = new();
|
|
private int _maxActiveSlots;
|
|
private bool _activeCacheDirty = true;
|
|
|
|
public event Action OnChanged;
|
|
public event Action<IReadOnlyList<ModifierInstance>> OnActiveModifiersChanged;
|
|
|
|
public IReadOnlyList<ModifierInstance> All => _instances;
|
|
public int MaxActiveSlots => _maxActiveSlots;
|
|
|
|
public ModifierRegistry(int maxActiveSlots = 5)
|
|
{
|
|
this._maxActiveSlots = maxActiveSlots;
|
|
}
|
|
|
|
public IReadOnlyList<ModifierInstance> Active
|
|
{
|
|
get
|
|
{
|
|
if (_activeCacheDirty)
|
|
RebuildActiveCache();
|
|
return _activeCache;
|
|
}
|
|
}
|
|
|
|
public int ActiveCount
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < _instances.Count; i++)
|
|
if (_instances[i].IsActive) count++;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public void SetMaxActiveSlots(int slots)
|
|
{
|
|
_maxActiveSlots = slots;
|
|
}
|
|
|
|
public ModifierInstance Add(ModifierDefinition definition)
|
|
{
|
|
var instance = new ModifierInstance(definition);
|
|
_instances.Add(instance);
|
|
_activeCacheDirty = true;
|
|
OnChanged?.Invoke();
|
|
return instance;
|
|
}
|
|
|
|
public void Remove(ModifierInstance instance)
|
|
{
|
|
if (!_instances.Contains(instance)) return;
|
|
|
|
bool wasActive = instance.IsActive;
|
|
instance.IsActive = false;
|
|
_instances.Remove(instance);
|
|
_activeCacheDirty = true;
|
|
|
|
if (wasActive)
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
|
|
OnChanged?.Invoke();
|
|
}
|
|
|
|
public bool TryActivate(ModifierInstance instance)
|
|
{
|
|
if (instance.IsActive) return false;
|
|
if (!_instances.Contains(instance)) return false;
|
|
if (ActiveCount >= _maxActiveSlots) return false;
|
|
|
|
instance.IsActive = true;
|
|
_activeCacheDirty = true;
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
OnChanged?.Invoke();
|
|
return true;
|
|
}
|
|
|
|
public void Deactivate(ModifierInstance instance)
|
|
{
|
|
if (!instance.IsActive) return;
|
|
|
|
instance.IsActive = false;
|
|
_activeCacheDirty = true;
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
OnChanged?.Invoke();
|
|
}
|
|
|
|
public void ConsumeChargesOnActive()
|
|
{
|
|
bool changed = false;
|
|
|
|
for (int i = _instances.Count - 1; i >= 0; i--)
|
|
{
|
|
var inst = _instances[i];
|
|
if (!inst.IsActive) continue;
|
|
if (!inst.Definition.HasLimitedUses) continue;
|
|
|
|
inst.ConsumeCharge();
|
|
|
|
if (inst.IsExpired)
|
|
{
|
|
_instances.RemoveAt(i);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
_activeCacheDirty = true;
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
OnChanged?.Invoke();
|
|
}
|
|
}
|
|
|
|
public List<ModifierSaveEntry> GetSaveData()
|
|
{
|
|
var entries = new List<ModifierSaveEntry>();
|
|
for (int i = 0; i < _instances.Count; i++)
|
|
{
|
|
var inst = _instances[i];
|
|
var entry = new ModifierSaveEntry
|
|
{
|
|
modifierId = inst.Definition.Id,
|
|
isActive = inst.IsActive,
|
|
remainingUses = inst.RemainingUses,
|
|
stacks = inst.Stacks,
|
|
};
|
|
|
|
foreach (var kvp in inst.CustomState)
|
|
{
|
|
entry.customState.Add(new CustomStateEntry
|
|
{
|
|
key = kvp.Key,
|
|
value = kvp.Value,
|
|
});
|
|
}
|
|
|
|
entries.Add(entry);
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
public void LoadSaveData(List<ModifierSaveEntry> entries, ModifierCatalog catalog)
|
|
{
|
|
_instances.Clear();
|
|
_activeCacheDirty = true;
|
|
|
|
if (entries == null) return;
|
|
|
|
for (int i = 0; i < entries.Count; i++)
|
|
{
|
|
var entry = entries[i];
|
|
var definition = catalog.FindById(entry.modifierId);
|
|
|
|
if (definition == null)
|
|
{
|
|
Debug.LogWarning($"Modifier '{entry.modifierId}' not found in catalog, skipping.");
|
|
continue;
|
|
}
|
|
|
|
var instance = new ModifierInstance(definition)
|
|
{
|
|
IsActive = entry.isActive,
|
|
RemainingUses = entry.remainingUses,
|
|
Stacks = entry.stacks,
|
|
};
|
|
|
|
if (entry.customState != null)
|
|
{
|
|
foreach (var cs in entry.customState)
|
|
instance.CustomState[cs.key] = cs.value;
|
|
}
|
|
|
|
_instances.Add(instance);
|
|
}
|
|
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
OnChanged?.Invoke();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
_instances.Clear();
|
|
_activeCacheDirty = true;
|
|
OnActiveModifiersChanged?.Invoke(Active);
|
|
OnChanged?.Invoke();
|
|
}
|
|
|
|
private void RebuildActiveCache()
|
|
{
|
|
_activeCache.Clear();
|
|
for (int i = 0; i < _instances.Count; i++)
|
|
{
|
|
if (_instances[i].IsActive)
|
|
_activeCache.Add(_instances[i]);
|
|
}
|
|
_activeCacheDirty = false;
|
|
}
|
|
}
|
|
}
|