oecs-sharp/Game.CardWars/CardEffectRegistry.cs

96 lines
3.2 KiB
C#
Raw Normal View History

using OECS;
namespace Game.CardWars;
/// <summary>
/// A card effect that can be registered with the effect dispatcher.
/// </summary>
public interface ICardEffect
{
CardEffect Effect { get; }
/// <summary>
/// Called when the card is played face-up or flipped face-up.
/// Return true if fully resolved. Return false if a pending component
/// was set and the effect needs a player command to continue.
/// </summary>
bool Resolve(World world, Entity card, Entity player, Entity owner);
/// <summary>
/// Called when the player provides a choice to continue a pending effect.
/// The effect handler is responsible for reading the correct pending
/// component type from the singleton and removing it when done.
/// </summary>
bool ResolveChoice(World world, Entity target);
}
/// <summary>
/// Registry of card effects, ordered by registration.
/// </summary>
public static class CardEffectRegistry
{
private static readonly List<ICardEffect> _effects = new();
private static bool _frozen;
public static void Add<TEffect>() where TEffect : ICardEffect, new()
{
if (_frozen)
throw new InvalidOperationException("Cannot add effects after the registry is frozen.");
_effects.Add(new TEffect());
}
public static void Freeze() => _frozen = true;
/// <summary>
/// Resolve a card effect. Returns true if fully resolved.
/// </summary>
public static bool Dispatch(World world, CardEffect effect, Entity card, Entity player, Entity owner)
{
foreach (var e in _effects)
{
if (e.Effect == effect)
return e.Resolve(world, card, player, owner);
}
return true;
}
/// <summary>
/// Look up the handler for the currently pending effect and resolve it.
/// </summary>
public static bool DispatchChoice(World world, Entity target)
{
// Find which pending component is active and dispatch to the matching handler.
if (world.HasSingleton<PendingMercenary>())
return DispatchByEffect(world, CardEffect.Mercenary, target);
if (world.HasSingleton<PendingDancer>())
return DispatchByEffect(world, CardEffect.Dancer, target);
if (world.HasSingleton<PendingPaladin>())
return DispatchByEffect(world, CardEffect.Paladin, target);
if (world.HasSingleton<PendingNun>())
return DispatchByEffect(world, CardEffect.Nun, target);
if (world.HasSingleton<PendingScout>())
return DispatchByEffect(world, CardEffect.Scout, target);
if (world.HasSingleton<PendingPegasus>())
return DispatchByEffect(world, CardEffect.Pegasus, target);
if (world.HasSingleton<PendingCurseMaster>())
return DispatchByEffect(world, CardEffect.CurseMaster, target);
return true;
}
private static bool DispatchByEffect(World world, CardEffect effect, Entity target)
{
foreach (var e in _effects)
{
if (e.Effect == effect)
return e.ResolveChoice(world, target);
}
return true;
}
public static void ClearForTests()
{
_effects.Clear();
_frozen = false;
}
}