Skip to content

Utility Buffs

Utility buffs protect fighters without changing their stats. Cowculator supports shield_up, which grants a shield based on the target's maximum health.

Shield strength

The shield's value determines the percentage of the target's maximum health granted as protection:

shield = round_half_up(target.maximum_health × value)

Example

A fighter has 1,000 maximum health and receives a shield with value: 0.25. The shield grants 250 protection.

How shields protect health

Shields absorb direct attack damage before health is reduced:

  • If the shield absorbs the full hit, health does not change.
  • If the hit exceeds the shield, the remaining damage reaches health.
  • Damage over time bypasses shields and applies directly to health.

Example

A fighter with 100 shield receives 120 direct damage. The shield absorbs 100, becomes depleted, and the remaining 20 reduces health.

Independent shields

Each applied shield is tracked separately. It has its own:

  • Runtime status ID
  • Remaining shield amount
  • Remaining duration

The battle result reports their combined amount as the fighter's current shield. For example, two shields worth 60 and 100 provide 160 total protection, but each shield keeps its own duration and can expire independently.

Reapplication and stacking

Later same-name shield applications use the stack_policy and max_stacks values already active on those shields. Once every matching shield has been depleted, expired, or removed, the next application uses its own configuration.

Established values Same-name shield reapplication
stack_policy: "replace" Remove the previous shield and replace it with the new one
stack_policy: "stack", below max_stacks Add a new independent shield to the combined amount
stack_policy: "stack", at max_stacks Reject the new shield and leave all existing shields unchanged

Rejection produces an apply_status_rejected battle event with the max_stacks_reached outcome. Use the event's structured data to show feedback.

Looking for exact fields?

Use the OpenAPI reference for the complete event payload and utility-status schema.

Damage, expiry, and removal

Direct damage consumes individual shields from oldest to newest.

  • A fully consumed shield is removed immediately.
  • A partially consumed shield keeps its remaining duration.
  • When a shield expires, only its remaining amount is removed from the combined shield.
  • Explicit status removal also subtracts only the selected shield's amount.

Other shields keep their amounts and durations when one is depleted, expires, or is removed.

When one hit fully consumes one or more shields, replay its events in the returned order: shield_changed with a damage_absorption trigger, then one remove_status event for each depleted shield from oldest to newest, then deal_damage. This keeps the combined shield amount, individual status list, and health change in sync.

See ApplyStatus for the shared status configuration and BattleResult for replaying shield changes.