Wednesday, December 31, 2014

Ability System

One of the core parts of any RPG is casting spells. Implementing a spell system can get pretty hairy, and I wanted a system that was robust enough to handle both traditional offensive spells (fireball, magic missile), buffs (sheild), damage over time (poison), debuffs (curse) and healing. Additionally, items would be able to "cast" spells, either through one time use (healing potion) or a proc (flaming sword that catches enemies on fire).

The Ability class is what I came up with.

An ability is anything spell-like a character can use. The key parts:

public AbilityTargetType targetType { get; set; }
The target type defines what type of character, tile or group are affected by the ability. A self healing spell would only have target Self. But something like fireball would have LOS (line of sight) target. 

These types are used in the logic that executes each ability to return a list of character affected by the ability.

 public enum AbilityTargetType
 {
 Self,
 SingleFriend,
 SingleFoe,
 AllFriends,
 AllFoes,
 PointEmpty,
 PointTarget,
 LOSEmpty,
 LOSTarget,
 }
public TilePatternType tilePatternType { get; set; }
For AoE (Area of Effect) abilities, the Tile Pattern type is key. Something like fireball explodes in a large circle around the radius.

 The Tile Pattern is used to return a group of tiles surrounding the target point. From there, you can determine the characters affected by each ability. Targets of type Self, AllFriends, etc ignore the TilePattern attribute.

 public enum TilePatternType
 {
 Single,
 FourAdj,
 EightAdj,
 NineSquare,
 ThreeLineVert,
 ThreeLineHor,
 }
 public List<ActiveEffect> activeEffects { get; set; }
 public List<PassiveEffect> passiveEffects { get; set; }
Abilities also contain a list of active and passive effects. Both Active and Passive effects are pretty similar. The main difference is that an active effect is "applied" to a character each turn, while a Passive Effect simply changes stats. So an active effect would be used for damage, healing, or damage over time. Buffs that give HP or extra stats would be passive effects.

The effects also contain a statType attribute:
public StatType statType { get; set; }

 public enum StatType
 {
 ActionPoints,
 Armor,
 Damage, 
 Heal,
 HitPoints, //temp buff to hitpoints
 Attack,
 Teleport, //move character to target
 Knockback, // move targets away from character
 Explode, //move characters away from target
 Stuck, //character cannot move
 Dispell, //remove active effects
 Stun, //player can't do anything
 }
StatType is sort of a catch-all of everything in the game. There are obvious stats listed in here, like ActionPoints, Armor, Attack, etc. But there are also concepts like Teleport, Knockback and Explode, which actually move the target on the board in specific ways. Any unique "effect" needs to have a unique stat type, and then be implemented in the AbilityHelper method.

So far the ability system is flexible enough that new abilities can be described in data and will give the game a ton of breadth and range.

You can even come up with new and interesting abilities by combining multiple active effects in interesting ways.

A "charge" ability for a warrior class is implemented like this:

 public static Ability getCharge()
 {
  ActiveEffect chargeEffect = new ActiveEffect() { name = "Charge", duration = 1, minAmount = 5,maxAmount=5, statType = StatType.Teleport };
  ActiveEffect knockbackEffect = new ActiveEffect() { name = "Knockback", duration = 1, minAmount = 1,maxAmount=1, statType = StatType.Knockback };
  ActiveEffect damageEffect = new ActiveEffect() { name = "ChargeDamage", duration = 1, minAmount = 10,maxAmount=20, statType = StatType.Damage };

  Ability charge = new Ability()
  {
   name = "Charge",
   description = "Charge in a straight line towards an enemy, causing damage",
   ap = 5,
   range = 5,
   uses = 1,
   targetType = AbilityTargetType.LOSTarget,
   tilePatternType = TilePatternType.Single,
   activeEffects = new List<ActiveEffect>() { knockbackEffect, chargeEffect, damageEffect },
   passiveEffects = null,
  };

  return charge;
 }
As you can see, the charge has three effects. First, the target is knocked back a space. Then damage is done. Finally, the character teleports to the target's tile.

No comments:

Post a Comment