Abstract
Problem: How should RPG status effects (DOTs, buffs, summoned creatures, held portals, traps) be architected at a systems level?
Approach: Tim Cain draws on his experience building status effect systems for Fallout, Arcanum, and Pillars of Eternity to outline a universal data structure and three-method lifecycle pattern.
Findings: Every status effect needs a target, caster, source reference, and runtime management data. The lifecycle is handled by three methods β Begin, Tick, and End β each with distinct responsibilities. The hardest part isn't the core system but the edge cases: save/load persistence across map transitions, safe cleanup when called from unexpected places, and resisting the temptation to overload the system.
Key insight: The End method must be safely callable from many different places (tick expiry, creature death, caster death, map unload), so it must never assume a specific calling context or that referenced objects still exist.
The Data Structure
A status effect is any effect placed on an object in the world β usually a creature, but it can also be a door (hold portal), a location (glyph trap), or a summoned entity (zombies, conjured weapons).
Every status effect data structure needs:
- Target object β the creature, door, location, or item receiving the effect
- Caster β who created it (player, enemy, trap)
- Source information β where to look up the effect's rules (spell, item, creature ability)
- Runtime data β tick rate, time remaining, pointers to associated objects (e.g., the summoned zombie itself)
The Three Methods: Begin, Tick, End
Begin
When a status effect is created:
- Instantiate the data structure and add it to a list
- Create any associated game objects (summoned creatures, conjured items)
- Create UI/UX elements: icons, particle effects, sounds, ground markers
- Store references to everything created so you can maintain and clean it up later
Where to keep the list depends on the game. Options include a single master list of all active effects, per-creature lists, per-caster lists, or a world-level list for location-based effects. The choice depends on how ticking works.
Tick
The periodic update is the core of the system. How often it fires depends on the game type:
- Real-time games: Tick every frame/heartbeat update. Sort the list by next-update time so you can early-out as soon as you hit an effect that doesn't need updating yet β very efficient.
- Turn-based games: Tick per turn. Effects can live on the target creature (DOT activates on the target's turn), on the caster (caster's maintained spells update on their turn), or on a master list checked each round.
During a tick:
- Check time remaining β if expired, call End
- Apply the effect's ongoing logic (damage, size changes, damage type transitions)
- Update UI elements (countdown bars, color shifts, icon changes, sound transitions)
End
Cleanup when the effect expires or is terminated:
- Destroy or handle associated objects (summoned creatures die or collapse; dead bodies may remain)
- Remove UI elements (icons, particles, sounds)
- Remove the status effect from whichever list it lives on
The Critical Safety Rule
The End method gets called from many places: from Tick (timer expired), from creature death (target dies, remove its DOTs), from caster death (maintained spells collapse), from map transitions (objects destroyed). It must be safe to call from any context. Every reference it touches must be validated β objects may already be destroyed.
Versatility and the Temptation to Abuse
Status effects are extremely versatile. Spells, abilities, traps, summoned creatures, environmental hazards β they can all be status effects under the hood. But this versatility invites scope creep. People see the system and think "can I also use this for X?" which leads to complexity explosions.
Save/Load: The Hard Part
Persisting status effects across map transitions is one of the hardest parts of save/load systems. Consider: a player casts Hold Portal on a door, descends a dungeon level, then returns. The system must:
- Save the status effect with a timestamp when leaving the map
- On re-entry, reload the effect, calculate elapsed time (delta), check if the caster is still alive, check if the timer expired
- Reconstruct any associated objects (particle effects, fog walls) β either from saved state or by re-creating and re-orienting them
- Only then safely call Tick or End as appropriate
The associated objects (targets, casters, summoned entities, visual effects) are what make save/load particularly difficult. Tim notes this was one of the hardest aspects of the save/load systems he built, and recommends his separate video on saving and loading for more detail.