using System.Text.Json.Serialization; namespace NeonSprawl.Server.Game.AbilityInput; /// POST body for ability cast intent (NEO-31). public sealed class AbilityCastRequest { public const int CurrentSchemaVersion = 1; [JsonPropertyName("schemaVersion")] public int SchemaVersion { get; init; } [JsonPropertyName("slotIndex")] public int SlotIndex { get; init; } [JsonPropertyName("abilityId")] public string? AbilityId { get; init; } /// /// Must match the server's current combat lock (same string as GET …/target lockedTargetId) for /// accepted: true; NEO-28 adds invalid_target / out_of_range denies when it does not. /// [JsonPropertyName("targetId")] public string? TargetId { get; init; } } /// Combat outcome block on successful cast accept (NEO-82). public sealed class CombatResolutionJson { [JsonPropertyName("abilityId")] public required string AbilityId { get; init; } [JsonPropertyName("targetId")] public required string TargetId { get; init; } [JsonPropertyName("damageDealt")] public int DamageDealt { get; init; } [JsonPropertyName("targetRemainingHp")] public int TargetRemainingHp { get; init; } [JsonPropertyName("targetDefeated")] public bool TargetDefeated { get; init; } } /// POST response for cast submit (prototype accept/deny; NEO-31 + NEO-28 target rules). public sealed class AbilityCastResponse { public const int CurrentSchemaVersion = 1; [JsonPropertyName("schemaVersion")] public int SchemaVersion { get; init; } = CurrentSchemaVersion; [JsonPropertyName("accepted")] public bool Accepted { get; init; } [JsonPropertyName("reasonCode")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? ReasonCode { get; init; } /// Present only when is true after combat resolve (NEO-82). [JsonPropertyName("combatResolution")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CombatResolutionJson? CombatResolution { get; init; } }