//
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
namespace MUnique.OpenMU.Tests;
using Moq;
using MUnique.OpenMU.GameLogic;
using MUnique.OpenMU.GameLogic.PlayerActions.Skills;
using MUnique.OpenMU.Pathfinding;
///
/// Tests for the .
///
[TestFixture]
internal class FrustumBasedTargetFilterTest
{
///
/// Tests that a single projectile can hit a target in the center of the frustum.
///
[Test]
public void SingleProjectile_TargetInCenter_CanHit()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 1);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(100, 105); // Directly in front (positive Y)
// Rotation 128 points in +Y direction (180 degrees in 0-255 system)
var result = filter.IsTargetWithinBounds(attacker, target, 128, 0);
Assert.That(result, Is.True);
}
///
/// Tests that with triple shot, a target directly in front can be hit by the all projectiles.
///
[Test]
public void TripleShot_TargetNear_CanBeHitByAllProjectiles()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(100, 101);
// Rotation 128 points in +Y direction
// Check if all projectiles can hit
Assert.That(filter.IsTargetWithinBounds(attacker, target, 128, 0), Is.True);
Assert.That(filter.IsTargetWithinBounds(attacker, target, 128, 1), Is.True);
Assert.That(filter.IsTargetWithinBounds(attacker, target, 128, 2), Is.True);
}
///
/// Tests that with triple shot, a target in the center can be hit by the center projectile.
///
[Test]
public void TripleShot_TargetInCenter_CanBeHitByCenterProjectile()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(100, 105); // Directly in front (positive Y)
// Rotation 128 points in +Y direction
// Check if the center projectile (index 1) can hit
var result = filter.IsTargetWithinBounds(attacker, target, 128, 1);
Assert.That(result, Is.True);
}
///
/// Tests that with triple shot, a target on the left side can be hit by the left projectile.
///
[Test]
public void TripleShot_TargetOnLeft_CanBeHitByLeftProjectile()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(98, 105); // To the left and in front (2 units left, within frustum)
// Rotation 128 points in +Y direction
// Left projectile should be able to hit (index 0)
var leftResult = filter.IsTargetWithinBounds(attacker, target, 128, 0);
Assert.That(leftResult, Is.True);
// Right projectile should NOT be able to hit (index 2)
var rightResult = filter.IsTargetWithinBounds(attacker, target, 128, 2);
Assert.That(rightResult, Is.False);
}
///
/// Tests that with triple shot, a target on the right side can be hit by the right projectile.
///
[Test]
public void TripleShot_TargetOnRight_CanBeHitByRightProjectile()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(102, 105); // To the right and in front (2 units right, within frustum)
// Rotation 128 points in +Y direction
// Right projectile should be able to hit (index 2)
var rightResult = filter.IsTargetWithinBounds(attacker, target, 128, 2);
Assert.That(rightResult, Is.True);
// Left projectile should NOT be able to hit (index 0)
var leftResult = filter.IsTargetWithinBounds(attacker, target, 128, 0);
Assert.That(leftResult, Is.False);
}
///
/// Tests that a target outside the frustum cannot be hit by any projectile.
///
[Test]
public void TripleShot_TargetOutsideFrustum_CannotBeHit()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(110, 105); // Far to the right, outside frustum
// Rotation 128 points in +Y direction
// No projectile should be able to hit
for (int i = 0; i < 3; i++)
{
var result = filter.IsTargetWithinBounds(attacker, target, 128, i);
Assert.That(result, Is.False, $"Projectile {i} should not hit target outside frustum");
}
}
///
/// Tests that the old IsTargetWithinBounds method still works for backward compatibility.
///
[Test]
public void IsTargetWithinBounds_TargetInFrustum_ReturnsTrue()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(100, 105); // Directly in front
// Rotation 128 points in +Y direction
var result = filter.IsTargetWithinBounds(attacker, target, 128);
Assert.That(result, Is.True);
}
///
/// Tests that the old IsTargetWithinBounds method returns false for targets outside the frustum.
///
[Test]
public void IsTargetWithinBounds_TargetOutsideFrustum_ReturnsFalse()
{
var filter = new FrustumBasedTargetFilter(1f, 4.5f, 7f, 3);
var attacker = CreateLocateable(100, 100);
var target = CreateLocateable(110, 105); // Far to the right, outside frustum
// Rotation 128 points in +Y direction
var result = filter.IsTargetWithinBounds(attacker, target, 128);
Assert.That(result, Is.False);
}
private static ILocateable CreateLocateable(byte x, byte y)
{
var mock = new Mock();
mock.Setup(l => l.Position).Returns(new Point(x, y));
return mock.Object;
}
}