special abilities

Started by
10 comments, last by frob 6 years, 10 months ago
Hi people,

Some background context:
Tactics game with characters that need to execute unique special moves.

I don't know if I am over thinking this but I was wondering what is the best way to code "special abilities"?
I mean I could probably hard code it(maybe - haven't tried yet) but I am planning every character to have a unique ability of some kind... And I don't know how to structure it correctly.

sample abilities:
aoe damage,
life drain,
debuff added on hit,
delayed attacks
stun on hit
snare on hit
interrupt on hit
aura buffs
etc etc etc
as oppose to a regular attack which just checks some damage against some defense.

my point is the list will go as long as I can think up new abilities for new characters and I want it to simple to implement each time if possible.

Any tips for a beginner like me?

Thanks!
Advertisement
There are a lot of details for each one, and you may end up with a different path than others take.

That type of thing is often implemented with a command pattern. You define a common method like DoTheThing() and all the various kinds of actions implement their own details for the interface.

If you are building full systems (and since you tagged it as unity) I'd make a MonoBehaviour that provides a set of operations and abstract or virtual functions, then child classes that specialize those methods uniquely. Then let anything work with the behaviors to do what they are supposed to do. Allow them to be chained, or have their parameters adjusted independently, whatever you need.

Alternatively, if it isn't being done inside Unity's code, do a similar thing inside your battle system's processing. Use a factory method of some type to generate the objects following the interface with appropriate data, then call the methods on them.

my point is the list will go as long as I can think up new abilities for new characters and I want it to simple to implement each time if possible

In general, you can't.

Being able to simple extend in any direction means you can simple extend in every direction, which means you cannot pre-define any structure, since that blocks all extensions that work differently than the structure assumes. Without structure there is nothing to extend.

So in any case, you have to set a limit somewhere, and work within those limits. Going outside those limits is possible, but then some assumptions you made become invalid, which means you have to rewrite parts, in the worst case, rewrite everything.

A second consideration here is that more is not always better. Suppose I write a game with 300 unique attacks. Are you going to remember all of them? Probably not. Are you going to remember how each of the 300 attacks works out against the 299 counter-attacks? That's around 9,000 unique combinations to remember. Do you ever have a chance to find out the best strategy to fight an enemy? You have 10 unique attacks, I have 10 unique attacks, which one to do in which order, depending on the order of attacks that the opponent does? That's about 10! * 10! variations, good luck finding a strategy. Of course when I switch to a different 10 of the 300, you're back at square one, you can't use previous experience, since everything is unique, right?

Anyway, the technical solution you're looking for here is attacking in multiple dimensions. "damage / defense" is one dimension. "stunnness" for example could be a second dimension, "life force" could be a third dimension, etc. An attack works in all dimensions, just some of the dimensions have 0 force. You also have to define how recovery works in each dimension. Maybe damage doesn't reduce in time, but life-force always increases if not full, etc. Delayed attacks can be done by a character getting future attacks (in 3 turns, foo attack will happen), reducing the number of turns until it hits 0, and then you execute it. It's also another dimension (attack force now, 1 turn in the future, 2 turns in the future, etc etc).

The idea is that you build a structure where all attacks fit into, in some way. Once you have that, it's a large number game, where you have to decide all the attack values for all attacks in all dimensions.

Obviously, the above attack structure blocks any attack idea that doesn't fit in the structure. You can add more dimensions of course, but the more dimensions you add, the harder it becomes to balance things, and to make it a fun strategy game. It is probably better to err at keeping it too simple. That's ok though, as you can make a next improved game then :)

If you read over his list more carefully, these are all quite common in certain genres. For example, the Dragon Age series offers all of those abilities and more besides.

Something like a high-level battleaxe may have AoE damage, plus short-term life drain, plus interrupt on hit.

A magic weapon may add a debuff on hit (slow, snare, stunned). A poisoned weapon may add a poison debuff. A fire-enhanced weapon may add a fire debuff in turn briefly causing a panic debuff, an ice-enchanted weapon may add slow or stun debuffs.

A blunt weapon or a shield strike may have a knockback effect, interrupt effect, and possibly a combo effect against already stunned or frozen enemies.

sorry for late reply, thanks guys. appreciate it I'll look into the command thing.

@Alberth
I don't think a massive amount of options is bad for perfect information games, it stops it from being solved quickly, think chess vs checkers. or shogi vs chess if your familiar. I prefer shogi > chess > checkers.

In terms of balancing, I found out perfectly balanced games are not always the best route anyway despite how everyone wants it. As long as something isn't blatantly overpowered and everything is counterable it will find a continually shifting meta game ideally.

again, thanks for the replies!

I don't think a massive amount of options is bad for perfect information games, it stops it from being solved quickly, think chess vs checkers. or shogi vs chess if your familiar. I prefer shogi > chess > checkers.
Ha, my thoughts immediately jumped to Go as counter-example, the 4000 years old game that you explain in about 5 minutes, and takes a life time to master.

But fair enough, it's your game, you decide about the rules :)

If you really want this to be as flexible as possible I would code "actions" for each part of an ability. An "shoot arrow" ability would consist of a "shoot" action and a "damage" action. "shoot" would simply need a direction, speed and target and once it hits something "damage" will run. A fireball would use "shoot", "damage", "aoe" and another "damage" for aoe since we want to decouple damage from aoe since you might want to have a aoe slow spell later.

You can create infinite actions but with just a dozen you can already make thousands of unique abilities. Consider implementing a split projectile, chain, teleport, dot, status effect, etc. This takes a lot of work to implement properly, but once you have this right you can create abilities with json and create a tool that exports correctly to your expected json format.

To get a little bit into detail. An ability is basically a list of actions, and you run them one by one. Some abilities need a target (shooting) some might not (aura) some might even be always on like a passive, this needs to be stored in the ability itself and actions should have access to these variables. Whenever an ability is cast you work down the list of actions.

  1. A explosive arrow will first run the shoot action with a sprite effect attached to it until it hits something. The position or creature that has been hit becomes the target.
  2. Now the damage action will run, this does instant damage to the target if possible.
  3. Now the AOE action is triggered with a particle effect attached to it. AOE creates a list of targets within the area.
  4. Now another damage action will be triggered that deals X fire damage to all targets supplied by the AOE action.

I reverse engineered how DOTA 2 handles abilities with some success. It's great for modding and you can learn a lot from it's data driven design. https://developer.valvesoftware.com/wiki/Dota_2_Workshop_Tools/Scripting/Abilities_Data_Driven

... An "shoot arrow" ability would consist of a "shoot" action and a "damage" action. ...

For systems like this you should think even more generic. Remember the stated purpose was to encode special abilities.

A weapon can have any number of attributes attached through composition (or components if you prefer the word).

You can query the weapon to get packets of information back. Perhaps the name ("Sword of Stabbing", "Vorpal Axe of Gushing Death") and the attributes ("97 attack, 25 AoE, +34 poison, +75 fire, +20 against undead"). All those attributes can be put together by querying the attributes for their details and converting the results to words. Maybe one adds 14 to attack, another adds +34 poison, another adds 15 fire, another adds 40 fire, another adds 20 fire, and so on.

To apply them, you might have a system that takes that packet of combined details (97 attack, 25 AoE, +34 poison, +75 fire, +20 undead) and bundle of details of the strike (direct hit, within AoE, position, etc) and bundle of details of the attackers (47 strength, 47 magic, level 23, no active buffs, etc.) and the bundle of details about the defender (37 main defense, 17 additional poison resistance, -40 additional fire resistance, etc.) and combines them all into a computed damage, giving a bundle of data describing the damage of the attack.

As another alternative, you may take the bundle of details about the defender and attacker and pass them around to all of the weapon's components. You'd use a similar system to query each attribute about how they affect the attack, with the end result being a similar bundle of data describing the damage of the attack.

When you've got that final bundle of damage data you can display it to the player however you want.

Thus it doesn't matter what the weapon was, an axe or sword or spear or throwing knives or arrows or magic fireball, all of them can be queried for the damage they do to any defending object.

The same applies to the actions themselves, although somewhat differently. You might ask the character's weapon if it can hit a specific target. If the attribute includes an AoE, that's something visual you can draw. If it can hit the target the yes/no becomes the choice of graphic, weapon metadata provides the graphics to use, AoE describes the size of the graphic. That enables all weapons to use the same code, regardless of their being short range or long range or magical or something else.

Can you provide more context on the tactics aspect? Great replies in this thread but they seem to be focused on action style games. The ideal structure for tactics game abilities will be dependent on how your systems are set up.

Also, look into C#'s delegates and events. Again, the structure of your systems will determine the best direction for expandable abilities/effects, but the ability to inject unique code into a commonly fired event could be of great organizational use to you. With events you can easily combine multiple effects in the same call too.

Setting up an "ability"-System is thought to complex. You need to brake down what you are trying to achieve with as simple "bricks" as possible. A weapon shouldnt normaly now that it is a weapon but the combat handling code should as same as a player shouldnt manage a hit by himself. Taking this simple view into account let you come to the conclusion that abilities are simply states that are took into computation of an result X from a system Y in your game so you should handle them not as "when I hit with the axe it shoots a fireball on my enemy" but instead as "the axe has a missle effect of kind 'Fireball' attached the combat system will iterate over it and create a missle of kind 'Fireball' at position W with direction Z" and let the fireball do the thing it naturally does.

We did something like this in an economy game where "Wood Cutting" was one action that was iterated from the action controller, validated to have an axe attached and facing something wooden (like a tree). Our items have had proeprty slots e.g. for an effect that raises speed of the "Wood Cutting" action or the ammount of logs generated. The axe dosent now what current action was nor if it is hitting a tree or stone wall either.

To speed things up you should break your abilites into basic tasks/properties chained with other tasks/properties where tasks are to go back to the fireball example, to create a missle of type X at position Y with direction Z where properties are took into account on computing a result only. Setting this up in a tree structure like with NodeCanvas (http://nodecanvas.paradoxnotion.com/) in Unity structuring your actions/conditions to an abilities behavior would be very simple and extensible

This topic is closed to new replies.

Advertisement