Damage Calculator (DP)

obi

formerly david stone
is a Site Content Manager Alumnusis a Programmer Alumnusis a Senior Staff Member Alumnusis a Smogon Discord Contributor Alumnusis a Researcher Alumnusis a Top Contributor Alumnusis a Battle Simulator Moderator Alumnus
I made a damage calculator in C++ for DP. I did it partly to learn C++, but also because it seems like none of the other calculators out there get it exactly right (often they are off just a bit due to rounding). To the best of my knowledge, this will always output the correct number.

This is what I have yet to add:

Unaware
Simple
2v2 support

In the two supported ambiguous cases (the order of Me First vs. Tinted Lens and the order of DeepSeaScale vs. Rock-type in Sandstorm Special Defense bonus), my calculator does the multiplication in the same order as Shoddybattle.

I also don't yet have a way to auto-calculate the power of variable power moves (coming eventually, but that's after the next step).

I plan to give it a way to automatically enter a lot of this data just by saying who the defender is, what the attack is, etc.

There is currently no real interface. It's just a command-line prompt. If you enter stupid data ("What is the attackers level?" "df!") you'll cause some sort of strange error. Creating a nice interface is the last of my goals. However, it is a goal, as it's something I'd like to learn.

This is partly a learning thing for me, so here is the source code for it. If you see a way to improve it / spot an error, please let me know.

Code:
// Pokemon DP Damage Calculator, Beta release 1, 2008-Jan-25 23:06 EST

#include <iostream>
#include <cmath>
#include <string>
using namespace std;

inline string lcase(const string str)	// convert strings to lowercase
{
	char *const pstr = _strlwr(_strdup(str.c_str()));
	const string ret = pstr;
	free(pstr);
	return ret;
}

int main ()
{
calculate:	// goto anchor
	double level;	// Attacker's level
	double power;	// Move's base power
	double HH = 1;	// Helping Hand
	double BPAIM = 1;	// Base Power Attacker Item Modifier (Muscle Band, Wise Glasses, Type-boosting items)
	double Charge = 1;	// Charge
	double sport = 1;	// Mud Sport / Water Sport
	double BPAAM = 1;	// Base Power Attacker Ability Modifier (Blaze, Iron Fist, Overgrow, Reckless, Rivalry, Swarm, Technician, Torrent)
	double BPDAM = 1;	// Base Power Defender Ability Modifier (Dry Skin, Heatproof, Thick Fat)
	double atk;	// Attacking stat
	double ASM = 0;	// Attacking Stat Modifier
	double AAM = 1; // Attack Ability Modifier (Flower Gift (on the attacker), Guts, Huge Power, Hustle, Pure Power, Slow Start, Solar Power)
	double AIM = 1;	// Attack Item Modifier (Choice Band, Choice Specs, DeepSeaTooth, Light Ball, Thick Club)
	double def;	// Defending stat
	double DSM = 0;	// Defending Stat Modifier
	double DAM = 1;	// Defense Ability Modifier (Flower Gift (on the defender), Marvel Scale)
	double DIM = 1;	// Defense Item Modifier (DeepSeaScale, Metal Powder, Soul Dew)
	double SS = 1;	// Sandstorm Special Defense bonus to Rocks
	double boom = 1;	// Explosion / Selfdestuct Defense modifier
	double BRN = 1;	// Burn
	double RL = 1;	// Reflect / Light Screen
	double weather = 1;	// Sunny Day / Rain Dance
	double FF = 1;	// Flash Fire
	double CH = 1;	// Critical Hit
	double item = 1;	// Life Orb, Metronome
	double TL = 1;	// Tinted Lens
	double MF = 1;	// Me First
	double STAB = 1;	// Same Type Attack Bonus (STAB)
	string spectrum;	// Whether the move is physical or special
	string type;	// What type the move is
	double Type1 = 1;	// Effectiveness on the defender's first type
	double Type2 = 1;	// Effectiveness on the defender's second type
	double AEM = 1;	// Ability Effectiveness Multiplier (Solid Rock, Filter)
	double EB = 1;	// Expert Belt
	double RB = 1;	// Resistance berries
	double HP = 1;	// HP
	int maxDamage = 0;
	int minDamage = 0;
	int midDamage = 0;	// Temporary variable to find chance to OHKO
	double R;	// The Random number
	double probability = 0;	// Chance to OHKO
	double probabilityPercent;
	double maxPercent;
	double minPercent;
	string recalculate;
	cout << "How effective is the attack on the defender's first type? (0 for No Effect, .5 for Not Very Effective, 1 for neutral, 2 for Super Effective) ";
	cin >> Type1;
	if (Type1 != 0)
	{
		cout << "How effective is the attack on the defender's second type? (0 for No Effect, .5 for Not Very Effective, 1 for neutral, 2 for Super Effective) ";
		cin >> Type2;
		if (Type2 != 0)
		{
			cout << "What is the attacker's level? ";
			cin >> level;
			cout << "Is the move physical or special? ";
			cin >> spectrum;
			spectrum = lcase(spectrum);
			cout << "What type is the move? ";
			cin >> type;
			type = lcase(type);
			cout << "What is the base power of the move? ";
			cin >> power;
			if (power <= 60)
			{
				cout << "Does the attacker have Technician? (1.5 for yes, 1 for no) ";
				cin >> BPAAM;
			}
			cout << "What is the attacking stat? ";
			cin >> atk;
			cout << "What is the attacking stat modifier? (-6 through 6) ";
			cin >> ASM;
			if (ASM >= 0)	// Converts stages to multipliers
				ASM = (2 + ASM) / 2;
			else
				ASM = 2 / (2 - ASM);
			cout << "Does Pikachu have a Light Ball? (2 for yes, 1 for no) ";
			cin >> AIM;
			if (AIM == 1)
			{
				cout << "Is there a type-boosting item in play? (1.2 for yes, 1 for no) ";
				cin >> BPAIM;
			}
			if (spectrum == "physical")	// Physical attacks
			{
				if (BPAAM == 1)
				{
					cout << "Does the attacker have Pure Power / Huge Power? (2 for yes, 1 for no) ";
					cin >> AAM;
					if (AAM == 1)
					{
						cout << "Is Guts activated? (1.5 for yes, 1 for no) ";
						cin >> AAM;
						if (AAM == 1)
						{
							cout << "Is Hustle activated? (1.5 for yes, 1 for no) ";
							cin >> AAM;
							if (AAM == 1)
							{
								cout << "Is Slow Start active? (.5 for yes, 1 for no) ";
								cin >> AAM;
								if (AAM == 1)
								{
									cout << "Does the attacker have Flower Gift activated? (1.5 for yes, 1 for no) ";
									cin >> AAM;
								}
							}
						}
					}
				}
				if ((AIM == 1) && (BPAIM == 1))
				{
					cout << "Is the attacker holding a Choice Band? (1.5 for yes, 1 for no) ";
					cin >> AIM;
					if (AIM == 1)
					{
						if (AIM == 1)
						{
							cout << "Does Cubone / Marowak have a Thick Club? (2 for yes, 1 for no) ";
							cin >> AIM;
							if (AIM == 1)
							{
								cout << "Is the attacker holding a Muscle Band? (1.1 for yes, 1 for no) ";
								cin >> BPAIM;
							}
						}
					}
				}
			}
			else	// Special attacks
			{
				cout << "Is Solar Power active? (1.5 for yes, 1 for no) ";
				cin >> AAM;
				cout << "Is the attacker holding Choice Specs? (1.5 for yes, 1 for no) ";
				cin >> AIM;
				if ((AIM == 1) && (BPAIM == 1))
				{
					cout << "Is the attacker holding Wise Glasses? (1.1 for yes, 1 for no) ";
					cin >> BPAIM;
				}
			}
			if ((AIM == 1) && (BPAIM == 1))
			{
				cout << "Is the attacker holding a Life Orb? (1.3 for yes, 1 for no) ";
				cin >> item;
				if (item == 1)
				{
					cout << "Is the attacker holding a Metronome? (2 for yes, 1 for no) ";
					cin >> item;
					if (item > 1)
					{
						cout << "How many times has the attack been used already? ";
						cin >> item;
						item = (item / 10) + 1;
						if (item > 2)
							item = 2;
					}
				}
			}
			cout << "What is the defending stat? ";
			cin >> def;
			cout << "What is the defending stat modifier? (-6 through 6)";
			cin >> DSM;	
			if (DSM >= 0)	// Converts stages to multipliers
				DSM = (2 + DSM) / 2;
			else
				DSM = 2 / (2 - DSM);
			if (spectrum == "physical")
			{
				cout << "Is Reflect in play? (2 for yes, 1 for no) ";
				cin >> RL;
				cout << "Is the attacker burned? (2 for yes, 1 for no) ";
				cin >> BRN;
				cout << "Is the attacker using Explosion or Selfdestruct? (2 for yes, 1 for no) ";
				cin >> boom;
				cout << "Does the defender have Marvel Scale activated? (1.5 for yes, 1 for no) ";
				cin >> DAM;
				cout << "Is Ditto holding Metal Powder? (1.5 for yes, 1 for no) ";
				cin >> DIM;
				if (BPAAM == 1)
				{
					cout << "Is Iron Fist activated? (1.2 for yes, 1 for no) ";
					cin >> BPAAM;
					if (BPAAM == 1)
					{
						cout << "Is Reckless activated? (1.2 for yes, 1 for no) ";
						cin >> BPAAM;
					}
				}
			}
			else
			{
				cout << "Is Light Screen in play? (2 for yes, 1 for no) ";
				cin >> RL;
				cout << "Is the defender a Rock type during Sandstorm? (1.5 for yes, 1 for no) ";
				cin >> SS;
				cout << "Is Flower Gift activated on the target? (1.5 for yes, 1 for no) ";
				cin >> DAM;
				cout << "Is Latias or Latios holding Soul Dew? (1.5 for yes, 1 for no) ";
				cin >> DIM;
				if (DIM == 1)
				{
					cout << "Is Ditto holding Metal Powder? (1.5 for yes, 1 for no) ";
					cin >> DIM;
					if (DIM == 1)
					{
						cout << "Is Clamperl holding DeepSeaScale? (2 for yes, 1 for no) ";
						cin >> DIM;
					}
				}
			}
			if (BPAAM == 1)
			{
				cout << "Is Rivalry activated? (1.25 for same gender, .75 for opposite gender, 1 for no) ";
				cin >> BPAAM;
			}
			if ((type == "fire") || (type == "ice"))
			{
				cout << "Does the defender have Thick Fat? (.5 for yes, 1 for no) ";
				cin >> BPDAM;
				if (type == "fire")
				{
					if (BPDAM == 1)
					{
						cout << "Does the defender have Heatproof? (.5 for yes, 1 for no) ";
						cin >> BPDAM;
						if (BPDAM == 1)
						{
							cout << "Does the defender have Dry Skin? (1.25 for yes, 1 for no) ";
							cin >> BPDAM;
						}
					}
					cout << "Is Sunny Day in effect? (1.5 for yes, 1 for no) ";
					cin >> weather;
					if (weather == 1)
					{
						cout << "Is Rain Dance in effect? (.5 for yes, 1 for no) ";
						cin >> weather;
					}
					cout << "Is Flash Fire activated? (1.5 for yes, 1 for no) ";
					cin >> FF;
					if (BPAAM == 1)
					{
						cout << "Is Blaze activated? (1.5 for yes, 1 for no) ";
						cin >> BPAAM;
					}
				}
			}
			else if (type == "water")
			{
				cout << "Is Rain Dance in effect? (1.5 for yes, 1 for no) ";
				cin >> weather;
				if (weather == 1)
				{
					cout << "Is Sunny Day in effect? (.5 for yes, 1 for no) ";
					cin >> weather;
				}
				if (BPAAM == 1)
				{
					cout << "Is Torrent activated? (1.5 for yes, 1 for no) ";
					cin >> BPAAM;
				}
			}
			else if (type == "electric")
			{
				cout << "Was Charge used on the previous turn? (2 for yes, 1 for no) ";
				cin >> Charge;
			}
			else if (type == "grass")
			{
				if (BPAAM == 1)
				{
					cout << "Is Overgrow activated? (1.5 for yes, 1 for no) ";
					cin >> BPAAM;
				}
			}
			else if (type == "bug")
			{
				if (BPAAM == 1)
				{
					cout << "Is Swarm activated? (1.5 for yes, 1 for no) ";
					cin >> BPAAM;
				}
			}
			cout << "Is the attacker using the move Me First? (1.5 for yes, 1 for no) ";
			cin >> MF;
			cout << "Is the attack of the same type as the attacker (STAB)? (1.5 for yes, 1 for no) ";
			cin >> STAB;
			if (Type1 * Type2 > 1)
			{
				cout << "Does the defender have Filter / Solid Rock? (.75 for yes, 1 for no) ";
				cin >> AEM;
				if ((AIM == 1) && (BPAIM) && (item = 1))
				{
					cout << "Is the attacker holding an Expert Belt? (1.2 for yes, 1 for no) ";
					cin >> EB;
				}
			}
			else if ((Type1 * Type2 < 1) && (Type1 * Type2 != 0))
			{
				cout << "Does the attacker have the ability Tinted Lens? (2 for yes, 1 for no) ";
				cin >> TL;
			}
			if (Type1 * Type2 >= 1)
			{
				if (type != "normal")
				{
					cout << "Is the defender holding a resistance berry that will activate? (2 for yes, 1 for no) ";
					cin >> RB;
				}
				else if (Type1 * Type2 > 1)
				{
					cout << "Is the defender holding a Chilan Berry? (2 for yes, 1 for no) ";
					cin >> RB;
				}
			}
			cout << "Is the attacker's ally using Helping Hand? (1.5 for yes, 1 for no) ";
			cin >> HH;
			cout << "Is the move a critical hit? (2 for yes, 1 for no, 3 for Sniper) ";
			cin >> CH;
			if (CH != 1)
			{
				if (ASM < 1)
					ASM = 1;
				if (DSM > 1)
					DSM = 1;
				RL = 1;
			}
			cout << "What is the defender's HP? ";
			cin >> HP;
			power = floor(floor(floor(floor(floor(floor(power * HH) * BPAIM) * Charge) * sport) * BPAAM) * BPDAM);
			if (power == 0)
				power = 1;
			atk = floor(floor(floor(atk * ASM) * AAM) * AIM);
			if (atk == 0)
				atk = 1;
			def = floor(floor(floor(floor(floor(def * DSM) * DAM) * DIM) * SS) / boom);
			if (def == 0)
				def = 1;
			maxDamage = floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(level * 2 / 5 + 2) * power * atk / 50) / def) / BRN) / RL) * weather) * FF + 2) * CH * item) * TL * MF) * STAB) * Type1) * Type2) * AEM) * EB) / RB);
			minDamage = floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(level * 2 / 5 + 2) * power * atk / 50) / def) / BRN) / RL) * weather) * FF + 2) * CH * item) * TL * MF) * .85) * STAB) * Type1) * Type2) * AEM) * EB) / RB);
			maxPercent = 100 * maxDamage / HP;
			minPercent = 100 * minDamage / HP;
		}
	}
	if (maxDamage >= HP)
	{
		R = 217;
		while ((R <= 255) && (midDamage < HP))	// Cycles through all possible values for R until it finds the lowest R that grants a OHKO, only if such a value is possible
		{
			midDamage = floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(level * 2 / 5 + 2) * power * atk / 50) / def) / BRN) / RL) * weather) * FF + 2) * CH * item) * TL * MF) * floor(R * 100 / 255)) / 100) * STAB) * Type1) * Type2) * AEM) * EB) / RB);
			R = R + 1;
		}
		probability = (256 - R);
		probabilityPercent = (probability / 39) * 100;
		cout << "There is a " << probability << "/39 chance to OHKO, or " << probabilityPercent << "%\n";
		cout << "Damage is " << minDamage << "-" << HP << ", or " << minPercent << "%-100%\n";
	}
	else
		cout << "Damage is " << minDamage << "-" << maxDamage << ", or " << minPercent << "%-" << maxPercent << "%" << '\n';
	cout << "Would you like to calculate again? (1 for yes, 0 for no)";
	cin >> recalculate;
	if (recalculate != "0")
		goto calculate;	// Brings you back to the start to recalculate
	return 0;
}
So, want to help me beta test it? I don't anticipate any errors, but whatever.

I know the structure is a bit funny (as in the order it asks about everything), but expect that to be improved next version (likely some time tomorrow?).
 

Attachments

Cathy

Banned deucer.
I know it was I who suggested that lcase() function but it turns out that strlwr() is actually a Microsoft-extension and not part of the C standard library (it failed to compile in gcc). If anybody else is compiling it in gcc, I used this version of lcase():

Code:
#include <cctype>
#include <algorithm>
inline string lcase(string s) {
    transform(s.begin(), s.end(), s.begin(), (int( *)(int))toupper);
    return s;
}
This should work in VC++ as well.
 
It works fine and produces a decent result. A few suggestions.
~ What is the point of asking for the type of the attacking move? You already ask us for STAB and it doesn't autocalculate effectiveness. Same thing with Physical/Special
~ Why not amalgamate all the separate prompts for items into one (eg: 1 = Choice Specs 2 = Wise Glasses etc.)
~ The same for abilities
~ Could you get it to accept arguments on the command line as that makes it easier to create shortcuts to certain results. I have six on my desktop for each of my pokemon that all go something like
Code:
[I]ruby damagecalc7.rb ? 202 ? ? ? 3 3 -[/I]
It saves time because you only have to enter half the info each time.
~ When the attack could OHKO the pokemon the result is a bit confusing...
Code:
Damage is 292-100, or 292%-100%
With the same variables but with a poke with more HP it is more sane.

Finally, you have errors on compile: I know nothing about C so I don't know whether they matter or not!

Code:
tim@tim-laptop:~$ g++ ObiDamageCalc.c
ObiDamageCalc.c: In function ‘int main()’:
ObiDamageCalc.c:356: warning: converting to ‘int’ from ‘double’
ObiDamageCalc.c:357: warning: converting to ‘int’ from ‘double’
ObiDamageCalc.c:367: warning: converting to ‘int’ from ‘double’
It's obvious you have spent a lot of time on this though so kudos to you.

Working Linux binaries are attached if anyone's interested...
 

Attachments

X-Act

np: Biffy Clyro - Shock Shock
is a Site Content Manager Alumnusis a Programmer Alumnusis a Smogon Discord Contributor Alumnusis a Top Researcher Alumnusis a Top CAP Contributor Alumnusis a Top Tiering Contributor Alumnusis a Top Contributor Alumnusis a Smogon Media Contributor Alumnusis an Administrator Alumnus
Replacing

Code:
maxDamage = floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(level * 2 / 5 + 2) * power * atk / 50) / def) / BRN) / RL) * weather) * FF + 2) * CH * item) * TL * MF) * STAB) * Type1) * Type2) * AEM) * EB) / RB);
with

Code:
maxDamage = (int) floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(floor(level * 2 / 5 + 2) * power * atk / 50) / def) / BRN) / RL) * weather) * FF + 2) * CH * item) * TL * MF) * STAB) * Type1) * Type2) * AEM) * EB) / RB);
and doing the same thing for minDamage one line later and for midDamage 10 lines later should cure the compiler warnings by typecasting the answer to an integer value. The problem was that floor(x) returns a double value, not an int (unnaturally). Alternatively, you could use integer division and get rid of all those floor functions!

You don't need to do the following, but it's better to do without goto. I'd put

Code:
do
instead of

Code:
calculate:
and

Code:
while (recalculate != "0");
instead of

Code:
if (recalculate != "0")
  goto calculate;
Also, replace

Code:
cout << "Damage is " << minDamage << "-" << HP << ", or " << minPercent << "%-100%\n";
with

Code:
if (minDamage > HP)
  cout << "Damage is " << HP << ", or 100%\n";
else
  cout << "Damage is " << minDamage << "-" << HP << ", or " << minPercent << "%-100%\n";
Hope this helps a bit with debugging. :)

@timw06: The type is asked because of such things as Thick Fat. The physical versus special is for Reflect/Light Screen etc.
 

Aldaron

geriatric
is a Tournament Director Alumnusis a Battle Simulator Admin Alumnusis a Smogon Discord Contributor Alumnusis a Top Tiering Contributor Alumnusis a Top Contributor Alumnusis an Administrator Alumnus
I downloaded it and extracted it. When I tried to run it, I got this:

"The application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem"

I have Windows XP.
 
i'm getting the same error. some time back when i had installed anope on my computer, i got the exact same error, which was subsequently fixed by copying a .manifest file from the net. could that be the issue obi?

i tried compiling using mingw32, but it's a bulky 500k executable, or i would have posted a link here

edit: colinjf, compile it using the g++ command and not gcc
 

Cathy

Banned deucer.
I did use g++ to invoke gcc. As I said, that change is required because strlwr() is a Microsoft extension. My post was intended to help other people compiling using gcc in a POSIX environment.
 
pear: good idea, man. stripped and UPX'ed down to 82 KB, zips to 81 kb, so did not bother to zip further. http://ryubahamut.googlepages.com/damcalc.exe but not sure whether this requires the mingw32 runtime or not. XP users may attempt running this.

ColinJF: perhaps i'm able to compile under msys because the mingw32 dll uses windows runtime? that might be the case. sorry!
 
It's just a command-line prompt. If you enter stupid data ("What is the attackers level?" "df!") you'll cause some sort of strange error.
That is what you call a RTE (Run Time Error.) Most RTEs are the cause of bad/lazy programming. When you are developing an application and debugging/testing it, you need to think like a user. You want to make your application is as fool-proof as possible. If somebody tries to enter just a space or fake input, you need to have a way to validate the input. It is really easy to validate input with Regular Expressions. Since this is basically just checking for numbers mostly, I would recommend checking to see if the input is an integer with a simple while loop. Keep repeating the loop until the input is valid.
 

obi

formerly david stone
is a Site Content Manager Alumnusis a Programmer Alumnusis a Senior Staff Member Alumnusis a Smogon Discord Contributor Alumnusis a Researcher Alumnusis a Top Contributor Alumnusis a Battle Simulator Moderator Alumnus
Life Orb appears to do nothing. I don't know what the error is, as it was working in prior versions. Can anyone spot the error?
 
the only "problem" i have is you enter waterfall's data (80 power/water type) and it asks if your using selfdestruct/explosion but other than that i really have no complaints
 

Users Who Are Viewing This Thread (Users: 1, Guests: 0)

Top