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 (refreshin v1)- Stat mods —
add/mul/overrideon closed keys (move_speed,damage_dealt,armor_physical,attr.strength,regen.health, …) - Periodic damage/heal ticks (
interval_sec, optionaldamage_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.
ActiveStatuson entities- Apply / refresh same id / expire / clear on death
- Unequip clears template
grant_effects_while_equippedand inactive instancewhile_equippedgrants - Combat path:
damage_dealt,damage_taken,armor_physical, resists - Movement:
move_speed; regen/drain:regen.*/drain.*; attrs:attr.* - Protocol:
StatusEffectHudon 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_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-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:
- Inventory → select oil →
e→ pick wearable → Enter (UseGrant) - Binding appears on that instance (e.g. “fortify · while equipped · 50m left”)
- Equip the piece → entity shows Fortify while worn
- After
duration_secfrom 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.