Overall it looks pretty good. You do a good job separating code.
your play function in main.cpp is getting a little bloated.
You are passing by pointer in many places
void fight(Player *player) {
...
}
Where you could and probably should be passing by reference
void fight(Player &player) {
...
}
I try to only pass by pointer whenever NULL is a valid value to pass.
You item inheritance tree could be problematic. Suppose you eventually want to have an item that you can both equip and consume. Inheritance doesn't solve this problem well. An alternate solution to polymorphic items is applying polymorphism to individual concerns of an item.
// forward declaration
class Item;
class IUseBehavior {
public:
virtual void useOn(Item& item, Player& on) = 0;
}
class Item {
protected:
string name;
int levelReq;
IUseBehavior* useBehavior;
public:
Item(string name, IUseBehavior* useBehavior;, int levelReq);
void useOn(Player& player);
...
}
...
void Item::useOn(Player& player) {
if (useBehavior) {
useBehavior->useOn(*this, player);
}
}
You can then have your standard equip and consume behavior
void Equipment::useOn(Item& item, Player& on) {
// pass the item with the stats so the player can save the item for when it gets unequipped
on.equip(item, equipmentStats);
}
void Consumable::useOn(Item& item, Player& on) {
on.consume(consumeStats);
}
Then you can add your edible items
void EditbleEquipment::useOn(Item& item, Player& on) {
int pChoice;
cout << "Use Item --> Would you like to equip it or eat it?" << endl;
cout << "[1:Equip], [2:Eat]" << endl;
cin >> pChoice;
if (pChoice == 1) {
on.equip(item, equipmentStats);
} else if (pChoice == 2) {
on.consume(consumeStats);
} else {
cout << "Invalid choice" << endl;
}
}
You have some "using namespace" statements in header files. This is considered bad practice since it pollutes the global namespace for any files that directly or indirectly include it.