Sign in to follow this  
MAGIgullorks

Monsterfight error

Recommended Posts

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