private static double nShotPercentage(Move attack, Pokemon attacker, Pokemon defender, StatModifier atkMod, StatModifier defMod, int numHitsNonCrit, int numHitsCrit) { int rawHitDamageNC = damage(attack, attacker, defender, atkMod, defMod, MAX_RANGE, false); int minDamageNC = rawHitDamageNC * MIN_RANGE / 255; int[] probsNC = new int[rawHitDamageNC - minDamageNC + 1]; for (int i = MIN_RANGE; i <= MAX_RANGE; i++) { int dmg = rawHitDamageNC * i / 255; probsNC[dmg - minDamageNC]++; } int rawHitDamageCR = damage(attack, attacker, defender, atkMod, defMod, MAX_RANGE, true); int minDamageCR = rawHitDamageCR * MIN_RANGE / 255; int[] probsCR = new int[rawHitDamageCR - minDamageCR + 1]; for (int i = MIN_RANGE; i <= MAX_RANGE; i++) { int dmg = rawHitDamageCR * i / 255; probsCR[dmg - minDamageCR]++; } double chances = 0; int rawHP = defender.getHP(); if (numHitsNonCrit > 0) { for (int i = minDamageNC; i <= rawHitDamageNC; i++) { chances += nShotPctInner(minDamageNC, rawHitDamageNC, minDamageCR, rawHitDamageCR, rawHP, 0, i, numHitsNonCrit, numHitsCrit, probsNC, probsCR); } } else { for (int i = minDamageCR; i <= rawHitDamageCR; i++) { chances += nShotPctInner(minDamageNC, rawHitDamageNC, minDamageCR, rawHitDamageCR, rawHP, 0, i, numHitsNonCrit, numHitsCrit, probsNC, probsCR); } } return 100.0 * chances / Math.pow(MAX_RANGE - MIN_RANGE + 1, numHitsNonCrit + numHitsCrit); } private static double nShotPctInner(int minDamageNC, int maxDamageNC, int minDamageCR, int maxDamageCR, int hp, int stackedDmg, int rolledDamage, int hitsLeftNonCrit, int hitsLeftCrit, int[] probsNC, int[] probsCR) { boolean wasCritical = false; if (hitsLeftNonCrit > 0) { hitsLeftNonCrit--; } else { hitsLeftCrit--; wasCritical = true; } stackedDmg += rolledDamage; if (stackedDmg >= hp || (stackedDmg + hitsLeftNonCrit * minDamageNC + hitsLeftCrit * minDamageCR) >= hp) { return Math.pow(MAX_RANGE - MIN_RANGE + 1, hitsLeftNonCrit + hitsLeftCrit) * (wasCritical ? probsCR[rolledDamage - minDamageCR] : probsNC[rolledDamage - minDamageNC]); } else if (hitsLeftNonCrit == 0 && hitsLeftCrit == 0) { return 0; } else if (stackedDmg + hitsLeftNonCrit * maxDamageNC + hitsLeftCrit * maxDamageCR < hp) { return 0; } else { double chances = 0; if (hitsLeftNonCrit > 0) { for (int i = minDamageNC; i <= maxDamageNC; i++) { chances += nShotPctInner(minDamageNC, maxDamageNC, minDamageCR, maxDamageCR, hp, stackedDmg, i, hitsLeftNonCrit, hitsLeftCrit, probsNC, probsCR); } } else { for (int i = minDamageCR; i <= maxDamageCR; i++) { chances += nShotPctInner(minDamageNC, maxDamageNC, minDamageCR, maxDamageCR, hp, stackedDmg, i, hitsLeftNonCrit, hitsLeftCrit, probsNC, probsCR); } } return chances * (wasCritical ? probsCR[rolledDamage - minDamageCR] : probsNC[rolledDamage - minDamageNC]); } }