Thread: Help with combat algorithm

  1. #1
    Registered User
    Join Date
    Aug 2010
    Posts
    26

    Help with combat algorithm

    This is for a personal hobby project of mine, im working on a console based choose your own adventure with free movement between areas using grid coordinats IE [0,0,0] and im working on static monster encounters and the combat portion of it. I would like to do random dice rolls with dmg based on atk/defense of player and monster as well as hitrate, ive already got some starter code i worked on but there is still a fair bit im not able to grasp.


    Several of my questions:

    Can i use nested if else statements to continue the fight step by step until the monster or players hp is <= 0 and how do i return the value of the dmg done to a players global variable. I would like to pre-set the stats for each individual monster possible have a Combat() function which then loads a Monster function IE Monster001() or Zombie() Skeleton() etc.


    How do i calaculate in hit %. I'm using rand() for the dice rolls but how to incorporate % chance the hit is successful.

    How do i fetch the value of total dmg from each random dice to subtract it from player / monster hp.

    Then after how do i assign pre-decided exp per monster to the player in the event of victory or return the player to a death message if he fails. I'm using nested switchs for the accual menu options in each area and using goto only for Actions and Error/default for the switch. As well as each area has an AREA### goto for certain moves between areas that are oposite the flow of the code.

    At some point in the future id also like to assign equipment to an inventory system using strings and and equip feature which adds stats to players stats pre-combat as well.


    Here is my current dmg algorith code.




    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <cstdlib>
    #include <time.h>
    
    using namespace std;
    /*
    These constants define our upper
    and our lower bounds. 
    */
    int Test = 0;
    int MonsterLevel = 1;
    int MonsterHitPoints = 15;
    int MonsterAttack = 8;
    int MonsterDefense = 3;
    int PlayerLevel = 1;
    int PlayerHitPoints = 25;
    int PlayerAttack = 10;
    int PlayerDefense = 5;
    
    int LowMonster = 2;
    int HighMonster = MonsterAttack - PlayerDefense;
    int LowPlayer = 2;
    int HighPlayer = PlayerAttack - MonsterDefense;
    int main()
    {
    /*
    Variables to hold random values
    for the first and the second die on
    each roll.
    */
    int first_die, sec_die;
    /*
    Declare variable to hold seconds on clock.
    */
    time_t seconds;
    /*
    Get value from system clock and
    place in seconds variable.
    */
    time(&seconds);
    /*
    Convert seconds to a unsigned
    integer.
    */
    srand((unsigned int) seconds);
    /*
    Get first and second random numbers.
    */
    if ( (MonsterHitPoints >= 1) && (PlayerHitPoints >= 1) )
    {
    cout << "Monsters & Player Can Fight HP ok.\n";
    first_die = rand() % (HighPlayer - LowPlayer + 1) + LowPlayer;
    sec_die = rand() % (HighPlayer - LowPlayer +1) + LowPlayer;
    
    cout<< "Players attack is (" << first_die << ", "
    << sec_die << "}" << endl << endl;
    
    first_die = rand() % (HighMonster - LowMonster + 1) + LowMonster;
    sec_die = rand() % (HighMonster - LowMonster + 1) + LowMonster;
    
    cout<< "Monsters attack is (" << first_die << ", "
    << sec_die << "}" << endl << endl;
    
    }
    else if ( (MonsterHitPoints <= 0) && (PlayerHitPoints <= 0) );
    {
    cout << "Unable to fight! Player or Monster HP are 0.\n";
    cin >> Test;
    }
    return 0;
    }
    Last edited by Snaef98; 08-29-2010 at 04:40 PM.

  2. #2
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    Typically for this you would use a loop.
    Code:
    while(monsterHP > 0 && playerHP > 0){
    }//while
    Then you could write your handlers for what happened after that loop condition is false.
    Code:
    if(monsterHP <= 0){
    //Player won
    }
    if(playerHP <= 0){
    //Monster won
    }//if
    Of course this can become more complicated. Say the player attacks first and kills the monster, obviously the dead monster can't do damage on the player. So you could also write your loops this way
    Code:
    while(true){
    //Do player attack
    if(monsterHP <= 0){
       break;
    }//if
    
    //Do monster attack
    if(playerHP <= 0){
        break;
    }//if
    }//while
    All depends on how you want to handle it.
    Last edited by prog-bman; 08-29-2010 at 09:50 PM.
    Woop?

  3. #3
    Registered User
    Join Date
    Aug 2010
    Posts
    26

    New code after several hours of work today

    I think i have the bases covered in the event of a 1 hit kill blow, but ive yet to figure out how to deal with when the player kills the monster on his turn, its dual cycle so the monster is dead yet he finishes his blow before the loop ends. not sure use some kind of boolean check? any help would be appreciated. thx


    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <cstdlib>
    #include <time.h>
    #include <string>
    using namespace std;
    
    // Strings and extra variables
    string PlayerName; // Player's name
    string MonsterName = "Zombie";  // Monster name or type
    char NextRound;  // Continue to next combat cycle
    
    // MONSTER VARIABLES
    int MonsterLevel = 1;
    int MonsterHitPoints = 10;
    int MonsterAttack = 8;
    int MonsterDefense = 3;
    int MonsterHitRate = 60;
    
    // PLAYER VARIABLES
    int PlayerLevel = 1;
    int PlayerExperience = 0;
    int PlayerGold = 100;
    int PlayerHitPoints = 25;
    int PlayerAttack = 10;
    int PlayerDefense = 5;
    int PlayerHitRate = 75;
    
    // Monster damage variables using rand
    // Also subtracts player defense from monsters damage
    int LowMonster = 2;
    int HighMonster = MonsterAttack - PlayerDefense;
    
    // Player damage variables using rand
    // Also subtraces monster defense from players damage
    int LowPlayer = 2;
    int HighPlayer = PlayerAttack - MonsterDefense;
    
    // Variable to see if player or monster land a blow
    int PlayerHitCheck = 0;
    int MonsterHitCheck = 0;
    
    // Player % chance to hit high and low
    int PlayerHitLow = 1;
    int PlayerHitHigh = 100;
    
    // Monster % chance to hit high and low
    int MonsterHitLow = 1;
    int MonsterHitHigh = 100;
    
    // Player & Monster damage results die 1 + die 2
    int MonsterDamageResults = 0;
    int PlayerDamageResults = 0;
    
    
    
    
    int main()
    {
    /*
    Variables to hold random values
    for the first and the second die on
    each roll.
    */
    int first_die, sec_die;
    /*
    Declare variable to hold seconds on clock.
    */
    time_t seconds;
    /*
    Get value from system clock and
    place in seconds variable.
    */
    time(&seconds);
    /*
    Convert seconds to a unsigned
    integer.
    */
    srand((unsigned int) seconds);
    /*
    Get first and second random numbers.
    */
    /// COMBAT SCRIPT BELOW
    	cout << "You encounter a Level 1 Zombie. Prepare to fight!\n";
    	cout << "What is your name? <a-z>\n";
    	cin >> PlayerName;
    
    	while ( ( PlayerHitPoints >= 0 ) && ( MonsterHitPoints >= 0 ) )
    	{
    	if ( (MonsterHitPoints >= 1) && (PlayerHitPoints >= 1) )
    	{
    		cout << "Starting combat round between [" << PlayerName <<"] & [" << MonsterName <<"]!\n";
    		PlayerHitCheck = rand() % (PlayerHitHigh - PlayerHitLow +1) + PlayerHitLow;
    		
    		if (PlayerHitCheck <= 25)
    		{
    			cout << "" << PlayerName <<" swing's at the " << MonsterName << " and misses!\n";
    			cout << "Press <c> and enter to continue to the next combat round.\n";
    			cin >> NextRound;
    		}
    		else
    		{
    			cout << "" << PlayerName <<" swing's at the " << MonsterName <<" and lands a blow!\n";
    			first_die = rand() % (HighPlayer - LowPlayer + 1) + LowPlayer;  // Calculate player damage of first dice roll
    			sec_die = rand() % (HighPlayer - LowPlayer +1) + LowPlayer;     // Calculate player damage of second dice roll
    			cout << "" << PlayerName <<"'s attack is (" << first_die << ", "
    			<< sec_die << "}\n\n";
    			PlayerDamageResults = sec_die + first_die; // Calculate total damage done by player
    			cout << "" << PlayerName << " hits " << MonsterName << " for " << PlayerDamageResults << " damage.\n";
    			MonsterHitPoints = MonsterHitPoints - PlayerDamageResults; // Subtract damage from monsters hitpoints
    			cout << "" << PlayerName <<"'s hitpoints are: " << PlayerHitPoints << ".\n";
    			cout << "" << MonsterName <<"'s hitpoints are: " << MonsterHitPoints << ".\n";
    			cout << "Press <c> and enter to continue to the next combat round.\n";
    			cin >> NextRound;
    			
    			
    			MonsterHitCheck = rand() % (MonsterHitHigh - MonsterHitLow +1) + MonsterHitLow; // Check to see if monster hits player
    		}	
    		if (MonsterHitCheck <= 40)
    		{
    			cout << "" << MonsterName <<" swing's at " << PlayerName << " and misses!\n";
    			cout << "Press <c> and enter to continue to the next combat round.\n";
    			cin >> NextRound;
    		}	
    		else
    		{
    			cout << "" << MonsterName <<" swing's at " << PlayerName <<" and lands a blow!\n";
    			first_die = rand() % (HighMonster - LowMonster + 1) + LowMonster; // Calculate monster damage of first dice roll
    			sec_die = rand() % (HighMonster - LowMonster + 1) + LowMonster;   // Calculate monster damage of second dice roll
    			cout << "" << MonsterName <<"'s attack is (" << first_die << ", "
    			<< sec_die << "}\n\n";
    			MonsterDamageResults = sec_die + first_die; // Calculate total damage done by monster
    			cout << "" << MonsterName <<" hits " << PlayerName <<" for " << MonsterDamageResults << " damage.\n";
    			PlayerHitPoints = PlayerHitPoints - MonsterDamageResults; // Subtract damage from players hitpoints
    			cout << "" << PlayerName <<"'s hitpoints are: " << PlayerHitPoints << ".\n";
    			cout << "" << MonsterName <<"'s hitpoints are: " << MonsterHitPoints << ".\n";
    			cout << "Press <c> and enter to continue to the next combat round.\n";
    			cin >> NextRound;
    		}
    	}
    	else
    	{   // If & Else statements in the event a 1 hit kill blow is scored
    		if ( (PlayerHitPoints <=0) && ( MonsterHitPoints >=1) )
    		{
    			cout << "" << PlayerName <<" has died! [GAME OVER]\n\n";
    			cout << "Do you wish to reload your saved game? (Currently Unsupported)\n\n";
    			cin >> NextRound;
    	}
    		else
    		{
    		cout << "" << MonsterName <<" has died! [VICTORY!]\n\n";
    		cout << "You find 8 gold pieces on the " << MonsterName <<"!\n";
    		cout << "You gain 10 experience points!\n";
    		PlayerGold = PlayerGold + 8;               // Award player gold
    		PlayerExperience = PlayerExperience + 10;  // Award player experience
    		cout << "Players Experience:" << PlayerExperience <<"\n";
    		cin >> NextRound;
    		}
    	}
    }       // If & Else statements end of combat cycle
    	if ( (PlayerHitPoints <=0) && ( MonsterHitPoints >=1) )
    	{
    		cout << "" << PlayerName <<" has died! [GAME OVER]\n\n";
    		cout << "Do you wish to reload your saved game? (Currently Unsupported)\n\n";
    		cin >> NextRound;
    	}
    	else
    	{
    		cout << "" << MonsterName <<" has died! [VICTORY!]\n\n";
    		cout << "You find 8 gold pieces on the " << MonsterName <<"!\n";
    		cout << "You gain 10 experience points!\n";
    		PlayerGold = PlayerGold + 8;              // Award player gold
    		PlayerExperience = PlayerExperience + 10; // Award player experience
    		cout << "Players Experience:" << PlayerExperience <<"\n";
    		cin >> NextRound;
    	
    	}
    	return 0;
    }

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I've always found that algorithms like this are much easier to formulate and work with if you assume all values lie in range 0.0f to 1.0f. This makes all operations on the data much simpler since you know the min and the max values.

  5. #5
    Registered User
    Join Date
    Aug 2010
    Posts
    26
    I'm pretty new to C++ and im only just starting to really get the hang of this. I don't see how a float would fix this bug then again ive yet to really work with floats due to the fact i havn't done conversions on variables yet.

  6. #6
    Registered User
    Join Date
    Aug 2010
    Posts
    26
    I also have another problem im trying to create a function to level up the character which will be run after each battle to check and if needed update level,atk,defense,hitrate, exp to next level,


    i can update almost every single stat long as its a set # per levelup but when it comes to updating the exp to next level from a list of const ints im stuck!


    Code:
    int ExperienceCalculator()
    {
    	// Variables that store the experience for next level
    	const int NextExperienceUp2 = 100;
    	const int NextExperienceUp3 = 225;
    	const int NextExperienceUp4 = 400;
    	const int NextExperienceUp5 = 925; 
    	const int NextExperienceUp6 = 1400;
    	const int NextExperienceUp7 = 2425;
    	const int NextExperienceUp8 = 3650;
    	const int NextExperienceUp9 = 5675;
    	const int NextExperienceUp10 = 8150;
    	
    	// Variables that store the total exp at next level
    	const int NextExperience2 = 100;
    	const int NextExperience3 = 325;
    	const int NextExperience4 = 725;
    	const int NextExperience5 = 1650; 
    	const int NextExperience6 = 3025;
    	const int NextExperience7 = 5475;
    	const int NextExperience8 = 7900;
    	const int NextExperience9 = 11550;
    	const int NextExperience10 = 19700;
    	
    	// Variable that store new hit points value for next level (Base 20 + 5 per level)
    	const int PlayerHitPointsUp = 5;
    
    	// Variable that store new attack value for next level (Base 12 + 2 per level)
    	const int PlayerAttackUp = 2;
    	
    	// Variable that store new defense value for next level (Base 6 + 3 per level)
    	const int PlayerDefenseUp = 3;
    
    	// Variable that stores new hitrate value for next level (Base 50% + 1% per level)
    	const int PlayerHitRateUp = 1;
    
    	cout << "Checking players level & experience stats.\n";
    
    	if (PlayerExperience >= PlayerNextExperience)
    	{
    		cout << "Leveling up player.\n";
    		++PlayerLevel;
    		PlayerHitPoints = PlayerHitPoints + PlayerHitPointsUp;
    		PlayerAttack = PlayerAttack + PlayerAttackUp;
    		PlayerDefense = PlayerDefense + PlayerDefenseUp;
    		PlayerHitRate = PlayerHitRate + PlayerHitRateUp;
    		cout << "Done leveling up player.\n";
    		cout << "Updating experience to next level.\n";
    	}
    	else
    	{
    		cout << "Player does not need to be leveled up.\n";
    		cout << "Returning to game...\n";
    	}	
    	return 0;
    }
    Last edited by Snaef98; 08-30-2010 at 01:06 AM.

  7. #7
    Registered User NeonBlack's Avatar
    Join Date
    Nov 2007
    Posts
    431
    Have you tried something similar to this?

    Code:
    const int NextExperienceLevels[] = {-1, 0, 100, 325, 375, ...};
    if (PlayerExperience >= PlayerNextExperience)
    {
        ...
        if (PlayerLevel < MaxLevel) PlayerNextExperience = NextExperienceLevel[PlayerLevel+1];
    }
    I copied it from the last program in which I passed a parameter, which would have been pre-1989 I guess. - esbo

  8. #8
    Registered User
    Join Date
    Aug 2010
    Posts
    26
    I tried using an array and it didn't work but it wasn't written exactly like that. Also what is MaxLevel for since i don't have a variable by that name.

  9. #9
    Registered User NeonBlack's Avatar
    Join Date
    Nov 2007
    Posts
    431
    What I posted is what's called an example. It's intended to give you ideas on how to implement your program.

    If you tried something that didn't work, you can post it and someone here will be more than willing to help you fix it.
    I copied it from the last program in which I passed a parameter, which would have been pre-1989 I guess. - esbo

  10. #10
    Registered User
    Join Date
    Aug 2010
    Posts
    26
    This is what i have right now. At the moment im using a static 500xp per lvl but at some point i want to change it to an exp chart that starts out low and increases with each level.
    Code:
    int ExperienceCalculator()
    {
    	HANDLE hConsole; // Code for colored text
    	hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // Code for colored text
    	// Variables that store the experience for next level (Currently unused STATIC 500xp/level)
    	const int NextExperienceUp2 = 100;
    	const int NextExperienceUp3 = 225;
    	const int NextExperienceUp4 = 400;
    	const int NextExperienceUp5 = 925; 
    	const int NextExperienceUp6 = 1400;
    	const int NextExperienceUp7 = 2425;
    	const int NextExperienceUp8 = 3650;
    	const int NextExperienceUp9 = 5675;
    	const int NextExperienceUp10 = 8150;
    	
    	// Variables that store the total exp at next level (Currently unused STATIC 500xp/level)
    	const int NextExperience2 = 100;
    	const int NextExperience3 = 325;
    	const int NextExperience4 = 725;
    	const int NextExperience5 = 1650; 
    	const int NextExperience6 = 3025;
    	const int NextExperience7 = 5475;
    	const int NextExperience8 = 7900;
    	const int NextExperience9 = 11550;
    	const int NextExperience10 = 19700;
    	
    	// Variable that store new hit points value for next level (Base 20 + 5 per level)
    	const int PlayerHitPointsUp = 5;
    
    	// Variable that store new attack value for next level (Base 6 + 2 per level)
    	const int PlayerAttackUp = 2;
    	
    	// Variable that store new defense value for next level (Base 3 + 3 per level)
    	const int PlayerDefenseUp = 3;
    
    	// Variable that stores new hitrate value for next level (Base 50% + 1% per level)
    	const int PlayerHitRateUp = 1;
        {
    	SetConsoleTextAttribute(hConsole, 15); // Colored Text Red
    	}	
    	cout << "\n[";
    	{
    	SetConsoleTextAttribute(hConsole, 12); // Colored Text Red
    	}	
    	cout << " SYSTEM MESSAGE: ";
    	{
    	SetConsoleTextAttribute(hConsole, 15); // Colored Text Red
    	}	
    	cout << "Experience Calculator ]\n";
    	cout << "\nChecking players level & experience stats.\n";
    
    	if (PlayerExperience >= PlayerNextExperience)
    	{
    		cout << "Leveling up player.\n";
    		++PlayerLevel;
    		PlayerHitPoints = PlayerHitPoints + PlayerHitPointsUp;
    		PlayerMaxHitPoints = PlayerLevel * 5 + 15;
    		PlayerAttack = PlayerAttack + PlayerAttackUp;
    		PlayerDefense = PlayerDefense + PlayerDefenseUp;
    		PlayerHitRate = PlayerHitRate + PlayerHitRateUp;
    		PlayerNextExperience = PlayerLevel * 500;
    		cout << "Done leveling up player.\n";
    		cout << "Returning to game...\n\n";
    	}
    	else
    	{
    		cout << "\nPlayer does not need to be leveled up.\n";
    		cout << "Returning to game...\n\n";
    	}	
    	return 0;
    }
    Last edited by Snaef98; 09-01-2010 at 02:34 AM.

  11. #11
    Registered User
    Join Date
    Aug 2010
    Posts
    26
    Is this what you were talking about? it appears to work, but not sure if there is any bugs could you check it over, also should i move the array over to globals? How will this effect saving as i now have save/load in my game.

    Code:
    int ExperienceCalculator()
    {
    	HANDLE hConsole; // Code for colored text
    	hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // Code for colored text
    	// Array that stores the exp needed for each level
    	const int NextExperienceLevels[] = {0, 100, 225, 400, 925, 1400, 2425, 3650, 5675, 8150};
    	// Variables that store the experience for next level (Currently Unused - Guide Only)
    	const int NextExperienceUp2 = 100;
    	const int NextExperienceUp3 = 225;
    	const int NextExperienceUp4 = 400;
    	const int NextExperienceUp5 = 925; 
    	const int NextExperienceUp6 = 1400;
    	const int NextExperienceUp7 = 2425;
    	const int NextExperienceUp8 = 3650;
    	const int NextExperienceUp9 = 5675;
    	const int NextExperienceUp10 = 8150;
    	
    	// Variables that store the total exp at next level (Currently Unused - Guide Only)
    	const int NextExperience2 = 100;
    	const int NextExperience3 = 325;
    	const int NextExperience4 = 725;
    	const int NextExperience5 = 1650; 
    	const int NextExperience6 = 3025;
    	const int NextExperience7 = 5475;
    	const int NextExperience8 = 7900;
    	const int NextExperience9 = 11550;
    	const int NextExperience10 = 19700;
    	
    	// Variable that store new hit points value for next level (Base 20 + 5 per level)
    	const int PlayerHitPointsUp = 5;
    
    	// Variable that store new attack value for next level (Base 6 + 2 per level)
    	const int PlayerAttackUp = 2;
    	
    	// Variable that store new defense value for next level (Base 3 + 3 per level)
    	const int PlayerDefenseUp = 3;
    
    	// Variable that stores new hitrate value for next level (Base 50% + 1% per level)
    	const int PlayerHitRateUp = 1;
        {
    	SetConsoleTextAttribute(hConsole, 15); // Colored Text Red
    	}	
    	cout << "\n[";
    	{
    	SetConsoleTextAttribute(hConsole, 12); // Colored Text Red
    	}	
    	cout << " SYSTEM MESSAGE: ";
    	{
    	SetConsoleTextAttribute(hConsole, 15); // Colored Text Red
    	}	
    	cout << "Experience Calculator ]\n";
    	cout << "\nChecking players level & experience stats.\n";
    
    	while ( PlayerExperience >= PlayerNextExperience)
    	if (PlayerExperience >= PlayerNextExperience)
    	{
    		cout << "Leveling up player.\n";
    		if (PlayerLevel < PlayerMaxLevel) PlayerNextExperience = NextExperienceLevels[PlayerLevel+1];
    		++PlayerLevel;
    		PlayerHitPoints = PlayerHitPoints + PlayerHitPointsUp;
    		PlayerMaxHitPoints = PlayerLevel * 5 + 15;
    		PlayerAttack = PlayerAttack + PlayerAttackUp;
    		PlayerDefense = PlayerDefense + PlayerDefenseUp;
    		PlayerHitRate = PlayerHitRate + PlayerHitRateUp;
    	}
    	else
    	{
    		cout << "\nPlayer does not need to be leveled up.\n";
    		cout << "Returning to game...\n\n";
    	}	
    		cout << "Done leveling up player.\n";
    		cout << "Returning to game...\n\n";
    	return 0;
    }
    Last edited by Snaef98; 09-01-2010 at 03:54 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Implement of a Fast Time Series Evaluation Algorithm
    By BiGreat in forum C Programming
    Replies: 7
    Last Post: 12-04-2007, 02:30 AM
  2. Replies: 4
    Last Post: 12-10-2006, 07:08 PM
  3. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  4. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM