MiningManager.java 14 KB

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