Monsterfight error
First off, I dont know how to do that scroll thing for code, but its not incredibly long. For some reason, when I fight the rat, he can hurt me negative numbers for some reason, and so can the I, even though i have the if (HHIT or MHIT less than 0 then they equal zero.) Can someone help me on this? Heres the code: (Only the battle part I have done so far.) And i have to have them in this order or they dont work.
void stats()
{
if (SHOWGAINLVL = 1)
{
if (HEXP > 100 && HEXP < 150 && HNEWLVL == 1)
{
HHP = 115;
HLVL = 1;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 150 && HEXP < 220 && HNEWLVL == 2)
{
HHP = 123;
HLVL = 2;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 500 && HEXP < 1000 && HNEWLVL == 3)
{
HHP = 146;
HLVL = 3;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 1000 && HEXP < 2500 && HNEWLVL == 4)
{
HHP = 168;
HLVL = 4;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 2500 && HEXP < 5000 && HNEWLVL == 5)
{
HHP = 189;
HLVL = 5;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 5000 && HEXP < 10000 && HNEWLVL == 6)
{
HHP = 205;
HLVL = 6;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 10000 && HEXP < 25000 && HNEWLVL == 7)
{
HHP = 231;
HLVL = 7;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
else if (HEXP > 50000 && HEXP < 100000 && HNEWLVL == 8)
{
HHP = 254;
HLVL = 8;
HNEWLVL++;
cout << "You advance a new lvl!" << endl;
}
SHOWGAINLVL = 0;
}
if (HLVL == 0)
{
HATTACK = rand() % 4 + 1;
HDEFENSE = rand() % 4 + 1;
}
else if (HLVL == 1)
{
HATTACK = rand() % 5 + 1;
HDEFENSE = rand()% 5 + 1;
}
else if (HLVL == 2)
{
HATTACK = rand() % 6 + 1;
HDEFENSE = rand() % 6 + 1;
}
else if (HLVL == 3)
{
HATTACK = rand() % 7 + 1;
HDEFENSE = rand() % 7 + 1;
}
else if (HLVL == 4)
{
HATTACK = rand() % 8 + 1;
HDEFENSE = rand() % 8 + 1;
}
else if (HLVL == 5)
{
HATTACK = rand() % 10 + 1;
HDEFENSE = rand() % 10 + 1;
}
else if (HLVL == 6)
{
HATTACK = rand() % 11 + 2;
HDEFENSE = rand() % 11 + 2;
}
else if (HLVL == 7)
{
HATTACK = rand() % 13 + 3;
HDEFENSE = rand() % 13 + 3;
}
else if (HLVL == 8)
{
HATTACK = rand() % 15 + 5;
HDEFENSE = rand() % 15 + 5;
}
else if (HLVL == 9)
{
HATTACK = rand() % 16 + 6;
HATTACK = rand() % 16 + 6;
}
return;
}
void battle()
{
for (;;)
{
cout << "What do you want to do?" << endl;
cout << "1)Attack" << endl;
cout << "2)Use Magic" << endl;
cout << "3)Drink Potion" << endl;
cin >> HEROCHOICE;
if (HEROCHOICE == 1)
{
if (MHP > 0)
{
stats();
if (ICURRENTMONSTER == 1)
{MATTACK = rand() % 2 + 1; MDEFENSE = rand() % 2 + 1;}
else if (ICURRENTMONSTER == 2)
{MATTACK = rand() % 3 + 1; MDEFENSE = rand() % 3 + 1;}
else if (ICURRENTMONSTER == 3)
{MATTACK = rand() % 7 + 1; MDEFENSE = rand() % 5 + 1;}
MHIT = MATTACK - HDEFENSE;
HHIT = HATTACK - MDEFENSE;
if (HHIT < 1)
{
HHIT = 0;
}
else if (MHIT < 1)
{
MHIT = 0;
}
MHP = MHP - HHIT;
HHP = HHP - MHIT;
}
cout << "You hit the ";
if (ICURRENTMONSTER == 1)
{cout << "giant rat ";}
cout << HHIT << ", and the ";
if (ICURRENTMONSTER == 1)
{cout << "giant rat";}
cout << " hit you " << MHIT << "." << endl;
cout << "You have " << HHP << " health, the ";
if (ICURRENTMONSTER == 1)
{cout << "giant rat";}
cout << " has " << MHP << " health." << endl;
}
else if (HEROCHOICE == 2)
{
cout << "UNDER CONSTRUCTION" << endl;
}
else if (HEROCHOICE == 3)
{
cout << "UNDERSCONSTRUCTION" << endl;
}
if (MHP < 1)
{
cout << "You killed the ";
if (ICURRENTMONSTER == 1)
{cout << "giant rat!" << endl;}
cout << "You recieved " << GAINEDXP << " exp!" << endl;
SHOWGAINLVL = 1;
stats();
return;
}
else if (HHP < 1)
{
cout << "You die..." << endl;
cout << "Would you like to see your stats one more time before you end?" << endl;
cin >> MENUCHOICE;
system("CLS");
if (MENUCHOICE == 'y' || MENUCHOICE == 'Y')
{
menu();
}
}
}
}
void giant_rat()
{//giant_rat
GAINEDXP = rand() % 25 + 20;
MHP = 15;
ICURRENTMONSTER = 1;
battle();
return;
}//giant_rat end
yes, it only shows you advanced a lvl if you defeat the monster, then it is possible to go through those and find the right one.
Quote:Original post by MAGIgullorksNope. It's equivalent to:
yes, it only shows you advanced a lvl if you defeat the monster, then it is possible to go through those and find the right one.
SHOWGAINLVL = 1;
if (1)
You probably want:
if (SHOWGAINLVL == 1)
If you set your compiler's warning level to the highest possible, it will (probably) warn you about this sort of thing.
Here is a Zahlman-esque refactoring of your current code. I have assumed basic familiarity with arrays, if you have any questions don't hesitate to ask.
The level information should probably be all compacted into a single structure, but its done now [grin].
Warning: code not compiled or tested.
// First off, if we find we are making heavy use of a particular expression// it should probably be a function in its own right// This returns a random number between 1 and value.int random(int value){ return (rand() % value) + 1;}// We have two main actors in the game, the Hero and the Monster// I guessed these from the prefixes "H" and "M" respectively// We can make actual types for these in C++, which makes dealing with them easier// I found all the "Hero" data I could, and grouped it into a single structure.// These were the values I found:struct Hero{ int attack; int defense; int hit_points; int level; int experience;};// Likewise, I grouped the "Monster" information into another structure.// The "string" type is provided by the C++ standard library header <string>// It is used to store text.struct Monster{ int attack; int defense; int hit_points; int gained_experience; string name;};// I have kept it a simple as possible, so I am not going to talk about// classes or constructors.// Instead, here is a function that builds a hero for us.// Your code did not include the hero's initial stats, so I have left them outHero make_hero(){ Hero hero; hero.attack = // some starting value hero.defense = // some starting value hero.hit_points = 100; hero.level = 0; hero.experience = 0; return hero;}// Again, we also need a way of making monsters.// From your code, I can see that you have fully implemented a "giant rat" monster// But you had a fragment that alluded to higher level monsters.// To make your code extensible, we only hard code the monsters statistics// at a single point: monster creation// Later on, you could load the data from a file or an array or whatever//// Because (currently) the monster's attack and defense are linked, I've used a parameter// called "nastiness" which is used to generate the both.// We use the "random" function above to do the hard work.// Finally, the "name" parameter is passed by const reference// It is usually a good idea to pass complex types by reference.Monster make_monster(int nastiness, const string &name, int hit_points, int hit_points, int experience){ Monster monster; monster.attack = random(nastiness); monster.defense = random(nastiness); monster.name = name; monster.hit_points = hit_points; monster.gained_experience = experience; return monster;}// I am going to skip leveling and experience for the moment.// To keep the compiler happy, you are going to need to forward declare some functions// With the code I am proposing, you would need to forward declare two functions// * level_up()// * generate_stats()// like so:void level_up(Hero &hero);void generate_stats( Hero &hero );// The next function again removes some redunancy from the damage calculations// It is very simple:int calc_damage(int attack, int defense){ int damage = attack - defense; if(damage < 0) { return 0; } return damage;}// The monster and hero attack each other!// The hero and monster structures are passed by reference// In normal C++, we pass by *value*, which means the values passed to the function// are copies of those in the calling function.// an example is:// ------------------------// void decrement( int i )// {// --i;// }//// int main()// {// int value = 1// cout << value << '\n';// decrement(value);// cout << value << '\n';// }// ------------------------// if you run this code, you will see it prints "1" twice// The following code shows pass by reference:// ------------------------// void decrement( int &i )// {// --i;// }//// int main()// {// int value = 1// cout << value << '\n';// decrement(value);// cout << value << '\n';// }// ------------------------// This will print "1", followed by "0". The function calls no longer copy the parameters// Here, decrement() is really decrementing "value" in main, whereas before it was// decrementing a copy of value.//// The same thing applies to attack: if we change the value of the hero or monster// parameters, the calling code will see itvoid attack(Hero &hero, Monster &monster){ // your code seems to randomly change the statistics of the hero // in between strikes, by caling the stats() function // I've left it in here for the moment, but consider whether that is really // what you want generate_stats(hero); // making use of the helper function above int monster_damage = calc_damage(monster.attack,hero.defense); hero.hit_points -= monster_damage; int hero_damage = calc_damage(hero.attack,monster.defense); monster.hit_points -= hero_damage; cout << "You hit the " << monster.name << ' ' << hero_damage << ", and the "; cout << monster.name << " hit you " << monster_damage << ".\n"; cout << "You have " << hero.hit_points << " health, the "; cout << monster.name << " has " << monster.hit_points << " health." << endl;}// These two may need to be modified to take the Hero and Monster references// like attack() when they are fully implementedvoid useMagic(){ cout << "UNDER CONSTRUCTION" << endl;}void drinkPotion(){ cout << "UNDER CONSTRUCTION" << endl;}// You can never have too many functions :)// Here is another helper function, which can keep the calling code clean.int chooseAction(){ cout << "What do you want to do?" << endl; cout << "1)Attack" << endl; cout << "2)Use Magic" << endl; cout << "3)Drink Potion" << endl; int choice; cin >> choice; return choice;}// Another simple helper function, displayed when the hero diesvoid death_message(){ cout << "You die..." << endl; cout << "Would you like to see your stats one more time before you end?" << endl; char choice; cin >> choice; system("CLS"); if (choice == 'y' || choice == 'Y') { menu(); }}// This is the biggest function yet!// One of the side effects of moving the code around (called refactoring)// is that it usually results in the code being simpler and clearer// Your code had two gigantic functions. This code has a lot more functions,// but most of them are very short and this aids readability// It can take a while to see this (when I started programming I had very long functions too)// As a general rule, if you have to scroll up and down to read your functions:// they are too long!void battle(){ // here the monster and hero are created. // Alternatively, they could be passed to the function (again, by reference) // from the calling code (which I don't have access to). Monster monster = make_monster(1,"giant rat",15,rand() % 25 + 20), Hero hero = make_hero(); // You wrote a nice infinite loop in your code. // While there are occasions when we use such loops, most loops have terminating conditions // Yours is simple: we battle() until someone dies! while(monster.hit_points > 0 && hero.hit_points > 0) { // Here is an example of how our helper functions increase readability int heroChoice = chooseAction(); if (heroChoice == 1) { attack(hero,monster); } else if (heroChoice == 2) { useMagic(); } else if (heroChoice == 3) { drinkPotion(); } } // one someone dies, all we have to do is figure out whether it was // the monster or the player if(monster.hit_points <= 0) { cout << "You killed the " << monster.name << "!\n"; cout << "You recieved " << monster.gained_experience << " exp!" << endl; hero.experience += monster.gained_experience; level_up(hero); } else // if the monster didn't die, it *must* have been the player { death_message(); }}// The next bit of code deals with leveling.// I see you made some good use of the Copy & Paste feature of your IDE for this ;)// The best way is actually to remove the data from the code.// Currently we have 9 different levels, 0 to 8.// We can define this constant as it will help us later.const int NUMBER_OF_LEVELS = 9;// This structure tells us how to generate the stats for a particular level// In your code, all the stats were// hero_attach = rand() % X + Y// where X and Y varied between different levels// The right way to do that (without lots of copypasta)// is to store this data in an array.// Because the players levels go from 0..8, we can use the players level itself// as an index into the array.struct LevelStatistics{ int random; int base;};// Now we define the actual data.// I took this from your current code, but double check it -// I could have made a few mistakes ;)LevelStatistics level_stats[NUMBER_OF_LEVELS] ={ {4,1}, // level 0... {5,1}, {6,1}, {7,1}, {8,1}, {10,1}, {11,2}, {13,3}, {15,5}, // to level 8 // note: with your current level system you cannot reach level 9 // Look carefully at your current stats function for why this is // {16,6}};// This helper function does two things:// 1) error checking. A hero must have a positive level, and can never reach level 9 (yet)// we can use the assert macro for this. It will warn us if our code is faulty and allows// "impossible" situations to take place, like level -42.// 2) again, it reduces the amount of copy and pasting we need to do to generate statistics.int generate_level_value(int level){ assert(level < NUMBER_OF_LEVELS && level >= 0); LevelStatistics data = level_stats[level]; return rand() % data.random + data.base;}// The next structure is used to determine whether a level up is possible// We have two values, the minimum experience necessary and the new value of the// players hit pointsstruct NextLevelData{ int minimum_experience; int hit_points;};// And finally our array of data.// Again, this information was taken from your current code.NextLevelData next_level[NUMBER_OF_LEVELS]{ {0 , 100}, // level 0... {100 , 115}, {150 , 123}, {500 , 146}, {1000 , 168}, {2500 , 189}, {5000 , 205}, {10000, 231}, {50000, 254}, // to 8};// This tests if the hero can level up.// It is simple enough.// First, we sanity check the hero's current level.// Next, If we are already at level 8, we can't.// - remember, level 8 is NUMBER_OF_LEVELS - 1// If we haven't reached the max, we simply test if we have reached the minimum// experience for the next level.bool can_level_up(const Hero &hero){ assert(level < NUMBER_OF_LEVELS && level >= 0); if(hero.level == NUMBER_OF_LEVELS - 1) { return false; } return hero.experience >= next_level[hero.level + 1].minimum_experience;}// Leveling up is now easy// If we can level up (according to the above helper function)// we do so, if not we print the reason.void level_up(Hero &hero){ if(can_level_up(hero)) { hero.level++; hero.hit_points = next_level[hero.level].hit_points; cout << "You advance to a new level: " << hero.level << '\n'; } else if(hero.level == NUMBER_OF_LEVELS) { cout << "You are at the highest possible level, congratulations!\n"; } else { cout << "You don't have enough experience to level up yet.\n"; }}// Finally, we implement this function for use in the "battle" functionvoid generate_stats( Hero &hero ){ assert(hero.level >= 0 && hero.level < NUMBER_OF_LEVELS) hero.attack = generate_level_value(hero.level); hero.defense = generate_level_value(hero.level);}
The level information should probably be all compacted into a single structure, but its done now [grin].
Warning: code not compiled or tested.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement