# LibCombatPulse-1.0
LibCombatPulse-1.0 is a lightweight WoW Retail library (LibStub-style) that acts as a **shared combat event bus**.
It lets addons publish and consume **normalized combat/progress/utility events** without requiring direct dependencies between addons.
This copy is shipped as a standalone addon (`LibCombatPulse-1.0`), and may also be embedded inside other addons.
## Key Features
- **Multiple consumers**
- Any addon can register one or more consumers via `NewConsumer()`.
- **Event filtering**
- Filter by confidence and by categories/kinds/direction/eventType.
- **Consumer safety**
- Events are shallow-copied per-consumer by default (`copyEvent=true`) to avoid cross-consumer mutation bugs.
- **Schema normalization**
- `Emit()` fills/normalizes basic fields like `kind` and `timestamp`.
## Library Versioning
- **MAJOR:** `LibCombatPulse-1.0`
- **MINOR:** `2`
LibStub will keep the newest MINOR version loaded.
## Loading / Access
```lua
local LibStub = _G.LibStub
local LCP = LibStub and LibStub:GetLibrary("LibCombatPulse-1.0", true)
if not (LCP and LCP.NewConsumer) then
return
end
```
## Registering a Consumer
```lua
local handle = LCP:NewConsumer("MyAddon", {
OnEvent = function(ev)
-- ev is a normalized event table
-- IMPORTANT: treat ev as read-only
end,
}, {
-- Options (all optional)
minConfidence = "LOW", -- LOW | MED | HIGH
enableCombat = true,
enableProgress = true,
enableInterrupts = true,
enableCooldowns = true,
-- Additional opt-in filters
-- kinds = { damage=true, heal=true, miss=true },
-- directions = { incoming=true, outgoing=true },
-- eventTypes = { OUTGOING_DAMAGE_COMBAT=true },
copyEvent = true, -- default true
})
-- Later
-- handle:Disable()
-- handle:Enable()
-- handle:Unregister()
```
## Event Contract (Practical)
LibCombatPulse does not enforce a strict schema, but the following fields are common.
### Required / Normalized
- `kind` *(string)*
- Examples: `damage`, `heal`, `miss`, `aura_gain`, `aura_fade`, `interrupt`, `cast_stop`, `cooldown_ready`, `xp`, `honor`, `reputation`
- `timestamp` *(number)*
- Seconds (from `GetTime()`), filled if missing.
### Common Optional Fields
- `eventType` *(string)*
- Original producer event type (example: `OUTGOING_DAMAGE_COMBAT`, `INCOMING_DAMAGE`, `COMBAT_TEXT_MISS`, `COOLDOWN_READY`).
- `direction` *(string)*
- Usually `incoming` or `outgoing`.
- `spellId` *(number)*
- `spellName` *(string)*
- `targetName` *(string)*
- `amount` *(number)*
- `amountText` *(string)*
- `confidence` *(string)*
- `LOW`, `MED`, `HIGH`.
### Kind-Specific Fields
- For `kind == "miss"`:
- `missType` *(string)* (ex: `DODGE`, `PARRY`, `BLOCK`, `MISS`)
- For `kind == "cooldown_ready"`:
- `method` *(string)* (producer-specific; ex: `BASE_CD`, `ACTIONBAR`, etc.)
- For combat damage/heal:
- `isCrit` *(boolean)*
- `isPeriodic` *(boolean)*
- `amountSource` *(string)* (producer-specific provenance)
## Producer Notes
LibCombatPulse itself is only a dispatcher. Producers (addons) decide what to emit and with what confidence.
If multiple addons emit events, consumers should rely on:
- `eventType`
- `direction`
- `confidence`
- producer-specific fields (like `amountSource`, `method`, etc.)
to select what they trust.