neon-sprawl/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetsWorldApiTests.cs

151 lines
6.2 KiB
C#

using NeonSprawl.Server.Game.AbilityInput;
using NeonSprawl.Server.Game.Combat;
using NeonSprawl.Server.Game.Targeting;
namespace NeonSprawl.Server.Tests.Game.Combat;
public class CombatTargetsWorldApiTests
{
private static async Task BindSlot0PulseAsync(HttpClient client)
{
var post = await client.PostAsJsonAsync(
"/game/players/dev-local-1/hotbar-loadout",
new HotbarLoadoutUpdateRequest
{
SchemaVersion = HotbarLoadoutUpdateRequest.CurrentSchemaVersion,
Slots = [new HotbarSlotBindingJson { SlotIndex = 0, AbilityId = PrototypeAbilityRegistry.PrototypePulse }],
});
post.EnsureSuccessStatusCode();
}
private static async Task LockPrototypeNpcMeleeAsync(HttpClient client)
{
var response = await client.PostAsJsonAsync(
"/game/players/dev-local-1/target/select",
new TargetSelectRequest
{
SchemaVersion = TargetSelectRequest.CurrentSchemaVersion,
TargetId = PrototypeNpcRegistry.PrototypeNpcMeleeId,
});
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadFromJsonAsync<TargetSelectResponse>();
Assert.NotNull(body);
Assert.True(body!.SelectionApplied);
}
private static AbilityCastRequest PulseCastRequest() =>
new()
{
SchemaVersion = AbilityCastRequest.CurrentSchemaVersion,
SlotIndex = 0,
AbilityId = PrototypeAbilityRegistry.PrototypePulse,
TargetId = PrototypeNpcRegistry.PrototypeNpcMeleeId,
};
[Fact]
public async Task GetCombatTargets_ShouldReturnSchemaV1_WithThreeTargetsAtFullHp()
{
// Arrange
await using var factory = new InMemoryWebApplicationFactory();
var client = factory.CreateClient();
// Act
var response = await client.GetAsync("/game/world/combat-targets");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<CombatTargetsListResponse>();
Assert.NotNull(body);
Assert.Equal(CombatTargetsListResponse.CurrentSchemaVersion, body!.SchemaVersion);
Assert.NotNull(body.Targets);
Assert.Equal(3, body.Targets.Count);
var ids = body.Targets.Select(static t => t.TargetId).ToList();
Assert.Equal(PrototypeNpcRegistryTests.InstancesInIdOrder, ids);
var elite = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcEliteId);
Assert.Equal(200, elite.MaxHp);
Assert.Equal(200, elite.CurrentHp);
Assert.False(elite.Defeated);
var melee = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcMeleeId);
Assert.Equal(100, melee.MaxHp);
Assert.Equal(100, melee.CurrentHp);
Assert.False(melee.Defeated);
var ranged = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcRangedId);
Assert.Equal(80, ranged.MaxHp);
Assert.Equal(80, ranged.CurrentHp);
Assert.False(ranged.Defeated);
}
[Fact]
public async Task GetCombatTargets_ShouldReflectCastDamage_AfterOnePulseOnMelee()
{
// Arrange
await using var factory = new InMemoryWebApplicationFactory();
var client = factory.CreateClient();
await BindSlot0PulseAsync(client);
await LockPrototypeNpcMeleeAsync(client);
var castResponse = await client.PostAsJsonAsync(
"/game/players/dev-local-1/ability-cast",
PulseCastRequest());
castResponse.EnsureSuccessStatusCode();
var castBody = await castResponse.Content.ReadFromJsonAsync<AbilityCastResponse>();
// Act
var response = await client.GetAsync("/game/world/combat-targets");
var body = await response.Content.ReadFromJsonAsync<CombatTargetsListResponse>();
// Assert
Assert.NotNull(castBody);
Assert.True(castBody!.Accepted);
Assert.NotNull(castBody.CombatResolution);
Assert.Equal(75, castBody.CombatResolution!.TargetRemainingHp);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(body);
var melee = body!.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcMeleeId);
Assert.Equal(75, melee.CurrentHp);
Assert.False(melee.Defeated);
var ranged = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcRangedId);
Assert.Equal(80, ranged.CurrentHp);
Assert.False(ranged.Defeated);
}
[Fact]
public async Task GetCombatTargets_ShouldShowDefeated_AfterFourPulsesOnMelee()
{
// Arrange
await using var factory = new InMemoryWebApplicationFactory();
var client = factory.CreateClient();
Assert.NotNull(factory.FakeClock);
await BindSlot0PulseAsync(client);
await LockPrototypeNpcMeleeAsync(client);
var cast = PulseCastRequest();
for (var i = 0; i < 4; i++)
{
var castResponse = await client.PostAsJsonAsync("/game/players/dev-local-1/ability-cast", cast);
castResponse.EnsureSuccessStatusCode();
if (i < 3)
{
factory.FakeClock!.Advance(TimeSpan.FromSeconds(3) + TimeSpan.FromMilliseconds(50));
}
}
// Act
var response = await client.GetAsync("/game/world/combat-targets");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<CombatTargetsListResponse>();
Assert.NotNull(body);
var melee = body!.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcMeleeId);
Assert.Equal(0, melee.CurrentHp);
Assert.True(melee.Defeated);
var ranged = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcRangedId);
Assert.Equal(80, ranged.CurrentHp);
Assert.False(ranged.Defeated);
var elite = body.Targets.Single(t => t.TargetId == PrototypeNpcRegistry.PrototypeNpcEliteId);
Assert.Equal(200, elite.CurrentHp);
Assert.Equal(200, elite.MaxHp);
Assert.False(elite.Defeated);
}
}