First, a definition of an ability in this context: any usable THING that a player or NPC can use during or outside of combat, often known as attacks, skills or spells.
Abilities can take on many different forms - attack, healing, buff, debuff, DOT, HOT, transportation, enchantment, mechanic-bending, and just about anything else you can think of.
The question is: how do you adaquately represent abilities within the code, without duplicating code, remaining as efficient as possible, and still not a complete pain to program against?
Early on when I was new to development, I used a giant set of variables - damage, debuff1, debuff2, etc. (actually called maladict1/2 at the time) Over time I learned that not only was this not efficient to program with, but it was also extremely poor design from an object-oriented perspective.
Lately I've been using a single list in my code to manage the different properties of an ability. Generic things (like casting cost, time delay, or cooldown) still receive their own variables - because those are broad, they matter for 98% of all abilities. Specific mechanics however, such as damaging an opponent, healing yourself, healing your party, slowing time, creating natural disasters, or teleporting your enemy 50 yards away - all receive an entry in the list.
A self-damaging powerful attack might be:
effects = list(DAMAGE_ENEMY = 120, DAMAGE_SELF = 10, DAMAGE_TYPE = PHYSICAL)
Which would cause 120% physical damage to the enemy and 10% to yourself.
A debuff with a DOT component might be:
effects = list(APPLY_SLOW = user.GetInflictedCondition(SLOW), DAMAGE_OVER_TIME=20, DAMAGE_TYPE = MAGICAL)
(you'll notice the method call above, these lists are created within New() for substantially more flexibility, and since only one copy of each ability is instantiated it's not a load)
However even this system has it's limitations. Handling damage abilities that use multiple elements, for example, is hackish at best (looping through the list and executing each element in order, for example) and handling complex abilities that may require multiple usages of similar types is also poor.
What are your strategies for handling abilities in your own games - and why? I find that, no matter how often I revisit this topic, I don't tend to make much ground in solving the solution with the "best" method that feels the least like hacking, and still maintains the above criteria: fast to execute and fast to program.