Package com.gmail.nossr50.skills.fishing

Source Code of com.gmail.nossr50.skills.fishing.FishingManager

package com.gmail.nossr50.skills.fishing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.WeatherType;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fish;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.Skeleton.SkeletonType;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Wool;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionType;
import org.bukkit.util.Vector;

import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.config.treasure.TreasureConfig;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.SecondaryAbility;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.datatypes.skills.XPGainReason;
import com.gmail.nossr50.datatypes.treasure.EnchantmentTreasure;
import com.gmail.nossr50.datatypes.treasure.FishingTreasure;
import com.gmail.nossr50.datatypes.treasure.Rarity;
import com.gmail.nossr50.datatypes.treasure.ShakeTreasure;
import com.gmail.nossr50.events.skills.fishing.McMMOPlayerFishingTreasureEvent;
import com.gmail.nossr50.events.skills.fishing.McMMOPlayerShakeEvent;
import com.gmail.nossr50.events.skills.secondaryabilities.SecondaryAbilityWeightedActivationCheckEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.runnables.skills.KrakenAttackTask;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.skills.fishing.Fishing.Tier;
import com.gmail.nossr50.util.BlockUtils;
import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.ItemUtils;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillUtils;

public class FishingManager extends SkillManager {
    private final long FISHING_COOLDOWN_SECONDS = 1000L;

    private int fishingTries = 0;
    private long fishingTimestamp = 0L;
    private Location fishingTarget;
    private Item fishingCatch;
    private Location hookLocation;

    public FishingManager(McMMOPlayer mcMMOPlayer) {
        super(mcMMOPlayer, SkillType.FISHING);
    }

    public boolean canShake(Entity target) {
        return target instanceof LivingEntity && getSkillLevel() >= Tier.ONE.getLevel() && Permissions.secondaryAbilityEnabled(getPlayer(), SecondaryAbility.SHAKE);
    }

    public boolean canMasterAngler() {
        return getSkillLevel() >= AdvancedConfig.getInstance().getMasterAnglerUnlockLevel() && Permissions.secondaryAbilityEnabled(getPlayer(), SecondaryAbility.MASTER_ANGLER);
    }

    public boolean unleashTheKraken() {
        return unleashTheKraken(true);
    }

    private boolean unleashTheKraken(boolean forceSpawn) {
        if (!forceSpawn && (fishingTries < AdvancedConfig.getInstance().getKrakenTriesBeforeRelease() || fishingTries <= Misc.getRandom().nextInt(200))) {
            return false;
        }

        Player player = getPlayer();
        World world = player.getWorld();

        player.setPlayerWeather(WeatherType.DOWNFALL);

        Entity vehicle = player.getVehicle();

        if (vehicle != null && vehicle.getType() == EntityType.BOAT) {
            vehicle.eject();
            vehicle.remove();
        }

        player.teleport(player.getTargetBlock(null, 100).getLocation(), TeleportCause.PLUGIN);

        String unleashMessage = AdvancedConfig.getInstance().getPlayerUnleashMessage();

        if (!unleashMessage.isEmpty()) {
            player.sendMessage(unleashMessage);
        }

        Location location = player.getLocation();
        boolean globalEffectsEnabled = AdvancedConfig.getInstance().getKrakenGlobalEffectsEnabled();

        if (globalEffectsEnabled) {
            world.strikeLightningEffect(location);
            world.strikeLightningEffect(location);
            world.strikeLightningEffect(location);

            world.playSound(location, Sound.GHAST_SCREAM, Misc.GHAST_VOLUME, Misc.getGhastPitch());
            mcMMO.p.getServer().broadcastMessage(ChatColor.RED + AdvancedConfig.getInstance().getServerUnleashMessage().replace("(PLAYER)", player.getDisplayName()));
        }
        else {
            world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false);
            world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false);
            world.createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false);

            player.playSound(location, Sound.GHAST_SCREAM, Misc.GHAST_VOLUME, Misc.getGhastPitch());
        }

        if (player.getItemInHand().getType() == Material.FISHING_ROD) {
            player.setItemInHand(null);
        }

        Creature kraken = (Creature) world.spawnEntity(player.getEyeLocation(), (Misc.getRandom().nextInt(100) == 0 ? EntityType.CHICKEN : EntityType.SQUID));
        kraken.setCustomName(AdvancedConfig.getInstance().getKrakenName());

        if (!kraken.isValid()) {
            int attackInterval = AdvancedConfig.getInstance().getKrakenAttackInterval() * Misc.TICK_CONVERSION_FACTOR;
            new KrakenAttackTask(kraken, player, player.getLocation()).runTaskTimer(mcMMO.p, attackInterval, attackInterval);

            if (!forceSpawn) {
                fishingTries = 0;
            }

            return true;
        }

        kraken.setMaxHealth(AdvancedConfig.getInstance().getKrakenHealth());
        kraken.setHealth(kraken.getMaxHealth());

        int attackInterval = AdvancedConfig.getInstance().getKrakenAttackInterval() * Misc.TICK_CONVERSION_FACTOR;
        new KrakenAttackTask(kraken, player).runTaskTimer(mcMMO.p, attackInterval, attackInterval);

        if (!forceSpawn) {
            fishingTries = 0;
        }

        return true;
    }

    public boolean exploitPrevention() {
        if (!AdvancedConfig.getInstance().getKrakenEnabled()) {
            return false;
        }

        Block targetBlock = getPlayer().getTargetBlock(BlockUtils.getTransparentBlocks(), 100);

        if (!targetBlock.isLiquid()) {
            return false;
        }

        long currentTime = System.currentTimeMillis();
        boolean hasFished = (currentTime < fishingTimestamp + FISHING_COOLDOWN_SECONDS);

        fishingTries = hasFished ? fishingTries + 1 : Math.max(fishingTries - 1, 0);
        fishingTimestamp = currentTime;

        Location targetLocation = targetBlock.getLocation();
        boolean sameTarget = (fishingTarget != null && fishingTarget.equals(targetLocation));

        fishingTries = sameTarget ? fishingTries + 1 : Math.max(fishingTries - 1, 0);
        fishingTarget = targetLocation;

        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.
        if (!Fishing.iceFishingBiomes.contains(block.getBiome()) && (block.getRelative(BlockFace.DOWN, 3).getType() != Material.STATIONARY_WATER)) {
            return false;
        }

        Player player = getPlayer();

        if (!Permissions.secondaryAbilityEnabled(getPlayer(), SecondaryAbility.ICE_FISHING)) {
            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
     *
     * @param rankChange     The # of levels to change rank for the food
     * @param eventFoodLevel The initial change in hunger from the event
     *
     * @return the modified change in hunger for the event
     */
    public int handleFishermanDiet(int rankChange, int eventFoodLevel) {
        return SkillUtils.handleFoodSkills(getPlayer(), skill, eventFoodLevel, Fishing.fishermansDietRankLevel1, Fishing.fishermansDietMaxLevel, rankChange);
    }

    public void iceFishing(Fish hook, Block block) {
        // 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);

                if (relative.getType() == Material.ICE) {
                    relative.setType(Material.STATIONARY_WATER);
                }
            }
        }

        // Recast in the new spot
        EventUtils.callFakeFishEvent(getPlayer(), hook);
    }

    public void masterAngler(Fish hook) {
        Player player = getPlayer();
        Location location = hook.getLocation();
        double biteChance = hook.getBiteChance();

        hookLocation = location;

        if (Fishing.masterAnglerBiomes.contains(location.getBlock().getBiome())) {
            biteChance = biteChance * AdvancedConfig.getInstance().getMasterAnglerBiomeModifier();
        }

        if (player.isInsideVehicle() && player.getVehicle().getType() == EntityType.BOAT) {
            biteChance = biteChance * AdvancedConfig.getInstance().getMasterAnglerBoatModifier();
        }

        hook.setBiteChance(Math.min(biteChance, 1.0));
    }

    /**
     * Process the results from a successful fishing trip
     *
     * @param fishingCatch The {@link Item} initially caught
     */
    public void handleFishing(Item fishingCatch) {
        this.fishingCatch = fishingCatch;
        int fishXp = ExperienceConfig.getInstance().getFishXp(fishingCatch.getItemStack().getData());
        int treasureXp = 0;
        Player player = getPlayer();
        FishingTreasure treasure = null;

        if (Config.getInstance().getFishingDropsEnabled() && Permissions.secondaryAbilityEnabled(player, SecondaryAbility.FISHING_TREASURE_HUNTER)) {
            treasure = getFishingTreasure();
            this.fishingCatch = null;
        }

        if (treasure != null) {
            ItemStack treasureDrop = treasure.getDrop().clone(); // Not cloning is bad, m'kay?
            Map<Enchantment, Integer> enchants = new HashMap<Enchantment, Integer>();

            if (Permissions.secondaryAbilityEnabled(player, SecondaryAbility.MAGIC_HUNTER) && ItemUtils.isEnchantable(treasureDrop)) {
                enchants = handleMagicHunter(treasureDrop);
            }

            McMMOPlayerFishingTreasureEvent event = EventUtils.callFishingTreasureEvent(player, treasureDrop, treasure.getXp(), enchants);

            if (!event.isCancelled()) {
                treasureDrop = event.getTreasure();
                treasureXp = event.getXp();
            }
            else {
                treasureDrop = null;
                treasureXp = 0;
            }

            // Drop the original catch at the feet of the player and set the treasure as the real catch
            if (treasureDrop != null) {
                boolean enchanted = false;

                if (!enchants.isEmpty()) {
                    treasureDrop.addUnsafeEnchantments(enchants);
                    enchanted = true;
                }

                if (enchanted) {
                    player.sendMessage(LocaleLoader.getString("Fishing.Ability.TH.MagicFound"));
                }

                if (Config.getInstance().getFishingExtraFish()) {
                    Misc.dropItem(player.getEyeLocation(), fishingCatch.getItemStack());
                }

                fishingCatch.setItemStack(treasureDrop);
            }
        }

        applyXpGain(fishXp + treasureXp, XPGainReason.PVE);
    }

    /**
     * Handle the vanilla XP boost for Fishing
     *
     * @param experience The amount of experience initially awarded by the event
     *
     * @return the modified event damage
     */
    public int handleVanillaXpBoost(int experience) {
        return experience * getVanillaXpMultiplier();
    }

    public Location getHookLocation() {
        return hookLocation;
    }

    /**
     * Handle the Shake ability
     *
     * @param target The {@link LivingEntity} affected by the ability
     */
    public void shakeCheck(LivingEntity target) {
        fishingTries--; // Because autoclicking to shake is OK.

        SecondaryAbilityWeightedActivationCheckEvent activationEvent = new SecondaryAbilityWeightedActivationCheckEvent(getPlayer(), SecondaryAbility.SHAKE, getShakeProbability() / activationChance);
        mcMMO.p.getServer().getPluginManager().callEvent(activationEvent);
        if ((activationEvent.getChance() * activationChance) > Misc.getRandom().nextInt(activationChance)) {
            List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);

            if (possibleDrops == null || possibleDrops.isEmpty()) {
                return;
            }

            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;
            }

            // Extra processing depending on the mob and drop type
            switch (target.getType()) {
                case SHEEP:
                    Sheep sheep = (Sheep) target;

                    if (drop.getType() == Material.WOOL) {
                        if (sheep.isSheared()) {
                            return;
                        }

                        drop = new Wool(sheep.getColor()).toItemStack(drop.getAmount());
                        sheep.setSheared(true);
                    }
                    break;

                case SKELETON:
                    if (((Skeleton) target).getSkeletonType() == SkeletonType.WITHER) {
                        switch (drop.getType()) {
                            case SKULL_ITEM:
                                drop.setDurability((short) 1);
                                break;

                            case ARROW:
                                drop.setType(Material.COAL);
                                break;

                            default:
                                break;
                        }
                    }
                    break;

                default:
                    break;
            }

            McMMOPlayerShakeEvent shakeEvent = new McMMOPlayerShakeEvent(getPlayer(), drop);

            drop = shakeEvent.getDrop();

            if (shakeEvent.isCancelled() || drop == null) {
                return;
            }

            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(), XPGainReason.PVE);
        }
    }

    /**
     * Process the Treasure Hunter ability for Fishing
     *
     * @return The {@link FishingTreasure} found, or null if no treasure was found.
     */
    private FishingTreasure getFishingTreasure() {
        double diceRoll = Misc.getRandom().nextDouble() * 100;
        diceRoll -= getPlayer().getItemInHand().getEnchantmentLevel(Enchantment.LUCK);

        FishingTreasure treasure = null;

        for (Rarity rarity : Rarity.values()) {
            double dropRate = TreasureConfig.getInstance().getItemDropRate(getLootTier(), rarity);

            if (diceRoll <= dropRate) {
                if (rarity == Rarity.TRAP) {
                    handleTraps();
                    break;
                }

                List<FishingTreasure> fishingTreasures = TreasureConfig.getInstance().fishingRewards.get(rarity);

                if (fishingTreasures.isEmpty()) {
                    return null;
                }

                treasure = fishingTreasures.get(Misc.getRandom().nextInt(fishingTreasures.size()));
                break;
            }

            diceRoll -= dropRate;
        }

        if (treasure == null) {
            return null;
        }

        ItemStack treasureDrop = treasure.getDrop().clone();
        short maxDurability = treasureDrop.getType().getMaxDurability();

        if (maxDurability > 0) {
            treasureDrop.setDurability((short) (Misc.getRandom().nextInt(maxDurability)));
        }

        if (treasureDrop.getAmount() > 1) {
            treasureDrop.setAmount(Misc.getRandom().nextInt(treasureDrop.getAmount()) + 1);
        }

        treasure.setDrop(treasureDrop);

        return treasure;
    }

    private void handleTraps() {
        Player player = getPlayer();

        if (Permissions.trapsBypass(player)) {
            return;
        }

        if (Misc.getRandom().nextBoolean()) {
            player.sendMessage(LocaleLoader.getString("Fishing.Ability.TH.Boom"));

            TNTPrimed tnt = (TNTPrimed) player.getWorld().spawnEntity(fishingCatch.getLocation(), EntityType.PRIMED_TNT);
            fishingCatch.setPassenger(tnt);

            Vector velocity = fishingCatch.getVelocity();
            double magnitude = velocity.length();
            fishingCatch.setVelocity(velocity.multiply((magnitude + 1) / magnitude));

            tnt.setMetadata(mcMMO.tntsafeMetadataKey, mcMMO.metadataValue);
            tnt.setFuseTicks(3 * Misc.TICK_CONVERSION_FACTOR);
        }
        else {
            player.sendMessage(LocaleLoader.getString("Fishing.Ability.TH.Poison"));

            ThrownPotion thrownPotion = player.getWorld().spawn(fishingCatch.getLocation(), ThrownPotion.class);
            thrownPotion.setItem(new Potion(PotionType.POISON).splash().toItemStack(1));

            fishingCatch.setPassenger(thrownPotion);
        }
    }

    /**
     * Process the Magic Hunter ability
     *
     * @param treasureDrop The {@link ItemStack} to enchant
     *
     * @return true if the item has been enchanted
     */
    private Map<Enchantment, Integer> handleMagicHunter(ItemStack treasureDrop) {
        Map<Enchantment, Integer> enchants = new HashMap<Enchantment, Integer>();
        List<EnchantmentTreasure> fishingEnchantments = null;

        double diceRoll = Misc.getRandom().nextDouble() * 100;

        for (Rarity rarity : Rarity.values()) {
            if (rarity == Rarity.TRAP || rarity == Rarity.RECORD) {
                continue;
            }

            double dropRate = TreasureConfig.getInstance().getEnchantmentDropRate(getLootTier(), rarity);

            if (diceRoll <= dropRate) {
                fishingEnchantments = TreasureConfig.getInstance().fishingEnchantments.get(rarity);
                break;
            }

            diceRoll -= dropRate;
        }

        if (fishingEnchantments == null) {
            return enchants;
        }

        List<Enchantment> validEnchantments = getPossibleEnchantments(treasureDrop);
        List<EnchantmentTreasure> possibleEnchants = new ArrayList<EnchantmentTreasure>();

        for (EnchantmentTreasure enchantmentTreasure : fishingEnchantments) {
            if (validEnchantments.contains(enchantmentTreasure.getEnchantment())) {
                possibleEnchants.add(enchantmentTreasure);
            }
        }

        if (possibleEnchants.isEmpty()) {
            return enchants;
        }

        // This make sure that the order isn't always the same, for example previously Unbreaking had a lot more chance to be used than any other enchant
        Collections.shuffle(possibleEnchants, Misc.getRandom());

        int specificChance = 1;

        for (EnchantmentTreasure enchantmentTreasure : possibleEnchants) {
            Enchantment possibleEnchantment = enchantmentTreasure.getEnchantment();

            if (treasureDrop.getItemMeta().hasConflictingEnchant(possibleEnchantment) || Misc.getRandom().nextInt(specificChance) != 0) {
                continue;
            }

            enchants.put(possibleEnchantment, enchantmentTreasure.getLevel());

            specificChance *= 2;
        }

        return enchants;
    }

    private List<Enchantment> getPossibleEnchantments(ItemStack treasureDrop) {
        Material dropType = treasureDrop.getType();

        if (Fishing.ENCHANTABLE_CACHE.containsKey(dropType)) {
            return Fishing.ENCHANTABLE_CACHE.get(dropType);
        }

        List<Enchantment> possibleEnchantments = new ArrayList<Enchantment>();

        for (Enchantment enchantment : Enchantment.values()) {
            if (enchantment.canEnchantItem(treasureDrop)) {
                possibleEnchantments.add(enchantment);
            }
        }

        Fishing.ENCHANTABLE_CACHE.put(dropType, possibleEnchantments);
        return possibleEnchantments;
    }

    /**
     * Gets the vanilla XP multiplier
     *
     * @return the vanilla XP multiplier
     */
    private int getVanillaXpMultiplier() {
        int skillLevel = getSkillLevel();

        for (Tier tier : Tier.values()) {
            if (skillLevel >= tier.getLevel()) {
                return tier.getVanillaXPBoostModifier();
            }
        }

        return 0;
    }
}
TOP

Related Classes of com.gmail.nossr50.skills.fishing.FishingManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.