84 lines
3.2 KiB
C#
84 lines
3.2 KiB
C#
|
|
using Theriapolis.Core.Data;
|
||
|
|
using Theriapolis.Core.Rules.Combat;
|
||
|
|
using Theriapolis.Core.Rules.Stats;
|
||
|
|
using Theriapolis.Core.Util;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace Theriapolis.Tests.Combat;
|
||
|
|
|
||
|
|
public sealed class InitiativeTests
|
||
|
|
{
|
||
|
|
private readonly ContentResolver _content = new(new ContentLoader(TestHelpers.DataDirectory));
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void NewEncounter_AppendsInitiativeLogEntry()
|
||
|
|
{
|
||
|
|
var combatants = MakeThree();
|
||
|
|
var enc = new Encounter(0xCAFEUL, 1, combatants);
|
||
|
|
Assert.Contains(enc.Log, l => l.Type == CombatLogEntry.Kind.Initiative);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void InitiativeOrder_ContainsEveryCombatantExactlyOnce()
|
||
|
|
{
|
||
|
|
var combatants = MakeThree();
|
||
|
|
var enc = new Encounter(0xCAFEUL, 1, combatants);
|
||
|
|
Assert.Equal(combatants.Count, enc.InitiativeOrder.Count);
|
||
|
|
Assert.Equal(combatants.Count, enc.InitiativeOrder.Distinct().Count());
|
||
|
|
foreach (int idx in enc.InitiativeOrder)
|
||
|
|
Assert.InRange(idx, 0, combatants.Count - 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void EndTurn_AdvancesToNextLivingCombatant()
|
||
|
|
{
|
||
|
|
var combatants = MakeThree();
|
||
|
|
var enc = new Encounter(0xCAFEUL, 1, combatants);
|
||
|
|
var first = enc.CurrentActor;
|
||
|
|
enc.EndTurn();
|
||
|
|
Assert.NotEqual(first.Id, enc.CurrentActor.Id);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void EndTurn_WrappingIncrementsRoundCounter()
|
||
|
|
{
|
||
|
|
var combatants = MakeThree();
|
||
|
|
var enc = new Encounter(0xCAFEUL, 1, combatants);
|
||
|
|
Assert.Equal(1, enc.RoundNumber);
|
||
|
|
// Advance N turns to wrap once.
|
||
|
|
for (int i = 0; i < combatants.Count; i++) enc.EndTurn();
|
||
|
|
Assert.Equal(2, enc.RoundNumber);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void CheckForVictory_EndsWhenOnlyOneSideRemains()
|
||
|
|
{
|
||
|
|
var brigand = _content.Npcs.Templates.First(t => t.Id == "brigand_footpad");
|
||
|
|
var wolf = _content.Npcs.Templates.First(t => t.Id == "wolf");
|
||
|
|
var hero = Combatant.FromNpcTemplate(brigand, id: 1, new Vec2(0, 0));
|
||
|
|
var foe = Combatant.FromNpcTemplate(wolf, id: 2, new Vec2(1, 0));
|
||
|
|
// Force opposite allegiances. Brigand defaults Hostile; rebuild "hero" as Player-side.
|
||
|
|
hero = Combatant.FromNpcTemplate(brigand with { DefaultAllegiance = "player" }, id: 1, new Vec2(0, 0));
|
||
|
|
var enc = new Encounter(1UL, 1, new[] { hero, foe });
|
||
|
|
// Knock out the foe.
|
||
|
|
Resolver.ApplyDamage(foe, foe.MaxHp);
|
||
|
|
Assert.True(enc.CheckForVictory());
|
||
|
|
Assert.True(enc.IsOver);
|
||
|
|
Assert.Contains(enc.Log, l => l.Type == CombatLogEntry.Kind.EncounterEnd);
|
||
|
|
}
|
||
|
|
|
||
|
|
private List<Combatant> MakeThree()
|
||
|
|
{
|
||
|
|
var brigand = _content.Npcs.Templates.First(t => t.Id == "brigand_footpad");
|
||
|
|
var wolf = _content.Npcs.Templates.First(t => t.Id == "wolf");
|
||
|
|
var captain = _content.Npcs.Templates.First(t => t.Id == "brigand_captain");
|
||
|
|
// Mix allegiances so CheckForVictory doesn't end the encounter immediately.
|
||
|
|
return new List<Combatant>
|
||
|
|
{
|
||
|
|
Combatant.FromNpcTemplate(brigand with { DefaultAllegiance = "player" }, id: 1, new Vec2(0, 0)),
|
||
|
|
Combatant.FromNpcTemplate(wolf, id: 2, new Vec2(2, 0)),
|
||
|
|
Combatant.FromNpcTemplate(captain, id: 3, new Vec2(4, 0)),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|