Battle unit gauges extension point; battle action schemas

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cthangoverandClaude Opus 5.5 committed 2026-10-24 10:01:08 +02:00
1 parent 44462624cd
commit d2f710a6a1
12 files changed
+231

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
namespace Cthangover.Core.Battle
{
/// <summary>
/// One extra bar of a battle unit next to its health (mana, rage, ammo…), as an
/// <see cref="IBattleUnitGauge"/> reads it at this moment.
/// </summary>
public class BattleGauge
{
/// <summary>Stable id (a stat id, for example) the cores key their rows by.</summary>
public string Id { get; set; }
/// <summary>Short label, a locale key or plain text ("MP").</summary>
public string Label { get; set; }
/// <summary>Current value.</summary>
public int Current { get; set; }
/// <summary>Maximum; a bar with Max &lt;= 0 is not drawn.</summary>
public int Max { get; set; }
/// <summary>Fill colour as HTML ("#4a8cff"); null = the theme's info colour.</summary>
public string Color { get; set; }
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Cthangover.Core.Battle
{
using Cthangover.Core.Mods.Consumers;
/// <summary>Registers every <see cref="IBattleUnitGauge"/> of a loaded mod assembly in <see cref="BattleUnitGauges"/>.</summary>
public class BattleUnitGaugeConsumer : ModTypeConsumer<IBattleUnitGauge>
{
/// <inheritdoc />
public override string Id => "turn_battle_base.unit_gauges";
/// <inheritdoc />
protected override void Add(IBattleUnitGauge instance, string modId) => BattleUnitGauges.Add(instance);
/// <inheritdoc />
protected override void Remove(IBattleUnitGauge instance, string modId) => BattleUnitGauges.Remove(instance);
}
}
+54
View File
@@ -0,0 +1,54 @@
namespace Cthangover.Core.Battle
{
using System;
using System.Collections.Generic;
using System.Linq;
using Cthangover.Core.Characters;
using Cthangover.Core.Utils;
/// <summary>
/// The registered <see cref="IBattleUnitGauge"/>s and the bars they give for a unit. A
/// provider calls <see cref="NotifyChanged"/> when a value moved (mana spent), so the
/// cores redraw that unit; cores also read the bars whenever they redraw it themselves.
/// </summary>
public static class BattleUnitGauges
{
private static readonly List<IBattleUnitGauge> Providers = new();
/// <summary>Raised with a unit id (null = every unit) when its bars changed.</summary>
public static event Action<string> Changed;
/// <summary>Registers a provider.</summary>
public static void Add(IBattleUnitGauge gauge)
{
if (gauge != null && !Providers.Contains(gauge))
Providers.Add(gauge);
}
/// <summary>Removes a provider (its mod is unloaded).</summary>
public static void Remove(IBattleUnitGauge gauge) => Providers.Remove(gauge);
/// <summary>Every bar of <paramref name="unit"/> with a positive maximum, providers in order; a failing provider is logged and skipped.</summary>
public static List<BattleGauge> Read(Character unit)
{
var result = new List<BattleGauge>();
if (unit == null)
return result;
foreach (var provider in Providers.OrderBy(p => p.Order).ToList())
{
try
{
result.AddRange((provider.Read(unit) ?? Enumerable.Empty<BattleGauge>()).Where(g => g != null && g.Max > 0));
}
catch (Exception ex)
{
GameLogger.Log("BATTLE", $"gauge provider {provider.GetType().Name} failed for '{unit.ID}': {ex.Message}", LogLevel.Error);
}
}
return result;
}
/// <summary>Tells the cores that the bars of <paramref name="unitId"/> changed.</summary>
public static void NotifyChanged(string unitId) => Changed?.Invoke(unitId);
}
}
+20
View File
@@ -0,0 +1,20 @@
namespace Cthangover.Core.Battle
{
using System.Collections.Generic;
using Cthangover.Core.Characters;
/// <summary>
/// Supplies extra bars of battle units (found in mod assemblies by
/// <see cref="BattleUnitGaugeConsumer"/>): a mod that adds a resource — mana of
/// <c>battle_formulas</c>, a rage meter — shows it in every battle core that draws
/// <see cref="BattleUnitGauges"/>, without knowing the cores.
/// </summary>
public interface IBattleUnitGauge
{
/// <summary>Order among the providers (lower first).</summary>
int Order { get; }
/// <summary>The bars of <paramref name="unit"/> now; empty when it has none.</summary>
IEnumerable<BattleGauge> Read(Character unit);
}
}