Skip to content

Dynamic Effects

Dynamic effects are the simplest integration path. They are created by firing a ModEvent from any Papyrus script — no quest script or plugin registration required.

They are ideal for:

  • Temporary conditions (a teasing encounter, a debuff)
  • Effects that come and go infrequently
  • Mods that don't want to maintain a persistent plugin quest

Performance

Dynamic effects are stored in a map<string, EffectData> per actor. Calling SetDynamicArousalEffect or ModDynamicArousalEffect very frequently (e.g. every frame) is expensive. For high-frequency updates prefer a static effect.

Creating or replacing a dynamic effect

; slaSetArousalEffect(Actor who, string effectId, float initialValue, int functionId, float param, float limit)
int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)             ; Actor to affect
ModEvent.PushString(handle, "MyMod_Tease") ; Unique effect ID — namespace it to avoid collisions
ModEvent.PushFloat(handle, 50.0)           ; Initial value added to arousal immediately
ModEvent.PushInt(handle, 1)                ; Function ID (see table below)
ModEvent.PushFloat(handle, 2.0 / 24.0)     ; param: half-life of 2 hours
ModEvent.PushFloat(handle, 0.0)            ; limit: decay stops at 0
ModEvent.Send(handle)

Setting a new effect with the same effectId on the same actor replaces the previous one. The initialValue is applied as a delta relative to the effect's current value — if the effect already exists and has value 30, and you pass initialValue = 50, arousal increases by 20.

To clear an effect, set functionId = 0 and initialValue = 0:

int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_Tease")
ModEvent.PushFloat(handle, 0.0)
ModEvent.PushInt(handle, 0)
ModEvent.PushFloat(handle, 0.0)
ModEvent.PushFloat(handle, 0.0)
ModEvent.Send(handle)

Modifying an existing dynamic effect

Adds modifier to an effect's current value, clamping at limit:

; slaModArousalEffect(Actor who, string effectId, float modifier, float limit)
int handle = ModEvent.Create("slaModArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_Tease")
ModEvent.PushFloat(handle, -20.0)   ; reduce by 20
ModEvent.PushFloat(handle, 0.0)     ; clamp: don't go below 0
ModEvent.Send(handle)

The limit direction is inferred from modifier: if modifier < 0, limit is treated as a lower bound; if modifier > 0, it is an upper bound.

Timed function IDs

ID Name Behaviour
0 None Effect stays at its current value indefinitely
1 Decay Value halves every param game days. Stops (and removes effect) when it reaches limit
2 Linear Value changes by param per game day. Stops at limit
3 Sine wave value = (sin(time * param) + 1.0) * limit — oscillates continuously, never stops
4 Delayed step value = 0 until param game days have elapsed, then value = limit

For function 1 (decay), if param is negative the effect grows until reaching limit.

Example recipes

Post-sex arousal that fades over 4 hours

int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_PostSex")
ModEvent.PushFloat(handle, 100.0)      ; start at 100
ModEvent.PushInt(handle, 1)            ; decay
ModEvent.PushFloat(handle, 4.0 / 24.0) ; half-life = 4 in-game hours
ModEvent.PushFloat(handle, 0.0)        ; remove when it reaches ~0
ModEvent.Send(handle)

Teasing effect capped at 50

int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_Tease")
ModEvent.PushFloat(handle, 0.0)
ModEvent.PushInt(handle, 2)              ; linear
ModEvent.PushFloat(handle, 200.0 * 24.0) ; +200 per hour
ModEvent.PushFloat(handle, 50.0)         ; cap at 50
ModEvent.Send(handle)

Penalty that recovers over a day

int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_Penalty")
ModEvent.PushFloat(handle, -50.0)       ; start at -50
ModEvent.PushInt(handle, 2)             ; linear
ModEvent.PushFloat(handle, 50.0 * 24.0) ; +50 per hour
ModEvent.PushFloat(handle, 0.0)         ; stop at 0
ModEvent.Send(handle)

Ambient oscillating arousal

int handle = ModEvent.Create("slaSetArousalEffect")
ModEvent.PushForm(handle, who)
ModEvent.PushString(handle, "MyMod_Ambient")
ModEvent.PushFloat(handle, 0.0)
ModEvent.PushInt(handle, 3)      ; sine
ModEvent.PushFloat(handle, 1.0)  ; frequency: one cycle per game day
ModEvent.PushFloat(handle, 10.0) ; amplitude: oscillates 0–10
ModEvent.Send(handle)

Cross-fork note

These ModEvents are only registered by real SLA NG — OSL Aroused and other forks do not provide them. If your mod must run on multiple forks, guard the ModEvent path behind a version check; see Compatibility.