Skip to main content
added 301 characters in body
Source Link
Jerry Coffin
  • 34.1k
  • 4
  • 77
  • 145

Naming

Some of the names you've used are shortened to the point that I'm not sure what they're intended to mean. Just for a couple of examples, inte and stre--I'd de-abbreviate these to the point that somebody reading the code can easily understand what they're supposed to really mean.

Naming

Some of the names you've used are shortened to the point that I'm not sure what they're intended to mean. Just for a couple of examples, inte and stre--I'd de-abbreviate these to the point that somebody reading the code can easily understand what they're supposed to really mean.

added 234 characters in body
Source Link
Jerry Coffin
  • 34.1k
  • 4
  • 77
  • 145

...and most of the rest of the game can work with this new player class without any modification at all. Likewise, I can add a new ability to an existing player class by simply deciding on a name and a relative cost for using that ability--I don't have to modify all the ability-related logic to take the newly added ability into account.

player.pclass.show();
cin >> input;

// This logic isn't complete--we need to add a call to `can_afford` to see 
// whether the player can afford to use an ability.
if (input > player.pclass.ability_count())
    ability = None;
else { 
    ability = player.pclass[input];
    player.manna -= ability.cost();
}

Note how this has eliminated huge amounts of repetition in the code, with essentially identical logic repeated once for every ability of every player class.

Prevent mistakes

I'd also consider checking whether the player can afford to use a particular ability before displaying that ability. This way they only choose from the abilities they can use, rather than trying to choose an ability they can't actually afford, then finding out too late that they made a bad choice and nothing happens.

...and most of the rest of the game can work with this new player class without any modification at all.

player.pclass.show();
cin >> input;
if (input > player.pclass.ability_count())
    ability = None;
else { 
    ability = player.pclass[input];
    player.manna -= ability.cost();
}

Note how this has eliminated huge amounts of repetition in the code, with essentially identical logic repeated once for every ability of every player class.

...and most of the rest of the game can work with this new player class without any modification at all. Likewise, I can add a new ability to an existing player class by simply deciding on a name and a relative cost for using that ability--I don't have to modify all the ability-related logic to take the newly added ability into account.

player.pclass.show();
cin >> input;

// This logic isn't complete--we need to add a call to `can_afford` to see 
// whether the player can afford to use an ability.
if (input > player.pclass.ability_count()
    ability = None;
else { 
    ability = player.pclass[input];
    player.manna -= ability.cost();
}

Note how this has eliminated huge amounts of repetition in the code, with essentially identical logic repeated once for every ability of every player class.

Prevent mistakes

I'd also consider checking whether the player can afford to use a particular ability before displaying that ability. This way they only choose from the abilities they can use, rather than trying to choose an ability they can't actually afford, then finding out too late that they made a bad choice and nothing happens.

Source Link
Jerry Coffin
  • 34.1k
  • 4
  • 77
  • 145

First of all, let me join others in pointing out what sweet ASCII art you've done. This definitely has the beginnings of a much nicer text game than most.

I'd start by defining some structures to hold data about specific things in the game. For a couple of examples:

struct Ability {
    std::string name;
    int level_adder;

    int cost(int level, int inte) { 
        return (level + level_adder) * inte;
    }

    bool can_afford(int level, int inte, int manna) { 
        return cost(level, inte) <= manna;
    }

    void show(int level, int inte) { 
        std::cout << name << "[" << cost() << " manna]\n";
    }       
};

class PlayerClass {
    std::string name;
    std::vector<Ability> abilities;
    size_t ability_count() { return abilities.size(); }

    void show(int level, int inte) {
        for (int i=0; i<abilities.size(); i++)
            std::cout << "[" << i << "] ";
            abilities[i].show(level, inte);
    }

    Ability const &operator[](size_t index) const { 
        return abilities.at(index);
    }
};

With these, we can define all the data for the Player classes something like this:

PlayerClass Champion{
    "Champion",
    { "Cleaving Strike", 0},
    { "Melting Thrust", 0},
    {"Critical Bash", 0},
    {"Purify", 1}
};

PlayerClass Necromancer{
    "Necromancer",
    { "Shadow Strike", 0},
    { "cripple", 0},
    { "Mutilate", 0},
    { "Life Tap", 2}
};

...and so on for the other player classes. For only one example, this makes it much easier to add more player classes in the future--for example, I can sit down and decide I want to add a "thief" class:

PlayerClass Thief { 
    "Thief",
    { "Pick Pocket", 0},
    { "Grab Purse", 0},
    { "Rob Business", 1},
    { "Rob Bank", 4}
};

...and most of the rest of the game can work with this new player class without any modification at all.

Then we can define a player to hold (for example) a reference to a PlayerClass object:

class Player { 
    PlayerClass &pclass;
    // ...
};

With this, getability obviously returns (possibly a pointer or reference to) an Ability object, and looks something like this:

player.pclass.show();
cin >> input;
if (input > player.pclass.ability_count())
    ability = None;
else { 
    ability = player.pclass[input];
    player.manna -= ability.cost();
}

Note how this has eliminated huge amounts of repetition in the code, with essentially identical logic repeated once for every ability of every player class.