1

In my game I want characters to be able to cast spells which deal a certain amount of damage of a certain type to other characters in the game.

I also want abilities that negate an amount of damage of a certain type to be equipped to a character.

I don't want to have to program a huge wall of damage resistances that usually is 0 for every single character in the game (plus I want abilities that can also double damage or transform it), I want the triggered ability to be able to modify other abilities. so I thought of placing the spell objects themselves on the stack so that other abilities can edit them. but here's the problem. each ability has different names, numbers and types of variables. how do I access every ability that deals fire damage without programming a case in the ability modifier class for every single ability that deals a certain amount of damage of a certain type. do I have to write a long list of ability attributes in the super class, most of which I won't use? if I do then its just as bad as having to write a huge list of variables that modify abilities on each character. I want to program a game without having to write long lists of attributes on classes that don't get used 99% of the time. Is this even possible?

e.g. I want a passive ability that doubles the amount of fire damage you deal.

I DON'T want to do this: Spell.target.fireDamageMultiplier = 2; because then I will have tons of similar attributes on every single entity

I CAN'T do this: Spell.damage *= 2; because not every ability has a damage attribute

I DON'T want to do this: Firebolt.damage *= 2; because then I have to write a special case for every ability that has a damage attribute

I thought of having different classes of abilities than my ability can inherit from but I heard not to do this and c# doesn't have multiple inheritance anyway. I also read to favor composition of inheritance but then again I have the problem of having a long list of variables(or spell type references) for each spell most of which I won't use. so this still hasn't solved my problem of writing messy code that gets out of control the more abilities I add.

So how do I edit abilities without writing a special case for every single ability?

M.Anthony
  • 11
  • 3

4 Answers4

1

I have implemented something slightly similar, and came up with a solution that may work for you. It sounds like you want Character A to cast a spell on Character B, and Character B may be wearing some type of armor (or protection or something that ultimately does something like armor). So, structure the code like that.

The Character class should have a list of CastModifier objects and a list of ReceiveModifier objects. (I don't want to use the term "spell" in the names, as it is ambiguous as to whether the spell is being cast by them or cast onto them).

When a character casts a spell, it is sent through a CastSpell function that applies those CastModifiers to the instance of the spell. And when a character has a spell cast on him, he receives it via a ReceiveSpell function, which runs through the ReceiveModifier objects.

So if A casts a fire spell with 100 damage and he has a *2 fire damage buff, it will send the object with 200 fire damage to character B. If B has a -50 fire damage protection buff, then he receives the spell via ReceiveSpell, which reduces the damage to 150 before applying that damage to his health. Also, you need to dictate the order of operations inside the CastModifier and ReceiveModifier classes - set it so that cast applies multiplication before addition, and receive applies addition before multiplication, for example (the orders should be reversed between the two). And try to be consistent with the operations; I always multiplied and added, so sometimes I multiplied by a fraction or I added a negative number.

I used some inheritance in my implementation, so there would be an ImmediateSpell class and a DurationSpell class to separate spells that have a 1-time hit from those that inflict damage over time. Multiple inheritance would have been helpful for the damage classes, but it was sufficient to set that as a property of the spell.

user3685427
  • 247
  • 1
  • 3
0

Well, from game design perspective, the character could have "fire boost" and "fire resistance" stats. Then, there could be abilities that increase and decrease those stats and damage of this type would be increased/decreased accordingly. And if "resistance" stat is negative, then character would take more damage from that element. Most RPGs handle elemental damage this way.

Euphoric
  • 36,735
  • 6
  • 78
  • 110
0

I don't think you need many classes, nor members of those classes, to hold lots of variety.

Instead, you just want to identify the directions of variation, e.g. elements (Fire, Ice, Shadow), effects (Damage, Flight, Healing, RunSpeed), magnitude (100 damage, 50% increased speed), duration (instant, 100s, 1 day) and so forth. Each of those categories is a variable, and the values can be read in from JSON / DB / etc.

Consider e.g.

class Spell {
    Effect effect;
    Set<Elements> elements;
    Number baseMagnitude;
    Number baseDuration;
}

class BuffEffect {
    Effect modifiedEffect;
    Element affectedElement;
    Func<Number, Number> magnitudeModifier; // or some modifier stacking scheme
    Func<Number, Number> durationModifier;
}

class Character {
    List<BuffEffect> activeBuffs;

    void castSpellOn(Spell spell, Character target) {
        Number magnitude = spell.baseMagnitude;
        Number duration = spell.baseDuration;

        var applicable = from buff in activeBuffs
                         where buff.modifiedEffect == spell.effect and spell.elements.Contains(buff.affectedElement)
                         select buff

        foreach (buff in applicable) {
            magnitude = buff.magnitudeModifier(magnitude);
            duration = buff.magnitudeDuration(duration);
            // Or apply stacking scheme
        }

        // Same for target's resistances

        // do stuff to target
    }
}
Caleth
  • 10,519
  • 2
  • 23
  • 35
0

A good start would be to give each thing in the game (both characters and items) a list of special attributes (note: using containment here). That list may be empty, or it may contain attributes that inherit from an abstract base class (single inheritance).

This obviates any need for every item in the game to have every attribute associated with it.

Each spell (or any other action) should know what attributes will affect its outcome. So when casting a spell, search the caster and everything they are carrying for relevant attributes. Then search the victim, and everything they are carrying, for relevant attributes that might protect them. You can now calculate the outcome.

Simon B
  • 9,167
  • 4
  • 26
  • 33