소스 검색

More event work.

GJ 11 년 전
부모
커밋
a65bcb9e5d

+ 44 - 0
src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerTreasureEvent.java

@@ -0,0 +1,44 @@
+package com.gmail.nossr50.events.skills;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.inventory.ItemStack;
+
+import com.gmail.nossr50.datatypes.skills.SkillType;
+
+public abstract class McMMOPlayerTreasureEvent extends McMMOPlayerSkillEvent implements Cancellable {
+    private boolean cancelled;
+    private ItemStack treasure;
+    private int xpGained;
+
+    protected McMMOPlayerTreasureEvent(Player player, SkillType skill, ItemStack treasure, int xpGained) {
+        super(player, skill);
+        this.treasure = treasure;
+        this.xpGained = xpGained;
+        this.cancelled = false;
+    }
+
+    public ItemStack getTreasure() {
+        return treasure;
+    }
+
+    public void setTreasure(ItemStack item) {
+        this.treasure = item;
+    }
+
+    public int getXpGained() {
+        return xpGained;
+    }
+
+    public void setXpGained(int xpGained) {
+        this.xpGained = xpGained;
+    }
+
+    public boolean isCancelled() {
+        return cancelled;
+    }
+
+    public void setCancelled(boolean newValue) {
+        this.cancelled = newValue;
+    }
+}

+ 21 - 0
src/main/java/com/gmail/nossr50/events/skills/excavation/McMMOPlayerExcavationTreasureEvent.java

@@ -0,0 +1,21 @@
+package com.gmail.nossr50.events.skills.excavation;
+
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.events.skills.McMMOPlayerTreasureEvent;
+
+public class McMMOPlayerExcavationTreasureEvent extends McMMOPlayerTreasureEvent {
+    private Block block;
+
+    public McMMOPlayerExcavationTreasureEvent(Player player, ItemStack treasure, int xpGained, Block block) {
+        super(player, SkillType.EXCAVATION, treasure, xpGained);
+        this.block = block;
+    }
+
+    public Block getBlock() {
+        return block;
+    }
+}

+ 13 - 0
src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingCombatEvent.java

@@ -0,0 +1,13 @@
+package com.gmail.nossr50.events.skills.fishing;
+
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+
+import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.events.skills.McMMOPlayerCombatEvent;
+
+public abstract class McMMOPlayerFishingCombatEvent extends McMMOPlayerCombatEvent {
+    public McMMOPlayerFishingCombatEvent(Player player, Entity damager, Entity damagee, DamageCause cause, double damage) {
+        super(player, damager, damagee, cause, damage, SkillType.FISHING);
+    }
+}

+ 5 - 23
src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingTreasureEvent.java

@@ -3,29 +3,11 @@ package com.gmail.nossr50.events.skills.fishing;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 
-public class McMMOPlayerFishingTreasureEvent extends McMMOPlayerFishingEvent {
-    private ItemStack treasure;
-    private int xp;
+import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.events.skills.McMMOPlayerTreasureEvent;
 
-    public McMMOPlayerFishingTreasureEvent(Player player, ItemStack treasure, int xp) {
-        super(player);
-        this.treasure = treasure;
-        this.xp = xp;
-    }
-
-    public ItemStack getTreasure() {
-        return treasure;
-    }
-
-    public void setTreasure(ItemStack item) {
-        this.treasure = item;
-    }
-
-    public int getXp() {
-        return xp;
-    }
-
-    public void setXp(int xp) {
-        this.xp = xp;
+public class McMMOPlayerFishingTreasureEvent extends McMMOPlayerTreasureEvent {
+    public McMMOPlayerFishingTreasureEvent(Player player, ItemStack treasure, int xpGained) {
+        super(player, SkillType.FISHING, treasure, xpGained);
     }
 }

+ 5 - 3
src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerShakeEvent.java

@@ -1,13 +1,15 @@
 package com.gmail.nossr50.events.skills.fishing;
 
+import org.bukkit.entity.Fish;
+import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 
-public class McMMOPlayerShakeEvent extends McMMOPlayerFishingEvent {
+public class McMMOPlayerShakeEvent extends McMMOPlayerFishingCombatEvent {
     private ItemStack drop;
 
-    public McMMOPlayerShakeEvent(Player player, ItemStack drop) {
-        super(player);
+    public McMMOPlayerShakeEvent(Player player, Fish hook, ItemStack drop, LivingEntity target, double damage) {
+        super(player, hook, target, DamageCause.PROJECTILE, damage);
         this.drop = drop;
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/listeners/BlockListener.java

@@ -179,7 +179,7 @@ public class BlockListener implements Listener {
         /* EXCAVATION */
         else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && SkillType.EXCAVATION.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) {
             ExcavationManager excavationManager = mcMMOPlayer.getExcavationManager();
-            excavationManager.excavationBlockCheck(blockState);
+            excavationManager.blockBreak(blockState);
 
             if (mcMMOPlayer.getAbilityMode(AbilityType.GIGA_DRILL_BREAKER)) {
                 excavationManager.gigaDrillBreaker(blockState);

+ 2 - 2
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -522,13 +522,13 @@ public class EntityListener implements Listener {
 
             case COOKED_FISH: /* RESTORES 2 1/2 HUNGER - RESTORES 5 HUNGER @ 1000 */
                 if (Permissions.fishermansDiet(player)) {
-                    event.setFoodLevel(UserManager.getPlayer(player).getFishingManager().handleFishermanDiet(Fishing.fishermansDietRankLevel1, newFoodLevel));
+                    event.setFoodLevel(UserManager.getPlayer(player).getFishingManager().fishermansDiet(Fishing.fishermansDietRankLevel1, newFoodLevel));
                 }
                 return;
 
             case RAW_FISH:    /* RESTORES 1 HUNGER - RESTORES 2 1/2 HUNGER @ 1000 */
                 if (Permissions.fishermansDiet(player)) {
-                    event.setFoodLevel(UserManager.getPlayer(player).getFishingManager().handleFishermanDiet(Fishing.fishermansDietRankLevel2, newFoodLevel));
+                    event.setFoodLevel(UserManager.getPlayer(player).getFishingManager().fishermansDiet(Fishing.fishermansDietRankLevel2, newFoodLevel));
                 }
                 return;
 

+ 5 - 19
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -7,7 +7,6 @@ import org.bukkit.block.Block;
 import org.bukkit.block.BlockState;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Item;
-import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.EventPriority;
@@ -212,24 +211,15 @@ public class PlayerListener implements Listener {
 
         switch (event.getState()) {
             case FISHING:
-                if (!Permissions.krakenBypass(player)) {
-                    event.setCancelled(fishingManager.exploitPrevention());
-                }
+                event.setCancelled(fishingManager.exploitPrevention());
                 return;
 
             case CAUGHT_FISH:
-                if (Permissions.vanillaXpBoost(player, SkillType.FISHING)) {
-                    event.setExpToDrop(fishingManager.handleVanillaXpBoost(event.getExpToDrop()));
-                }
+                event.setExpToDrop(fishingManager.vanillaXpBoost(event.getExpToDrop()));
                 return;
 
             case IN_GROUND:
-                Block block = player.getTargetBlock(null, 100);
-
-                if (fishingManager.canIceFish(block)) {
-                    event.setCancelled(true);
-                    fishingManager.iceFishing(event.getHook(), block);
-                }
+                event.setCancelled(fishingManager.iceFishing(event.getHook(), player.getTargetBlock(null, 100)));
                 return;
 
             default:
@@ -258,9 +248,7 @@ public class PlayerListener implements Listener {
 
         switch (event.getState()) {
             case FISHING:
-                if (fishingManager.canMasterAngler()) {
-                    fishingManager.masterAngler(event.getHook());
-                }
+                fishingManager.masterAngler(event.getHook());
                 return;
 
             case CAUGHT_FISH:
@@ -268,9 +256,7 @@ public class PlayerListener implements Listener {
                 return;
 
             case CAUGHT_ENTITY:
-                if (fishingManager.canShake(caught)) {
-                    fishingManager.shakeCheck((LivingEntity) caught);
-                }
+                fishingManager.shake(event.getHook(), caught);
                 return;
 
             default:

+ 16 - 16
src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java

@@ -26,22 +26,6 @@ public class AxesManager extends SkillManager {
         super(mcMMOPlayer, SkillType.AXES);
     }
 
-    private boolean canUseAxeMastery(LivingEntity target) {
-        return target.isValid() && Permissions.bonusDamage(getPlayer(), skill);
-    }
-
-    private boolean canCriticalHit(LivingEntity target) {
-        return target.isValid() && Permissions.criticalStrikes(getPlayer()) && SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Axes.criticalHitMaxChance, Axes.criticalHitMaxBonusLevel);
-    }
-
-    private boolean canImpact(LivingEntity target) {
-        return target.isValid() && Axes.hasArmor(target) && Permissions.armorImpact(getPlayer());
-    }
-
-    private boolean canUseGreaterImpact(LivingEntity target) {
-        return target.isValid() && !Axes.hasArmor(target) && Permissions.greaterImpact(getPlayer()) && (Axes.greaterImpactChance > Misc.getRandom().nextInt(getActivationChance()));
-    }
-
     /**
      * Handle the effects of the Axe Mastery ability
      *
@@ -178,4 +162,20 @@ public class AxesManager extends SkillManager {
     private double calculateCriticalHitBonus(double damage, boolean isPlayer) {
         return (damage * (isPlayer ? Axes.criticalHitPVPModifier : Axes.criticalHitPVEModifier)) - damage;
     }
+
+    private boolean canUseAxeMastery(LivingEntity target) {
+        return target.isValid() && Permissions.bonusDamage(getPlayer(), skill);
+    }
+
+    private boolean canCriticalHit(LivingEntity target) {
+        return target.isValid() && Permissions.criticalStrikes(getPlayer()) && SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Axes.criticalHitMaxChance, Axes.criticalHitMaxBonusLevel);
+    }
+
+    private boolean canImpact(LivingEntity target) {
+        return target.isValid() && Axes.hasArmor(target) && Permissions.armorImpact(getPlayer());
+    }
+
+    private boolean canUseGreaterImpact(LivingEntity target) {
+        return target.isValid() && !Axes.hasArmor(target) && Permissions.greaterImpact(getPlayer()) && (Axes.greaterImpactChance > Misc.getRandom().nextInt(getActivationChance()));
+    }
 }

+ 19 - 5
src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java

@@ -3,12 +3,16 @@ package com.gmail.nossr50.skills.excavation;
 import java.util.List;
 
 import org.bukkit.Location;
+import org.bukkit.block.Block;
 import org.bukkit.block.BlockState;
+import org.bukkit.entity.Player;
 
+import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure;
+import com.gmail.nossr50.events.skills.excavation.McMMOPlayerExcavationTreasureEvent;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
@@ -24,7 +28,7 @@ public class ExcavationManager extends SkillManager {
      *
      * @param blockState The {@link BlockState} to check ability activation for
      */
-    public void excavationBlockCheck(BlockState blockState) {
+    public void blockBreak(BlockState blockState) {
         int xp = Excavation.getBlockXP(blockState);
 
         if (Permissions.excavationTreasureHunter(getPlayer())) {
@@ -34,10 +38,20 @@ public class ExcavationManager extends SkillManager {
                 int skillLevel = getSkillLevel();
                 Location location = blockState.getLocation();
 
+                Player player = getPlayer();
+                Block block = blockState.getBlock();
+
                 for (ExcavationTreasure treasure : treasures) {
                     if (skillLevel >= treasure.getDropLevel() && SkillUtils.treasureDropSuccessful(treasure.getDropChance(), activationChance)) {
-                        xp += treasure.getXp();
-                        Misc.dropItem(location, treasure.getDrop());
+                        McMMOPlayerExcavationTreasureEvent event = new McMMOPlayerExcavationTreasureEvent(player, treasure.getDrop(), treasure.getXp(), block);
+                        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+                        if (event.isCancelled()) {
+                            continue;
+                        }
+
+                        xp += event.getXpGained();
+                        Misc.dropItem(location, event.getTreasure());
                     }
                 }
             }
@@ -52,8 +66,8 @@ public class ExcavationManager extends SkillManager {
      * @param blockState The {@link BlockState} to check ability activation for
      */
     public void gigaDrillBreaker(BlockState blockState) {
-        excavationBlockCheck(blockState);
-        excavationBlockCheck(blockState);
+        blockBreak(blockState);
+        blockBreak(blockState);
 
         SkillUtils.handleDurabilityChange(getPlayer().getItemInHand(), Config.getInstance().getAbilityToolDamage());
     }

+ 128 - 130
src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java

@@ -73,14 +73,6 @@ public class FishingManager extends SkillManager {
         super(mcMMOPlayer, SkillType.FISHING);
     }
 
-    public boolean canShake(Entity target) {
-        return target instanceof LivingEntity && getSkillLevel() >= Tier.ONE.getLevel() && Permissions.shake(getPlayer());
-    }
-
-    public boolean canMasterAngler() {
-        return getSkillLevel() >= AdvancedConfig.getInstance().getMasterAnglerUnlockLevel() && Permissions.masterAngler(getPlayer());
-    }
-
     public boolean unleashTheKraken() {
         return unleashTheKraken(true);
     }
@@ -161,11 +153,13 @@ public class FishingManager extends SkillManager {
     }
 
     public boolean exploitPrevention() {
-        if (!AdvancedConfig.getInstance().getKrakenEnabled()) {
+        Player player = getPlayer();
+
+        if (Permissions.krakenBypass(player) || !AdvancedConfig.getInstance().getKrakenEnabled()) {
             return false;
         }
 
-        Block targetBlock = getPlayer().getTargetBlock(BlockUtils.getTransparentBlocks(), 100);
+        Block targetBlock = player.getTargetBlock(BlockUtils.getTransparentBlocks(), 100);
 
         if (!targetBlock.isLiquid()) {
             return false;
@@ -186,66 +180,6 @@ public class FishingManager extends SkillManager {
         return unleashTheKraken(false);
     }
 
-    public boolean canIceFish(Block block) {
-        if (getSkillLevel() < AdvancedConfig.getInstance().getIceFishingUnlockLevel()) {
-            return false;
-        }
-
-        if (block.getType() != Material.ICE) {
-            return false;
-        }
-
-        // Make sure this is a body of water, not just a block of ice.
-        Biome biome = block.getBiome();
-        boolean isFrozenBiome = (biome == Biome.FROZEN_OCEAN || biome == Biome.FROZEN_RIVER || biome == Biome.TAIGA || biome == Biome.TAIGA_HILLS || biome == Biome.ICE_PLAINS || biome == Biome.ICE_MOUNTAINS);
-
-        if (!isFrozenBiome && (block.getRelative(BlockFace.DOWN, 3).getType() != Material.STATIONARY_WATER)) {
-            return false;
-        }
-
-        Player player = getPlayer();
-
-        if (!Permissions.iceFishing(player)) {
-            return false;
-        }
-
-        return EventUtils.simulateBlockBreak(block, player, false);
-    }
-
-    /**
-     * Gets the loot tier
-     *
-     * @return the loot tier
-     */
-    public int getLootTier() {
-        int skillLevel = getSkillLevel();
-
-        for (Tier tier : Tier.values()) {
-            if (skillLevel >= tier.getLevel()) {
-                return tier.toNumerical();
-            }
-        }
-
-        return 0;
-    }
-
-    /**
-     * Gets the Shake Mob probability
-     *
-     * @return Shake Mob probability
-     */
-    public double getShakeProbability() {
-        int skillLevel = getSkillLevel();
-
-        for (Tier tier : Tier.values()) {
-            if (skillLevel >= tier.getLevel()) {
-                return tier.getShakeChance();
-            }
-        }
-
-        return 0.0;
-    }
-
     /**
      * Handle the Fisherman's Diet ability
      *
@@ -254,29 +188,35 @@ public class FishingManager extends SkillManager {
      *
      * @return the modified change in hunger for the event
      */
-    public int handleFishermanDiet(int rankChange, int eventFoodLevel) {
+    public int fishermansDiet(int rankChange, int eventFoodLevel) {
         return SkillUtils.handleFoodSkills(getPlayer(), skill, eventFoodLevel, Fishing.fishermansDietRankLevel1, Fishing.fishermansDietMaxLevel, rankChange);
     }
 
-    public void iceFishing(Fish hook, Block block) {
+    public boolean iceFishing(Fish hook, Block block) {
+        if (!canIceFish(block)) {
+            return false;
+        }
+
         // Make a hole
         block.setType(Material.STATIONARY_WATER);
 
-        for (int x = -1; x <= 1; x++) {
-            for (int z = -1; z <= 1; z++) {
-                Block relative = block.getRelative(x, 0, z);
+        for (BlockFace face : BlockFace.values()) {
+            Block relative = block.getRelative(face);
 
-                if (relative.getType() == Material.ICE) {
-                    relative.setType(Material.STATIONARY_WATER);
-                }
+            if (relative.getType() == Material.ICE) {
+                relative.setType(Material.STATIONARY_WATER);
             }
         }
 
         // Recast in the new spot
-        EventUtils.callFakeFishEvent(getPlayer(), hook);
+        return !EventUtils.callFakeFishEvent(getPlayer(), hook).isCancelled();
     }
 
     public void masterAngler(Fish hook) {
+        if (!canUseMasterAngler()) {
+            return;
+        }
+
         Player player = getPlayer();
         Location location = hook.getLocation();
         Biome biome = location.getBlock().getBiome();
@@ -325,7 +265,7 @@ public class FishingManager extends SkillManager {
 
             if (!event.isCancelled()) {
                 treasureDrop = event.getTreasure();
-                treasureXp = event.getXp();
+                treasureXp = event.getXpGained();
             }
             else {
                 treasureDrop = null;
@@ -357,10 +297,10 @@ public class FishingManager extends SkillManager {
      *
      * @param experience The amount of experience initially awarded by the event
      *
-     * @return the modified event damage
+     * @return the modified event experience
      */
-    public int handleVanillaXpBoost(int experience) {
-        return experience * getVanillaXpMultiplier();
+    public int vanillaXpBoost(int experience) {
+        return experience * (Permissions.vanillaXpBoost(getPlayer(), skill) ? getVanillaXpMultiplier() : 1);
     }
 
     public Location getHookLocation() {
@@ -370,73 +310,101 @@ public class FishingManager extends SkillManager {
     /**
      * Handle the Shake ability
      *
-     * @param target The {@link LivingEntity} affected by the ability
+     * @param entity The {@link Entity} affected by the ability
      */
-    public void shakeCheck(LivingEntity target) {
+    public void shake(Fish hook, Entity entity) {
+        if (!canShake(entity)) {
+            return;
+        }
+
         fishingTries--; // Because autoclicking to shake is OK.
 
-        if (getShakeProbability() > Misc.getRandom().nextInt(getActivationChance())) {
-            List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
+        LivingEntity target = (LivingEntity) entity;
+        List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
 
-            if (possibleDrops == null || possibleDrops.isEmpty()) {
-                return;
-            }
+        if (possibleDrops == null || possibleDrops.isEmpty()) {
+            return;
+        }
 
-            ItemStack drop = Fishing.chooseDrop(possibleDrops);
+        ItemStack drop = Fishing.chooseDrop(possibleDrops);
 
-            // It's possible that chooseDrop returns null if the sum of probability in possibleDrops is inferior than 100
-            if (drop == null) {
-                return;
-            }
+        // It's possible that chooseDrop returns null if the sum of probability in possibleDrops is inferior than 100
+        if (drop == null) {
+            return;
+        }
 
-            // Extra processing depending on the mob and drop type
-            switch (target.getType()) {
-                case SHEEP:
-                    Sheep sheep = (Sheep) target;
+        // Extra processing depending on the mob and drop type
+        switch (target.getType()) {
+            case SHEEP:
+                Sheep sheep = (Sheep) target;
+                drop = new Wool(sheep.getColor()).toItemStack(drop.getAmount());
+                sheep.setSheared(true);
 
-                    if (drop.getType() == Material.WOOL) {
-                        if (sheep.isSheared()) {
-                            return;
-                        }
+            case SKELETON:
+                if (((Skeleton) target).getSkeletonType() == SkeletonType.WITHER) {
+                    switch (drop.getType()) {
+                        case SKULL_ITEM:
+                            drop.setDurability((short) 1);
+                            break;
 
-                        drop = new Wool(sheep.getColor()).toItemStack(drop.getAmount());
-                        sheep.setSheared(true);
+                        case ARROW:
+                            drop.setType(Material.COAL);
+                            break;
+
+                        default:
+                            break;
                     }
-                    break;
+                }
+                break;
 
-                case SKELETON:
-                    if (((Skeleton) target).getSkeletonType() == SkeletonType.WITHER) {
-                        switch (drop.getType()) {
-                            case SKULL_ITEM:
-                                drop.setDurability((short) 1);
-                                break;
+            default:
+                break;
+        }
 
-                            case ARROW:
-                                drop.setType(Material.COAL);
-                                break;
+        McMMOPlayerShakeEvent event = new McMMOPlayerShakeEvent(getPlayer(), hook, drop, target, Math.max(target.getMaxHealth() / 4, 1)); // TODO: Config option for shake damage
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
 
-                            default:
-                                break;
-                        }
-                    }
-                    break;
+        if (event.isCancelled()) {
+            return;
+        }
 
-                default:
-                    break;
+        Misc.dropItem(target.getLocation(), event.getDrop());
+        CombatUtils.dealDamage(target, event.getDamage());
+        applyXpGain(ExperienceConfig.getInstance().getFishingShakeXP());
+    }
+
+    /**
+     * Gets the loot tier
+     *
+     * @return the loot tier
+     */
+    public int getLootTier() {
+        int skillLevel = getSkillLevel();
+
+        for (Tier tier : Tier.values()) {
+            if (skillLevel >= tier.getLevel()) {
+                return tier.toNumerical();
             }
+        }
 
-            McMMOPlayerShakeEvent event = new McMMOPlayerShakeEvent(getPlayer(), drop);
+        return 0;
+    }
 
-            drop = event.getDrop();
+    /**
+     * Gets the Shake Mob probability
+     *
+     * @return Shake Mob probability
+     */
+    public double getShakeProbability() {
+        int skillLevel = getSkillLevel();
 
-            if (event.isCancelled() || drop == null) {
-                return;
+        for (Tier tier : Tier.values()) {
+            if (skillLevel >= tier.getLevel()) {
+                return tier.getShakeChance();
             }
-
-            Misc.dropItem(target.getLocation(), drop);
-            CombatUtils.dealDamage(target, Math.max(target.getMaxHealth() / 4, 1)); // Make it so you can shake a mob no more than 4 times.
-            applyXpGain(ExperienceConfig.getInstance().getFishingShakeXP());
         }
+
+        return 0.0;
     }
 
     /**
@@ -616,4 +584,34 @@ public class FishingManager extends SkillManager {
 
         return 0;
     }
+
+    private boolean canShake(Entity target) {
+        return target.isValid() && target instanceof LivingEntity && getSkillLevel() >= Tier.ONE.getLevel() && Permissions.shake(getPlayer()) && getShakeProbability() > Misc.getRandom().nextInt(getActivationChance());
+    }
+
+    private boolean canUseMasterAngler() {
+        return getSkillLevel() >= AdvancedConfig.getInstance().getMasterAnglerUnlockLevel() && Permissions.masterAngler(getPlayer());
+    }
+
+    private boolean canIceFish(Block block) {
+        if (getSkillLevel() < AdvancedConfig.getInstance().getIceFishingUnlockLevel() || block.getType() != Material.ICE) {
+            return false;
+        }
+
+        // Make sure this is a body of water, not just a block of ice.
+        Biome biome = block.getBiome();
+        boolean isFrozenBiome = (biome == Biome.FROZEN_OCEAN || biome == Biome.FROZEN_RIVER || biome == Biome.TAIGA || biome == Biome.TAIGA_HILLS || biome == Biome.ICE_PLAINS || biome == Biome.ICE_MOUNTAINS);
+
+        if (!isFrozenBiome || (block.getRelative(BlockFace.DOWN, 3).getType() != Material.STATIONARY_WATER)) {
+            return false;
+        }
+
+        Player player = getPlayer();
+
+        if (!Permissions.iceFishing(player)) {
+            return false;
+        }
+
+        return EventUtils.simulateBlockBreak(block, player, false);
+    }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/util/Misc.java

@@ -174,7 +174,7 @@ public final class Misc {
      * @param itemStack The item to drop
      */
     public static void dropItem(Location location, ItemStack itemStack) {
-        if (itemStack.getType() == Material.AIR) {
+        if (itemStack == null || itemStack.getType() == Material.AIR) {
             return;
         }