
Status effects¶
Status: Working — YAML-loaded effect content, stacking strategies, stat modifiers (flat + percent),
damage/healtick primitives, andon-apply/on-expiresound + particle hooks all active. Full ability-sequence tick actions (running an arbitraryAbilitySequenceon each tick) are not yet wired — currently onlydamageandhealprimitives are supported in thetickblock. Default sample effects (poison,regen,strength_boost,slow) ship inplugins/rpg-core/status-effects/example.yml.
A fully custom (de)buff framework. Vanilla PotionEffects on entities are cancelled (per vanilla suppression) — only our StatusEffect system applies.
Design intent¶
Status effects exist as a separate system from abilities because they model things abilities can't do cleanly: duration, stacking rules (refresh vs stack-power vs independent), and persistent stat modifiers that remain active across multiple damage events. An ability fires once and resolves; a status effect sits on the entity, modifies its stats, and ticks independently until it expires. Using abilities to replicate "burning for 5 seconds" would require a chain of delayed effects with shared state — this system handles all of that declaratively in YAML.
What a status effect is¶
Each effect is defined in YAML (planned location: plugins/rpg-core/status-effects/<file>.yml, or shipped with addons like rpg-alchemy). An effect has:
- ID (
poison,strength,slow,regen,stun,vulnerability, etc.) - Display name + icon (CustomModelData)
- Stat modifiers (additive or percent, applied while active)
- Periodic tick action (e.g., "deal 1 true damage every 20 ticks")
- Stacking strategy
- Hidden flag (e.g., for boss invisibility)
Schema¶
poison:
display: "&2Poison"
category: debuff # buff | debuff | neutral
stacking: refresh # refresh | stack-power | take-max | independent
hidden: false
stat-modifiers: # while active
defense:
kind: percent
value: -10
tick:
interval-ticks: 20
action: damage # damage | heal
amount: 2
source: poison # shown in damage indicators
on-apply:
sound:
key: entity.spider.hurt
volume: 1.0
pitch: 1.5
particles:
type: DRIPPING_WATER # Bukkit Particle enum name (case-insensitive)
count: 8
spread: 0.3 # shorthand — all three axes; override per-axis with spread-x/y/z
on-expire:
particles:
type: SMOKE_NORMAL
count: 4
Stacking strategies¶
| Strategy | Behavior |
|---|---|
refresh |
If reapplied with new.level >= current.level, replace duration; else ignore |
stack-power |
Sum levels; sum durations (capped) |
take-max |
Take the higher of (currentLevel, newLevel); longer duration wins |
independent |
Multiple copies run in parallel with independent durations and levels (e.g., from different sources) |
Application¶
- Item right-click (
CONSUMABLEitems) - Ability effect (
apply_status{id=, level=, duration=, target=}) - Mob hit (mob's ability uses
apply_status) - Admin command (
/rpg status apply <effect> [player] [duration]) - Region flag (e.g., a "haste zone" applies a
hasteeffect while inside)
Lifecycle¶
- Apply —
StatusEffectService.apply(target, effectId, level, durationTicks, sourceId). Stacking rules resolved. - Tick — on every interval tick, the effect runs its
tick.action(an ability invocation in DSL form). - Modify stats — while active, modifiers are folded into the target's
StatHolderaggregation. - Expire — when duration reaches 0 (or
StatusEffectService.clearis called),on-expireruns and modifiers are removed.
Built-in effect catalog¶
These effects ship in plugins/rpg-core/status-effects/example.yml on first run. They're ready to use in abilities, consumables, and region flags without any authoring.
| ID | Category | What it does |
|---|---|---|
poison |
debuff | Deals 2 damage every 20 ticks (source: poison); −10% defense while active |
regen |
buff | Heals 1 HP every 10 ticks |
strength_boost |
buff | +25 flat strength while active |
slow |
debuff | −30% speed while active |
burning |
debuff | Deals 3 fire damage every 20 ticks (source: fire); spawns FLAME particles on apply |
frozen |
debuff | −80% speed while active; spawns SNOWFLAKE particles on apply |
silenced |
debuff | Ability listener suppresses all ability casts while this effect is active; no stat mods |
haste |
buff | +50% mining_speed while active |
Define your own in plugins/rpg-core/status-effects/<file>.yml following the schema below. Addons (e.g., rpg-alchemy) can ship their own files alongside.
API surface¶
StatusEffectService svc = RpgServices.statusEffects();
svc.apply(entity, "poison", 2, 200, "source-id-for-stacking");
svc.clear(entity, "poison");
List<ActiveEffect> active = svc.active(entity);
Effects display¶
Players see their active effects via:
/effectscommand — opens a GUI listing active effects with time remaining and icon- Optional HUD line in scoreboard / action bar (configured in
rpg-hud) - Damage indicators show a small tag when a status-effect tick deals damage (configurable)
hidden: true effects don't appear in the GUI or HUD (used for boss invisibility, internal flags).