namespace NeonSprawl.Server.Game.Combat; /// /// Orchestrates deterministic combat resolution: ability catalog damage + prototype target HP (NEO-81). /// Cast HTTP wiring: (NEO-82). /// public static class CombatOperations { /// /// Resolves one ability against one prototype combat target using catalog damage and the health store. /// Defeated targets deny before damage application; zero-damage abilities succeed without mutating HP. /// public static CombatResult TryResolve( string abilityId, string targetId, IAbilityDefinitionRegistry abilityRegistry, ICombatEntityHealthStore healthStore) { if (!abilityRegistry.TryNormalizeKnown(abilityId, out var normalizedAbility) || !abilityRegistry.TryGetDefinition(normalizedAbility, out var definition)) { return Deny(CombatReasonCodes.UnknownAbility); } if (!healthStore.TryGet(targetId, out var snapshot)) { return Deny(CombatReasonCodes.UnknownTarget); } if (snapshot.Defeated) { return Deny(CombatReasonCodes.TargetDefeated, snapshot.CurrentHp); } if (definition.BaseDamage == 0) { return new CombatResult( Success: true, ReasonCode: null, DamageDealt: 0, TargetRemainingHp: snapshot.CurrentHp, TargetDefeated: snapshot.Defeated); } if (!healthStore.TryApplyDamage(targetId, definition.BaseDamage, out var after)) { return Deny(CombatReasonCodes.UnknownTarget); } return new CombatResult( Success: true, ReasonCode: null, DamageDealt: definition.BaseDamage, TargetRemainingHp: after.CurrentHp, TargetDefeated: after.Defeated); } private static CombatResult Deny(string reasonCode, int? targetRemainingHp = null) => new( Success: false, ReasonCode: reasonCode, DamageDealt: 0, TargetRemainingHp: targetRemainingHp, TargetDefeated: false); }