Best way to go about doing this

So Im trying to strengthen my knowledge of using classes correctly and i've come a little further. I'm trying to make all my classes like I was told is the best way to do it for the most part which is have them all work independently and be able to take care of themselves. I have a few questions about some things.

1. I want to know how I would go about setting the players class to a pre-made class. I have a player class that derives from character, and I made a few character classes but how do I set the players class to one of them? Maybe i'm overthinking it.

SEEMS TO BE FIXED: 2. I cannot seem to get the stuff in the players inventory to save in vectors between functions. everything gets erased when it goes out of scope. This is especially a problem with a vector of Item class objects or any other class object, I cant seem to get it to work, I tried references but no luck, how would I pass a vector of class objects to and from other functions? or what is the best way to pass class objects to from functions if using a vector isnt.

3. Side question, is there a way I can make a vector contain an number of types and not just two? like now i'm using pair so I can have two types, I could use tuple if I wanted three, but what if I wanted like 7 or 8 or more? what could I do then?


FIXED: Also, as a side note, i'm getting an error when trying to enter a name into the player object, not sure why. When I comment out Player player("Player") the code compiles. I get this error though:

Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __thiscall Character::Character(void)" (??0Character@@QAE@XZ) referenced in function "public: __thiscall Player::Player(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Player@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) ConsoleApplication1 C:\Users\thund\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.obj 1


Heres the full code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#include <iostream>
#include <string>
#include <vector>

using namespace std;


class Character
{
	public:
		Character(string characterClass, int health, int maxHealth, int attackPower, int maxAttackPower, int money) :
			characterClass(characterClass),
			health(health),
			maxHealth(maxHealth),
			attackPower(attackPower),
			maxAttackPower(maxAttackPower),
			money(money) {}

		Character();

		string GetCharacterClass() { return characterClass; }

		int GetHealth() const { return health; }
		int GetAttackPwr() const { return attackPower; }
		int GetMaxAttackPwr() const { return maxAttackPower; }
		int GetMaxHealth() const { return maxHealth; }
		int GetMoney() const { return money; }

		void TakeDamage(const int& damageTaken);
		void RestoreHealth(const int& restoreAmount);
		void UpgradeAttackPower(const int& upgradeAmount);
		void DisplayCharacterInfo(Character& character);

	private:
		string characterClass{};
		int health{};
		int maxHealth{};
		int attackPower{};
		int maxAttackPower{};
		int money{};
};

class Item
{
public:
	Item(string itemName, int itemPrice) : itemName(itemName), itemPrice(itemPrice) {}

	void ProcessTransaction(Character& character);

	string GetItemName() const { return itemName; }
	int GetItemPrice() const { return itemPrice; }


private:
	string itemName{};
	int itemPrice{};
};

class Player : public Character
{
	public:
		Player(string name) :
			name(name) {}

		void ShowPlayersInventory();
		string ShowPlayersName() const { return name; }

		void AddItemToInventory(string itemName, int amountToAdd);
		void RemoveItemFromInventory();
		void UseItem();

	private:
		string name{};
		vector < std::pair<string, int>> inventory;
};

void Player::AddItemToInventory(string itemName, int amountToAdd)
{
	inventory.push_back(std::make_pair(itemName, amountToAdd));
}

void Player::ShowPlayersInventory()
{
	for (int i = 0; i < inventory.size(); i++)
	{
		cout << inventory[i].first << " " << inventory[i].second << endl;
	}
}

void Item::ProcessTransaction(Character& character)
{
	if (character.GetMoney() >= GetItemPrice())
	{
		character.GetMoney() - GetItemPrice();
		cout << "You purchased the " << GetItemName() << " for " << GetItemPrice() << endl;
		cout << "You have $" << character.GetMoney() << " left" << endl;
	}
	else if (character.GetMoney() <= GetItemPrice())
	{
		cout << "You do not have the money needed for that" << endl;
	}
}

ostream& operator<< (ostream& os, Character& character)
{
	os << "Class Name: " << character.GetCharacterClass() << endl;
	os << "Health: " << character.GetHealth() << endl;
	os << "Max Health: " << character.GetMaxHealth() << endl;
	os << "Attack Power: " << character.GetAttackPwr() << endl;
	os << "Max Attack Power: " << character.GetMaxAttackPwr() << endl;
	os << "Money: " << character.GetMoney() << endl;

	return os;
}

void Character::RestoreHealth(const int& restoreAmount)
{
	if (health + restoreAmount <= maxHealth)
	{
		health += restoreAmount;
	}
	else if (health + restoreAmount >= maxHealth)
	{
		health = maxHealth;
	}
}


void Character::TakeDamage(const int& damageTaken)
{
	if (health > 0)
	{
		health -= damageTaken;

		if (health <= 0)
		{
			health = 0;
			cout << "The " << GetCharacterClass() << ", was defeated." << endl;
		}
	}
}


void Character::DisplayCharacterInfo(Character& character)
{
	cout << character << endl;
}


void Shop(Player& player);

int main()
{
	cout << "ITEMS HELD" << endl;

	Character Knight("Knight", /*Health*/ 100, /*Max Health*/ 150, /*Attack Power*/ 5, /*Max Attack Power*/ 5, /*Money*/ 100);
	Character Samurai("Samurai", /*Health*/ 45, /*Max Health*/ 200, /*Attack Power*/ 5, /*Max Attack Power*/ 8, /*Money*/ 100);
	Character Marine("Marine", /*Health*/ 80, /*Max Health*/ 150, /*Attack Power*/ 2, /*Max Attack Power*/ 3, /*Money*/ 100);

	Player player("Player");

	Shop(player);

	player.ShowPlayersInventory();

	return 0;
}


void Shop(Player& player)
{
	Item Healthpack("Health Pack", /*Item Price*/ 800);
	Item Map("Map", /*Item Price*/ 150);

	vector<string> shopInventory;

	shopInventory.push_back(Healthpack.GetItemName());
	shopInventory.push_back(Map.GetItemName());

	int choice{};
	int counter = 1;
	int amount{};

	while (choice != -3)
	{
		amount = 0;

		cout << "What would you like to buy?" << endl;

		for (int i = 0; i < shopInventory.size(); i++)
		{
			cout << counter++ << ") " << shopInventory[i] << endl;
		}

		cin >> choice;

		if (choice == -3)
		{
			continue;
		}

		cout << "How many do you want?" << endl;
		cin >> amount;

		switch (choice - 1)
		{
		case 0:
			player.AddItemToInventory(Healthpack.GetItemName(), amount);
			break;
		case 1:
			player.AddItemToInventory(Map.GetItemName(), amount);
			break;
		default:
			cout << "Invalid Choice" << endl;
		}
	}
}
Last edited on
Since you defined the Character zero argument constructor you must either declare it as default, or implement that function with the proper defaults.


Ah, thank you, I swear i tried that and it didnt work, but its working now. Thanks!

Also seems like the vector isnt deleting its contents when it goes out of function scope now but let me know if i'm wrong, and any other improvements I could make to the code.
Last edited on

3. Side question, is there a way I can make a vector contain an number of types and not just two? like now i'm using pair so I can have two types, I could use tuple if I wanted three, but what if I wanted like 7 or 8 or more? what could I do then?



A vector of another class/structure perhaps?

1. I want to know how I would go about setting the players class to a pre-made class. I have a player class that derives from character, and I made a few character classes but how do I set the players class to one of them? Maybe i'm overthinking it.

What is the difference between some random character and some random player?

A vector of another class/structure perhaps?


What would that look like? I'm not really sure how I would even start writing something like that.

What is the difference between some random character and some random player?


Well the character has a few differences, they can have money, which the characters can too, but i'm going to remove that. Also they player can have an inventory and there will be more features that are player specific too.

I'm just wondering if I just use a character as the player character, say a Samurai, and I call other samurai to fight against, wont it affect the players samurai character? thats where I think the player choosing to have that class would be pertinent, but the other differences i mentioned before being the biggest things.
What would that look like?

You already have several classes, so I don't understand what you don't understand.


Well the character has a few differences,

Then perhaps a player is just a specialization of a character?

I'm just wondering if I just use a character as the player character, say a Samurai, and I call other samurai to fight against, wont it affect the players samurai character?

What? Why would one character affect another? Isn't it possible to have many different "Samurai"? And many different "Players"?

Each character, regardless of the type of character, will need to keep track of it's own "special" features. For example if you have multiple "Samurai" isn't it likely that each "Samurai" would have different health, attack specifications, etc, due to "training" (level)?
is there a way I can make a vector contain an number of types
Look at std::any.

https://en.cppreference.com/w/cpp/utility/any

While each element would contain only one instance of a type, each element could hold whatever you type want.

I could use tuple if I wanted three, but what if I wanted like 7 or 8 or more?
std::tuple can hold as many values as you want, there are practical limits to the number of types that can be queued up. Yes, a tuple can be constructed to hold 7, 8 or more types/values if you want.
You already have several classes, so I don't understand what you don't understand.


Tuple is what i was looking for, I thought tuple could only hold 3 values max, i didnt know it could hold way more than that.

Then perhaps a player is just a specialization of a character?


Sure, i mean its a special type of character because its the player, but normally in games you pick a class that you play as, like i said, perhaps im overthinking this but the thing is, I have a player class because the player has things the characters dont, since characters are NPCs there are some differences, and I already have a Samurai character made, but want to be able to use it as a player object. Hopefully that made some sense, i'm having a hard time trying to communicate what im thinking sometimes even though I know exactly what I want in my head.


What? Why would one character affect another? Isn't it possible to have many different "Samurai"? And many different "Players"?


Yeah now that I think about it that makes sense, for some reason I though of something totally different.

std::tuple can hold as many values as you want, there are practical limits to the number of types that can be queued up. Yes, a tuple can be constructed to hold 7, 8 or more types/values if you want.


Thank you! thats exactly what I needed!

Now I just need to figure out how to "set" the players call to the predefined character classes.
Last edited on
Tuple is what i was looking for, I thought tuple could only hold 3 values max, i didnt know it could hold way more than that.

Why don't you just use a std::vector<Item> instead of the pair, or tuple?
From a re-use standpoint, in most games generically speaking, a player character has a human interface, and a NPC has an AI. If you can interchange only those 2 things at will (hint, hint) you have a nice tight setup with a lot of reuse going on. However, you may need more ... the AI may be running a 'shop' that needs to give the human players a way to buy/sell ... similar perhaps to how humans trade with each other, but also very different, and that is one example. You have to figure out which parts are more or less the same and which are special, and the special ones need to be something you can swap out depending on something. Which all you can say to that is design first and have things flexible enough to make it happen if you change your mind later.

an entity probably should have a character class, whether that is just an enum that triggers some minor stuff or a full on class that does things radically differently depends on that design...
Last edited on
hmm, well mainly what I want to do is when the player chooses a class, it assigns things that that class has to the player, for example the name of the class, the damage that class does, max attack damage etc, how would I go about doing that? Perhaps my way of thinking about it is wrong.

Heres my current code if you need it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#include <iostream>
#include <string>
#include <vector>

using namespace std;

/*
===========================================================
CHARACTER CLASS
===========================================================
*/

class Character
{
public:
	Character(string characterClass, int health, int maxHealth, int attackPower, int maxAttackPower, int money) :
		characterClass(characterClass),
		health(health),
		maxHealth(maxHealth),
		attackPower(attackPower),
		maxAttackPower(maxAttackPower),
		money(money) {}

	Character() = default;

	string GetCharacterClass() { return characterClass; }

	int GetHealth() const { return health; }
	int GetAttackPwr() const { return attackPower; }
	int GetMaxAttackPwr() const { return maxAttackPower; }
	int GetMaxHealth() const { return maxHealth; }
	int GetMoney() const { return money; }

	void TakeDamage(const int& damageTaken);
	void RestoreHealth(const int& restoreAmount);
	void UpgradeAttackPower(const int& upgradeAmount);
	void DisplayCharacterInfo(Character& character);

private:
	string characterClass{};
	int health{};
	int maxHealth{};
	int attackPower{};
	int maxAttackPower{};
	int money{};
};


/*
===========================================================
ITEM CLASS
===========================================================
*/

class Item
{
public:
	Item(string itemName, int itemPrice) : itemName(itemName), itemPrice(itemPrice) {}

	void ProcessTransaction(Character& character);

	string GetItemName() const { return itemName; }
	int GetItemPrice() const { return itemPrice; }


private:
	string itemName{};
	int itemPrice{};
};


/*
===========================================================
PLAYER CLASS
===========================================================
*/

class Player : public Character
{
public:
	Player(string name, string className, float experience, int level) :
		name(name),
		chosenClass("Default"),
		experience(experience),
		level(level) {}

	void ShowPlayersInventory();
	string ShowPlayersName() const { return name; }
	float GetPlayersCurrentExperience() const { return experience; }
	int GetPlayersCurrentLevel() const { return level; }
	string GetPlayersName() const { return name; }

	void AddItemToInventory(string itemName, int amountToAdd);
	void RemoveItemFromInventory();
	void UseItem();
	void PickCharacterClass(Character& character, Player& player);
	void GiveExperience(int xpToGive);
	void LevelUp(int level);

private:
	string name{};
	string chosenClass{};
	float experience{};
	int level{};
	vector < std::pair<string, int>> inventory{};
};

/*
===========================================================
GIVE EXPERIENCE FUNCTION
===========================================================
*/

void Player::GiveExperience(int xpToGive)
{
	experience += xpToGive;
}

void Player::LevelUp(int giveLevel)
{
	level += giveLevel;
}

void Player::PickCharacterClass(Character& character, Player& player)
{

}

void Player::AddItemToInventory(string itemName, int amountToAdd)
{
	inventory.push_back(std::make_pair(itemName, amountToAdd));
}

void Player::ShowPlayersInventory()
{
	for (int i = 0; i < inventory.size(); i++)
	{
		cout << inventory[i].first << " " << inventory[i].second << endl;
	}
}

void Item::ProcessTransaction(Character& character)
{
	if (character.GetMoney() >= GetItemPrice())
	{
		character.GetMoney() - GetItemPrice();
		cout << "You purchased the " << GetItemName() << " for " << GetItemPrice() << endl;
		cout << "You have $" << character.GetMoney() << " left" << endl;
	}
	else if (character.GetMoney() <= GetItemPrice())
	{
		cout << "You do not have the money needed for that" << endl;
	}
}

ostream& operator<< (ostream& os, Character& character)
{
	os << "Class Name: " << character.GetCharacterClass() << endl;
	os << "Health: " << character.GetHealth() << endl;
	os << "Max Health: " << character.GetMaxHealth() << endl;
	os << "Attack Power: " << character.GetAttackPwr() << endl;
	os << "Max Attack Power: " << character.GetMaxAttackPwr() << endl;
	os << "Money: " << character.GetMoney() << endl;

	return os;
}

void Character::RestoreHealth(const int& restoreAmount)
{
	if (health + restoreAmount <= maxHealth)
	{
		health += restoreAmount;
	}
	else if (health + restoreAmount >= maxHealth)
	{
		health = maxHealth;
	}
}


void Character::TakeDamage(const int& damageTaken)
{
	if (health > 0)
	{
		health -= damageTaken;

		if (health <= 0)
		{
			health = 0;
			cout << "The " << GetCharacterClass() << ", was defeated." << endl;
		}
	}
}


void Character::DisplayCharacterInfo(Character& character)
{
	cout << character << endl;
}


void Shop(Player& player);

int main()
{
	Character Knight("Knight", /*Health*/ 100, /*Max Health*/ 150, /*Attack Power*/ 5, /*Max Attack Power*/ 5, /*Money*/ 100);
	Character Samurai("Samurai", /*Health*/ 45, /*Max Health*/ 200, /*Attack Power*/ 5, /*Max Attack Power*/ 8, /*Money*/ 100);
	Character Marine("Marine", /*Health*/ 80, /*Max Health*/ 150, /*Attack Power*/ 2, /*Max Attack Power*/ 3, /*Money*/ 100);
	Character Archer("Archer", /*Health*/ 10, /*Max Health*/ 20, /*Attack Power*/ 6, /*Max Attack Power*/ 8, /*Money*/ 100);

	string name = "Default Player";
	string className = "No Class";
	float experience = 0;
	int level = 1;

	cout << "Please enter a name for your character" << endl;
	cin >> name;

	Player player(name, className, experience, level);

	cout << "You named your character " << player.GetPlayersName() << endl;

	//Shop(player);

	//player.ShowPlayersInventory();

	cout << player.GetPlayersCurrentExperience() << endl;
	cout << player.GetPlayersCurrentLevel() << endl;
	player.GiveExperience(500);
	cout << player.GetPlayersCurrentExperience() << endl;
	cout << player.GetPlayersCurrentLevel() << endl;
	player.LevelUp(4);
	cout << player.GetPlayersCurrentLevel() << endl;

	return 0;
}

/*
===========================================================
SHOP FUNCTION
===========================================================
*/

void Shop(Player& player)
{
	Item Healthpack("Health Pack", /*Item Price*/ 800);
	Item Map("Map", /*Item Price*/ 150);

	vector<string> shopInventory;

	shopInventory.push_back(Healthpack.GetItemName());
	shopInventory.push_back(Map.GetItemName());

	int choice{};
	int counter = 1;
	int amount{};

	while (choice != -3)
	{
		amount = 0;

		cout << "What would you like to buy?" << endl;

		for (int i = 0; i < shopInventory.size(); i++)
		{
			cout << counter++ << ") " << shopInventory[i] << endl;
		}

		cin >> choice;

		if (choice == -3)
		{
			continue;
		}

		cout << "How many do you want?" << endl;
		cin >> amount;

		switch (choice - 1)
		{
		case 0:
			player.AddItemToInventory(Healthpack.GetItemName(), amount);
			break;
		case 1:
			player.AddItemToInventory(Map.GetItemName(), amount);
			break;
		default:
			cout << "Invalid Choice" << endl;
		}
	}
}
Last edited on
Ok so I think I may have figured it out. The main problem was the player constructor wasnt saving the values fo the selected class but I did some digging and found a solution. This isnt the full code I did a simple remake of it since im on another PC and dont have access to my full code, but this seems to work fine, but let me know if there are any issues I need to fix:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>

using namespace std;

class Character
{
	public:
		Character(string className, int baseHealth, int maxHealth, int baseDamage, int maxDamage): className(className), 
																																													   baseHealth(baseHealth),
																																													   maxHealth(maxHealth),
																																													   baseDamage(baseDamage),
																																													   maxDamage(maxDamage){}
		Character() = default;
																													   																																											   
		string GetClassName() const { return className; }
		int GetBaseHealth() const { return baseHealth; }
		int GetMaxHealth() const { return maxHealth; }
		int GetBaseDamage() const { return baseDamage; }
		int GetMaxDamage() const { return maxDamage; }
		
	private:
		string className{};
		int baseHealth{};
		int maxHealth{};
		int baseDamage{};
		int maxDamage{};
};

class Player : public Character
{
	public:
		Player(string className, int baseHealth, int maxHealth, int baseDamage, int maxDamage) : Character(className, baseHealth, maxHealth, baseDamage, maxDamage){}
		
	private:
};

int main()
{
	Character Knight("Knight", 100, 250, 5, 10);
	
	Player player(Knight.GetClassName(), Knight.GetBaseHealth(), Knight.GetMaxHealth(), Knight.GetBaseDamage(), Knight.GetMaxDamage());
	
	cout << player.GetClassName() << endl;
	cout << player.GetBaseHealth() << endl;
	cout << player.GetMaxHealth() << endl;
	cout << player.GetBaseDamage() << endl;
	cout << player.GetMaxDamage() << endl;
	
	return 0;
}


Ok so I dont know whats going on but for some reason the site absolutley refuses to show the code for my Character class after className(className),

so here it is:

Character(string className, int baseHealth, int maxHealth, int baseDamage, int maxDamage): className(className),
baseHealth(baseHealth),
maxHealth(maxHealth),
baseDamage(baseDamage),
maxDamage(maxDamage){}
Last edited on
player.GetPlayersCurrentExperience() The Department of Redundancy Department would be proud. :) Never use a class's name in it's members.

void Shop(Player& player) should be void Player::Shop()

when the player chooses a class, it assigns things that that class has to the player, for example the name of the class, the damage that class does, max attack damage etc
CharacterClass should be a C++ class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CharacterClass {
public:
    string name;
    unsigned damageDone;
    unsigned maxAttackDamage;
   // etc.
   CharacterClass(const string &n, unsigned dd, unsigned maxDone) :
        name(n), damageDone(dd), maxAttackDamage(maxDone)
       {}
}

CharacterClass thief("Thief", 2, 4);
CharacterClass knight("Knight", 10, 5);
...

class Character {
public:
   Character (CharacterClass &cl) : cclass(cl) {}
   const CharacterClass &cclass;
};


Now you can create a character by simply passing the class. In reality, you'd probabyl make this a little more complex: you'd store the CharacterClass's in a collection and Character's constructor would pass the name of the class.

void Item::ProcessTransaction(Character& character) What does "process" mean? Buy? Sell? Reconcile the books? Choose a more meaningful name. In this case, it looks like buy() would do, so maybe this should be Character::buy(Item &);
CharacterClass should be a C++ class.


I though thats what it is?

I changed ProcessTransaction to Buy() and Sell(), those I put in the player class since the player is the one who can buy and sell, "NPC's" cant do that so they shouldn't have that functionality. I changed some names as well.

So a character class has the stuff character has in it then character is what makes the character classes? but what about player? the player needs to be special since it does things the other classes cant since they arent "controllable" and i put that in quotes since this is just a console game, but the player should be able to choose a class and do damage based on those classes stats.

also for character info would I be able to use a this pointer instead of a reference to a character object? I mean writing Knight.GetClassName(Knight) would be better if it knew the object already instead of having to tell it. not sure though, i never use pointers, including this pointers.

Another thing i'm wondering is in the shop class, I want to make it so the line:

AddItemToInventory(Healthpack.GetName(), amount);

can take a generic object and replace it with whatever the player chooses, so if the player chooses health pack then it will add it to the inventory instead of me having to write out a switch statement with tons of push backs, there could be hundreds of items in the future so I wanted to future proof that. I was looking at templates, is that a good way to go or is there a better way? I'm looking into templates, I never used them before so im doing some research.

Heres the updated code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <iostream>
#include <string>
#include <vector>

using namespace std;

/*
===========================================================
CHARACTER CLASS
===========================================================
*/

class Character
{
public:
	Character(string className, int health, int maxHealth, int attackPower, int maxAttackPower) :
		className(className),
		health(health),
		maxHealth(maxHealth),
		attackPower(attackPower),
		maxAttackPower(maxAttackPower){}

	Character() = default;

	string GetClassName() { return className; }

	int GetHealth() const { return health; }
	int GetAttackPwr() const { return attackPower; }
	int GetMaxAttackPower() const { return maxAttackPower; }
	int GetMaxHealth() const { return maxHealth; }

	void TakeDamage(const int& damageTaken);
	void RestoreHealth(const int& restoreAmount);
	void UpgradeAttackPower(const int& upgradeAmount);
	void DisplayInfo(Character& character);

private:
	string className{};
	int health{};
	int maxHealth{};
	int attackPower{};
	int maxAttackPower{};
};


/*
===========================================================
ITEM CLASS
===========================================================
*/

class Item
{
public:
	Item(string name, unsigned price) : name(name), price(price) {}

	string GetName() const { return name; }
	int GetPrice() const { return price; }


private:
	string name{};
	unsigned price{};
};


/*
===========================================================
PLAYER CLASS
===========================================================
*/

class Player : public Character
{
public:
	Player(string name, string chosenClass, float experience, unsigned level, int money, string characterClass, int health, int maxHealth, int attackPower, int maxAttackPower) :
		Character(characterClass, health, maxHealth, attackPower, maxAttackPower){}

	void GetInventory();
	float GetExperience() const { return experience; }
	int GetLevel() const { return level; }
	string GetName() const { return name; }
	int GetMoney() const { return money; }

	void AddItemToInventory(string itemName, int amountToAdd);
	void RemoveItemFromInventory();
	void UseItem();
	void GiveExperience(int xpToGive);
	void LevelUp(int level);
	void Buy(Character& character);
	void Sell();
	void Shop();


private:
	string name{};
	string chosenClass{};
	float experience{};
	unsigned level{};
	vector < std::pair<string, int>> inventory{};
	int money{};
};

/*
===========================================================
GIVE EXPERIENCE FUNCTION
===========================================================
*/

void Player::GiveExperience(int xpToGive)
{
	experience += xpToGive;
}

void Player::LevelUp(int giveLevel)
{
	level += giveLevel;
}

void Player::AddItemToInventory(string itemName, int amountToAdd)
{
	inventory.push_back(std::make_pair(itemName, amountToAdd));
}

void Player::GetInventory()
{
	for (int i = 0; i < inventory.size(); i++)
	{
		cout << inventory[i].first << " " << inventory[i].second << endl;
	}
}

ostream& operator<< (ostream& os, Character& character)
{
	os << "Class Name: " << character.GetClassName() << endl;
	os << "Health: " << character.GetHealth() << endl;
	os << "Max Health: " << character.GetMaxHealth() << endl;
	os << "Attack Power: " << character.GetAttackPwr() << endl;
	os << "Max Attack Power: " << character.GetMaxAttackPower() << endl;

	return os;
}

void Character::RestoreHealth(const int& restoreAmount)
{
	if (health + restoreAmount <= maxHealth)
	{
		health += restoreAmount;
	}
	else if (health + restoreAmount >= maxHealth)
	{
		health = maxHealth;
	}
}


void Character::TakeDamage(const int& damageTaken)
{
	if (health > 0)
	{
		health -= damageTaken;

		if (health <= 0)
		{
			health = 0;
			cout << "The " << GetClassName() << ", was defeated." << endl;
		}
	}
}


void Character::DisplayInfo(Character& character)
{
	cout << character << endl;
}


int main()
{
	Character Knight("Knight", /*Health*/ 100, /*Max Health*/ 150, /*Attack Power*/ 5, /*Max Attack Power*/ 5);
	Character Samurai("Samurai", /*Health*/ 45, /*Max Health*/ 200, /*Attack Power*/ 5, /*Max Attack Power*/ 8);
	Character Marine("Marine", /*Health*/ 80, /*Max Health*/ 150, /*Attack Power*/ 2, /*Max Attack Power*/ 3);
	Character Archer("Archer", /*Health*/ 10, /*Max Health*/ 20, /*Attack Power*/ 6, /*Max Attack Power*/ 8);

	string name{};
	float experience = 0;
	unsigned level = 1;

	Player player(name, Knight.GetClassName(), experience, level, 100, Knight.GetClassName(), Knight.GetHealth(), Knight.GetMaxHealth(), Knight.GetAttackPwr(), Knight.GetMaxAttackPower());

	cout << "Please enter a name for your character" << endl;
	cin >> name;

	cout << "You named your character " << player.GetName() << endl;

	player.Shop();

	player.GetInventory();

	return 0;
}

/*
===========================================================
SHOP FUNCTION
===========================================================
*/

void Player::Shop()
{
	Item Healthpack("Health Pack", /*Item Price*/ 800);
	Item Map("Map", /*Item Price*/ 150);

	vector<string> shopInventory;

	shopInventory.push_back(Healthpack.GetName());
	shopInventory.push_back(Map.GetName());

	int choice{};
	int counter = 1;
	int amount{};

	while (choice != -3)
	{
		amount = 0;

		cout << "What would you like to buy?" << endl;

		for (int i = 0; i < shopInventory.size(); i++)
		{
			cout << counter++ << ") " << shopInventory[i] << endl;
		}

		cin >> choice;

		if (choice == -3)
		{
			continue;
		}

		cout << "How many do you want?" << endl;
		cin >> amount;

		switch (choice - 1)
		{
		case 0:
			AddItemToInventory(Healthpack.GetName(), amount);
			break;
		case 1:
			AddItemToInventory(Map.GetName(), amount);
			break;
		default:
			cout << "Invalid Choice" << endl;
		}
	}
}
Last edited on
[quote]CharacterClass should be a C++ class.

I though thats what it is?[/quote] I may have misunderstood. I thought you were basically saying that the className implied some of the other values for a character (like maxHealth). If that's true then you'd just want to pass the class name to the constructor and derive the other values from the name.

Player::inventory should probably be a vector<Item> or set<Item>. You might find that adding a quantity member to Item is handy. This would indicate how many or how much of the item is present. Then the shop has it's own inventory. When you buy something from the shop, the shop's quantity goes down and the player's quantity goes up.

Why does void Character::DisplayInfo(Character& character) exist? Would you even do something like player1.DisplayInfo(player2)? Why not just do cout << player2 instead?

You can simplify void Character::RestoreHealth(const int& restoreAmount):
1
2
3
4
void Character::RestoreHealth(const int restoreAmount)
{
    health = std::max(maxHealth, health+restoreAmount)
}
Note that I'm passing restoreAmount by value. There's no need to pass it by const reference since an int is small.
I though thats what it is?
I may have misunderstood. I thought you were basically saying that the className implied some of the other values for a character (like maxHealth). If that's true then you'd just want to pass the class name to the constructor and derive the other values from the name.[/quote]

Yeah thats basically what i was aiming for, I figured it out, I just did:

1
2
Player(string name, string chosenClass, float experience, unsigned level, int money, string characterClass, int health, int maxHealth, int attackPower, int maxAttackPower) :
		Character(characterClass, health, maxHealth, attackPower, maxAttackPower){}


Now when i call player.GetClassName(); it shows the name of the class the player chose, along with all of that classes variables.

Player::inventory should probably be a vector<Item> or set<Item>. You might find that adding a quantity member to Item is handy. This would indicate how many or how much of the item is present. Then the shop has it's own inventory. When you buy something from the shop, the shop's quantity goes down and the player's quantity goes up.


Ah, yes i'll add a quantity to the shop. Yeah i think making the inventory an Item type would be good.

Why does void Character::DisplayInfo(Character& character) exist? Would you even do something like player1.DisplayInfo(player2)? Why not just do cout << player2 instead?


That was a mistake on my part, I deleted that.

You can simplify void Character::RestoreHealth(const int& restoreAmount):
1
2
3
4
void Character::RestoreHealth(const int restoreAmount)
{
health = std::max(maxHealth, health+restoreAmount)
}
Note that I'm passing restoreAmount by value. There's no need to pass it by const reference since an int is small.


I'll have to look into that, when I give the player 5 health with that code it set the health to max instead of just adding 5. I deleted the references to the ints.

Heres the updated code:
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
#include <iostream>
#include <string>
#include <vector>

using namespace std;

/*
===========================================================
CHARACTER CLASS
===========================================================
*/

class Character
{
public:
	Character(string className, int health, int maxHealth, int attackPower, int maxAttackPower) :
		className(className),
		health(health),
		maxHealth(maxHealth),
		attackPower(attackPower),
		maxAttackPower(maxAttackPower){}

	Character() = default;

	string GetClassName() { return className; }

	int GetHealth() const { return health; }
	int GetAttackPwr() const { return attackPower; }
	int GetMaxAttackPower() const { return maxAttackPower; }
	int GetMaxHealth() const { return maxHealth; }

	void TakeDamage(const int damageTaken);
	void RestoreHealth(const int restoreAmount);
	void UpgradeAttackPower(const int upgradeAmount);

private:
	string className{};
	int health{};
	int maxHealth{};
	int attackPower{};
	int maxAttackPower{};
};


/*
===========================================================
ITEM CLASS
===========================================================
*/

class Item
{
public:
	Item(string name, unsigned price) : name(name), price(price) {}

	string GetName() const { return name; }
	int GetPrice() const { return price; }


private:
	string name{};
	unsigned price{};
};


/*
===========================================================
PLAYER CLASS
===========================================================
*/

class Player : public Character
{
public:
	Player(string name, string chosenClass, float experience, unsigned level, int money, string characterClass, int health, int maxHealth, int attackPower, int maxAttackPower) :
		name(name),
		Character(characterClass, health, maxHealth, attackPower, maxAttackPower){}

	void GetInventory();
	float GetExperience() const { return experience; }
	float GetExperienceNeeded() const { return experienceNeeded; }
	int GetLevel() const { return level; }
	string GetName() const { return name; }
	int GetMoney() const { return money; }

	void AddItemToInventory(string itemName, int amountToAdd);
	void RemoveItemFromInventory();
	void UseItem();
	void GiveExperience(const int xpToGive);
	void LevelUp(const int level);
	void Buy(Character& character);
	void Sell();
	void Shop();


private:
	string name{};
	string chosenClass{};
	int experience{};
	int experienceNeeded = 10;
	unsigned level{};
	vector < std::pair<string, int>> inventory{};
	int money{};
};

/*
===========================================================
GIVE EXPERIENCE FUNCTION
===========================================================
*/

void Player::GiveExperience(const int xpToGive)
{
	const float multiplier = 1.7; //Amount to multiply XP needed by.
	unsigned levelUpAmount = 0;

	experience += xpToGive;

	//This wiil apply all the levels the player earns if they get a huge XP boost that spans multiple levels.
	while (experience >= experienceNeeded)
	{
		levelUpAmount++;
		experienceNeeded = experienceNeeded * multiplier;
		cout << "Level up amount " << levelUpAmount << endl; //Debug only
	}
	LevelUp(levelUpAmount);
}

//Add amount of xp to multiply by.
void Player::LevelUp(const int giveLevel)
{
	level += giveLevel;
}

void Player::AddItemToInventory(string itemName, const int amountToAdd)
{
	inventory.push_back(std::make_pair(itemName, amountToAdd));
}

void Player::GetInventory()
{
	for (int i = 0; i < inventory.size(); i++)
	{
		cout << inventory[i].first << " " << inventory[i].second << endl;
	}
}

ostream& operator<< (ostream& os, Character& character)
{
	os << "Class Name: " << character.GetClassName() << endl;
	os << "Health: " << character.GetHealth() << endl;
	os << "Max Health: " << character.GetMaxHealth() << endl;
	os << "Attack Power: " << character.GetAttackPwr() << endl;
	os << "Max Attack Power: " << character.GetMaxAttackPower() << endl;

	return os;
}

void Character::RestoreHealth(const int restoreAmount)
{
	if (health + restoreAmount <= maxHealth)
	{
		health += restoreAmount;
	}
	else if (health + restoreAmount >= maxHealth)
	{
		health = maxHealth;
	}
}


void Character::TakeDamage(const int damageTaken)
{
	if (health > 0)
	{
		health -= damageTaken;

		if (health <= 0)
		{
			health = 0;
			cout << "The " << GetClassName() << ", was defeated." << endl;
		}
	}
}


int main()
{
	Character Knight
	(
		"Knight", /*Class Name*/
		120, /*Health*/
		150, /*Max Health*/
		3, /*Attack Power*/
		6 /*Max Attack Power*/
	);

	Character Samurai
	(
		"Samurai", /*Class Name*/
		40, /*Health*/
		60, /*Max Health*/
		7, /*Attack Power*/
		10 /*Max Attack Power*/
	);

	Character Marine
	(
		"Marine", /*Class Name*/
		80, /*Health*/
		150, /*Max Health*/
		2, /*Attack Power*/
		3 /*Max Attack Power*/
	);

	Character Archer
	(
		"Archer", /*Class Name*/
		 10, /*Health*/ 
		 20, /*Max Health*/ 
		 6, /*Attack Power*/
		 8 /*Max Attack Power*/
	);

	float experience = 0;
	unsigned level = 1;
	string name{};
	int startingMoney = 100;

	cin >> name;

	Player player
	(
		name,
		Knight.GetClassName(), 
		experience,
		level,
		startingMoney,
		Knight.GetClassName(), 
		Knight.GetHealth(), 
		Knight.GetMaxHealth(), 
		Knight.GetAttackPwr(), 
		Knight.GetMaxAttackPower()
	);

	cout << player.GetClassName() << endl;
	cout << player.GetExperience() << endl;
	cout << player.GetName() << endl;
	cout << player.GetExperienceNeeded() << endl;

	int choice = 0;

	while (choice != -3)
	{
		cout << "Current XP " << player.GetExperience() << endl;
		cout << "Experience Needed " << player.GetExperienceNeeded() << endl;
		cout << "Level " << player.GetLevel() << "\n" << endl;

		cout << "What would you liketo do?" << endl;
		cout << "1) Give XP" << endl;
		cin >> choice;

		switch (choice)
		{
			case 1:
				player.GiveExperience(13);
				break;
			default:
				cout << "Invalid Choice" << endl;
		}
	}

	player.Shop();

	player.GetInventory();

	return 0;
}

/*
===========================================================
SHOP FUNCTION
===========================================================
*/

void Player::Shop()
{
	Item Healthpack("Health Pack", /*Item Price*/ 800);
	Item Map("Map", /*Item Price*/ 150);

	vector<string> shopInventory;

	shopInventory.push_back(Healthpack.GetName());
	shopInventory.push_back(Map.GetName());

	int choice{};
	int counter = 1;
	int amount{};

	while (choice != -3)
	{
		amount = 0;

		cout << "What would you like to buy?" << endl;

		for (int i = 0; i < shopInventory.size(); i++)
		{
			cout << counter++ << ") " << shopInventory[i] << endl;
		}

		cin >> choice;

		if (choice == -3)
		{
			continue;
		}

		cout << "How many do you want?" << endl;
		cin >> amount;

		switch (choice - 1)
		{
		case 0:
			AddItemToInventory(Healthpack.GetName(), amount);
			break;
		case 1:
			AddItemToInventory(Map.GetName(), amount);
			break;
		default:
			cout << "Invalid Choice" << endl;
		}
	}
}
Last edited on
when I give the player 5 health with that code it set the health to max instead of just adding 5
OOPS! My bad. That should be
1
2
3
4
void Character::RestoreHealth(const int restoreAmount)
{
    health = std::min(maxHealth, health+restoreAmount)
}
ah, thank you!
Topic archived. No new replies allowed.