Home Content-Driven Status Effects

Content-Driven Status Effects

Status effects are a YAML catalog. Content references an effect id; the sim applies mods and periodic ticks from that definition. Designers do not hard-code “frost” or “fortify” in Rust.

Two clocks (do not confuse them)

Clock Where authored What it means
Effect default duration Status effects tab → duration_sec on the effect (e.g. fortify = 12s) How long the buff lasts on an entity when applied as a normal status (ability, potion self-apply, while-equipped sync).
Instance binding TTL Items → grants_item_status.duration_sec (e.g. fortify oil = 3600s / 1 hour) How long the enchantment stays on that unique gear instance. Inventory/Equip show this countdown (e.g. “50m left” after ~10 minutes of play).

When a while_equipped binding is active and the item is worn, the entity gets the named effect (using the effect’s own duration/refresh rules while equipped). When the binding expires, the enchantment falls off the item.

Catalog (named effects)

Author once under assets/combat/status_effects/ (admin → Status effects):

  • id, label, polarity (buff / debuff / neutral)
  • duration_sec, clear_on_death, stacking (refresh in v1)
  • Stat modsadd / mul / override on closed keys (move_speed, damage_dealt, armor_physical, attr.strength, regen.health, …)
  • Periodic damage/heal ticks (interval_sec, optional damage_type)

Schema: schemas/status-effect.schema.json.

Ops (runtime)

Per modifier: Add, Mul, or Override (priority + newest on ties). Collect Muls × (base + Adds); Override wins when present.

  • ActiveStatus on entities
  • Apply / refresh same id / expire / clear on death
  • Unequip clears template grant_effects_while_equipped and inactive instance while_equipped grants
  • Combat path: damage_dealt, damage_taken, armor_physical, resists
  • Movement: move_speed; regen/drain: regen.* / drain.*; attrs: attr.*
  • Protocol: StatusEffectHud on combat HUD; gfx does not open T1/T2 solely because a buff is active

Attach points (complete picture)

┌─────────────────────────────────────────────────────────────────┐
│  Status effect catalog (id → duration, mods, periodic)          │
│  assets/combat/status_effects/*.yaml                            │
└────────────────────────────┬────────────────────────────────────┘
                             │ referenced by id
     ┌───────────────────────┼───────────────────────┐
     ▼                       ▼                       ▼
 Abilities              Item templates          Instance grants
 on_hit apply_status    (all mints of template) (one item_instance_id)
 requires_*_status
Attach Content field Applies to Duration / chance
Ability hit on_hit: [{ kind: apply_status, effect_id, target }] Entity Effect’s duration_sec
Ability gate requires_target_status / requires_self_status Rotation eligibility
Weapon / ammo template on_hit_effects: [id…] Hit victim (every mint) Effect’s duration_sec
Wearable template grant_effects_while_equipped: [id…] Wearer while equipped While worn (cleared on unequip); effect refresh uses catalog
Consumable self apply_status_ids / clears_status_ids Drinker Effect’s duration_secno per-item chance/TTL UI
Grant consumable grants_item_status: { effect_id, mode, success_chance, copper_cost, duration_sec?, target_tags? } One gear instance via picker Binding TTL = grant duration_sec; apply chance = success_chance (+ INT/WIS/evocation clamp)

Modes for grants_item_status (not “consumable type”)

These describe how the bound effect fires on the gear, not how you drink the oil:

mode Meaning Typical item
on_hit When that weapon/ammo hits, apply effect to the target Frost edge scroll → sword
while_equipped While that piece is worn/held, grant effect to the wearer Fortify oil → ring/armor

Fortify oil is a consumable that performs a grant; its mode must be while_equipped, not on_hit. Content-admin Items/Consumables use a catalog <select> for effect_id (not a free-text datalist); mode defaults to while_equipped when creating a new grant row.

Fortify oil (worked example)

Authored on the item (assets/items/consumables.yaml):

grants_item_status:
  effect_id: fortify
  mode: while_equipped
  success_chance: 1.0
  copper_cost: 0
  duration_sec: 3600.0   # ← 1 hour binding TTL (inventory countdown)

Do not put fortify in apply_status_ids for this oil (that would drink-apply a 12s entity buff and skip the gear picker).

Play loop:

  1. Inventory → select oil → e → pick wearable → Enter (UseGrant)
  2. Binding appears on that instance (e.g. “fortify · while equipped · 50m left”)
  3. Equip the piece → entity shows Fortify while worn
  4. After duration_sec from step 1, binding expires off the item

Admin map

Tab Edit
Status effects Catalog: duration, mods, periodic
Items / Consumables apply_status_ids (self), grants_item_status (instance bind + chance + binding TTL + mode)
Abilities on_hit apply_status, status gates
Settings inventory.grant_success_chance_min/max, max_item_status_bindings

Samples

Id / item Role
frost_effect DoT + slow + −armor
poison DoT + halved health regen
battle_shout / weaken / fortify Combat buffs/debuffs
frost_ring Template grant_effects_while_equipped: [fortify]
frost_edge_scroll Grant on_hit frost onto a weapon (chance + copper)
fortify_oil Grant while_equipped fortify onto gear for 3600s
frost_ward_scroll clears_status_ids: [frost_effect]

Player UX

  • Grant picker: inventory e / Move → Apply onto gear…
  • Inventory & Equip show instance bindings + remaining binding time
  • Character / Equip show active entity statuses
  • Combat dock status strip only when combat UI is already open (target / in combat / cast) — buffs alone do not open T1/T2

Out of scope (deferred)

Multi-stack formulas, dispel schools, CC (stun/root), enchanting-station procs beyond this substrate.

Ops / reload

Edit YAML → content publish (or restart worker). Designer short note: docs/status-effects.md.