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