Sign in to follow this  
MAGIgullorks

Monsterfight error

Recommended Posts

MAGIgullorks    100
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

Share this post


Link to post
Share on other sites
Evil Steve    2017
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)

Share this post


Link to post
Share on other sites
Gage64    1235
If you set your compiler's warning level to the highest possible, it will (probably) warn you about this sort of thing.

Share this post


Link to post
Share on other sites
rip-off    10979
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 out
Hero 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 it
void 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 implemented
void 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 dies
void 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 points
struct 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" function
void 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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this