Smogon Community Damage Calculator (DP)
 Register FAQ Social Groups Calendar Search Today's Posts Mark Forums Read

Jan 25th, 2008, 11:01:24 PM   #1
david stone
Fast-moving, smart, sexy and alarming.

Join Date: Aug 2005
Posts: 5,152
Damage Calculator (DP)

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?).
Attached Files
 Damage Calculator.zip (9.2 KB, 195 views)
__________________
Previously obi.
Technical Machine, a Pokemon AI.
"Strategy without tactics is the slowest route to victory. Tactics without strategy is the noise before defeat." - Sun Tzu

Last edited by david stone; Jan 25th, 2008 at 11:11:55 PM.

 Jan 25th, 2008, 11:32:34 PM #2 Cathy**   Administrator Join Date: Jul 2007 Posts: 1,051 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 #include inline string lcase(string s) { transform(s.begin(), s.end(), s.begin(), (int( *)(int))toupper); return s; }``` This should work in VC++ as well. Last edited by Cathy; Jan 25th, 2008 at 11:45:10 PM.
Jan 26th, 2008, 5:38:48 AM   #3
timw06

Join Date: Jun 2007
Posts: 543

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:
`ruby damagecalc7.rb ? 202 ? ? ? 3 3 -`
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...
Attached Files
 ObiDamageCalc.zip (8.3 KB, 23 views)

 Jan 26th, 2008, 7:13:43 AM #4 X-Act np: Biffy Clyro - Shock Shock     Join Date: Feb 2006 Posts: 4,679 Malta 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. __________________ http://users.smogon.com/X-Act For all your Pokemon needs (and more!) including: the Defensive EVs applet, the Probabilities of Breeding IVs in Pokemon applet, and the Ratings of Pokemon Base Stats applet (now Version 2.0!). And also the IV to PID applet!
 Jan 26th, 2008, 11:43:25 AM #5 X-Trader     Join Date: Aug 2007 Posts: 4,991 Obi, the Damage Calculator that is attached doesn't work on Macs.
 Jan 26th, 2008, 12:06:11 PM #6 Aldaron* Don't tell me what to do.     Super Moderator Join Date: Aug 2007 Posts: 3,370 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.
 Jan 26th, 2008, 1:14:48 PM #7 ryubahamut     Join Date: Jan 2007 Posts: 999 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 __________________ Code: ``` * !!!!!!!IF YOU CHANGE TABS TO SPACES, YOU WILL BE KILLED!!!!!!! * !!!!!!!!!!!!!!DOING SO FUCKS THE BUILD PROCESS!!!!!!!!!!!!!!!!```
 Jan 26th, 2008, 3:05:55 PM #8 Cathy**   Administrator Join Date: Jul 2007 Posts: 1,051 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. Last edited by Cathy; Jan 26th, 2008 at 3:45:03 PM.
Jan 26th, 2008, 4:36:53 PM   #9
pear

Join Date: Mar 2006
Posts: 270
Sillhouettes! In the sky! Wings are carrying me through the night!

Quote:
 i tried compiling using mingw32, but it's a bulky 500k executable, or i would have posted a link here
Did you try using strip.exe on it?
__________________
avatar spliced by YoshiToshi

 Jan 26th, 2008, 6:09:25 PM #10 ryubahamut     Join Date: Jan 2007 Posts: 999 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! __________________ Code: ``` * !!!!!!!IF YOU CHANGE TABS TO SPACES, YOU WILL BE KILLED!!!!!!! * !!!!!!!!!!!!!!DOING SO FUCKS THE BUILD PROCESS!!!!!!!!!!!!!!!!```
Jan 26th, 2008, 6:15:30 PM   #11
Justin8649

Join Date: Jan 2005
Posts: 2,625

Quote:
 Originally Posted by Fat Obi 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.

 Jan 27th, 2008, 1:36:55 AM #12 david stone Fast-moving, smart, sexy and alarming.     Join Date: Aug 2005 Posts: 5,152 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? __________________ Previously obi. Technical Machine, a Pokemon AI. "Strategy without tactics is the slowest route to victory. Tactics without strategy is the noise before defeat." - Sun Tzu
 Jan 27th, 2008, 4:08:12 AM #13 X-Act np: Biffy Clyro - Shock Shock     Join Date: Feb 2006 Posts: 4,679 Malta What's the latest version of the program? I can try to help. __________________ http://users.smogon.com/X-Act For all your Pokemon needs (and more!) including: the Defensive EVs applet, the Probabilities of Breeding IVs in Pokemon applet, and the Ratings of Pokemon Base Stats applet (now Version 2.0!). And also the IV to PID applet!
 Jan 28th, 2008, 11:16:17 PM #14 chip_the_fox     Join Date: Sep 2007 Posts: 218 houma 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