SalvageManager.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package com.gmail.nossr50.skills.salvage;
  2. import com.gmail.nossr50.config.AdvancedConfig;
  3. import com.gmail.nossr50.config.Config;
  4. import com.gmail.nossr50.config.experience.ExperienceConfig;
  5. import com.gmail.nossr50.datatypes.interactions.NotificationType;
  6. import com.gmail.nossr50.datatypes.player.McMMOPlayer;
  7. import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
  8. import com.gmail.nossr50.datatypes.skills.SubSkillType;
  9. import com.gmail.nossr50.locale.LocaleLoader;
  10. import com.gmail.nossr50.mcMMO;
  11. import com.gmail.nossr50.skills.SkillManager;
  12. import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
  13. import com.gmail.nossr50.util.EventUtils;
  14. import com.gmail.nossr50.util.Misc;
  15. import com.gmail.nossr50.util.Permissions;
  16. import com.gmail.nossr50.util.StringUtils;
  17. import com.gmail.nossr50.util.player.NotificationManager;
  18. import com.gmail.nossr50.util.random.RandomChanceSkillStatic;
  19. import com.gmail.nossr50.util.random.RandomChanceUtil;
  20. import com.gmail.nossr50.util.skills.RankUtils;
  21. import com.gmail.nossr50.util.skills.SkillUtils;
  22. import com.gmail.nossr50.util.sounds.SoundManager;
  23. import com.gmail.nossr50.util.sounds.SoundType;
  24. import org.bukkit.Location;
  25. import org.bukkit.Material;
  26. import org.bukkit.enchantments.Enchantment;
  27. import org.bukkit.entity.Player;
  28. import org.bukkit.inventory.ItemStack;
  29. import org.bukkit.inventory.meta.EnchantmentStorageMeta;
  30. import java.util.Map;
  31. import java.util.Map.Entry;
  32. public class SalvageManager extends SkillManager {
  33. private boolean placedAnvil;
  34. private int lastClick;
  35. public SalvageManager(McMMOPlayer mcMMOPlayer) {
  36. super(mcMMOPlayer, PrimarySkillType.SALVAGE);
  37. }
  38. /**
  39. * Handles notifications for placing an anvil.
  40. */
  41. public void placedAnvilCheck() {
  42. Player player = getPlayer();
  43. if (getPlacedAnvil()) {
  44. return;
  45. }
  46. if (Config.getInstance().getSalvageAnvilMessagesEnabled()) {
  47. NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Listener.Anvil");
  48. }
  49. if (Config.getInstance().getSalvageAnvilPlaceSoundsEnabled()) {
  50. SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL);
  51. }
  52. togglePlacedAnvil();
  53. }
  54. public void handleSalvage(Location location, ItemStack item) {
  55. Player player = getPlayer();
  56. Salvageable salvageable = mcMMO.getSalvageableManager().getSalvageable(item.getType());
  57. if (item.getItemMeta() != null && item.getItemMeta().isUnbreakable()) {
  58. NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable");
  59. return;
  60. }
  61. // Permissions checks on material and item types
  62. if (!Permissions.salvageItemType(player, salvageable.getSalvageItemType())) {
  63. NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission");
  64. return;
  65. }
  66. if (!Permissions.salvageMaterialType(player, salvageable.getSalvageMaterialType())) {
  67. NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission");
  68. return;
  69. }
  70. /*int skillLevel = getSkillLevel();*/
  71. int minimumSalvageableLevel = salvageable.getMinimumLevel();
  72. // Level check
  73. if (getSkillLevel() < minimumSalvageableLevel) {
  74. NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Salvage.Skills.Adept.Level", String.valueOf(salvageable.getMinimumLevel()), StringUtils.getPrettyItemString(item.getType()));
  75. return;
  76. }
  77. int potentialSalvageYield = Salvage.calculateSalvageableAmount(item.getDurability(), salvageable.getMaximumDurability(), salvageable.getMaximumQuantity());
  78. if (potentialSalvageYield <= 0) {
  79. NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.TooDamaged");
  80. return;
  81. }
  82. potentialSalvageYield = Math.min(potentialSalvageYield, getSalvageLimit()); // Always get at least something back, if you're capable of salvaging it.
  83. location.add(0.5, 1, 0.5);
  84. Map<Enchantment, Integer> enchants = item.getEnchantments();
  85. ItemStack enchantBook = null;
  86. if (!enchants.isEmpty()) {
  87. enchantBook = arcaneSalvageCheck(enchants);
  88. }
  89. //Lottery on Salvageable Amount
  90. int lotteryResults = 1;
  91. int chanceOfSuccess = 99;
  92. for(int x = 0; x < potentialSalvageYield-1; x++) {
  93. if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) {
  94. chanceOfSuccess-=3;
  95. chanceOfSuccess = Math.max(chanceOfSuccess, 90);
  96. lotteryResults+=1;
  97. }
  98. }
  99. if(lotteryResults == potentialSalvageYield && potentialSalvageYield != 1 && RankUtils.isPlayerMaxRankInSubSkill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE)) {
  100. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Perfect", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType()));
  101. } else if(salvageable.getMaximumQuantity() == 1 || getSalvageLimit() >= salvageable.getMaximumQuantity()) {
  102. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Normal", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType()));
  103. } else {
  104. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Untrained", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType()));
  105. }
  106. ItemStack salvageResults = new ItemStack(salvageable.getSalvageMaterial(), lotteryResults);
  107. //Call event
  108. if (EventUtils.callSalvageCheckEvent(player, item, salvageResults, enchantBook).isCancelled()) {
  109. return;
  110. }
  111. player.getInventory().setItemInMainHand(new ItemStack(Material.AIR));
  112. Location anvilLoc = location.clone();
  113. Location playerLoc = player.getLocation().clone();
  114. double distance = anvilLoc.distance(playerLoc);
  115. double speedLimit = .6;
  116. double minSpeed = .3;
  117. //Clamp the speed and vary it by distance
  118. double vectorSpeed = Math.min(speedLimit, Math.max(minSpeed, distance * .2));
  119. //Add a very small amount of height
  120. anvilLoc.add(0, .1, 0);
  121. if (enchantBook != null) {
  122. Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), enchantBook, vectorSpeed);
  123. }
  124. Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), salvageResults, vectorSpeed);
  125. // BWONG BWONG BWONG - CLUNK!
  126. if (Config.getInstance().getSalvageAnvilUseSoundsEnabled()) {
  127. SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK);
  128. }
  129. NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Skills.Success");
  130. }
  131. /*public double getMaxSalvagePercentage() {
  132. return Math.min((((Salvage.salvageMaxPercentage / Salvage.salvageMaxPercentageLevel) * getSkillLevel()) / 100.0D), Salvage.salvageMaxPercentage / 100.0D);
  133. }*/
  134. public int getSalvageLimit() {
  135. return (RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_SCRAP_COLLECTOR));
  136. }
  137. /**
  138. * Gets the Arcane Salvage rank
  139. *
  140. * @return the current Arcane Salvage rank
  141. */
  142. public int getArcaneSalvageRank() {
  143. return RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE);
  144. }
  145. /*public double getExtractFullEnchantChance() {
  146. int skillLevel = getSkillLevel();
  147. for (Tier tier : Tier.values()) {
  148. if (skillLevel >= tier.getLevel()) {
  149. return tier.getExtractFullEnchantChance();
  150. }
  151. }
  152. return 0;
  153. }
  154. public double getExtractPartialEnchantChance() {
  155. int skillLevel = getSkillLevel();
  156. for (Tier tier : Tier.values()) {
  157. if (skillLevel >= tier.getLevel()) {
  158. return tier.getExtractPartialEnchantChance();
  159. }
  160. }
  161. return 0;
  162. }*/
  163. public double getExtractFullEnchantChance() {
  164. if(Permissions.hasSalvageEnchantBypassPerk(getPlayer()))
  165. return 100.0D;
  166. return AdvancedConfig.getInstance().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank());
  167. }
  168. public double getExtractPartialEnchantChance() {
  169. return AdvancedConfig.getInstance().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank());
  170. }
  171. private ItemStack arcaneSalvageCheck(Map<Enchantment, Integer> enchants) {
  172. Player player = getPlayer();
  173. if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE) || !Permissions.arcaneSalvage(player)) {
  174. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed");
  175. return null;
  176. }
  177. ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
  178. EnchantmentStorageMeta enchantMeta = (EnchantmentStorageMeta) book.getItemMeta();
  179. boolean downgraded = false;
  180. int arcaneFailureCount = 0;
  181. for (Entry<Enchantment, Integer> enchant : enchants.entrySet()) {
  182. int enchantLevel = enchant.getValue();
  183. if(!ExperienceConfig.getInstance().allowUnsafeEnchantments()) {
  184. if(enchantLevel > enchant.getKey().getMaxLevel()) {
  185. enchantLevel = enchant.getKey().getMaxLevel();
  186. }
  187. }
  188. if (!Salvage.arcaneSalvageEnchantLoss
  189. || Permissions.hasSalvageEnchantBypassPerk(player)
  190. || RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
  191. enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true);
  192. }
  193. else if (enchantLevel > 1
  194. && Salvage.arcaneSalvageDowngrades
  195. && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
  196. enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true);
  197. downgraded = true;
  198. } else {
  199. arcaneFailureCount++;
  200. }
  201. }
  202. if(failedAllEnchants(arcaneFailureCount, enchants.entrySet().size()))
  203. {
  204. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed");
  205. return null;
  206. } else if(downgraded)
  207. {
  208. NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcanePartial");
  209. }
  210. book.setItemMeta(enchantMeta);
  211. return book;
  212. }
  213. private boolean failedAllEnchants(int arcaneFailureCount, int size) {
  214. return arcaneFailureCount == size;
  215. }
  216. /**
  217. * Check if the player has tried to use an Anvil before.
  218. * @param actualize
  219. *
  220. * @return true if the player has confirmed using an Anvil
  221. */
  222. public boolean checkConfirmation(boolean actualize) {
  223. Player player = getPlayer();
  224. long lastUse = getLastAnvilUse();
  225. if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getSalvageConfirmRequired()) {
  226. return true;
  227. }
  228. if (!actualize) {
  229. return false;
  230. }
  231. actualizeLastAnvilUse();
  232. NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name"));
  233. return false;
  234. }
  235. /*
  236. * Salvage Anvil Placement
  237. */
  238. public boolean getPlacedAnvil() {
  239. return placedAnvil;
  240. }
  241. public void togglePlacedAnvil() {
  242. placedAnvil = !placedAnvil;
  243. }
  244. /*
  245. * Salvage Anvil Usage
  246. */
  247. public int getLastAnvilUse() {
  248. return lastClick;
  249. }
  250. public void setLastAnvilUse(int value) {
  251. lastClick = value;
  252. }
  253. public void actualizeLastAnvilUse() {
  254. lastClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
  255. }
  256. }