public class Main { //Leave these as is static int[] statTable = new int [] {1, 2, 4, 8, 10, 15, 20, 25, 30, 35}; static int[] bTable = new int [] {3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; static int[] maxTable = new int[] {1, 1, 1, 1, 1, 2, 2, 2, 2, 2}; static double[] pTable = new double [] {0.97, 0.94/0.97, 0.91/0.94, 0.88/0.91, 0.85/0.88, 0.82/0.85, 0.79/0.82, 0.76/0.79, 0.73/0.76, 0.70/0.73}; static double realPDR = 0.0; public static void main(String[] args) { int points = 0, boss = 0, total = 0, minCrit = 0, maxCrit = 0, mainStat = 0, bossPDR = 300; //points is the number of hyper stat points you have, minus points you want to spend //for other uses besides these 6 damage increasing ones (stance, critical chance, etc). //minCrit and maxCrit assume 100+% critical chance //The hyper stat that increases your main stat can currently be interpreted 1 of two ways. //It is currently uncertain if potential % affects main stat received from hyper stats //1. If you think +stat hyper stats are affected by potential, put your base main stat into mainStat //(calculating this accurately is annoying) and subtract 50 to remove the current hyper passive. //2. If you think +stat hyper stats are not affected by potential, put what you see in your stat window //into mainStat, after subtracting 50 * (1+(how much % main stat you have/100)) to remove //the current hyper passive. //If you believe #1, please read example 1 below. //Example 1: If you have 3k base stat, you would subtract 50 from 3k to get 2950 to put for mainStat. //If you believe #2, please read example 2 below. //Example 2. If you have 15k with 300% stat, you would subtract 50 *(1+(300/100)) = 200 //from 15k to get 14800 to put for mainStat. //As you get more hyper points, the difference between these 2 interpretations is negligible. int bLevel = 0, tLevel = 0, minLevel = 0, maxLevel = 0, mainLevel = 0, pdrLevel = 0; //Leave these as is int total2 = total + 0; //total2 is a placeholder if your main attacking skill increases total damage double pdr = 0.1, pdr2 = pdr*1*1*1; //pdr2 is a placeholder if your main attacking skill reduces PDR, //pdr is currently set to 90% PDR (multiplicative) boolean fullCalculation = false; //does not factor in total2 or pdr2 if this is set to false System.out.println("***Before optimization***"); System.out.println("Points to allocate: "+points); System.out.println("Boss damage (level "+bLevel+"): "+boss); System.out.println("Total damage (level "+tLevel+"): "+total); System.out.println("Minimum critical damage (level "+minLevel+"): "+minCrit); System.out.println("Maximum critical damage (level "+maxLevel+"): "+maxCrit); System.out.println("Base main stat (level "+mainLevel+"): "+mainStat); System.out.println("PDR multiplier (level "+pdrLevel+"): "+pdr+" on a "+bossPDR+"% boss"); int[] optimized = new int[12]; //optimize_iterative(points, bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, false); if(fullCalculation){ optimized = optimize(points, bLevel, boss, tLevel, total2, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr2, bossPDR, false); } else { optimized = optimize(points, bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, false); } //System.out.println(optimized); System.out.println("***After optimization***"); System.out.println("Points to allocate: "+optimized[0]); System.out.println("Boss damage (level "+optimized[1]+"): "+optimized[2]); System.out.println("Total damage (level "+optimized[3]+"): "+optimized[4]); System.out.println("Minimum critical damage (level "+optimized[5]+"): "+optimized[6]); System.out.println("Maximum critical damage (level "+optimized[7]+"): "+optimized[8]); System.out.println("Base main stat (level "+optimized[9]+"): "+optimized[10]); System.out.println("PDR multiplier (level "+optimized[11]+"): "+realPDR+" on a "+bossPDR+"% boss"); } public static int[] optimize(int points, int bLevel, int boss, int tLevel, int total, int minLevel, int minCrit, int maxLevel, int maxCrit, int mainLevel, int mainStat, int pdrLevel, double pdr, int bossPDR, boolean fail){ if(points <= 0 || fail == true){ System.out.println("Optimization complete."); int[] optimized = new int[12]; optimized[0] = points; optimized[1] = bLevel; optimized[2] = boss; optimized[3] = tLevel; optimized[4] = total; optimized[5] = minLevel; optimized[6] = minCrit; optimized[7] = maxLevel; optimized[8] = maxCrit; optimized[9] = mainLevel; optimized[10] = mainStat; optimized[11] = pdrLevel; realPDR = pdr; return optimized; } fail = false; double[] relative = new double[6]; int failed = 0; if(bLevel >= 10 || statTable[bLevel] > points){ relative[0] = -1; failed++; } if(tLevel >= 10 || statTable[tLevel] > points){ relative[1] = -1; failed++; } if(minLevel >= 10 || statTable[minLevel] > points){ relative[2] = -1; failed++; } if(maxLevel >= 10 || statTable[maxLevel] > points){ relative[3] = -1; failed++; } if(mainLevel >= 10 || statTable[mainLevel] > points){ relative[4] = -1; failed++; } if(pdrLevel >= 10 || statTable[pdrLevel] > points){ relative[5] = -1; failed++; } for(int i = 0; i < 6; i++){ if(relative[i] >= 0.0){ switch(i){ case 0: relative[0] = ((double) (boss + total + bTable[bLevel] + 100) / (boss + total + 100)) / statTable[bLevel]; break; case 1: relative[1] = ((double) (boss + total + 3 + 100) / (boss + total + 100)) / statTable[tLevel]; break; case 2: relative[2] = ((double) (minCrit + maxCrit + 1 + 200) / (minCrit + maxCrit + 200)) / statTable[minLevel]; break; case 3: relative[3] = ((double) (minCrit + maxCrit + maxTable[maxLevel] + 200) / (minCrit + maxCrit + 200)) / statTable[maxLevel]; break; case 4: relative[4] = ((double) (mainStat + 15) / mainStat) / statTable[mainLevel]; break; case 5: relative[5] = ((100-(pdr * pTable[pdrLevel] * bossPDR)) / (100-(pdr * bossPDR))) / statTable[pdrLevel]; break; } } } int index = maximize(relative); switch(index){ case 0: return optimize(points-statTable[bLevel], bLevel+1, boss+bTable[bLevel], tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, fail); case 1: return optimize(points-statTable[tLevel], bLevel, boss, tLevel+1, total+3, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, fail); case 2: return optimize(points-statTable[minLevel], bLevel, boss, tLevel, total, minLevel+1, minCrit+1, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, fail); case 3: return optimize(points-statTable[maxLevel], bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel+1, maxCrit+maxTable[maxLevel], mainLevel, mainStat, pdrLevel, pdr, bossPDR, fail); case 4: return optimize(points-statTable[mainLevel], bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel+1, mainStat+15, pdrLevel, pdr, bossPDR, fail); case 5: return optimize(points-statTable[pdrLevel], bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel+1, pdr*pTable[pdrLevel], bossPDR, fail); default: System.out.println("Something wrong happened. Perhaps the optimization is done."); System.out.println("Points to allocate: "+points); System.out.println("Boss damage (level "+bLevel+"): "+boss); System.out.println("Total damage (level "+tLevel+"): "+total); System.out.println("Minimum critical damage (level "+minLevel+"): "+minCrit); System.out.println("Maximum critical damage (level "+maxLevel+"): "+maxCrit); System.out.println("Base main stat (level "+mainLevel+"): "+mainStat); System.out.println("PDR multiplier (level "+pdrLevel+"): "+pdr+" on a "+bossPDR+"% boss"); break; } if(failed == 6){ fail = true; return optimize(points, bLevel, boss, tLevel, total, minLevel, minCrit, maxLevel, maxCrit, mainLevel, mainStat, pdrLevel, pdr, bossPDR, fail); } return null; } public static int maximize(double[] tempArray){ double maximum = 0.0; int maxIndex = -1; for(int i = 0; i < 6; i++){ //System.out.println(tempArray[i]); if(tempArray[i] > maximum){ maximum = tempArray[i]; maxIndex = i; } } return maxIndex; } public static int[] optimize_iterative(int points, int bLevel, int boss, int tLevel, int total, int minLevel, int minCrit, int maxLevel, int maxCrit, int mainLevel, int mainStat, int pdrLevel, double pdr, int bossPDR, boolean fail){ while(points >= 0 && fail == false){ double[] relative = new double[6]; int failed = 0; if(bLevel >= 10 || statTable[bLevel] > points){ relative[0] = -1; failed++; } if(tLevel >= 10 || statTable[tLevel] > points){ relative[1] = -1; failed++; } if(minLevel >= 10 || statTable[minLevel] > points){ relative[2] = -1; failed++; } if(maxLevel >= 10 || statTable[maxLevel] > points){ relative[3] = -1; failed++; } if(mainLevel >= 10 || statTable[mainLevel] > points){ relative[4] = -1; failed++; } if(pdrLevel >= 10 || statTable[pdrLevel] > points){ relative[5] = -1; failed++; } for(int i = 0; i < 6; i++){ if(relative[i] >= 0.0){ if(i == 0){ relative[i] = ((double) (boss + total + bTable[bLevel] + 100) / (boss + total + 100)) / statTable[bLevel]; } else if (i == 1){ relative[i] = ((double) (boss + total + 3 + 100) / (boss + total + 100)) / statTable[tLevel]; } else if (i == 2){ relative[i] = ((double) (minCrit + maxCrit + 1 + 200) / (minCrit + maxCrit + 200)) / statTable[minLevel]; } else if (i == 3){ relative[i] = ((double) (minCrit + maxCrit + maxTable[maxLevel] + 200) / (minCrit + maxCrit + 200)) / statTable[maxLevel]; } else if (i == 4){ relative[i] = ((double) (mainStat + 15) / mainStat) / statTable[mainLevel]; } else if (i == 5){ relative[i] = ((100-(pdr * pTable[pdrLevel] * bossPDR)) / (100-(pdr * bossPDR))) / statTable[pdrLevel]; } } } int index = maximize(relative); switch(index){ case 0: points -= statTable[bLevel]; boss += bTable[bLevel]; bLevel++; break; case 1: points -= statTable[tLevel]; total += 3; tLevel++; break; case 2: points -= statTable[minLevel]; minCrit += 1; minLevel++; break; case 3: points -= statTable[maxLevel]; maxCrit += maxTable[maxLevel]; maxLevel++; break; case 4: points -= statTable[mainLevel]; mainStat += 15; mainLevel++; break; case 5: points -= statTable[pdrLevel]; pdr *= pTable[pdrLevel]; pdrLevel++; break; default: System.out.println("Something wrong happened. Perhaps the optimization is done."); System.out.println("Points to allocate: "+points); System.out.println("Boss damage (level "+bLevel+"): "+boss); System.out.println("Total damage (level "+tLevel+"): "+total); System.out.println("Minimum critical damage (level "+minLevel+"): "+minCrit); System.out.println("Maximum critical damage (level "+maxLevel+"): "+maxCrit); System.out.println("Base main stat (level "+mainLevel+"): "+mainStat); System.out.println("PDR multiplier (level "+pdrLevel+"): "+pdr+" on a "+bossPDR+"% boss"); break; } if(failed == 6){ fail = true; } } if(points <= 0 || fail == true){ System.out.println("Optimization complete."); int[] optimized = new int[12]; optimized[0] = points; optimized[1] = bLevel; optimized[2] = boss; optimized[3] = tLevel; optimized[4] = total; optimized[5] = minLevel; optimized[6] = minCrit; optimized[7] = maxLevel; optimized[8] = maxCrit; optimized[9] = mainLevel; optimized[10] = mainStat; optimized[11] = pdrLevel; realPDR = pdr; return optimized; } return null; } }