MiningManager.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. package com.gmail.nossr50.skills.mining;
  2. import com.gmail.nossr50.api.ItemSpawnReason;
  3. import com.gmail.nossr50.config.experience.ExperienceConfig;
  4. import com.gmail.nossr50.datatypes.experience.XPGainReason;
  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.datatypes.skills.SuperAbilityType;
  10. import com.gmail.nossr50.mcMMO;
  11. import com.gmail.nossr50.runnables.skills.AbilityCooldownTask;
  12. import com.gmail.nossr50.skills.SkillManager;
  13. import com.gmail.nossr50.util.*;
  14. import com.gmail.nossr50.util.player.NotificationManager;
  15. import com.gmail.nossr50.util.random.Probability;
  16. import com.gmail.nossr50.util.random.ProbabilityUtil;
  17. import com.gmail.nossr50.util.skills.RankUtils;
  18. import com.gmail.nossr50.util.skills.SkillUtils;
  19. import org.bukkit.Material;
  20. import org.bukkit.block.Block;
  21. import org.bukkit.block.BlockState;
  22. import org.bukkit.block.Container;
  23. import org.bukkit.enchantments.Enchantment;
  24. import org.bukkit.entity.Player;
  25. import org.bukkit.entity.TNTPrimed;
  26. import org.bukkit.event.entity.EntityExplodeEvent;
  27. import org.bukkit.inventory.ItemStack;
  28. import org.jetbrains.annotations.NotNull;
  29. import java.util.*;
  30. import static com.gmail.nossr50.util.ItemUtils.isPickaxe;
  31. public class MiningManager extends SkillManager {
  32. public static final String BUDDING_AMETHYST = "budding_amethyst";
  33. public static final Collection<Material> BLAST_MINING_BLACKLIST = Set.of(Material.SPAWNER);
  34. private final static Set<String> INFESTED_BLOCKS = Set.of("infested_stone", "infested_cobblestone",
  35. "infested_stone_bricks", "infested_cracked_stone_bricks", "infested_mossy_stone_bricks",
  36. "infested_chiseled_stone_bricks", "infested_deepslate");
  37. public MiningManager(@NotNull McMMOPlayer mcMMOPlayer) {
  38. super(mcMMOPlayer, PrimarySkillType.MINING);
  39. }
  40. public boolean canUseDemolitionsExpertise() {
  41. if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DEMOLITIONS_EXPERTISE))
  42. return false;
  43. return getSkillLevel() >= BlastMining.getDemolitionExpertUnlockLevel() && Permissions.demolitionsExpertise(getPlayer());
  44. }
  45. public boolean canDetonate() {
  46. Player player = getPlayer();
  47. return canUseBlastMining() && player.isSneaking()
  48. && (isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == mcMMO.p.getGeneralConfig().getDetonatorItem())
  49. && Permissions.remoteDetonation(player);
  50. }
  51. public boolean canUseBlastMining() {
  52. //Not checking permissions?
  53. return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_BLAST_MINING);
  54. }
  55. public boolean canUseBiggerBombs() {
  56. if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_BIGGER_BOMBS))
  57. return false;
  58. return getSkillLevel() >= BlastMining.getBiggerBombsUnlockLevel() && Permissions.biggerBombs(getPlayer());
  59. }
  60. public boolean canDoubleDrop() {
  61. return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS);
  62. }
  63. public boolean canMotherLode() {
  64. return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MOTHER_LODE);
  65. }
  66. /**
  67. * Process double drops & XP gain for Mining.
  68. *
  69. * @param blockState The {@link BlockState} to check ability activation for
  70. */
  71. @Deprecated(since = "2.2.024", forRemoval = true)
  72. public void miningBlockCheck(BlockState blockState) {
  73. miningBlockCheck(blockState.getBlock());
  74. }
  75. public void miningBlockCheck(Block block) {
  76. Player player = getPlayer();
  77. applyXpGain(ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, block), XPGainReason.PVE);
  78. if (!Permissions.isSubSkillEnabled(player, SubSkillType.MINING_DOUBLE_DROPS)) {
  79. return;
  80. }
  81. if (mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill))) {
  82. SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage());
  83. }
  84. if (!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, block.getType()) || !canDoubleDrop())
  85. return;
  86. boolean silkTouch = player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH);
  87. if (silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled())
  88. return;
  89. //Mining mastery allows for a chance of triple drops
  90. if (canMotherLode()) {
  91. //Triple Drops failed so do a normal double drops check
  92. if (!processTripleDrops(block)) {
  93. processDoubleDrops(block);
  94. }
  95. } else {
  96. //If the user has no mastery, proceed with normal double drop routine
  97. processDoubleDrops(block);
  98. }
  99. }
  100. private boolean processTripleDrops(@NotNull Block block) {
  101. //TODO: Make this readable
  102. if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, mmoPlayer)) {
  103. BlockUtils.markDropsAsBonus(block, 2);
  104. return true;
  105. } else {
  106. return false;
  107. }
  108. }
  109. private void processDoubleDrops(@NotNull Block block) {
  110. //TODO: Make this readable
  111. if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, mmoPlayer)) {
  112. boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER)
  113. && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops();
  114. BlockUtils.markDropsAsBonus(block, useTriple);
  115. }
  116. }
  117. /**
  118. * Detonate TNT for Blast Mining
  119. */
  120. public void remoteDetonation() {
  121. Player player = getPlayer();
  122. Block targetBlock = player.getTargetBlock(BlockUtils.getTransparentBlocks(), BlastMining.MAXIMUM_REMOTE_DETONATION_DISTANCE);
  123. //Blast mining cooldown check needs to be first so the player can be messaged
  124. if (!blastMiningCooldownOver()
  125. || targetBlock.getType() != Material.TNT
  126. || !EventUtils.simulateBlockBreak(targetBlock, player)) {
  127. return;
  128. }
  129. TNTPrimed tnt = player.getWorld().spawn(targetBlock.getLocation(), TNTPrimed.class);
  130. //SkillUtils.sendSkillMessage(player, SuperAbilityType.BLAST_MINING.getAbilityPlayer(player));
  131. NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, "Mining.Blast.Boom");
  132. //player.sendMessage(LocaleLoader.getString("Mining.Blast.Boom"));
  133. tnt.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT, mmoPlayer.getPlayerMetadata());
  134. tnt.setFuseTicks(0);
  135. tnt.setSource(player);
  136. targetBlock.setType(Material.AIR);
  137. mmoPlayer.setAbilityDATS(SuperAbilityType.BLAST_MINING, System.currentTimeMillis());
  138. mmoPlayer.setAbilityInformed(SuperAbilityType.BLAST_MINING, false);
  139. mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mmoPlayer.getPlayer(), new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING), (long) SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR);
  140. }
  141. private boolean isInfestedBlock(String material) {
  142. return INFESTED_BLOCKS.contains(material.toLowerCase(Locale.ENGLISH));
  143. }
  144. /**
  145. * Handler for explosion drops and XP gain.
  146. *
  147. * @param yield The % of blocks to drop
  148. * @param event The {@link EntityExplodeEvent}
  149. */
  150. public void blastMiningDropProcessing(float yield, EntityExplodeEvent event) {
  151. if (yield == 0)
  152. return;
  153. var increasedYieldFromBonuses = yield + (yield * getOreBonus());
  154. // Strip out only stuff that gives mining XP
  155. List<Block> ores = new ArrayList<>();
  156. List<Block> notOres = new ArrayList<>();
  157. for (Block targetBlock : event.blockList()) {
  158. if(mcMMO.getUserBlockTracker().isIneligible(targetBlock))
  159. continue;
  160. if (ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, targetBlock) != 0) {
  161. if (BlockUtils.isOre(targetBlock) && !(targetBlock instanceof Container)) {
  162. ores.add(targetBlock);
  163. }
  164. } else {
  165. notOres.add(targetBlock);
  166. }
  167. }
  168. int xp = 0;
  169. int dropMultiplier = getDropMultiplier();
  170. for(Block block : notOres) {
  171. if (isDropIllegal(block.getType()))
  172. continue;
  173. if (block.getType().isItem() && Probability.ofPercent(50).evaluate()) {
  174. ItemUtils.spawnItem(getPlayer(),
  175. Misc.getBlockCenter(block),
  176. new ItemStack(block.getType()),
  177. ItemSpawnReason.BLAST_MINING_DEBRIS_NON_ORES); // Initial block that would have been dropped
  178. }
  179. }
  180. for (Block block : ores) {
  181. // currentOreYield only used for drop calculations for ores
  182. float currentOreYield = increasedYieldFromBonuses;
  183. if (isDropIllegal(block.getType())) {
  184. continue;
  185. }
  186. // Always give XP for every ore destroyed
  187. xp += ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, block);
  188. while(currentOreYield > 0) {
  189. if (Probability.ofValue(currentOreYield).evaluate()) {
  190. Collection<ItemStack> oreDrops = isPickaxe(mmoPlayer.getPlayer().getInventory().getItemInMainHand())
  191. ? block.getDrops(mmoPlayer.getPlayer().getInventory().getItemInMainHand())
  192. : List.of(new ItemStack(block.getType()));
  193. ItemUtils.spawnItems(getPlayer(), Misc.getBlockCenter(block),
  194. oreDrops, BLAST_MINING_BLACKLIST, ItemSpawnReason.BLAST_MINING_ORES);
  195. if (mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled()) {
  196. for (int i = 1; i < dropMultiplier; i++) {
  197. ItemUtils.spawnItems(getPlayer(),
  198. Misc.getBlockCenter(block),
  199. oreDrops,
  200. BLAST_MINING_BLACKLIST,
  201. ItemSpawnReason.BLAST_MINING_ORES_BONUS_DROP);
  202. }
  203. }
  204. }
  205. currentOreYield = Math.max(currentOreYield - 1, 0);
  206. }
  207. }
  208. // Replace the event blocklist with the newYield list
  209. event.setYield(0F);
  210. applyXpGain(xp, XPGainReason.PVE);
  211. }
  212. /**
  213. * Checks if it would be illegal (in vanilla) to obtain the block
  214. * Certain things should never drop (such as budding_amethyst and infested blocks)
  215. *
  216. * @param material target material
  217. * @return true if it's not legal to get the block through normal gameplay
  218. */
  219. public boolean isDropIllegal(@NotNull Material material) {
  220. return isInfestedBlock(material.getKey().getKey())
  221. || material.getKey().getKey().equalsIgnoreCase(BUDDING_AMETHYST);
  222. }
  223. /**
  224. * Increases the blast radius of the explosion.
  225. *
  226. * @param radius to modify
  227. * @return modified radius
  228. */
  229. public float biggerBombs(float radius) {
  230. return (float) (radius + getBlastRadiusModifier());
  231. }
  232. public double processDemolitionsExpertise(double damage) {
  233. return damage * ((100.0D - getBlastDamageModifier()) / 100.0D);
  234. }
  235. /**
  236. * Gets the Blast Mining tier
  237. *
  238. * @return the Blast Mining tier
  239. */
  240. public int getBlastMiningTier() {
  241. return RankUtils.getRank(getPlayer(), SubSkillType.MINING_BLAST_MINING);
  242. }
  243. /**
  244. * Gets the Blast Mining tier
  245. *
  246. * @return the Blast Mining tier
  247. */
  248. public float getOreBonus() {
  249. return (float) (mcMMO.p.getAdvancedConfig().getOreBonus(getBlastMiningTier()) / 100F);
  250. }
  251. @Deprecated(since = "2.2.017", forRemoval = true)
  252. public static double getOreBonus(int rank) {
  253. return mcMMO.p.getAdvancedConfig().getOreBonus(rank);
  254. }
  255. public static double getDebrisReduction(int rank) {
  256. return mcMMO.p.getAdvancedConfig().getDebrisReduction(rank);
  257. }
  258. /**
  259. * Gets the Blast Mining tier
  260. *
  261. * @return the Blast Mining tier
  262. */
  263. public double getDebrisReduction() {
  264. return getDebrisReduction(getBlastMiningTier());
  265. }
  266. public static int getDropMultiplier(int rank) {
  267. return mcMMO.p.getAdvancedConfig().getDropMultiplier(rank);
  268. }
  269. /**
  270. * Gets the Blast Mining tier
  271. *
  272. * @return the Blast Mining tier
  273. */
  274. public int getDropMultiplier() {
  275. if (!mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled()) {
  276. return 0;
  277. }
  278. return switch (getBlastMiningTier()) {
  279. case 8, 7 -> 3;
  280. case 6, 5, 4, 3 -> 2;
  281. case 2, 1 -> 1;
  282. default -> 0;
  283. };
  284. }
  285. /**
  286. * Gets the Blast Mining tier
  287. *
  288. * @return the Blast Mining tier
  289. */
  290. public double getBlastRadiusModifier() {
  291. return BlastMining.getBlastRadiusModifier(getBlastMiningTier());
  292. }
  293. /**
  294. * Gets the Blast Mining tier
  295. *
  296. * @return the Blast Mining tier
  297. */
  298. public double getBlastDamageModifier() {
  299. return BlastMining.getBlastDamageDecrease(getBlastMiningTier());
  300. }
  301. private boolean blastMiningCooldownOver() {
  302. int timeRemaining = mmoPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING);
  303. if (timeRemaining > 0) {
  304. //getPlayer().sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));
  305. NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
  306. return false;
  307. }
  308. return true;
  309. }
  310. }