269 lines
9.2 KiB
C#
269 lines
9.2 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using NeonSprawl.Server.Game.AbilityInput;
|
|
using NeonSprawl.Server.Game.Combat;
|
|
using NeonSprawl.Server.Game.Npc;
|
|
using NeonSprawl.Server.Tests;
|
|
using NeonSprawl.Server.Tests.Game.Npc;
|
|
using Xunit;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Combat;
|
|
|
|
public sealed class CombatOperationsTests
|
|
{
|
|
private static AbilityDefinitionRegistry CreatePrototypeRegistry()
|
|
{
|
|
var rows = new Dictionary<string, AbilityDefRow>(StringComparer.Ordinal)
|
|
{
|
|
[PrototypeAbilityRegistry.PrototypeBurst] = new AbilityDefRow(
|
|
PrototypeAbilityRegistry.PrototypeBurst,
|
|
"Prototype Burst",
|
|
40,
|
|
5.0,
|
|
"attack"),
|
|
[PrototypeAbilityRegistry.PrototypeDash] = new AbilityDefRow(
|
|
PrototypeAbilityRegistry.PrototypeDash,
|
|
"Prototype Dash",
|
|
0,
|
|
4.0,
|
|
"movement"),
|
|
[PrototypeAbilityRegistry.PrototypeGuard] = new AbilityDefRow(
|
|
PrototypeAbilityRegistry.PrototypeGuard,
|
|
"Prototype Guard",
|
|
0,
|
|
6.0,
|
|
"utility"),
|
|
[PrototypeAbilityRegistry.PrototypePulse] = new AbilityDefRow(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
"Prototype Pulse",
|
|
25,
|
|
3.0,
|
|
"attack"),
|
|
};
|
|
var catalog = new AbilityDefinitionCatalog("/tmp/abilities", rows, catalogJsonFileCount: 1);
|
|
return new AbilityDefinitionRegistry(catalog);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithPulseOnFreshAlpha_ShouldDealCatalogDamage()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Null(result.ReasonCode);
|
|
Assert.Equal(25, result.DamageDealt);
|
|
Assert.Equal(75, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithFourPulses_ShouldDefeatTargetOnFourthResolve()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
_ = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
}
|
|
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(0, result.TargetRemainingHp);
|
|
Assert.True(result.TargetDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_OnDefeatedTarget_ShouldDenyWithTargetDefeated()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
for (var i = 0; i < 4; i++)
|
|
{
|
|
_ = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
}
|
|
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
store.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
|
|
// Assert
|
|
Assert.False(result.Success);
|
|
Assert.Equal(CombatReasonCodes.TargetDefeated, result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Equal(0, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
Assert.Equal(0, snapshot.CurrentHp);
|
|
Assert.True(snapshot.Defeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithGuardOnLiveTarget_ShouldSucceedWithZeroDamage()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypeGuard,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
store.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Null(result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Equal(100, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
Assert.Equal(100, snapshot.CurrentHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithGuardOnDefeatedTarget_ShouldDenyWithTargetDefeated()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
_ = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 100, out _);
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypeGuard,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.False(result.Success);
|
|
Assert.Equal(CombatReasonCodes.TargetDefeated, result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Equal(0, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithDashOnLiveTarget_ShouldSucceedWithZeroDamage()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypeDash,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Null(result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Equal(100, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithUnknownAbility_ShouldDenyWithUnknownAbility()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
"not_a_real_ability",
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.False(result.Success);
|
|
Assert.Equal(CombatReasonCodes.UnknownAbility, result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Null(result.TargetRemainingHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithUnknownTarget_ShouldDenyWithUnknownTarget()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
"not_a_target",
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.False(result.Success);
|
|
Assert.Equal(CombatReasonCodes.UnknownTarget, result.ReasonCode);
|
|
Assert.Equal(0, result.DamageDealt);
|
|
Assert.Null(result.TargetRemainingHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResolve_WithBurstOnFreshAlpha_ShouldDealFortyDamage()
|
|
{
|
|
// Arrange
|
|
var registry = CreatePrototypeRegistry();
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypeBurst,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(40, result.DamageDealt);
|
|
Assert.Equal(60, result.TargetRemainingHp);
|
|
Assert.False(result.TargetDefeated);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Host_ShouldResolveCombatDependenciesFromDi_WhenStartupSucceeds()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
using var client = factory.CreateClient();
|
|
_ = await client.GetAsync("/health");
|
|
var registry = factory.Services.GetRequiredService<IAbilityDefinitionRegistry>();
|
|
var store = factory.Services.GetRequiredService<ICombatEntityHealthStore>();
|
|
// Act
|
|
var result = CombatOperations.TryResolve(
|
|
PrototypeAbilityRegistry.PrototypePulse,
|
|
PrototypeNpcRegistry.PrototypeNpcMeleeId,
|
|
registry,
|
|
store);
|
|
// Assert
|
|
Assert.True(result.Success);
|
|
Assert.Equal(25, result.DamageDealt);
|
|
Assert.Equal(75, result.TargetRemainingHp);
|
|
}
|
|
}
|