Files
suaveplan/openspec/changes/enterprise-gaming-combat/proposal.md
2026-05-27 23:29:53 +01:00

4.9 KiB
Raw Blame History

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

type DamageType = 'physical' | 'fire' | 'ice' | 'lightning' | 'poison' | 'true'

interface CombatantStats {
  maxHealth: number
  maxArmor: number
  maxShield: number
  resistances: Partial<Record<DamageType, number>>   // 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

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

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.