feat(CS-P3): throne capture + settlement winner in state machine + tests
Some checks failed
.NET Core / build (push) Has been cancelled
Some checks failed
.NET Core / build (push) Has been cancelled
This commit is contained in:
@@ -12,6 +12,7 @@ public class CastleSiegeContext
|
|||||||
{
|
{
|
||||||
private readonly List<string> _registeredGuilds = new();
|
private readonly List<string> _registeredGuilds = new();
|
||||||
private DateTime _phaseStartedUtc;
|
private DateTime _phaseStartedUtc;
|
||||||
|
private string? _occupier;
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the <see cref="CastleSiegeContext"/> class.</summary>
|
/// <summary>Initializes a new instance of the <see cref="CastleSiegeContext"/> class.</summary>
|
||||||
/// <param name="configuration">The cycle timing configuration.</param>
|
/// <param name="configuration">The cycle timing configuration.</param>
|
||||||
@@ -36,6 +37,9 @@ public class CastleSiegeContext
|
|||||||
/// <summary>Gets the guild names registered for the current cycle.</summary>
|
/// <summary>Gets the guild names registered for the current cycle.</summary>
|
||||||
public IReadOnlyList<string> RegisteredGuilds => this._registeredGuilds;
|
public IReadOnlyList<string> RegisteredGuilds => this._registeredGuilds;
|
||||||
|
|
||||||
|
/// <summary>Gets the guild currently holding the throne during the siege (P3), or null.</summary>
|
||||||
|
public string? OccupierGuildName => this._occupier;
|
||||||
|
|
||||||
/// <summary>Advances the state machine based on the current time.</summary>
|
/// <summary>Advances the state machine based on the current time.</summary>
|
||||||
/// <param name="now">The current UTC time.</param>
|
/// <param name="now">The current UTC time.</param>
|
||||||
public ValueTask TickAsync(DateTime now)
|
public ValueTask TickAsync(DateTime now)
|
||||||
@@ -71,7 +75,13 @@ public class CastleSiegeContext
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case CastleSiegePhase.Settlement:
|
case CastleSiegePhase.Settlement:
|
||||||
// P1: no battle -> no winner determination yet. Settle immediately back to ownership.
|
// Winner = guild holding the throne at siege end (P3). If none captured, owner unchanged.
|
||||||
|
if (this._occupier is { } occupier)
|
||||||
|
{
|
||||||
|
this.SetOwner(occupier);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._occupier = null;
|
||||||
return this.TransitionAsync(CastleSiegePhase.Ownership, now);
|
return this.TransitionAsync(CastleSiegePhase.Ownership, now);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -85,6 +95,7 @@ public class CastleSiegeContext
|
|||||||
public ValueTask ForceStartRegistrationAsync(DateTime now)
|
public ValueTask ForceStartRegistrationAsync(DateTime now)
|
||||||
{
|
{
|
||||||
this._registeredGuilds.Clear();
|
this._registeredGuilds.Clear();
|
||||||
|
this._occupier = null;
|
||||||
return this.TransitionAsync(CastleSiegePhase.Registration, now);
|
return this.TransitionAsync(CastleSiegePhase.Registration, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +110,7 @@ public class CastleSiegeContext
|
|||||||
public ValueTask ResetAsync(DateTime now)
|
public ValueTask ResetAsync(DateTime now)
|
||||||
{
|
{
|
||||||
this._registeredGuilds.Clear();
|
this._registeredGuilds.Clear();
|
||||||
|
this._occupier = null;
|
||||||
return this.TransitionAsync(CastleSiegePhase.Ownership, now);
|
return this.TransitionAsync(CastleSiegePhase.Ownership, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +129,16 @@ public class CastleSiegeContext
|
|||||||
/// <param name="guildName">The owner guild name, or null to clear.</param>
|
/// <param name="guildName">The owner guild name, or null to clear.</param>
|
||||||
public void SetOwner(string? guildName) => this.OwnerGuildName = guildName;
|
public void SetOwner(string? guildName) => this.OwnerGuildName = guildName;
|
||||||
|
|
||||||
|
/// <summary>P3: a registered guild captures the throne during the siege. No-op outside the siege phase.</summary>
|
||||||
|
/// <param name="guildName">The capturing guild's name.</param>
|
||||||
|
public void CaptureThrone(string guildName)
|
||||||
|
{
|
||||||
|
if (this.Phase == CastleSiegePhase.Siege)
|
||||||
|
{
|
||||||
|
this._occupier = guildName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Returns a human-readable status summary for admin display.</summary>
|
/// <summary>Returns a human-readable status summary for admin display.</summary>
|
||||||
public string GetStatusText()
|
public string GetStatusText()
|
||||||
=> $"CS phase={this.Phase}, owner={this.OwnerGuildName ?? "(none)"}, "
|
=> $"CS phase={this.Phase}, owner={this.OwnerGuildName ?? "(none)"}, "
|
||||||
|
|||||||
@@ -67,6 +67,30 @@ public class CastleSiegeContextTest
|
|||||||
Assert.That(ctx.RegisteredGuilds, Does.Contain("Attackers"));
|
Assert.That(ctx.RegisteredGuilds, Does.Contain("Attackers"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests that the throne-holding guild at siege end becomes the owner on settlement (P3).</summary>
|
||||||
|
[Test]
|
||||||
|
public async Task ThroneCaptureDuringSiegeBecomesOwnerOnSettlementAsync()
|
||||||
|
{
|
||||||
|
var ctx = new CastleSiegeContext(Config());
|
||||||
|
await ctx.ForceStartRegistrationAsync(T0);
|
||||||
|
await ctx.ForcePhaseAsync(CastleSiegePhase.Siege, T0);
|
||||||
|
ctx.CaptureThrone("Attackers");
|
||||||
|
Assert.That(ctx.OccupierGuildName, Is.EqualTo("Attackers"));
|
||||||
|
await ctx.TickAsync(T0.AddMinutes(20)); // Siege -> Settlement
|
||||||
|
await ctx.TickAsync(T0.AddMinutes(20)); // Settlement -> Ownership (owner assigned)
|
||||||
|
Assert.That(ctx.Phase, Is.EqualTo(CastleSiegePhase.Ownership));
|
||||||
|
Assert.That(ctx.OwnerGuildName, Is.EqualTo("Attackers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests that capturing the throne outside the siege phase is a no-op.</summary>
|
||||||
|
[Test]
|
||||||
|
public void CaptureThroneOutsideSiegeIsNoOp()
|
||||||
|
{
|
||||||
|
var ctx = new CastleSiegeContext(Config());
|
||||||
|
ctx.CaptureThrone("Attackers");
|
||||||
|
Assert.That(ctx.OccupierGuildName, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
private static CastleSiegeConfiguration Config() => new()
|
private static CastleSiegeConfiguration Config() => new()
|
||||||
{
|
{
|
||||||
RegistrationDuration = TimeSpan.FromMinutes(5),
|
RegistrationDuration = TimeSpan.FromMinutes(5),
|
||||||
|
|||||||
Reference in New Issue
Block a user