4.9 KiB
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
- Damage pipeline — ordered modifier chain: resistances → armor absorption → shield drain → health damage.
- Status effect stacking — configurable max-stack count; refresh vs. stack vs. replace policy.
- Critical hit multiplier —
isCriticaldoubles damage before modifier chain. - OTel —
combat.damage_totalcounter (by type);combat.deaths_totalcounter;combat.active_combatantsgauge.
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.