151 lines
6.2 KiB
C#
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);
|
|
}
|
|
}
|