| 
					
				 | 
			
			
				@@ -15,8 +15,10 @@ public class FormulaManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private static File formulaFile = new File(mcMMO.getFlatFileDirectory() + "formula.yml"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // Experience needed to reach a level, cached values to improve conversion speed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final Map<Integer, Integer> experienceNeededLinear = new HashMap<Integer, Integer>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final Map<Integer, Integer> experienceNeededExponential = new HashMap<Integer, Integer>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Map<Integer, Integer> experienceNeededRetroLinear; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Map<Integer, Integer> experienceNeededStandardLinear; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Map<Integer, Integer> experienceNeededRetroExponential; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Map<Integer, Integer> experienceNeededStandardExponential; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private FormulaType previousFormula; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -26,9 +28,20 @@ public class FormulaManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public FormulaManager() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /* Setting for Classic Mode (Scales a lot of stuff up by * 10) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         retroModeEnabled = Config.getInstance().getIsRetroMode(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        initExperienceNeededMaps(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         loadFormula(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Initialize maps used for XP to next level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void initExperienceNeededMaps() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        experienceNeededRetroLinear = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        experienceNeededRetroExponential = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        experienceNeededStandardLinear = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        experienceNeededStandardExponential = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * Get the formula type that was used before converting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -60,7 +73,7 @@ public class FormulaManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         int totalXP = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (int level = 0; level < skillLevel; level++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            totalXP += getCachedXpToLevel(level, previousFormula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalXP += getXPtoNextLevel(level, previousFormula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         totalXP += skillXPLevel; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -83,7 +96,7 @@ public class FormulaManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         int maxLevel = Config.getInstance().getLevelCap(primarySkillType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         while (experience > 0 && newLevel < maxLevel) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            int experienceToNextLevel = getCachedXpToLevel(newLevel, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (experience - experienceToNextLevel < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 remainder = experience; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -106,42 +119,97 @@ public class FormulaManager { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @param formulaType The {@link FormulaType} used 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @return amount of experience needed to reach next level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public int getCachedXpToLevel(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        int experience; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public int getXPtoNextLevel(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          * Retro mode XP requirements are the default requirements 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          * Standard mode XP requirements are multiplied by a factor of 10 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        int xpNeededMultiplier = retroModeEnabled ? 1 : 10; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //TODO: When the heck is Unknown used? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (formulaType == FormulaType.UNKNOWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             formulaType = FormulaType.LINEAR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        int base = ExperienceConfig.getInstance().getBase(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        double multiplier = ExperienceConfig.getInstance().getMultiplier(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        double exponent = ExperienceConfig.getInstance().getExponent(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return processXPToNextLevel(level, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        switch (formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            case LINEAR: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!experienceNeededLinear.containsKey(level)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    experience = (int) Math.floor( xpNeededMultiplier * (base + level * multiplier)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    experienceNeededLinear.put(level, experience); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Gets the value of XP needed for the next level based on the level Scaling, the level, and the formula type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param level target level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param formulaType target formulaType 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private int processXPToNextLevel(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(mcMMO.isRetroModeEnabled()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return processXPRetroToNextLevel(level, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return processStandardXPToNextLevel(level, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return experienceNeededLinear.get(level); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Calculate the XP needed for the next level for the linear formula for Standard scaling (1-100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param level target level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return raw xp needed to reach the next level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private int processStandardXPToNextLevel(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<Integer, Integer> experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededStandardLinear : experienceNeededStandardExponential; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            case EXPONENTIAL: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!experienceNeededExponential.containsKey(level)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    experience = (int) Math.floor( xpNeededMultiplier * (multiplier * Math.pow(level, exponent) + base)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    experienceNeededExponential.put(level, experience); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(!experienceMapRef.containsKey(level)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int experienceSum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int retroIndex = (level * 10) + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return experienceNeededExponential.get(level); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //Sum the range of levels in Retro that this Standard level would represent 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for(int x = retroIndex; x < (retroIndex + 10); x++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //calculateXPNeeded doesn't cache results so we use that instead of invoking the Retro XP methods to avoid memory bloat 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                experienceSum += calculateXPNeeded(x, formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            experienceMapRef.put(level, experienceSum); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return experienceMapRef.get(level); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Calculates the XP to next level for Retro Mode scaling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Results are cached to reduce needless operations 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param level target level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param formulaType target formula type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return raw xp needed to reach the next level based on formula type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private int processXPRetroToNextLevel(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<Integer, Integer> experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededRetroLinear : experienceNeededRetroExponential; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!experienceMapRef.containsKey(level)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int experience = calculateXPNeeded(level, FormulaType.LINEAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            experienceMapRef.put(level, experience); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return experienceMapRef.get(level); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Does the actual math to get the XP needed for a level in RetroMode scaling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * Standard uses a sum of RetroMode XP needed levels for its own thing, so it uses this too 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param level target level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param formulaType target formulatype 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return the raw XP needed for the next level based on formula type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private int calculateXPNeeded(int level, FormulaType formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int base = ExperienceConfig.getInstance().getBase(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double multiplier = ExperienceConfig.getInstance().getMultiplier(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        switch(formulaType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case LINEAR: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return (int) Math.floor(base + level * multiplier); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case EXPONENTIAL: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                double exponent = ExperienceConfig.getInstance().getExponent(formulaType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return (int) Math.floor(multiplier * Math.pow(level, exponent) + base); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //TODO: Should never be called 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                mcMMO.p.getLogger().severe("Invalid formula specified for calculation, defaulting to Linear"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return calculateXPNeeded(level, FormulaType.LINEAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |