001package net.tnemc.plugincore.core.utils; 002 003 004import net.tnemc.plugincore.core.compatibility.PlayerProvider; 005 006import java.math.BigDecimal; 007 008public class Experience { 009 010 /** 011 * Calculates a player's total exp based on level and progress to next. 012 * 013 * @param player the Player 014 * 015 * @return the amount of exp the Player has 016 */ 017 public static BigDecimal getExperienceAsDecimal(PlayerProvider player) { 018 return new BigDecimal(getExperienceFromLevel(player.getExpLevel())) 019 .add(new BigDecimal(getExperienceToNext(player.getExpLevel()) * player.getExp())); 020 } 021 022 /** 023 * Calculates a player's total exp based on level and progress to next. 024 * 025 * @param player the Player 026 * 027 * @return the amount of exp the Player has 028 */ 029 public static int getExperience(PlayerProvider player) { 030 return getExperienceFromLevel(player.getExpLevel()) 031 + Math.round(getExperienceToNext(player.getExpLevel()) * player.getExp()); 032 } 033 034 /** 035 * Calculates total experience based on level. 036 * 037 * "One can determine how much experience has been collected to reach a level using the equations: 038 * Total Experience = [Level]2 + 6[Level] (at levels 0-15) 039 * 2.5[Level]2 - 40.5[Level] + 360 (at levels 16-30) 040 * 4.5[Level]2 - 162.5[Level] + 2220 (at level 31+)" 041 * 042 * @param level the level 043 * 044 * @return the total experience calculated 045 */ 046 public static int getExperienceFromLevel(int level) { 047 if (level > 30) { 048 return (int) (4.5 * level * level - 162.5 * level + 2220); 049 } 050 if (level > 15) { 051 return (int) (2.5 * level * level - 40.5 * level + 360); 052 } 053 return level * level + 6 * level; 054 } 055 056 /** 057 * Calculates level based on total experience. 058 * 059 * @param exp the total experience 060 * 061 * @return the level calculated 062 */ 063 public static double getLevelFromExperience(long exp) { 064 if (exp > 1395) { 065 return (Math.sqrt(72 * exp - 54215) + 325) / 18; 066 } 067 if (exp > 315) { 068 return Math.sqrt(40 * exp - 7839) / 10 + 8.1; 069 } 070 if (exp > 0) { 071 return Math.sqrt(exp + 9) - 3; 072 } 073 return 0; 074 } 075 076 /** 077 * 078 * "The formulas for figuring out how many experience orbs you need to get to the next level are as follows: 079 * Experience Required = 2[Current Level] + 7 (at levels 0-15) 080 * 5[Current Level] - 38 (at levels 16-30) 081 * 9[Current Level] - 158 (at level 31+)" 082 */ 083 private static int getExperienceToNext(int level) { 084 if (level > 30) { 085 return 9 * level - 158; 086 } 087 if (level > 15) { 088 return 5 * level - 38; 089 } 090 return 2 * level + 7; 091 } 092 093 /** 094 * Change a Player's exp. 095 * <p> 096 * This method should be used in place of built-in player experience methods, which does not properly 097 * account for different levels requiring different amounts of experience. 098 * 099 * @param player the Player affected 100 * @param exp the amount of experience to add or remove 101 */ 102 public static void setExperience(PlayerProvider player, int exp) { 103 final int playerExperience = getExperience(player); 104 final boolean remove = exp < playerExperience; 105 106 final int change = (remove)? playerExperience - exp : exp - playerExperience; 107 108 changeExperience(player, change, remove); 109 } 110 111 /** 112 * Change a player's exp level. 113 * @param player The Player affected. 114 * @param level the new level 115 */ 116 public static void setLevel(PlayerProvider player, int level) { 117 player.setExpLevel(level); 118 } 119 120 /** 121 * Change a player's exp level. 122 * @param player The Player affected. 123 * @param level the new level 124 * @param remove should this be a removal? 125 */ 126 public static void changeLevel(PlayerProvider player, int level, boolean remove) { 127 final int newLevel = (remove)? player.getExpLevel() - level : player.getExpLevel() + level; 128 player.setExpLevel(newLevel); 129 } 130 131 /** 132 * Change a Player's exp. 133 * <p> 134 * This method should be used in place of built-in player experience methods, which does not properly 135 * account for different levels requiring different amounts of experience. 136 * 137 * @param player the Player affected 138 * @param exp the amount of experience to add or remove 139 */ 140 public static void changeExperience(PlayerProvider player, int exp, boolean remove) { 141 int xp = ((remove)? getExperience(player) - exp : getExperience(player) + exp); 142 143 if (xp < 0) { 144 xp = 0; 145 } 146 147 double levelAndExp = getLevelFromExperience(xp); 148 149 int level = (int) levelAndExp; 150 player.setExpLevel(level); 151 player.setExp((int)(levelAndExp - level)); 152 } 153}