127 lines
5.3 KiB
C#
127 lines
5.3 KiB
C#
using NeonSprawl.Server.Game.AbilityInput;
|
|
using NeonSprawl.Server.Game.Combat;
|
|
using NeonSprawl.Server.Game.PositionState;
|
|
using NeonSprawl.Server.Game.Targeting;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Combat;
|
|
|
|
public sealed class PlayerCombatHealthApiTests
|
|
{
|
|
private static async Task MoveDevPlayerNearEliteAsync(HttpClient client)
|
|
{
|
|
var response = await client.PostAsJsonAsync(
|
|
"/game/players/dev-local-1/move",
|
|
new MoveCommandRequest
|
|
{
|
|
SchemaVersion = MoveCommandRequest.CurrentSchemaVersion,
|
|
Target = new PositionVector { X = -2, Y = 0.9, Z = -2 },
|
|
});
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
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 LockPrototypeNpcEliteAsync(HttpClient client)
|
|
{
|
|
var response = await client.PostAsJsonAsync(
|
|
"/game/players/dev-local-1/target/select",
|
|
new TargetSelectRequest
|
|
{
|
|
SchemaVersion = TargetSelectRequest.CurrentSchemaVersion,
|
|
TargetId = PrototypeNpcRegistry.PrototypeNpcEliteId,
|
|
});
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
private static AbilityCastRequest PulseCastRequest() =>
|
|
new()
|
|
{
|
|
SchemaVersion = AbilityCastRequest.CurrentSchemaVersion,
|
|
SlotIndex = 0,
|
|
AbilityId = PrototypeAbilityRegistry.PrototypePulse,
|
|
TargetId = PrototypeNpcRegistry.PrototypeNpcEliteId,
|
|
};
|
|
|
|
[Fact]
|
|
public async Task GetPlayerCombatHealth_ShouldReturnSchemaV1_WithFullHpBaseline()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
// Act
|
|
var response = await client.GetAsync("/game/players/dev-local-1/combat-health");
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
var body = await response.Content.ReadFromJsonAsync<PlayerCombatHealthResponse>();
|
|
Assert.NotNull(body);
|
|
Assert.Equal(PlayerCombatHealthResponse.CurrentSchemaVersion, body!.SchemaVersion);
|
|
Assert.Equal("dev-local-1", body.PlayerId);
|
|
Assert.Equal(PlayerCombatHealthDefaults.MaxHp, body.MaxHp);
|
|
Assert.Equal(PlayerCombatHealthDefaults.MaxHp, body.CurrentHp);
|
|
Assert.False(body.Defeated);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPlayerCombatHealth_ShouldReturnNotFound_WhenPlayerUnknown()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
// Act
|
|
var response = await client.GetAsync("/game/players/missing-player/combat-health");
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPlayerCombatHealth_ShouldDecreaseAfterEliteTelegraphComplete()
|
|
{
|
|
// Arrange
|
|
await using var factory = new InMemoryWebApplicationFactory();
|
|
var client = factory.CreateClient();
|
|
Assert.NotNull(factory.FakeClock);
|
|
await BindSlot0PulseAsync(client);
|
|
await MoveDevPlayerNearEliteAsync(client);
|
|
await LockPrototypeNpcEliteAsync(client);
|
|
var castResponse = await client.PostAsJsonAsync(
|
|
"/game/players/dev-local-1/ability-cast",
|
|
PulseCastRequest());
|
|
castResponse.EnsureSuccessStatusCode();
|
|
_ = await client.GetAsync("/game/world/npc-runtime-snapshot");
|
|
factory.FakeClock!.Advance(TimeSpan.FromSeconds(5));
|
|
_ = await client.GetAsync("/game/world/npc-runtime-snapshot");
|
|
factory.FakeClock.Advance(TimeSpan.FromSeconds(2.5));
|
|
// Act
|
|
var snapshotResponse = await client.GetAsync("/game/world/npc-runtime-snapshot");
|
|
var healthResponse = await client.GetAsync("/game/players/dev-local-1/combat-health");
|
|
// Assert
|
|
snapshotResponse.EnsureSuccessStatusCode();
|
|
healthResponse.EnsureSuccessStatusCode();
|
|
var snapshotBody = await snapshotResponse.Content.ReadFromJsonAsync<NpcRuntimeSnapshotResponse>();
|
|
var healthBody = await healthResponse.Content.ReadFromJsonAsync<PlayerCombatHealthResponse>();
|
|
Assert.NotNull(snapshotBody);
|
|
Assert.NotNull(healthBody);
|
|
var elite = snapshotBody!.NpcInstances.Single(row => row.NpcInstanceId == PrototypeNpcRegistry.PrototypeNpcEliteId);
|
|
Assert.Equal("recover", elite.State);
|
|
Assert.Equal(75, healthBody!.CurrentHp);
|
|
Assert.False(healthBody.Defeated);
|
|
Assert.Equal("dev-local-1", healthBody.PlayerId);
|
|
|
|
var store = factory.Services.GetRequiredService<IPlayerCombatHealthStore>();
|
|
store.TryGet("dev-local-1", out var storeSnapshot);
|
|
Assert.Equal(healthBody.CurrentHp, storeSnapshot.CurrentHp);
|
|
Assert.Equal(healthBody.MaxHp, storeSnapshot.MaxHp);
|
|
Assert.Equal(healthBody.Defeated, storeSnapshot.Defeated);
|
|
}
|
|
}
|