Files

100 lines
3.6 KiB
C#
Raw Permalink Normal View History

using Theriapolis.Core.Data;
using Theriapolis.Core.Rules.Character;
using Theriapolis.Core.Rules.Combat;
using Theriapolis.Core.Rules.Stats;
using Theriapolis.Core.Util;
using Xunit;
namespace Theriapolis.Tests.Combat;
public sealed class ReachAndCoverTests
{
private readonly ContentResolver _content = new(new ContentLoader(TestHelpers.DataDirectory));
[Fact]
public void EdgeToEdge_Adjacent_ReturnsZero()
{
var a = MakeMediumNpc(new Vec2(5, 5));
var b = MakeMediumNpc(new Vec2(6, 5));
Assert.Equal(0, ReachAndCover.EdgeToEdgeChebyshev(a, b));
}
[Fact]
public void EdgeToEdge_OneTileApart_ReturnsOne()
{
var a = MakeMediumNpc(new Vec2(5, 5));
var b = MakeMediumNpc(new Vec2(7, 5)); // 1 empty tile between
Assert.Equal(1, ReachAndCover.EdgeToEdgeChebyshev(a, b));
}
[Fact]
public void EdgeToEdge_LargeAttacker_FootprintCountedCorrectly()
{
var large = MakeLargeNpc(new Vec2(0, 0)); // occupies (0..1, 0..1)
var medium = MakeMediumNpc(new Vec2(3, 0)); // 1 empty tile between (large's right edge = 1, medium = 3)
Assert.Equal(1, ReachAndCover.EdgeToEdgeChebyshev(large, medium));
}
[Fact]
public void IsInReach_MeleeAdjacent_True()
{
var a = MakeMediumNpc(new Vec2(0, 0));
var b = MakeMediumNpc(new Vec2(1, 0));
var attack = new AttackOption { Name = "Bite", Damage = new DamageRoll(1, 4, 0, DamageType.Piercing), ReachTiles = 1 };
Assert.True(ReachAndCover.IsInReach(a, b, attack));
}
[Fact]
public void IsInReach_MeleeOutOfReach_False()
{
var a = MakeMediumNpc(new Vec2(0, 0));
var b = MakeMediumNpc(new Vec2(3, 0));
var attack = new AttackOption { Name = "Bite", Damage = new DamageRoll(1, 4, 0, DamageType.Piercing), ReachTiles = 1 };
Assert.False(ReachAndCover.IsInReach(a, b, attack));
}
[Fact]
public void IsInReach_RangedShortRange_True()
{
var a = MakeMediumNpc(new Vec2(0, 0));
var b = MakeMediumNpc(new Vec2(8, 0));
var bow = new AttackOption { Name = "Bow", Damage = new DamageRoll(1, 6, 0, DamageType.Piercing),
RangeShortTiles = 16, RangeLongTiles = 64 };
Assert.True(ReachAndCover.IsInReach(a, b, bow));
Assert.False(ReachAndCover.IsLongRange(a, b, bow));
}
[Fact]
public void IsInReach_RangedLongRange_TrueWithLongRangeFlag()
{
var a = MakeMediumNpc(new Vec2(0, 0));
var b = MakeMediumNpc(new Vec2(40, 0));
var bow = new AttackOption { Name = "Bow", Damage = new DamageRoll(1, 6, 0, DamageType.Piercing),
RangeShortTiles = 16, RangeLongTiles = 64 };
Assert.True(ReachAndCover.IsInReach(a, b, bow));
Assert.True(ReachAndCover.IsLongRange(a, b, bow));
}
[Fact]
public void StepToward_MovesOneTileTowardGoal()
{
var step = ReachAndCover.StepToward(new Vec2(0, 0), new Vec2(5, 3));
Assert.Equal(1, step.X);
Assert.Equal(1, step.Y);
}
[Fact]
public void StepToward_AtGoal_ReturnsSamePosition()
{
var step = ReachAndCover.StepToward(new Vec2(5, 5), new Vec2(5, 5));
Assert.Equal(5, step.X);
Assert.Equal(5, step.Y);
}
private Combatant MakeMediumNpc(Vec2 pos)
=> Combatant.FromNpcTemplate(_content.Npcs.Templates.First(t => t.Id == "wolf"), id: 1, pos);
private Combatant MakeLargeNpc(Vec2 pos)
=> Combatant.FromNpcTemplate(_content.Npcs.Templates.First(t => t.Id == "bear_brown"), id: 2, pos);
}