Monsterfight error

Started by
5 comments, last by rip-off 15 years, 8 months ago
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
Advertisement
Quote:Original post by MAGIgullorks
if (SHOWGAINLVL = 1)

Do you know what this line does?
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 MAGIgullorks
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.
Nope. It's equivalent to:
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.
I see... HOWD I MISS THAT?!
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.
// 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