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 the content files (admin → Status effects):

  • id, label, polarity (buff / debuff / neutral)
  • dot_color — #RRGGBB tint for world/HUD status dots
  • duration_sec, clear_on_death, stacking (refresh | stack | single), max_stacks (default 10 when stacking)
  • Stat mods — add / mul / override on closed keys (move_speed, damage_dealt, armor_physical, attr.strength, regen.health, …). On damage_dealt and damage_taken, optional damage_type limits the row to hits of that type (fire, frost, water, air, …). A blank type still applies to every hit.
  • 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 (optional per-type), 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)          │
│  the content files*.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_sec — no 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 editor 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 (the content files):

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

Latent marks

Set latent: true and the effect's mods and periodic ticks stay off until an ability uses on_hit: { kind: activate_latent, effect_id }.

Field Meaning
latent_window_sec How long the mark waits. Defaults to duration_sec
persist_until_cleansed The mark does not time out
consume_on_activate Remove the mark and start the real effect (or apply on_activate_status_ids)
on_activate_status_ids Normal statuses applied when the mark triggers
cleared_by Applying one of these removes a dormant mark and does not trigger it
concealment: invisible Hide the bearer from everyone else for the effect's duration

A boon leaves consume_on_activate false. Each activating spell pulses the effect once while the mark remains.

Catalog

Id Label What it does
frost_effect Frost Slow, less armor, more damage taken, frost damage each second for 8 s
poison Poison Halves health regen, 12 poison damage each second for 10 s
quicksand Quicksand Move speed ×0.2 for 8 s
burn_effect Burn 10 fire damage every 2 s for 12 s
mana_drain Mana Drain Stacks; drains mana. Up to 5 stacks
battle_shout Battle Shout +20% damage dealt and more strength
weaken Weaken More damage taken, less damage dealt
fortify Fortify More armor, less damage taken, stamina regen
mark_of_flame Mark of Flame Latent stigma. No effect until Feel the Flame. Does not expire. Absolution removes it without burning
severe_burn Severe Burn 28 fire damage each second for 10 s. Fire hits deal ×1.25 damage; frost hits deal ×0.75. Other types are unchanged. Applied when Mark of Flame is activated
absolution Absolution Cleanse key for Mark of Flame. No damage of its own
vitality Vitality Latent boon. Each Invoke Vitality heals 18 while the boon remains (20 s window)
latent_poison Latent Poison Same mods and poison tick as Poison, dormant until activated, then it runs as poison for 10 s
invisibility Invisible Hidden from other players and from NPCs for 8 s

Gear examples that are not statuses themselves:

Item Role
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).