The way I am implementing this in the game I am working on is to have a mixture of character states and what I have termed damage pipelines.
So a character can be
dead and character skills check against that state when deciding what options are available to them right now. Some attacks will change character state.
The damage pipeline idea works on the concept of having a tree of increasingly specialised damage types, a bit like this:
blunt |- - - - - - - - physical
shock |- elemental |
acid | |
| - magical
infernal |- spiritual |
Basically a creature has both an incoming and outgoing damage pipeline and a buff can be applied at any level, so something that buffs magical defences or attacks will affect everything to the left of
magical whereas one could alternatively apply a very specific buff to - for example -
fire which only affected attacks with that aspect.
This can simply model both positive and negative buffs and as long as you remember to pass all your attacks and defences through the pipeline, it's reasonably easy to work with.
Edit: In terms of my game I have two types of buff that typically come into play, some are standing buffs, typically related to equipment so while a certain item is equipped the user has a bonus to a certain defence or damage type, others are per-use or power based buffs where a character has a buff placed on them for a certain number of turns ( I'm working with turn-based play, which makes it easier, but could work fine otherwise ) in both cases the buff which is added to the pipeline has a value by which it affects that pipeline and a timeout - technically I am using an internal timeout so buffs remove themselves when they hit their limit, but you could as easily have a manager attached to your damage pipeline that just sweeps the buffs on that pipeline before running damage through it and removes any that are out of date - how exactly you would choose to operate this would probably depend somewhat on other factors, such as what you are showing in the interface to indicate if a buff is active- if you're timing out the "active buff" indicator you might as well pop it off the damage pipeline at the same time.
Damage Over Time is not treated as a buff in quite the same way - that is operated as an effect that - once per turn - inflicts typed damage through the damage pipeline for a certain number of turns. I use the same timed counter model for the cooldown on most powers- a turn based environment makes this easier but if I was working it in a real time system I would probably have this on virtual "turns" ever second or part thereof to get the same effect.
This DOT model gives some interesting possibilities because it is always going through the pipeline so if a character is hit with a 5 point fire DOT they apply a fire defence buff on the next turn to reduce the effect or on the other hand apply a weakness against fire debuff to an opponent after inflicting a damage over time attack.