Regarding Gladiator.display(redTeam);
: No, display
does not accept parameters, nor should it. It's a function to display stats for one Gladiator
and it should ideally be agnostic with regards to the team the gladiator fights for.
Instead, create a Team
class to hold a vector of Gladiator's and add a display
member function to it that loops though all gladiators and calls their display
functions.
struct Team {
void display() const {
for(const Gladiator& g : gladiators) {
g.display();
}
}
};
The Team
class will also come in handy when you later want to add functions for fightning another team. The Fight
function in the Team
class would then call the Fight
function on the Gladiator's it contains.
Both display
functions could be made into stream operators to make integration with standard streams seemless so that you can do this instead:
std::cout << a_gladiator; // print stats for one gladiator
std::cout << redteam; // print stats for all gladiators in a team
Here's an example where I've replaced the display
functions with stream operators and since randomness will probably be a big part of the fighting, I added an example usage of the <random>
library too and an example of how a Fight
function could be implemented in both classes.
#include <iostream>
#include <vector>
#include <random>
// "prng" will be the pseudo random number generator when fighting
// https://en.cppreference.com/w/cpp/header/random
std::random_device rd;
std::mt19937 prng(rd());
enum Result { r_loss=-1, r_draw=0, r_win=1};
Result win_or_loss(int h, int a) {
int r = h-a;
return (r==0) ? r_draw : (r>0?r_win:r_loss);
}
//-----------------------------------------------------------------------------
struct Gladiator {
std::string name;
int maxHealth;
int curHealth;
int evasion;
int critical;
// "damage" will hold the min and max values of damage
// and can be used with a pseudo random number generator
// to get the value of one strike that the Gladiator
// delivers
std::uniform_int_distribution<int> damage;
Gladiator(const std::string& Name, int MaxHealth, int Evasion,
int Critical, int DmgMin, int DmgRange) :
name(Name),
maxHealth(MaxHealth),
curHealth(maxHealth),
evasion(Evasion),
critical(Critical),
damage(DmgMin, DmgMin+DmgRange) // initialize with DmgMin and DmgRange
{}
// return r_win if this gladiator wins or r_loss if the opponent wins
// or r_draw if it's a draw
Result Fight(Gladiator& opponent) {
// perhaps reset health here, or at the end of the fight
curHealth = maxHealth;
opponent.curHealth = opponent.maxHealth;
std::cout << " The fight between " << name << " and " << opponent.name << " begins!\n";
// fight loop
while( curHealth>0 && opponent.curHealth>0 ) {
// use of evasion & critical must be added
// use the "damage" uniform int distributions with the
// random number generator to get the values for the hits
int my_hit = damage(prng);
int opponents_hit = opponent.damage(prng);
// add cool fight messages
std::cout << " " << name << " hit " << opponent.name << ", doing " << my_hit << " hp damage.\n";
std::cout << " " << opponent.name << " hit " << name << ", doing " << opponents_hit << " hp damage.\n";
curHealth -= opponents_hit;
opponent.curHealth -= my_hit;
}
// figure out who won
Result r = win_or_loss(curHealth, opponent.curHealth);
if(r==r_win) std::cout << " Gladiator " << name << " won!\n";
else if(r==r_loss) std::cout << " Gladiator " << opponent.name << " won!\n";
else std::cout << " It was a draw!\n";
return r;
}
// declare a function (in the form of a stream operator) for streaming
// a gladiator to an output stream, like std::cout
friend std::ostream& operator<<(std::ostream&, const Gladiator&);
};
// definition of the output stream operator for a Gladiator
std::ostream& operator<<(std::ostream& os, const Gladiator& g) {
os << " " << g.name << ":\n Health: " << g.curHealth << '/' << g.maxHealth <<
"\n Evasion: " << g.evasion << "\n Critical: " << g.critical <<
"\n Damage: " << g.damage.min() << '-' << g.damage.max() << "\n\n";
return os;
}
//-----------------------------------------------------------------------------
struct Team {
std::string name;
std::vector<Gladiator> m_gladiators;
Team(const std::string& Name) : Team(Name, {}) {}
Team(const std::string& Name, std::vector<Gladiator>&& gv) :
name(Name),
m_gladiators(std::move(gv))
{}
// return r_win if this team wins or r_loss if the opponent team wins
// or r_draw if it's a draw
Result Fight(Team& opponent) {
unsigned wins=0, losses=0;
std::cout << "Team " << name << " vs. " << opponent.name << "\n";
for(Gladiator& my_gladiator : m_gladiators) {
for(Gladiator& opponent_gladiator : opponent.m_gladiators) {
Result result = my_gladiator.Fight(opponent_gladiator);
if(result>0) {
++wins;
} else if(result<0) {
++losses;
}
}
}
Result r = win_or_loss(wins, losses);
if(r==r_win) std::cout << "Team " << name << " won!\n";
else if(r==r_loss) std::cout << "Team " << opponent.name << " won!\n";
else std::cout << "It was a draw\n";
return r;
}
// Just like for an individal Gladiator, declare a stream operator.
friend std::ostream& operator<<(std::ostream&, const Team&);
};
// stream all gladiators in a Team
std::ostream& operator<<(std::ostream& os, const Team& t) {
os << "Team " << t.name << " stats:\n";
for(const auto& g : t.m_gladiators) {
std::cout << g; // this uses the Gladiator output stream operator
}
return os;
}
//-----------------------------------------------------------------------------
int main() {
std::cout << "A battle will soon commence... First the Teams must be created.\n";
// if you'd like a dynamic amount of teams, you can make a Team vector like this:
std::vector <Team> teams = {
{"Red",
{
{"Spartacus", 100, 25, 27, 10, 17},
{"Crixus", 99, 24, 26, 12, 13}
}
},
{"Blue",
{
{"Commodus", 101, 30, 28, 11, 16},
{"Tetraites", 98, 31, 29, 10, 15}
}
}
};
// print info about all teams
for(const auto& team : teams) std::cout << team;
// let all teams fight
for(auto it_a=teams.begin(); it_a<(teams.end()-1); ++it_a) {
for(auto it_b=it_a+1; it_b<teams.end(); ++it_b) {
(*it_a).Fight(*it_b);
}
}
/*
std::cout << "------\n";
// or if you'd like to treat them separately, you can create
// referenses to the teams:
Team& redTeam = teams[0];
Team& blueTeam = teams[1];
// and use them individually
std::cout << redTeam;
std::cout << blueTeam;
redTeam.Fight(blueTeam);
*/
}