0

I'm currently working on a Magic system for a game I'm building and I feel like the references to the exact statistic are a bit complicated. I got a Vital class:

public int baseValue;
public int currValue;

public string statName;

For reference to the vitals used in the game, I have an enum:

public enum VitalName { Health, Mana}

I also have a Spell class:

public string spellName;
public MagicEffect magicEffect ;

with a derived BlackMagic class:

public int BaseDamage;

The MagicEffect Base Class has nothing but VitalModifier is derived from it:

public int vitalToAdjustIndex;

and finally, a LivingBeing class with this:

public Vital[] vitals = new Vital[Enum.GetValues(typeof(VitalName)).Length];

private void SetupVitals()
{
    for(int i = 0; i < vitals.Length; i++)
    {
        vitals[i] = new Vital
        {
            statName = ((VitalName)i).ToString()
        };
    }
}

Now, what's happening is that the LivingBeing.CastSpell() function has what I think is a rather long reference to find the exact vital to modify:

public void CastSpell(LivingBeing target, BlackMagic spellToCast)
{
    target.vitals[((VitalModifier)spellToCast.magicEffect).vitalToAdjustIndex].currValue -= spellToCast.BaseDamage;
}

It might just be me but using that rather long line seems like it's not needed. The reason I have to cast spellToCast.MagicEffect to a VitalModifier is because the MagicEffect property of a spell doesn't have a VitalToAdjustIndex property...

I realize that casting is a major issue in my code since I have to use 4 overload for the LivingBeing.CastSpell() because the Spell doesn't have a baseDamage property... so I end up having one overload for each type of spell (White, Special, Ailment and Effect).

I don't really know if there's another way to do it, but if there is a way to avoid multiple overloads or the need for all that casting, I'd be thankful

Also, should I put all the code in the same "box" when I ask a question or separate it like I did?

jdphenix
  • 15,022
  • 3
  • 41
  • 74
Schaezar
  • 47
  • 8
  • What happens when `CastSpell()` is passed a `BlackMagic` that has an effect that isn't a `VitalModifier`? – jdphenix Oct 18 '17 at 01:21
  • Well, it's not possible because the BlackMagic class is reserved for spells that will directly affect a vital. Either health or mana. If it's going to affect something else, I use a StatModifier that has attributeToModifyIndex and a multiplier and it's used on SpecialMagic class (something like a "Haste" spell that will modify the speed by the value of the multiplier, most probably 2.0f or 0.5f). That said, the question could be applied to other spell classes using a few different MagicEffects... that is exactly my issue... I don't want to overload for every single type of spell/modifer combo. – Schaezar Oct 18 '17 at 01:29
  • In answer to your last question, I personally would find it easier to read if you put all the class definitions together (you could still just show the relevant properties) like: `class Vital { public int BaseValue { get; set; } public int CurrValue { get; set; } } class Black Magic { public int BaseDamage { get; set; } }`. Also, "vital" is an adjective, isn't it (meaning "important" or "healthy")? Class names are typically nouns. – Rufus L Oct 18 '17 at 01:35
  • Thanks, I'll try to simplify things a bit next time. As for your question, vital is an adjective but I mean it more as VitalSign... Even though mana is arguably not something that is necessary to the life of the character. Also, the code comes partly from a tutorial by burgzerg as I was following the series for quite a bit and he does use Vital. – Schaezar Oct 18 '17 at 08:30

1 Answers1

0

First, modify Vital to use the VitalName enum for the name value. The name also needs to be immutable, because I'm going to use it in a dictionary.

class Vital
{
    public Vital(VitalName name) => Name = name;

    public int baseValue;
    public int currValue;
    public VitalName Name { get; }

    public override bool Equals(object obj)
    {
        return obj is Vital vital && Name == vital.Name;
    }

    public override int GetHashCode()
    {
        return 539060726 + Name.GetHashCode();
    }
}

Modify VitalModifier to use the VitalName enum to denote what it should change -

class VitalModifier : MagicEffect
{
    public VitalName VitalToAdjust;
}

Finally, change LivingBeing to use the changes.

class LivingBeing
{
    public LivingBeing()
    {
        SetupVitals();
    }

    public IDictionary<VitalName, Vital> vitals;

    private void SetupVitals()
    {
        var vitalNames = Enum.GetValues(typeof(VitalName)) as VitalName[];
        vitals = vitalNames.ToDictionary(name => name, name => new Vital(name));
    }

    public void CastSpell(LivingBeing target, BlackMagic spellToCast)
    {
        switch (spellToCast.magicEffect)
        {
            case VitalModifier m:
                target.vitals[m.VitalToAdjust].currValue -= spellToCast.BaseDamage;
                break;
            default:
                throw new UnexpectedSpellEffectException();
        }
    }
}

--

As an aside, when you are using fields on classes, consider properties instead.

jdphenix
  • 15,022
  • 3
  • 41
  • 74
  • While I agree that it is indeed much simpler, since I'm using Unity 2017, I believe I'm limited to C# 4 features by default and C# 6 by changing the scripting runtime version to .NET 4.6. But if I try to add your code, I get this error message quite a bit : C# Feature is not available in C# 6. Please use language version 7 or greater. I read something about compiling the code into a library in VS 2017 that would allow C# 7 to be used but... I have ABSOLUTELY no idea what it means. Thanks for the answer though, if I end up being able to use it, I'll most certainly do as it's WAY easier. – Schaezar Oct 18 '17 at 09:19
  • Ahh, that's too bad. That's important information to include in your question. – jdphenix Oct 19 '17 at 01:13
  • Yeah, sorry about that, but I did found a way to switch on the Type... It's a bit more complicated but kinda does the same job. I don't know how the whole CastSpell() function will end up but here's the solution I found after breaking Unity by trying to add C#7 support to it : spellsToCast.GetType().ToString(); switch(spellType) case "BlackMagic" case "WhiteMagic" And then nested switch on the VitalModifier, StatModifier and so on... my function will be rather long but it will work and do something different for each case – Schaezar Oct 19 '17 at 09:15