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;
|
|
}
|
|
}
|
|
}
|