package net.aufdemrand.denizen.npc.traits; import net.aufdemrand.denizen.nms.NMSHandler; import net.aufdemrand.denizen.nms.interfaces.FishingHelper; import net.aufdemrand.denizen.utilities.DenizenAPI; import net.aufdemrand.denizen.utilities.debugging.dB; import net.aufdemrand.denizencore.utilities.CoreUtilities; import net.citizensnpcs.api.persistence.Persist; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.util.PlayerAnimation; import org.bukkit.Location; import org.bukkit.entity.FishHook; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import java.util.ArrayList; public class FishingTrait extends Trait { @Persist("fishing") private boolean fishing = false; @Persist("catch type") private FishingHelper.CatchType catchType = FishingHelper.CatchType.NONE; @Persist("fishing spot") private Location fishingLocation = null; ArrayList<Location> available = new ArrayList<Location>(); Location fishingSpot = null; FishHook fishHook = null; Item fish = null; @Persist("catch chance") int catchPercent = 65; int reelCount = 100; int castCount = 0; @Override public void run() { reelCount++; castCount++; if (fish != null) { if (fish.getLocation().distance(npc.getEntity().getLocation()) < 3) { try { fish.remove(); } catch (Exception e) { } } } if (!fishing) { return; } if (reelCount == 400) { reel(); reelCount = 0; castCount = 325; } if (castCount == 400) { cast(); castCount = 0; } } // <--[action] // @Actions // start fishing // // @Triggers when the NPC starts fishing. // // @Context // None // // --> /** * Makes the NPC fish at the specified location * <p/> * TODO Reimplement variance, so each cast doesn't land in the exact same spot. * * @param location the location to fish at */ public void startFishing(Location location) { DenizenAPI.getDenizenNPC(npc).action("start fishing", null); fishingLocation = location.clone(); cast(); fishing = true; } // <--[action] // @Actions // stop fishing // // @Triggers when the NPC stops fishing. // // @Context // None // // --> /** * Makes the stop fishing. */ public void stopFishing() { DenizenAPI.getDenizenNPC(npc).action("stop fishing", null); reel(); reelCount = 100; castCount = 0; fishingLocation = null; fishing = false; } /** * Makes the NPC fish in the nearest water * <p/> * TODO Needs logic for handling that. */ public void startFishing() { fishing = true; fishingLocation = npc.getEntity().getLocation(); } // <--[action] // @Actions // cast fishing rod // // @Triggers when the NPC casts a fishing rod. // // @Context // None // // --> private void cast() { DenizenAPI.getDenizenNPC(npc).action("cast fishing rod", null); if (fishingLocation == null) { dB.echoError("Fishing location not found!"); return; } double v = 34; double g = 20; Location from = npc.getEntity().getLocation(); from = from.add(0, .33, 0); Location to = fishingLocation; Vector test = to.clone().subtract(from).toVector(); Double elev = test.getY(); Double testAngle = launchAngle(from, to, v, elev, g); if (testAngle == null) { return; } Double hangtime = hangtime(testAngle, v, elev, g); Vector victor = to.clone().subtract(from).toVector(); Double dist = Math.sqrt(Math.pow(victor.getX(), 2) + Math.pow(victor.getZ(), 2)); elev = victor.getY(); if (dist == 0) { return; } Double launchAngle = launchAngle(from, to, v, elev, g); if (launchAngle == null) { return; } victor.setY(Math.tan(launchAngle) * dist); victor = normalizeVector(victor); v = v + (.5 * Math.pow(hangtime, 2)); //Random rand = new Random(1234); v = v + (CoreUtilities.getRandom().nextDouble() - .8) / 2; victor = victor.multiply(v / 20.0); fishHook = NMSHandler.getInstance().getFishingHelper().spawnHook(from, (Player) npc.getEntity()); fishHook.setShooter((ProjectileSource) npc.getEntity()); fishHook.setVelocity(victor); PlayerAnimation.ARM_SWING.play((Player) npc.getEntity()); } // <--[action] // @Actions // reel in fishing rod // // @Triggers when the NPC reels in its fishing rod. // // @Context // None // // --> private void reel() { DenizenAPI.getDenizenNPC(npc).action("reel in fishing rod", null); int chance = (int) (Math.random() * 100); try { fishHook.remove(); } catch (Exception e) { } if (catchPercent > chance && fishHook != null && catchType != FishingHelper.CatchType.NONE) { try { fish.remove(); } catch (Exception e) { } Location location = fishHook.getLocation(); ItemStack result = NMSHandler.getInstance().getFishingHelper().getResult(fishHook, catchType); if (result != null) { fish = location.getWorld().dropItem(location, result); Location npcLocation = npc.getEntity().getLocation(); double d5 = npcLocation.getX() - location.getX(); double d6 = npcLocation.getY() - location.getY(); double d7 = npcLocation.getZ() - location.getZ(); double d8 = Math.sqrt(d5 * d5 + d6 * d6 + d7 * d7); double d9 = 0.1D; fish.setVelocity(new Vector(d5 * d9, d6 * d9 + Math.sqrt(d8) * 0.08D, d7 * d9)); } DenizenAPI.getDenizenNPC(npc).action("catch fish", null); } PlayerAnimation.ARM_SWING.play((Player) npc.getEntity()); } /** * Checks if the NPC is currently fishing * * @return boolean */ public boolean isFishing() { return fishing; } /** * Gets the location the NPC is casting to * Returns null if the NPC isn't fishing * * @return Location */ public Location getFishingLocation() { return fishingLocation; } public FishingTrait() { super("fishing"); } public static Double launchAngle(Location from, Location to, double v, double elev, double g) { Vector victor = from.clone().subtract(to).toVector(); Double dist = Math.sqrt(Math.pow(victor.getX(), 2) + Math.pow(victor.getZ(), 2)); double v2 = Math.pow(v, 2); double v4 = Math.pow(v, 4); double derp = g * (g * Math.pow(dist, 2) + 2 * elev * v2); if (v4 < derp) { return null; } else { return Math.atan((v2 - Math.sqrt(v4 - derp)) / (g * dist)); } } public static double hangtime(double launchAngle, double v, double elev, double g) { double a = v * Math.sin(launchAngle); double b = -2 * g * elev; if (Math.pow(a, 2) + b < 0) { return 0; } return (a + Math.sqrt(Math.pow(a, 2) + b)) / g; } public static Vector normalizeVector(Vector victor) { double mag = Math.sqrt(Math.pow(victor.getX(), 2) + Math.pow(victor.getY(), 2) + Math.pow(victor.getZ(), 2)); if (mag != 0) { return victor.multiply(1 / mag); } return victor.multiply(0); } public void setCatchType(FishingHelper.CatchType catchType) { this.catchType = catchType; } public void setCatchPercent(int catchPercent) { this.catchPercent = catchPercent; } }