13
\$\begingroup\$

I'm working on a simple text based adventure game. I've just finished working on the character creation portion. The code works perfectly fine when run, but I would just like to get some feedback to ensure that it checks off from a professional and efficient standpoint.

The values of the materials, weapons, and spells are representing the amount of damage points each does for further and future calculations with the characters stats later in the game.

The code itself essentially allows you to input a characters name. Then, the strength, stamina, and intellect is randomly generated so that your character build is different at the beginning of each game. Then, once that has finished, the code takes into account the weapon type, the material of the weapon, the spell type and adds additional damage based on the players stats.

I would just like to know if there is a better way of writing my code to make it look cleaner, or if there possibly any concerns that might cause me issues down the road when I add more functionality to the game. Seeing as I am a beginner to C++, I am not incredibly great at determining whether my code is optimal or not.

#include <iostream>
#include <string>
#include <ctime>

using namespace std;

/* Materials Structure */

typedef struct materials {
    int wood = 1, oak = 2, maple = 3, ash = 4, bronze = 2, iron = 3, steel = 4, mithril = 5, dragon = 6;
};

/* Weapon Structure */

typedef struct weapons {
    int dagger = 2, sword = 3, axe = 4, mace = 5, bow = 3, arrows = 2;
} weapons;

/* Spell Structure */

typedef struct spells {
    int fire = 4, frost = 6, dark = 8, chaos = 10;
} spells;


/* Character Structure */

typedef struct character {
    string name;
    int health = 100, mana = 100, strength, stamina, intellect, weaponAttack, spellAttack, souls = 0;
    spells spell;
    weapons weapon;
    materials material;
} character;

/* Function Declaration */

character characterCreation(string name);
void printInfo(character createChar);

/* Main Function */

int main() {
    string characterName;
    cout << "Please input character name: ";
    cin >> characterName;

    srand(time(NULL));
    character player = characterCreation(characterName);
    printInfo(player);

    system("pause");
    return 0;
}

/* Function Definition */

character characterCreation(string name) {
    character createChar;
    createChar.name = name;
    createChar.strength = rand() % 5 + 5;
    createChar.stamina = rand() % 5 + 5;
    createChar.intellect = rand() % 5 + 5;
    createChar.health += 2 * createChar.stamina;
    createChar.mana += 3 * createChar.intellect;
    createChar.weaponAttack = (createChar.weapon.dagger * createChar.material.bronze) + (2 * createChar.strength);
    createChar.spellAttack = (createChar.spell.fire + (createChar.intellect * 2));
    return createChar;
}

void printInfo(character createChar) {
    cout << createChar.name << endl;
    cout << createChar.health << endl;
    cout << createChar.mana << endl;
    cout << createChar.strength << endl;
    cout << createChar.stamina << endl;
    cout << createChar.intellect << endl;
    cout << createChar.weaponAttack << endl;
    cout << createChar.spellAttack << endl;
    cout << createChar.souls << endl;
}
\$\endgroup\$
  • \$\begingroup\$ Take a look at "ncurses" library. \$\endgroup\$ – outoftime Mar 16 at 22:48
  • 2
    \$\begingroup\$ If your goal is to write a text adventure (and not just a C++ exercise), have a look at the existing text adventure engines such as TADS and Inform 7. If you still decide to go with C++, understanding the architecture and feature sets in the existing engines will advise you in your own code's larger design. \$\endgroup\$ – user117529 Mar 17 at 2:46
10
\$\begingroup\$
typedef struct weapons {
    int dagger = 2, sword = 3, axe = 4, mace = 5, bow = 3, arrows = 2;
} weapons;

The typedef struct X { ... } X; pattern is a C-ism; in C++ you don't need the typedef and can just write struct X { ... };.

You're creating a struct type named weapons with a bunch of per-instance member variables. This is almost certainly not what you meant to do. Probably what you meant was

enum class Weapon {
    dagger = 2,
    sword = 3,
    axe = 4,
    mace = 5,
};

so that you could later write

Weapon w = Weapon::sword;
if (w == Weapon::axe) { ... }

What you actually wrote, unfortunately, is simply nonsense.


character characterCreation(string name);

Look up the C++ notion of "constructors" (and also destructors). What you have here would normally be spelled something like

Character::Character(const std::string& name) {
    this->name = name;
    this->strength = rand() % 5 + 5;
}

and so on.

Also consider writing yourself a helper function

int randint(int lo, int hi) {
    return rand() % (hi - lo) + lo;
}

so that you can write simply

    this->strength = randint(5, 10);

Ninety percent of what we call "programming" is just finding sources of repetition and eliminating them.

\$\endgroup\$
  • \$\begingroup\$ I apologize, I should have clarified what my code is doing and what my expectations were. My post is not a troll, I prefer not to waste peoples time if I do not have to. I will make edits to the question. The numbers on the materials, weapons, and spells simply represent the amount of damage. \$\endgroup\$ – Justin Mar 16 at 4:07
  • \$\begingroup\$ Thank you for the insight and helpful post though. I will take a look at more constructors and destructors. I used the struct with the hopes that I would be able to create a large combination of different weapon types/spells, being that my class has only just begun using structs I am not too familiar with constructors/destructors. \$\endgroup\$ – Justin Mar 16 at 4:26
  • \$\begingroup\$ randint(5,10), as written, only generates 5 to 9, inclusive. You’d want hi - lo + 1 to get the full range. \$\endgroup\$ – AJNeufeld Mar 16 at 5:13
  • 3
    \$\begingroup\$ @AJNeufeld: Half-open ranges are the building blocks of C++ (as well as most other programming languages), and the sooner OP gets familiar with them, the better. See here and here for places I've used the phrase "half-open range" in previous reviews. \$\endgroup\$ – Quuxplusone Mar 16 at 5:33
  • \$\begingroup\$ Nice answer, though rand() shouldn't be used, <random> is recommend instead \$\endgroup\$ – JVApen Mar 18 at 19:06
5
\$\begingroup\$

In general you should read more about the Language and Programming. Here are some links to get you started:

\$\endgroup\$
3
\$\begingroup\$

First, try not to declare all your types in the global namespace. Make your "own" space. This limits the exposure to other code you might integrate with.

Your materials, weapons, and spells seem to be enum candidates as they are used as values. So use them as enum-values and define there size explicitly. In this case I'm not recommending scoped enums since you want to do calculations easily on there values.

Added a constructor to your character.

characterCreation function should take string by universal reference to avoid unnecessary copies.

Have you print method take and ostream so you easily can change to the any stream of your choosing.

namespace YourNamespaceName {

enum materials : int {
    wood = 1, oak = 2, maple = 3, ash = 4, bronze = 2, iron = 3, steel = 4, mithril = 5, dragon = 6
};

enum weapons : int {
    dagger = 2, sword = 3, axe = 4, mace = 5, bow = 3, arrows = 2
};

enum spells : int {
    fire = 4, frost = 6, dark = 8, chaos = 10
};

struct character {
    explicit character(std::string &&name)
            : name(std::move(name)), strength(rand() % 5 + 5), stamina(rand() % 5 + 5), intellect(rand() % 5 + 5),
              weaponAttack(weapons::dagger * materials::bronze + 2 * strength),
              spellAttack(spells::fire + intellect * 2) {
        health += 2 * stamina;
        mana += 3 * intellect;
    }

    std::string name;
    int health = 100, mana = 100, strength, stamina, intellect, weaponAttack, spellAttack, souls = 0;
};

// Function Declaration
character characterCreation(std::string &&name);

std::ostream &printInfo(std::ostream &os, const character &createChar);

}  // close YourNamespaceName namespace

// Main Function

int main() {
    std::string characterName;
    std::cout << "Please input character name: ";
    std::cin >> characterName;

    std::srand(std::time(nullptr));
    auto player = YourNamespaceName::characterCreation(std::move(characterName));
    YourNamespaceName::printInfo(std::cout, player);

    system("pause");
    return 0;
}

namespace YourNamespaceName {

// Function Definition

character characterCreation(std::string &&name) {
    return character(std::move(name));
}

std::ostream &printInfo(std::ostream &os, const character &createChar) {
    return os << createChar.name << '\n'
              << createChar.health << '\n'
              << createChar.mana << '\n'
              << createChar.strength << '\n'
              << createChar.stamina << '\n'
              << createChar.intellect << '\n'
              << createChar.weaponAttack << '\n'
              << createChar.spellAttack << '\n'
              << createChar.souls << '\n';
}

}  // close YourNamespaceName namespace
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.