# OpenSpec Change: enterprise-gaming-combat - **Change ID**: enterprise-gaming-combat - **Package**: `@suaveplan/combat` - **Category**: gaming/combat - **Target path**: `gaming/combat/combat` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/combat.md` --- ## Summary Deliver `@suaveplan/combat` on the genesis branch from scratch at enterprise quality. The package provides core combat mechanics: multiple damage types (physical, elemental, true), health/armor/shield layers, resistances, status effects (burn, stun, slow, poison) with duration and tick logic, damage calculation pipeline with modifier chain, and `CombatManager` that processes hit events and emits `@suaveplan/events` combat messages. Genesis adds Zod schemas for all combat data, structured errors, OTel damage counters, injectable clock, and 100% coverage including property tests for damage pipeline commutativity. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `CombatError`; `COMBAT.*` codes | | `@suaveplan/types` (`workspace:^`) | `Clock`, `IdGenerator` | | `@suaveplan/events` (`workspace:^`) | `combat:hit`, `combat:death`, `combat:status` events | | `zod` (`catalog:forms`) | `DamageEvent`, `StatusEffect`, `CombatantStats` schemas | | `@opentelemetry/api` (`catalog:observability`) | Damage counter, death counter | --- ## Public API surface ```ts type DamageType = 'physical' | 'fire' | 'ice' | 'lightning' | 'poison' | 'true' interface CombatantStats { maxHealth: number maxArmor: number maxShield: number resistances: Partial> // 0–1 reduction defense: number } function createCombatant(id: string, stats: CombatantStats): Combatant interface Combatant { readonly id: string readonly health: number readonly armor: number readonly shield: number readonly isDead: boolean readonly statusEffects: readonly StatusEffect[] applyDamage(event: DamageEvent): DamageResult applyHealing(amount: number, type?: 'health' | 'shield'): void applyStatus(effect: StatusEffect): void tick(dt: number): void // processes status effect durations + ticks revive(health?: number): void } interface DamageEvent { sourceId: string targetId: string amount: number type: DamageType isCritical?: boolean modifiers?: DamageModifier[] } interface DamageResult { finalDamage: number healthDamage: number armorDamage: number shieldDamage: number wasKilled: boolean statusesApplied: string[] } interface StatusEffect { id: string name: string duration: number tickInterval?: number tickDamage?: number tickDamageType?: DamageType speedModifier?: number damageModifier?: number } interface DamageModifier { type: 'multiply' | 'add' | 'set' value: number priority?: number } function createCombatManager(options?: CombatManagerOptions): CombatManager interface CombatManager { registerCombatant(combatant: Combatant): void unregisterCombatant(id: string): void processHit(event: DamageEvent): DamageResult tick(dt: number): void getCombatant(id: string): Combatant | undefined } ``` ### Error codes ```ts type CombatErrorCode = | 'COMBAT_COMBATANT_NOT_FOUND' | 'COMBAT_TARGET_DEAD' | 'COMBAT_INVALID_DAMAGE' | 'COMBAT_STATUS_OVERFLOW' ``` --- ## New additions for genesis 1. **Damage pipeline** — ordered modifier chain: resistances → armor absorption → shield drain → health damage. 2. **Status effect stacking** — configurable max-stack count; refresh vs. stack vs. replace policy. 3. **Critical hit multiplier** — `isCritical` doubles damage before modifier chain. 4. **OTel** — `combat.damage_total` counter (by type); `combat.deaths_total` counter; `combat.active_combatants` gauge. --- ## File layout ```text gaming/combat/combat/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/index.ts types/common.ts types/common.md core/ combatant/ combatant.ts combatant.md combatant.types.ts combatant.test.ts index.ts damage-pipeline/ damage-pipeline.ts damage-pipeline.md damage-pipeline.types.ts damage-pipeline.test.ts index.ts status-effect/ status-effect.ts status-effect.md status-effect.types.ts status-effect.test.ts index.ts combat-manager/ combat-manager.ts combat-manager.md combat-manager.types.ts combat-manager.test.ts index.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Downstream**: `@suaveplan/weapons` feeds damage events into combat manager; `@suaveplan/r3f-combat` renders damage numbers. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`.