StatusEffectService
Apply, tick, and remove timed status effects on entities.
What is it for?
Use StatusEffectService when your mod has temporary buffs, debuffs, or states:
- A speed potion that lasts 30 seconds.
- A poison effect that ticks damage over time.
- A stacking armor buff.
- A status that should be removed on death.
It handles duration, refresh, stacking, overriding, and per-tick callbacks.
Core interfaces
public interface IStatusEffect
{
string Code { get; }
EnumStackMode StackMode { get; }
int MaxStacks { get; }
bool PersistThroughDeath { get; }
EffectCategory Category { get; } // Buff, Debuff, or None
IReadOnlyCollection<string> Tags { get; } // "fire", "slow", "poison", ...
void OnApply(Entity entity, IStatusEffectInstance instance);
void OnRemove(Entity entity, IStatusEffectInstance instance);
void OnTick(Entity entity, IStatusEffectInstance instance, float dt);
}
Categories
Effects can be classified as Buff, Debuff, or None. This enables dispel-by-category:
using ArcanumLib.Core;
using ArcanumLib.Effects;
var svc = ArcanumServices.Get<IStatusEffectService>()!;
svc.RemoveByCategory(entity, EffectCategory.Debuff);
Immunities and resistances
Effects can be tagged (e.g. "fire", "slow"). Entities can be made immune to or resistant to specific tags:
// Full immunity — effects with "fire" tag are rejected entirely
svc.AddImmunity(entity, "fire");
// 50% resistance — effects with "slow" tag last half as long
svc.AddResistance(entity, "slow", 0.5f);
// Check
bool isImmune = svc.IsImmune(entity, "fire");
// Remove
svc.RemoveImmunity(entity, "fire");
svc.RemoveResistance(entity, "slow");
Resistance reduces the effective duration: actualDuration = baseDuration * (1 - resistance). A resistance of 1.0 is equivalent to full immunity.
Stack modes
| Mode | Behaviour |
|---|---|
Independent | New, separate instance every time. |
Refresh | Resets the existing instance’s duration. |
Stack | Increases stack count up to MaxStacks. |
Override | Replaces the old instance. |
Quick example
using ArcanumLib.Core;
using ArcanumLib.Effects;
var svc = ArcanumServices.Get<IStatusEffectService>()!;
var instance = svc.Apply(entity, new SlowEffect(), durationMs: 10000);
Usage
Apply
var instance = svc.Apply(entity, myEffect, durationMs: 10000, data: null);
Tick
Call this from a client/server tick handler:
svc.Tick(dt); // dt in seconds
Remove
svc.RemoveAll(entity);
Example effect
public class SlowEffect : IStatusEffect
{
public string Code => "mymod:slow";
public EnumStackMode StackMode => EnumStackMode.Stack;
public int MaxStacks => 3;
public bool PersistThroughDeath => false;
public void OnApply(Entity entity, IStatusEffectInstance instance)
{
entity.Stats.Set("walkspeed", "mymodSlow", -0.1f * instance.StackCount, true);
}
public void OnRemove(Entity entity, IStatusEffectInstance instance)
{
entity.Stats.Remove("walkspeed", "mymodSlow");
}
public void OnTick(Entity entity, IStatusEffectInstance instance, float dt) { }
}
Stat modifier effect
For simple stat changes, inherit from StatModifierEffect:
var speedBuff = new StatModifierEffect(
code: "mymod:speedbuff",
statCategory: "walkspeed",
value: 0.2f)
{
StackMode = EnumStackMode.Refresh,
PersistThroughDeath = false
};
Events
svc.OnEffectApplied += (entity, instance) => { /* ... */ };
svc.OnEffectExpired += (entity, instance) => { /* ... */ };
Use events to drive UI, logging, or side effects without touching effect classes.
Lifecycle
StatusEffectServiceis registered inArcanumServicesbyStatusEffectModSystemduringStartClientSide/StartServerSide.StatusEffectModSystem.Dispose()unregisters the service and clears state on world unload.- Methods are safe to call before the service is ready; they will return no-ops / empty results when the service is not registered.