diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/BlightedSMP.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/BlightedSMP.java index 2630c6a8..08f138b1 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/BlightedSMP.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/BlightedSMP.java @@ -1,8 +1,7 @@ package fr.moussax.blightedSMP; import fr.moussax.blightedSMP.engine.entities.spawnable.engine.BlightedSpawnEngine; -import fr.moussax.blightedSMP.engine.fishing.hooks.LavaFishingHook; -import fr.moussax.blightedSMP.engine.fishing.hooks.VoidFishingHook; +import fr.moussax.blightedSMP.engine.fishing.hooks.CustomFishingHook; import fr.moussax.blightedSMP.registry.CommandsRegistry; import fr.moussax.blightedSMP.registry.EventsRegistry; import fr.moussax.blightedSMP.registry.RegistrySystem; @@ -70,8 +69,7 @@ public void onEnable() { @Override public void onDisable() { - LavaFishingHook.cleanupAll(); - VoidFishingHook.cleanupAll(); + CustomFishingHook.cleanupAll(); if (database != null) { database.closeConnection(); } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/EndFishing.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/EndFishing.java index 2d486752..ac52125b 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/EndFishing.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/EndFishing.java @@ -1,9 +1,9 @@ package fr.moussax.blightedSMP.content.fishing; import fr.moussax.blightedSMP.engine.fishing.FishingLootTable; -import fr.moussax.blightedSMP.registry.RegistryModule; -import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.fishing.FishingMethod; +import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; +import fr.moussax.blightedSMP.registry.RegistryModule; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.EntityType; @@ -19,12 +19,12 @@ public void register(FishingRegistryHandler registry) { public FishingLootTable provide() { return FishingLootTable.builder() - .setEntityRollChance(0.20) - .addVanillaEntity(EntityType.ENDERMITE, 3.0, GOOD_CATCH, "§b§lYUCK! §7You caught an §5Endermite§7!") - .addVanillaEntity(EntityType.SHULKER, 0.8, OUTSTANDING_CATCH, "§d§lRARE CATCH! §7You caught a §5Shulker§7!") - .addItem(Material.END_STONE, 3, 50.0, COMMON) - .addItem(Material.CHORUS_FRUIT, 2, 40.0, GOOD_CATCH) - .addItem(Material.ENDER_PEARL, 1, 10.0, GREAT_CATCH) + .entityRollChance(0.20) + .entity(EntityType.ENDERMITE, 3.0, GOOD_CATCH, "§b§lYUCK! §7You caught an §5Endermite§7!") + .entity(EntityType.SHULKER, 0.8, OUTSTANDING_CATCH, "§d§lRARE CATCH! §7You caught a §5Shulker§7!") + .item(Material.END_STONE, 3, 50.0, COMMON) + .item(Material.CHORUS_FRUIT, 2, 40.0, GOOD_CATCH) + .item(Material.ENDER_PEARL, 1, 10.0, GREAT_CATCH) .build(); } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/NetherFishing.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/NetherFishing.java index c74b91c3..4eb29921 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/NetherFishing.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/NetherFishing.java @@ -1,12 +1,10 @@ package fr.moussax.blightedSMP.content.fishing; import fr.moussax.blightedSMP.engine.fishing.FishingLootTable; -import fr.moussax.blightedSMP.registry.RegistryModule; -import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.fishing.FishingMethod; +import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.loot.LootCondition; -import fr.moussax.blightedSMP.engine.loot.results.ItemResult; -import fr.moussax.blightedSMP.engine.loot.results.gems.GemsResult; +import fr.moussax.blightedSMP.registry.RegistryModule; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; @@ -32,55 +30,58 @@ public void register(FishingRegistryHandler registry) { public FishingLootTable provide() { return FishingLootTable.builder() - .setEntityRollChance(0.15) - .addVanillaEntity(EntityType.MAGMA_CUBE, 2.0, GREAT_CATCH) - .addVanillaEntity(EntityType.GHAST, 20.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addVanillaEntity(EntityType.HOGLIN, 30.0, GREAT_CATCH, LootCondition.biome(Biome.CRIMSON_FOREST)) - .addVanillaEntity(EntityType.ENDERMAN, 30.0, GREAT_CATCH, LootCondition.biome(Biome.WARPED_FOREST)) - .addVanillaEntity(EntityType.SKELETON, 30.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.ROTTEN_FLESH, 2, 6, 120.0, COMMON) - .addItem(Material.QUARTZ, 4, 12, 110.0, COMMON) - .addItem(Material.MUSHROOM_STEW, 1, 110.0, COMMON) - .addItem(Material.GLOWSTONE_DUST, 4, 12, 110.0, COMMON) - .addItem(Material.COAL, 3, 8, 100.0, COMMON) - .addItem(Material.GOLD_NUGGET, 5, 15, 100.0, COMMON) - .addItem(Material.IRON_NUGGET, 3, 9, 100.0, COMMON) - .addItem(Material.COOKED_CHICKEN, 2, 6, 100.0, COMMON) - .addItem(Material.COOKED_PORKCHOP, 2, 6, 100.0, COMMON) - .addItem(Material.BAKED_POTATO, 3, 8, 90.0, COMMON) - .addItem(Material.STRING, 1, 4, 80.0, COMMON) - .addItem(Material.LEATHER, 1, 3, 80.0, COMMON) - .addItem("SULFUR", 2, 4, 60.0, COMMON) - .addItem(new GemsResult(), 2, 5, 60.0, GOOD_CATCH) - .addItem(Material.EXPERIENCE_BOTTLE, 3, 8, 55.0, GOOD_CATCH) - .addItem(Material.GOLD_INGOT, 2, 5, 55.0, GOOD_CATCH) - .addItem("ENCHANTED_QUARTZ", 1, 3, 50.0, GOOD_CATCH) - .addItem("ENCHANTED_GLOWSTONE_DUST", 1, 3, 50.0, GOOD_CATCH) - .addItem(Material.GOLDEN_CARROT, 3, 8, 50.0, GOOD_CATCH) - .addItem(Material.OBSIDIAN, 2, 4, 45.0, GOOD_CATCH) - .addItem(Material.BLAZE_ROD, 1, 3, 45.0, GOOD_CATCH) - .addItem(Material.SPECTRAL_ARROW, 8, 16, 40.0, GOOD_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.GILDED_BLACKSTONE, 1, 4, 40.0, GOOD_CATCH, LootCondition.biome(Biome.BASALT_DELTAS)) - .addItem("CREME_BRULEE", 1, 2, 40.0, GOOD_CATCH) - .addItem(ItemResult.randomDurability(Material.CROSSBOW, 0.10, 0.80), 1, 35.0, GOOD_CATCH) - .addItem(ItemResult.randomDurability(Material.GOLDEN_HELMET, 0.20, 0.75), 1, 35.0, GOOD_CATCH) - .addItem("FLAMES", 1, 35.0, GOOD_CATCH) - .addItem(ItemResult.of(Material.SUSPICIOUS_STEW, b -> - b.setItemMeta(meta -> ((SuspiciousStewMeta) meta).addCustomEffect( - new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 200, 0), false) - ) - ), 1, 35.0, GOOD_CATCH) - .addItem(Material.WARPED_FUNGUS_ON_A_STICK, 1, 30.0, GOOD_CATCH, LootCondition.biome(Biome.WARPED_FOREST)) - .addItem(Material.SOUL_SAND, 1, 2, 30.0, GOOD_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.ENDER_PEARL, 1, 2, 30.0, GOOD_CATCH) - .addItem(new GemsResult(), 6, 10, 30.0, GREAT_CATCH) - .addItem(Material.GOLDEN_APPLE, 1, 2, 25.0, GREAT_CATCH) - .addItem(Material.CRYING_OBSIDIAN, 1, 3, 25.0, GREAT_CATCH) - .addItem(Material.GHAST_TEAR, 1, 3, 25.0, GREAT_CATCH) - .addItem(ItemResult.of(Material.POTION, b -> b.setItemMeta(meta -> + .entityRollChance(0.15) + .entity(EntityType.MAGMA_CUBE, 2.0, GREAT_CATCH) + .entity(EntityType.GHAST, 20.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .entity(EntityType.HOGLIN, 30.0, GREAT_CATCH, LootCondition.biome(Biome.CRIMSON_FOREST)) + .entity(EntityType.ENDERMAN, 30.0, GREAT_CATCH, LootCondition.biome(Biome.WARPED_FOREST)) + .entity(EntityType.SKELETON, 30.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.ROTTEN_FLESH, 2, 6, 120.0, COMMON) + .item(Material.QUARTZ, 4, 12, 110.0, COMMON) + .item(Material.MUSHROOM_STEW, 1, 110.0, COMMON) + .item(Material.GLOWSTONE_DUST, 4, 12, 110.0, COMMON) + .item(Material.COAL, 3, 8, 100.0, COMMON) + .item(Material.GOLD_NUGGET, 5, 15, 100.0, COMMON) + .item(Material.IRON_NUGGET, 3, 9, 100.0, COMMON) + .item(Material.COOKED_CHICKEN, 2, 6, 100.0, COMMON) + .item(Material.COOKED_PORKCHOP, 2, 6, 100.0, COMMON) + .item(Material.BAKED_POTATO, 3, 8, 90.0, COMMON) + .item(Material.STRING, 1, 4, 80.0, COMMON) + .item(Material.LEATHER, 1, 3, 80.0, COMMON) + .item("SULFUR", 2, 4, 60.0, COMMON) + .gems(2, 5, 60.0, GOOD_CATCH) + .item(Material.EXPERIENCE_BOTTLE, 3, 8, 55.0, GOOD_CATCH) + .item(Material.GOLD_INGOT, 2, 5, 55.0, GOOD_CATCH) + .item("ENCHANTED_QUARTZ", 1, 3, 50.0, GOOD_CATCH) + .item("ENCHANTED_GLOWSTONE_DUST", 1, 3, 50.0, GOOD_CATCH) + .item(Material.GOLDEN_CARROT, 3, 8, 50.0, GOOD_CATCH) + .item(Material.OBSIDIAN, 2, 4, 45.0, GOOD_CATCH) + .item(Material.BLAZE_ROD, 1, 3, 45.0, GOOD_CATCH) + .item(Material.SPECTRAL_ARROW, 8, 16, 40.0, GOOD_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.GILDED_BLACKSTONE, 1, 4, 40.0, GOOD_CATCH, LootCondition.biome(Biome.BASALT_DELTAS)) + .item("CREME_BRULEE", 1, 2, 40.0, GOOD_CATCH) + .damagedItem(Material.CROSSBOW, 0.10, 0.80, 35.0, GOOD_CATCH) + .damagedItem(Material.GOLDEN_HELMET, 0.20, 0.75, 35.0, GOOD_CATCH) + .item("FLAMES", 1, 35.0, GOOD_CATCH) + .item(Material.SUSPICIOUS_STEW, b -> + b.setItemMeta(meta -> ((SuspiciousStewMeta) meta).addCustomEffect( + new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 200, 0), false) + ), + 1, + 35.0, + GOOD_CATCH + ) + .item(Material.WARPED_FUNGUS_ON_A_STICK, 1, 30.0, GOOD_CATCH, LootCondition.biome(Biome.WARPED_FOREST)) + .item(Material.SOUL_SAND, 1, 2, 30.0, GOOD_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.ENDER_PEARL, 1, 2, 30.0, GOOD_CATCH) + .gems(6, 10, 30.0, GREAT_CATCH) + .item(Material.GOLDEN_APPLE, 1, 2, 25.0, GREAT_CATCH) + .item(Material.CRYING_OBSIDIAN, 1, 3, 25.0, GREAT_CATCH) + .item(Material.GHAST_TEAR, 1, 3, 25.0, GREAT_CATCH) + .item(Material.POTION, b -> b.setItemMeta(meta -> ((PotionMeta) meta).setBasePotionType(PotionType.LONG_FIRE_RESISTANCE) - )), 1, 20.0, GREAT_CATCH) - .addItem(ItemResult.randomEnchantedBook( + ), 1, 20.0, GREAT_CATCH) + .enchantedBook( List.of( Enchantment.SMITE, Enchantment.PROTECTION, @@ -89,27 +90,29 @@ public FishingLootTable provide() { Enchantment.FEATHER_FALLING ), 3, - 5 - ), 1, 20.0, GREAT_CATCH) - .addItem(Material.SKELETON_SKULL, 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.DRIED_GHAST, 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem("SUSPICIOUS_FUNGUS", 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.RESPAWN_ANCHOR, 1, 15.0, GREAT_CATCH) - .addItem(Material.PIGLIN_HEAD, 1, 15.0, GREAT_CATCH) - .addItem(Material.NETHERITE_SCRAP, 1, 2, 15.0, GREAT_CATCH) - .addItem(Material.ANCIENT_DEBRIS, 1, 10.0, GREAT_CATCH) - .addItem(new GemsResult(), 12, 16, 10.0, OUTSTANDING_CATCH) - .addItem("FLAMES", 8, 16, 8.0, OUTSTANDING_CATCH) - .addItem(Material.MUSIC_DISC_PIGSTEP, 1, 5.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.CRIMSON_FOREST)) - .addItem(Material.MUSIC_DISC_TEARS, 1, 5.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) - .addItem(Material.SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) - .addItem(Material.WITHER_SKELETON_SKULL, 1, 3.0, OUTSTANDING_CATCH) - .addItem(ItemResult.of(Material.OMINOUS_BOTTLE, b -> b.setItemMeta( + 5, + 20.0, + GREAT_CATCH + ) + .item(Material.SKELETON_SKULL, 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.DRIED_GHAST, 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item("SUSPICIOUS_FUNGUS", 1, 15.0, GREAT_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.RESPAWN_ANCHOR, 1, 15.0, GREAT_CATCH) + .item(Material.PIGLIN_HEAD, 1, 15.0, GREAT_CATCH) + .item(Material.NETHERITE_SCRAP, 1, 2, 15.0, GREAT_CATCH) + .item(Material.ANCIENT_DEBRIS, 1, 10.0, GREAT_CATCH) + .gems(12, 16, 10.0, OUTSTANDING_CATCH) + .item("FLAMES", 8, 16, 8.0, OUTSTANDING_CATCH) + .item(Material.MUSIC_DISC_PIGSTEP, 1, 5.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.CRIMSON_FOREST)) + .item(Material.MUSIC_DISC_TEARS, 1, 5.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.SOUL_SAND_VALLEY)) + .item(Material.SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) + .item(Material.WITHER_SKELETON_SKULL, 1, 3.0, OUTSTANDING_CATCH) + .item(Material.OMINOUS_BOTTLE, b -> b.setItemMeta( meta -> ((OminousBottleMeta) meta).setAmplifier(4) - )), 1, 3.0, OUTSTANDING_CATCH) - .addItem("VENGEFUL_EYE", 1, 2.0, OUTSTANDING_CATCH) - .addItem(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) - .addItem(Material.NETHERITE_UPGRADE_SMITHING_TEMPLATE, 1, 1.0, OUTSTANDING_CATCH) + ), 1, 3.0, OUTSTANDING_CATCH) + .item("VENGEFUL_EYE", 1, 2.0, OUTSTANDING_CATCH) + .item(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) + .item(Material.NETHERITE_UPGRADE_SMITHING_TEMPLATE, 1, 1.0, OUTSTANDING_CATCH) .build(); } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldFishing.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldFishing.java index 4bd476bb..34b806f4 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldFishing.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldFishing.java @@ -1,12 +1,10 @@ package fr.moussax.blightedSMP.content.fishing; import fr.moussax.blightedSMP.engine.fishing.FishingLootTable; -import fr.moussax.blightedSMP.registry.RegistryModule; -import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.fishing.FishingMethod; +import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.loot.LootCondition; -import fr.moussax.blightedSMP.engine.loot.results.ItemResult; -import fr.moussax.blightedSMP.engine.loot.results.gems.GemsResult; +import fr.moussax.blightedSMP.registry.RegistryModule; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; @@ -46,48 +44,47 @@ public FishingLootTable provide() { context.biome() == Biome.DEEP_FROZEN_OCEAN; return FishingLootTable.builder() - .setEntityRollChance(0.15) - // TODO : Finish the fishing mods - .addVanillaEntity(EntityType.SQUID, 8.0, COMMON, "§b§lSPLASH! §7You caught a §9Squid§7!") - .addVanillaEntity(EntityType.SALMON, 5.0, GOOD_CATCH, "§e§lNICE! §7You caught a §6Salmon§7!") - .addVanillaEntityWithSound(EntityType.TROPICAL_FISH, 4.0, GOOD_CATCH, "§d§lCOLORFUL! §7You caught a §bTropical Fish§7!", LootCondition.biome(Biome.WARM_OCEAN)) - .addVanillaEntity(EntityType.PUFFERFISH, 2.0, GREAT_CATCH, "§e§lCAREFUL! §7You caught a §ePufferfish§7!") - .addVanillaEntity(EntityType.DOLPHIN, 0.5, OUTSTANDING_CATCH, "§b§lAMAZING! §7You caught a §9Dolphin§7!") - - .addItem(ItemResult.of(Material.STONE_BUTTON, builder -> builder.setItemName("Pebble")), 2, 8, 120.0, COMMON) - .addItem(Material.STICK, 2, 6, 110.0, COMMON) - .addItem(Material.LILY_PAD, 2, 6, 105.0, COMMON) - .addItem(Material.KELP, 2, 8, 100.0, COMMON) - .addItem(Material.STRING, 1, 4, 90.0, COMMON) - .addItem(Material.HANGING_ROOTS, 1, 3, 75.0, COMMON) - .addItem(Material.CLAY_BALL, 2, 8, 70.0, COMMON) - .addItem(Material.FLINT, 1, 3, 60.0, COMMON) - .addItem(Material.LEATHER, 1, 3, 55.0, COMMON) - .addItem(Material.ROTTEN_FLESH, 1, 3, 45.0, COMMON) - .addItem(Material.BOWL, 1, 2, 35.0, COMMON) - - .addItem("ENCHANTED_COD", 1, 2, 65.0, GOOD_CATCH) - .addItem("ENCHANTED_SALMON", 1, 2, 60.0, GOOD_CATCH) - .addItem(new GemsResult(), 2, 5, 60.0, GOOD_CATCH) - .addItem("BLIGHTED_ALGAE", 1, 3, 45.0, GOOD_CATCH) - .addItem("SMOKED_SALMON_PLATE", 1, 2, 45.0, GOOD_CATCH) - .addItem("SALTED_COD", 1, 2, 45.0, GOOD_CATCH) - .addItem(Material.NAUTILUS_SHELL, 1, 40.0, GOOD_CATCH) - .addItem(Material.INK_SAC, 1, 3, 35.0, GOOD_CATCH) - .addItem(Material.GLOW_INK_SAC, 1, 2, 30.0, GOOD_CATCH) - .addItem(Material.PRISMARINE_SHARD, 1, 4, 30.0, GOOD_CATCH) - .addItem("FISHERMANS_BAIT", 1, 2, 20.0, GOOD_CATCH) - .addItem("FISHERMANS_STEW", 1, 20.0, GOOD_CATCH) - - .addItem(new GemsResult(), 6, 10, 30.0, GREAT_CATCH) - .addItem("BARNACLE_CLUSTER", 1, 3, 35.0, GREAT_CATCH) - .addItem("CORAL_FRAGMENT", 1, 4, 30.0, GREAT_CATCH) - .addItem(Material.SPONGE, 1, 2, 20.0, GREAT_CATCH) - .addItem(Material.HEART_OF_THE_SEA, 1, 15.0, GREAT_CATCH) - .addItem("MESSAGE_IN_A_BOTTLE", 1, 15.0, GREAT_CATCH) - .addItem(Material.FILLED_MAP, 1, 12.0, GREAT_CATCH) - .addItem(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 8.0, GREAT_CATCH) - .addItem(ItemResult.randomEnchantedBook( + .entityRollChance(0.15) + .entity(EntityType.SQUID, 8.0, COMMON, "§b§lSPLASH! §7You caught a §9Squid§7!") + .entity(EntityType.SALMON, 5.0, GOOD_CATCH, "§e§lNICE! §7You caught a §6Salmon§7!") + .entity(EntityType.TROPICAL_FISH, 4.0, GOOD_CATCH, "§d§lCOLORFUL! §7You caught a §bTropical Fish§7!", true, LootCondition.biome(Biome.WARM_OCEAN)) + .entity(EntityType.PUFFERFISH, 2.0, GREAT_CATCH, "§e§lCAREFUL! §7You caught a §ePufferfish§7!") + .entity(EntityType.DOLPHIN, 0.5, OUTSTANDING_CATCH, "§b§lAMAZING! §7You caught a §9Dolphin§7!") + + .item(Material.STONE_BUTTON, builder -> builder.setItemName("Pebble"), 2, 8, 120.0, COMMON) + .item(Material.STICK, 2, 6, 110.0, COMMON) + .item(Material.LILY_PAD, 2, 6, 105.0, COMMON) + .item(Material.KELP, 2, 8, 100.0, COMMON) + .item(Material.STRING, 1, 4, 90.0, COMMON) + .item(Material.HANGING_ROOTS, 1, 3, 75.0, COMMON) + .item(Material.CLAY_BALL, 2, 8, 70.0, COMMON) + .item(Material.FLINT, 1, 3, 60.0, COMMON) + .item(Material.LEATHER, 1, 3, 55.0, COMMON) + .item(Material.ROTTEN_FLESH, 1, 3, 45.0, COMMON) + .item(Material.BOWL, 1, 2, 35.0, COMMON) + + .item("ENCHANTED_COD", 1, 2, 65.0, GOOD_CATCH) + .item("ENCHANTED_SALMON", 1, 2, 60.0, GOOD_CATCH) + .gems(2, 5, 60.0, GOOD_CATCH) + .item("BLIGHTED_ALGAE", 1, 3, 45.0, GOOD_CATCH) + .item("SMOKED_SALMON_PLATE", 1, 2, 45.0, GOOD_CATCH) + .item("SALTED_COD", 1, 2, 45.0, GOOD_CATCH) + .item(Material.NAUTILUS_SHELL, 1, 40.0, GOOD_CATCH) + .item(Material.INK_SAC, 1, 3, 35.0, GOOD_CATCH) + .item(Material.GLOW_INK_SAC, 1, 2, 30.0, GOOD_CATCH) + .item(Material.PRISMARINE_SHARD, 1, 4, 30.0, GOOD_CATCH) + .item("FISHERMANS_BAIT", 1, 2, 20.0, GOOD_CATCH) + .item("FISHERMANS_STEW", 1, 20.0, GOOD_CATCH) + + .gems(6, 10, 30.0, GREAT_CATCH) + .item("BARNACLE_CLUSTER", 1, 3, 35.0, GREAT_CATCH) + .item("CORAL_FRAGMENT", 1, 4, 30.0, GREAT_CATCH) + .item(Material.SPONGE, 1, 2, 20.0, GREAT_CATCH) + .item(Material.HEART_OF_THE_SEA, 1, 15.0, GREAT_CATCH) + .item("MESSAGE_IN_A_BOTTLE", 1, 15.0, GREAT_CATCH) + .item(Material.FILLED_MAP, 1, 12.0, GREAT_CATCH) + .item(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 8.0, GREAT_CATCH) + .enchantedBook( List.of( Enchantment.UNBREAKING, Enchantment.EFFICIENCY, @@ -96,42 +93,46 @@ public FishingLootTable provide() { Enchantment.AQUA_AFFINITY ), 1, - 3 - ), 1, 10.0, GREAT_CATCH) - .addItem("BLIGHTED_SUSHI", 1, 8.0, GREAT_CATCH) - - .addItem(new GemsResult(), 12, 16, 10.0, OUTSTANDING_CATCH) - .addItem("ABYSSAL_PEARL", 1, 5.0, OUTSTANDING_CATCH) - .addItem(ItemResult.randomEnchantedBook( + 3, + 10.0, + GREAT_CATCH + ) + .item("BLIGHTED_SUSHI", 1, 8.0, GREAT_CATCH) + + .gems(12, 16, 10.0, OUTSTANDING_CATCH) + .item("ABYSSAL_PEARL", 1, 5.0, OUTSTANDING_CATCH) + .enchantedBook( List.of( Enchantment.LUCK_OF_THE_SEA, Enchantment.LURE ), 4, - 5 - ), 1, 6.0, OUTSTANDING_CATCH) - .addItem("DROWNED_RESEARCH_CODEX", 1, 3.0, OUTSTANDING_CATCH) - .addItem(Material.TIDE_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) - .addItem(Material.TRIDENT, 1, 2.0, OUTSTANDING_CATCH) - .addItem(Material.MUSIC_DISC_13, 1, 2.0, OUTSTANDING_CATCH) - .addItem(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) - - - .addItem(Material.ICE, 3, 10, 90.0, COMMON, inFrozenWater) - .addItem(Material.SNOWBALL, 4, 16, 60.0, COMMON, inFrozenWater) - .addItem(Material.PACKED_ICE, 1, 3, 25.0, GOOD_CATCH, inFrozenWater) - .addItem(Material.BLUE_ICE, 1, 5.0, GREAT_CATCH, inFrozenWater) - - .addItem(Material.VINE, 2, 8, 70.0, COMMON, inSwamp) - .addItem(Material.SLIME_BALL, 1, 3, 45.0, GOOD_CATCH, inSwamp) - .addItem(Material.POISONOUS_POTATO, 1, 10.0, GREAT_CATCH, inSwamp) - - .addItem(Material.BAMBOO, 2, 8, 70.0, COMMON, inJungle) - .addItem(Material.COCOA_BEANS, 2, 6, 50.0, COMMON, inJungle) - .addItem(Material.TROPICAL_FISH_BUCKET, 1, 3.0, GREAT_CATCH, inJungle) - - .addItem(Material.PRISMARINE_CRYSTALS, 2, 6, 30.0, GREAT_CATCH, inDeepOcean) - .addItem(Material.SPONGE, 1, 2, 15.0, GREAT_CATCH, inDeepOcean) + 5, + 6.0, + OUTSTANDING_CATCH + ) + .item("DROWNED_RESEARCH_CODEX", 1, 3.0, OUTSTANDING_CATCH) + .item(Material.TIDE_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) + .item(Material.TRIDENT, 1, 2.0, OUTSTANDING_CATCH) + .item(Material.MUSIC_DISC_13, 1, 2.0, OUTSTANDING_CATCH) + .item(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) + + + .item(Material.ICE, 3, 10, 90.0, COMMON, inFrozenWater) + .item(Material.SNOWBALL, 4, 16, 60.0, COMMON, inFrozenWater) + .item(Material.PACKED_ICE, 1, 3, 25.0, GOOD_CATCH, inFrozenWater) + .item(Material.BLUE_ICE, 1, 5.0, GREAT_CATCH, inFrozenWater) + + .item(Material.VINE, 2, 8, 70.0, COMMON, inSwamp) + .item(Material.SLIME_BALL, 1, 3, 45.0, GOOD_CATCH, inSwamp) + .item(Material.POISONOUS_POTATO, 1, 10.0, GREAT_CATCH, inSwamp) + + .item(Material.BAMBOO, 2, 8, 70.0, COMMON, inJungle) + .item(Material.COCOA_BEANS, 2, 6, 50.0, COMMON, inJungle) + .item(Material.TROPICAL_FISH_BUCKET, 1, 3.0, GREAT_CATCH, inJungle) + + .item(Material.PRISMARINE_CRYSTALS, 2, 6, 30.0, GREAT_CATCH, inDeepOcean) + .item(Material.SPONGE, 1, 2, 15.0, GREAT_CATCH, inDeepOcean) .build(); } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldLavaFishing.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldLavaFishing.java index 3f7b25bd..51abb7eb 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldLavaFishing.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/content/fishing/OverworldLavaFishing.java @@ -1,12 +1,10 @@ package fr.moussax.blightedSMP.content.fishing; import fr.moussax.blightedSMP.engine.fishing.FishingLootTable; -import fr.moussax.blightedSMP.registry.RegistryModule; -import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.fishing.FishingMethod; +import fr.moussax.blightedSMP.engine.fishing.registry.FishingRegistryHandler; import fr.moussax.blightedSMP.engine.loot.LootCondition; -import fr.moussax.blightedSMP.engine.loot.results.ItemResult; -import fr.moussax.blightedSMP.engine.loot.results.gems.GemsResult; +import fr.moussax.blightedSMP.registry.RegistryModule; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; @@ -30,60 +28,60 @@ public void register(FishingRegistryHandler registry) { public FishingLootTable provide() { Consumer applyFireResistance = entity -> - entity.addPotionEffect( - new PotionEffect( - PotionEffectType.FIRE_RESISTANCE, - PotionEffect.INFINITE_DURATION, - 1, - false, - false - ) - ); + entity.addPotionEffect( + new PotionEffect( + PotionEffectType.FIRE_RESISTANCE, + PotionEffect.INFINITE_DURATION, + 1, + false, + false + ) + ); return FishingLootTable.builder() - .setEntityRollChance(0.15) - .addVanillaEntity(EntityType.MAGMA_CUBE, 50.0, GREAT_CATCH) - .addVanillaEntity(EntityType.SILVERFISH, 40.0, GREAT_CATCH, applyFireResistance) - .addVanillaEntity(EntityType.HUSK, 30.0, GREAT_CATCH, applyFireResistance) - .addVanillaEntity(EntityType.PARCHED, 30.0, GREAT_CATCH, applyFireResistance) - .addVanillaEntity(EntityType.WITCH, 20.0, GREAT_CATCH, applyFireResistance) - .addVanillaEntity(EntityType.ILLUSIONER, 10.0, GREAT_CATCH, applyFireResistance) - .addItem(Material.BONE, 2, 6, 120.0, COMMON) - .addItem(Material.DRIED_KELP, 5, 10, 120.0, COMMON) - .addItem(Material.FLINT, 2, 5, 110.0, COMMON) - .addItem(Material.GUNPOWDER, 2, 5, 110.0, COMMON) - .addItem(Material.COPPER_NUGGET, 5, 15, 100.0, COMMON) - .addItem(Material.IRON_NUGGET, 5, 15, 100.0, COMMON) - .addItem(Material.COAL, 3, 8, 100.0, COMMON) - .addItem(Material.STONE, 5, 10, 100.0, COMMON) - .addItem(ItemResult.of(Material.STONE_BUTTON, builder -> builder.setItemName("Pebble")), 2, 5, 100.0, COMMON) - .addItem(Material.TUFF, 5, 10, 60.0, GOOD_CATCH, LootCondition.atMostY(0)) - .addItem(new GemsResult(), 2, 5, 60.0, GOOD_CATCH) - .addItem(Material.EXPERIENCE_BOTTLE, 3, 8, 55.0, GOOD_CATCH) - .addItem(Material.COOKED_BEEF, 4, 8, 55.0, GOOD_CATCH) - .addItem(Material.LAPIS_LAZULI, 8, 16, 50.0, GOOD_CATCH) - .addItem(Material.REDSTONE, 8, 16, 50.0, GOOD_CATCH) - .addItem(Material.MAGMA_BLOCK, 5, 10, 50.0, GOOD_CATCH) - .addItem(Material.OBSIDIAN, 2, 4, 55.0, GOOD_CATCH) - .addItem(Material.POINTED_DRIPSTONE, 2, 8, 45.0, GOOD_CATCH, LootCondition.biome(Biome.DRIPSTONE_CAVES)) - .addItem("CREME_BRULEE", 1, 2, 40.0, GOOD_CATCH) - .addItem(Material.GOLDEN_APPLE, 1, 35.0, GOOD_CATCH) - .addItem(Material.LAVA_BUCKET, 1, 35.0, GOOD_CATCH) - .addItem(new GemsResult(), 6, 10, 30.0, GREAT_CATCH) - .addItem(Material.AMETHYST_CLUSTER, 2, 4, 20.0, GREAT_CATCH) - .addItem(Material.EMERALD, 3, 6, 20.0, GREAT_CATCH) - .addItem(Material.RAW_GOLD_BLOCK, 2, 15.0, GREAT_CATCH) - .addItem(Material.DIAMOND, 1, 3, 15.0, GREAT_CATCH) - .addItem(new GemsResult(), 12, 16, 10.0, OUTSTANDING_CATCH) - .addItem(Material.TOTEM_OF_UNDYING, 1, 5.0, OUTSTANDING_CATCH) - .addItem(Material.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) - .addItem(ItemResult.of(Material.OMINOUS_BOTTLE, b -> b.setItemMeta( - meta -> ((OminousBottleMeta) meta).setAmplifier(2) - )), 1, 3.0, OUTSTANDING_CATCH) - .addItem(Material.DIAMOND_BLOCK, 1, 2.0, OUTSTANDING_CATCH) - .addItem(Material.SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 1.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.DEEP_DARK)) - .addItem(ItemResult.of(Material.BUDDING_AMETHYST, b -> b.setRarity(ItemRarity.RARE)), 1, 1.0, OUTSTANDING_CATCH, LootCondition.atMostY(-30)) - .addItem(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) - .build(); + .entityRollChance(0.15) + .entity(EntityType.MAGMA_CUBE, 50.0, GREAT_CATCH) + .entity(EntityType.SILVERFISH, applyFireResistance, 40.0, GREAT_CATCH) + .entity(EntityType.HUSK, applyFireResistance, 30.0, GREAT_CATCH) + .entity(EntityType.PARCHED, applyFireResistance, 30.0, GREAT_CATCH) + .entity(EntityType.WITCH, applyFireResistance, 20.0, GREAT_CATCH) + .entity(EntityType.ILLUSIONER, applyFireResistance, 10.0, GREAT_CATCH) + .item(Material.BONE, 2, 6, 120.0, COMMON) + .item(Material.DRIED_KELP, 5, 10, 120.0, COMMON) + .item(Material.FLINT, 2, 5, 110.0, COMMON) + .item(Material.GUNPOWDER, 2, 5, 110.0, COMMON) + .item(Material.COPPER_NUGGET, 5, 15, 100.0, COMMON) + .item(Material.IRON_NUGGET, 5, 15, 100.0, COMMON) + .item(Material.COAL, 3, 8, 100.0, COMMON) + .item(Material.STONE, 5, 10, 100.0, COMMON) + .item(Material.STONE_BUTTON, builder -> builder.setItemName("Pebble"), 2, 5, 100.0, COMMON) + .item(Material.TUFF, 5, 10, 60.0, GOOD_CATCH, LootCondition.atMostY(0)) + .gems(2, 5, 60.0, GOOD_CATCH) + .item(Material.EXPERIENCE_BOTTLE, 3, 8, 55.0, GOOD_CATCH) + .item(Material.COOKED_BEEF, 4, 8, 55.0, GOOD_CATCH) + .item(Material.LAPIS_LAZULI, 8, 16, 50.0, GOOD_CATCH) + .item(Material.REDSTONE, 8, 16, 50.0, GOOD_CATCH) + .item(Material.MAGMA_BLOCK, 5, 10, 50.0, GOOD_CATCH) + .item(Material.OBSIDIAN, 2, 4, 55.0, GOOD_CATCH) + .item(Material.POINTED_DRIPSTONE, 2, 8, 45.0, GOOD_CATCH, LootCondition.biome(Biome.DRIPSTONE_CAVES)) + .item("CREME_BRULEE", 1, 2, 40.0, GOOD_CATCH) + .item(Material.GOLDEN_APPLE, 1, 35.0, GOOD_CATCH) + .item(Material.LAVA_BUCKET, 1, 35.0, GOOD_CATCH) + .gems(6, 10, 30.0, GREAT_CATCH) + .item(Material.AMETHYST_CLUSTER, 2, 4, 20.0, GREAT_CATCH) + .item(Material.EMERALD, 3, 6, 20.0, GREAT_CATCH) + .item(Material.RAW_GOLD_BLOCK, 2, 15.0, GREAT_CATCH) + .item(Material.DIAMOND, 1, 3, 15.0, GREAT_CATCH) + .gems(12, 16, 10.0, OUTSTANDING_CATCH) + .item(Material.TOTEM_OF_UNDYING, 1, 5.0, OUTSTANDING_CATCH) + .item(Material.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 3.0, OUTSTANDING_CATCH) + .item(Material.OMINOUS_BOTTLE, b -> b.setItemMeta( + meta -> ((OminousBottleMeta) meta).setAmplifier(2) + ), 1, 3.0, OUTSTANDING_CATCH) + .item(Material.DIAMOND_BLOCK, 1, 2.0, OUTSTANDING_CATCH) + .item(Material.SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE, 1, 1.0, OUTSTANDING_CATCH, LootCondition.biome(Biome.DEEP_DARK)) + .item(Material.BUDDING_AMETHYST, b -> b.setRarity(ItemRarity.RARE), 1, 1.0, OUTSTANDING_CATCH, LootCondition.atMostY(-30)) + .item(Material.ENCHANTED_GOLDEN_APPLE, 1, 1.0, OUTSTANDING_CATCH) + .build(); } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingComboTracker.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingComboTracker.java index 5a14c167..61146f4c 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingComboTracker.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingComboTracker.java @@ -125,10 +125,10 @@ private static void handleMilestoneFeedback(Player player, int combo) { public static void spawnBonusExperience(World world, Location location, int combo) { if (world == null || location == null) return; - int bonusOrbCount = Math.min(4, combo / 5); - if (bonusOrbCount <= 0) return; + int bonusExperience = getBonusExperience(combo); + if (bonusExperience <= 0) return; ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(location, EntityType.EXPERIENCE_ORB); - orb.setExperience(bonusOrbCount * 2); + orb.setExperience(bonusExperience); } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingListener.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingListener.java index 2f440ee8..925885d6 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingListener.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingListener.java @@ -1,6 +1,7 @@ package fr.moussax.blightedSMP.engine.fishing; import fr.moussax.blightedSMP.BlightedSMP; +import fr.moussax.blightedSMP.engine.fishing.hooks.CustomFishingHook; import fr.moussax.blightedSMP.engine.fishing.hooks.LavaFishingHook; import fr.moussax.blightedSMP.engine.fishing.hooks.VoidFishingHook; import fr.moussax.blightedSMP.engine.fishing.modifiers.FishingSpeedCalculator; @@ -47,15 +48,9 @@ public void onPlayerFishing(PlayerFishEvent event) { return; } - LavaFishingHook lavaHook = LavaFishingHook.get(hook); - if (lavaHook != null) { - handleCustomFishingReel(event, player, lavaHook::reelIn, lavaHook::remove, ItemType.LAVA_FISHING_ROD); - return; - } - - VoidFishingHook voidHook = VoidFishingHook.get(hook); - if (voidHook != null) { - handleCustomFishingReel(event, player, voidHook::reelIn, voidHook::remove, ItemType.VOID_FISHING_ROD); + CustomFishingHook customHook = CustomFishingHook.get(hook); + if (customHook != null) { + handleCustomFishingReel(event, player, customHook); return; } @@ -141,9 +136,7 @@ private double resolveFishingSpeed(BlightedPlayer blightedPlayer, ItemStack rod) private void handleCustomFishingReel( PlayerFishEvent event, Player player, - CustomReelAction reelAction, - Runnable removeAction, - ItemType rodType + CustomFishingHook customHook ) { PlayerFishEvent.State state = event.getState(); @@ -151,11 +144,11 @@ private void handleCustomFishingReel( || state == PlayerFishEvent.State.IN_GROUND || state == PlayerFishEvent.State.CAUGHT_FISH) { - if (reelAction.reelIn()) { - damageRod(player, rodType); + if (customHook.reelIn()) { + damageRod(player, customHook.getRequiredRodType()); } } else { - removeAction.run(); + customHook.remove(); } } @@ -264,9 +257,4 @@ private Vector calculateVelocity(Location origin, Location target) { return velocity; } - - @FunctionalInterface - private interface CustomReelAction { - boolean reelIn(); - } } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingLootTable.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingLootTable.java index c9a0ec68..839ff797 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingLootTable.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/FishingLootTable.java @@ -1,7 +1,8 @@ package fr.moussax.blightedSMP.engine.fishing; +import fr.moussax.bedrock.utils.ItemBuilder; import fr.moussax.blightedSMP.engine.entities.BlightedEntity; -import fr.moussax.blightedSMP.engine.player.BlightedPlayer; +import fr.moussax.blightedSMP.engine.items.BlightedItem; import fr.moussax.blightedSMP.engine.loot.*; import fr.moussax.blightedSMP.engine.loot.decorators.FeedbackSpecification; import fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality; @@ -9,16 +10,24 @@ import fr.moussax.blightedSMP.engine.loot.providers.AmountProvider; import fr.moussax.blightedSMP.engine.loot.results.EntityResult; import fr.moussax.blightedSMP.engine.loot.results.ItemResult; +import fr.moussax.blightedSMP.engine.loot.results.gems.GemsResult; import fr.moussax.blightedSMP.engine.loot.strategies.WeightedSelectionStrategy; +import fr.moussax.blightedSMP.engine.player.BlightedPlayer; +import lombok.Getter; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.block.Biome; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.util.Vector; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @@ -36,6 +45,7 @@ public final class FishingLootTable { private final LootTable entityTable; private final LootTable itemTable; + @Getter private final double entityRollChance; private FishingLootTable(LootTable entityTable, LootTable itemTable, double entityRollChance) { @@ -52,7 +62,7 @@ private FishingLootTable(LootTable entityTable, LootTable itemTable, double enti * @param velocity velocity of fishing hook * @return {@code true} if a loot entry was selected and executed */ - public boolean roll(BlightedPlayer player, Location location, Vector velocity) { + public boolean roll(@NonNull BlightedPlayer player, @NonNull Location location, @NonNull Vector velocity) { return roll(player, location, velocity, 0, 0); } @@ -65,7 +75,12 @@ public boolean roll(BlightedPlayer player, Location location, Vector velocity) { * @param luckOfSeaLevel player Luck of the Sea level * @return {@code true} if a loot entry was selected and executed */ - public boolean roll(BlightedPlayer player, Location location, Vector velocity, int luckOfSeaLevel) { + public boolean roll( + @NonNull BlightedPlayer player, + @NonNull Location location, + @NonNull Vector velocity, + int luckOfSeaLevel + ) { return roll(player, location, velocity, luckOfSeaLevel, 0); } @@ -79,23 +94,37 @@ public boolean roll(BlightedPlayer player, Location location, Vector velocity, i * @param combo current fishing combo count * @return {@code true} if a loot entry was selected and executed */ - public boolean roll(BlightedPlayer player, Location location, Vector velocity, int luckOfSeaLevel, int combo) { + public boolean roll( + @NonNull BlightedPlayer player, + @NonNull Location location, + @NonNull Vector velocity, + int luckOfSeaLevel, + int combo + ) { ThreadLocalRandom random = ThreadLocalRandom.current(); World world = Objects.requireNonNull(location.getWorld()); Biome biome = world.getBiome(location); LootContext context = new LootContext(player, world, biome, location, random, velocity); - double seaCreatureChanceBonus = Math.min(0.10, combo * 0.005); - double luckBonus = luckOfSeaLevel * LUCK_ENTITY_CHANCE_PER_LEVEL; - double finalEntityChance = Math.min(1.0, entityRollChance + luckBonus + seaCreatureChanceBonus); + double totalEntityChance = entityRollChance + + (luckOfSeaLevel * LUCK_ENTITY_CHANCE_PER_LEVEL) + + FishingComboTracker.getSeaCreatureChanceBonus(combo); - if (!entityTable.isEmpty() && random.nextDouble() <= finalEntityChance) { - entityTable.execute(context); - return true; + if (random.nextDouble() < totalEntityChance) { + List selected = entityTable.roll(context); + if (!selected.isEmpty()) { + for (LootTable.SelectedLoot loot : selected) { + loot.result().execute(context, loot.amount()); + } + return true; + } } - if (!itemTable.isEmpty()) { - itemTable.execute(context); + List selected = itemTable.roll(context); + if (!selected.isEmpty()) { + for (LootTable.SelectedLoot loot : selected) { + loot.result().execute(context, loot.amount()); + } return true; } @@ -103,9 +132,9 @@ public boolean roll(BlightedPlayer player, Location location, Vector velocity, i } /** - * Creates a new builder for configuring a fishing loot table. + * Creates a new builder for configuring a {@link FishingLootTable}. * - * @return fishing loot table builder + * @return new builder instance */ public static Builder builder() { return new Builder(); @@ -115,10 +144,14 @@ public static Builder builder() { * Fluent builder for constructing {@link FishingLootTable} instances. */ public static final class Builder { + private static final Function FISHING_FEEDBACK_MAPPER = quality -> switch (quality) { - case GOOD_CATCH -> FeedbackSpecification.full(" §5§lGOOD CATCH! §f| §7You found §f", Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 2.0f); - case GREAT_CATCH -> FeedbackSpecification.full(" §6§lGREAT CATCH! §f| §7You found §f", Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.5f); - case OUTSTANDING_CATCH -> FeedbackSpecification.full(" §d§lOUTSTANDING CATCH! §f| §7You found §f", Sound.ENTITY_PLAYER_LEVELUP, 1.5f); + case GOOD_CATCH -> + FeedbackSpecification.full(" §5§lGOOD CATCH! §f| §7You found §f", Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 2.0f); + case GREAT_CATCH -> + FeedbackSpecification.full(" §6§lGREAT CATCH! §f| §7You found §f", Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.5f); + case OUTSTANDING_CATCH -> + FeedbackSpecification.full(" §d§lOUTSTANDING CATCH! §f| §7You found §f", Sound.ENTITY_PLAYER_LEVELUP, 1.5f); default -> null; }; @@ -139,555 +172,1545 @@ public static final class Builder { * @param chance entity selection probability (clamped between 0.0 and 1.0) * @return this builder */ - public Builder setEntityRollChance(double chance) { + public Builder entityRollChance(double chance) { this.entityRollChance = Math.clamp(chance, 0.0, 1.0); return this; } /** - * Adds an entry to the entity loot pool. + * Adds a custom entry to the entity loot pool. * * @param entry entity loot entry * @return this builder */ - public Builder addEntity(LootEntry entry) { + public Builder entity(@NonNull LootEntry entry) { + Objects.requireNonNull(entry, "entry cannot be null"); entityTableBuilder.addEntry(entry); return this; } /** - * Adds multiple entries to the entity loot pool. + * Adds custom entries to the entity loot pool. * * @param entries entity loot entries * @return this builder */ - public Builder addEntities(LootEntry... entries) { + public Builder entity(@NonNull LootEntry... entries) { + Objects.requireNonNull(entries, "entries cannot be null"); entityTableBuilder.addEntries(entries); return this; } /** - * Adds an entry to the item loot pool. + * Adds a custom entry to the item loot pool. * * @param entry item loot entry * @return this builder */ - public Builder addItem(LootEntry entry) { + public Builder item(@NonNull LootEntry entry) { + Objects.requireNonNull(entry, "entry cannot be null"); itemTableBuilder.addEntry(entry); return this; } /** - * Adds multiple entries to the item loot pool. + * Adds custom entries to the item loot pool. * * @param entries item loot entries * @return this builder */ - public Builder addItems(LootEntry... entries) { + public Builder item(@NonNull LootEntry... entries) { + Objects.requireNonNull(entries, "entries cannot be null"); itemTableBuilder.addEntries(entries); return this; } /** - * Adds a weighted item result with a variable quantity range and catch feedback quality. + * Adds an item drop with default quantity (1) and common catch quality. * - * @param result loot result - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param material item material + * @param weight selection weight * @return this builder */ - public Builder addItem( - LootResult result, - int minimumAmount, - int maximumAmount, + public Builder item(@NonNull Material material, double weight) { + return item(material, 1, 1, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds an item drop with default quantity (1) and custom catch quality feedback. + * + * @param material item material + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull Material material, double weight, @NonNull FishingCatchQuality quality) { + return item(material, 1, 1, weight, quality, LootCondition.alwaysTrue()); + } + + /** + * Adds an item drop with default quantity (1), custom catch quality feedback, and selection condition. + * + * @param material item material + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder item( + @NonNull Material material, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(result, minimumAmount, maximumAmount, weight, quality, LootCondition.alwaysTrue()); + return item(material, 1, 1, weight, quality, condition); } /** - * Adds a weighted item result with a variable quantity range, catch feedback quality, and selection condition. + * Adds an item drop with fixed quantity and common catch quality. * - * @param result loot result - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param condition condition required for eligibility + * @param material item material + * @param count fixed drop quantity + * @param weight selection weight * @return this builder */ - public Builder addItem( - LootResult result, - int minimumAmount, - int maximumAmount, + public Builder item(@NonNull Material material, int count, double weight) { + return item(material, count, count, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds an item drop with fixed quantity and custom catch quality feedback. + * + * @param material item material + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull Material material, int count, double weight, @NonNull FishingCatchQuality quality) { + return item(material, count, count, weight, quality, LootCondition.alwaysTrue()); + } + + /** + * Adds an item drop with fixed quantity, custom catch quality feedback, and selection condition. + * + * @param material item material + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder item( + @NonNull Material material, + int count, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(LootEntry.weighted( - new GenericFeedbackDecorator<>(result, quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.range(minimumAmount, maximumAmount), - condition - )); + return item(material, count, count, weight, quality, condition); } /** - * Adds a weighted item result with a fixed quantity and catch feedback quality. + * Adds an item drop with variable quantity range and common catch quality. * - * @param result loot result - * @param amount drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param material item material + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight * @return this builder */ - public Builder addItem( - LootResult result, - int amount, + public Builder item(@NonNull Material material, int minAmount, int maxAmount, double weight) { + return item(material, minAmount, maxAmount, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds an item drop with variable quantity range and custom catch quality feedback. + * + * @param material item material + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item( + @NonNull Material material, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality ) { - return addItem(result, amount, amount, weight, quality, LootCondition.alwaysTrue()); + return item(material, minAmount, maxAmount, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a weighted item result with a fixed quantity, catch feedback quality, and selection condition. + * Adds an item drop with variable quantity range, custom catch quality feedback, and selection condition. * - * @param result loot result - * @param amount drop quantity + * @param material item material + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity * @param weight selection weight * @param quality catch quality tier for feedback * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - LootResult result, - int amount, + public Builder item( + @NonNull Material material, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(result, amount, amount, weight, quality, condition); + Objects.requireNonNull(material, "material cannot be null"); + return registerItemEntry(ItemResult.of(material), minAmount, maxAmount, weight, quality, condition); } /** - * Adds a vanilla Minecraft entity catch. + * Adds a modified item drop with default quantity (1) and common catch quality. * - * @param type entity type to spawn - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param material item material + * @param modifier item builder modifier callback + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull Material material, @NonNull Consumer modifier, double weight) { + return item(material, modifier, 1, 1, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a modified item drop with default quantity (1) and custom catch quality feedback. + * + * @param material item material + * @param modifier item builder modifier callback + * @param weight selection weight + * @param quality catch quality tier for feedback * @return this builder */ - public Builder addVanillaEntity(EntityType type, double weight, FishingCatchQuality quality) { - return addVanillaEntity(type, weight, quality, LootCondition.alwaysTrue()); + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + double weight, + @NonNull FishingCatchQuality quality + ) { + return item(material, modifier, 1, 1, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a vanilla Minecraft entity catch with a selection condition. + * Adds a modified item drop with default quantity (1), custom catch quality feedback, and selection condition. * - * @param type entity type to spawn + * @param material item material + * @param modifier item builder modifier callback * @param weight selection weight * @param quality catch quality tier for feedback * @param condition condition required for eligibility * @return this builder */ - public Builder addVanillaEntity( - EntityType type, + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addEntity(LootEntry.weighted( - new GenericFeedbackDecorator<>(EntityResult.vanilla(type), quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.fixed(1), - condition - )); + return item(material, modifier, 1, 1, weight, quality, condition); + } + + /** + * Adds a modified item drop with fixed quantity and common catch quality. + * + * @param material item material + * @param modifier item builder modifier callback + * @param count fixed drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int count, + double weight + ) { + return item(material, modifier, count, count, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); } /** - * Adds a vanilla Minecraft entity catch with an entity modifier. + * Adds a modified item drop with fixed quantity and custom catch quality feedback. * - * @param type entity type to spawn + * @param material item material + * @param modifier item builder modifier callback + * @param count fixed drop quantity * @param weight selection weight * @param quality catch quality tier for feedback - * @param modifier function to modify the spawned entity * @return this builder */ - public Builder addVanillaEntity( - EntityType type, + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int count, double weight, - FishingCatchQuality quality, - Consumer modifier + @NonNull FishingCatchQuality quality ) { - return addVanillaEntity(type, weight, quality, modifier, LootCondition.alwaysTrue()); + return item(material, modifier, count, count, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a vanilla Minecraft entity catch with an entity modifier and selection condition. + * Adds a modified item drop with fixed quantity, custom catch quality feedback, and selection condition. * - * @param type entity type to spawn + * @param material item material + * @param modifier item builder modifier callback + * @param count fixed drop quantity * @param weight selection weight * @param quality catch quality tier for feedback - * @param modifier function to modify the spawned entity * @param condition condition required for eligibility * @return this builder */ - public Builder addVanillaEntity( - EntityType type, + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int count, double weight, - FishingCatchQuality quality, - Consumer modifier, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addEntity(LootEntry.weighted( - new GenericFeedbackDecorator<>(EntityResult.vanilla(type, modifier), quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.fixed(1), - condition - )); + return item(material, modifier, count, count, weight, quality, condition); } /** - * Adds a vanilla Minecraft entity catch with a custom catch message. + * Adds a modified item drop with variable quantity range and common catch quality. * - * @param type entity type to spawn - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param catchMessage custom message sent on catch + * @param material item material + * @param modifier item builder modifier callback + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight * @return this builder */ - public Builder addVanillaEntity( - EntityType type, - double weight, - FishingCatchQuality quality, - String catchMessage + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int minAmount, + int maxAmount, + double weight ) { - return addVanillaEntity(type, weight, quality, catchMessage, LootCondition.alwaysTrue()); + return item(material, modifier, minAmount, maxAmount, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); } /** - * Adds a vanilla Minecraft entity catch with a custom catch message and selection condition. + * Adds a modified item drop with variable quantity range and custom catch quality feedback. * - * @param type entity type to spawn - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param catchMessage custom message sent on catch - * @param condition condition required for eligibility + * @param material item material + * @param modifier item builder modifier callback + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback * @return this builder */ - public Builder addVanillaEntity( - EntityType type, + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality, - String catchMessage, - LootCondition condition + @NonNull FishingCatchQuality quality ) { - return addEntity(LootEntry.weighted( - new GenericFeedbackDecorator<>( - EntityResult.vanilla(type), - quality, - catchQuality -> { - FeedbackSpecification baseSpecification = FISHING_FEEDBACK_MAPPER.apply(catchQuality); - return new FeedbackSpecification( - catchMessage, - baseSpecification != null ? baseSpecification.messagePrefix() : null, - baseSpecification != null ? baseSpecification.sound() : null, - baseSpecification != null ? baseSpecification.pitch() : 1.0f - ); - } - ), - weight, - AmountProvider.fixed(1), - condition - )); + return item(material, modifier, minAmount, maxAmount, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a vanilla Minecraft entity catch with sound-only feedback and a custom catch message. + * Adds a modified item drop with variable quantity range, custom catch quality feedback, and selection condition. * - * @param type entity type to spawn - * @param weight selection weight - * @param soundQuality catch quality tier for sound feedback - * @param catchMessage custom message sent on catch + * @param material item material + * @param modifier item builder modifier callback + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addVanillaEntityWithSound( - EntityType type, + public Builder item( + @NonNull Material material, + @NonNull Consumer modifier, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality soundQuality, - String catchMessage + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addVanillaEntityWithSound( - type, - weight, - soundQuality, - catchMessage, - LootCondition.alwaysTrue() - ); + Objects.requireNonNull(material, "material cannot be null"); + Objects.requireNonNull(modifier, "modifier cannot be null"); + return registerItemEntry(ItemResult.of(material, modifier), minAmount, maxAmount, weight, quality, condition); } /** - * Adds a vanilla Minecraft entity catch with sound-only feedback, a custom catch message, and selection condition. + * Adds a registered item drop with default quantity (1) and common catch quality. * - * @param type entity type to spawn - * @param weight selection weight - * @param soundQuality catch quality tier for sound feedback - * @param catchMessage custom message sent on catch - * @param condition condition required for eligibility + * @param itemId registered item identifier + * @param weight selection weight * @return this builder */ - public Builder addVanillaEntityWithSound( - EntityType type, - double weight, - FishingCatchQuality soundQuality, - String catchMessage, - LootCondition condition - ) { - return addEntity(LootEntry.weighted( - new GenericFeedbackDecorator<>( - EntityResult.vanilla(type), - soundQuality, - catchQuality -> { - FeedbackSpecification baseSpecification = FISHING_SOUND_MAPPER.apply(catchQuality); - return new FeedbackSpecification( - catchMessage, - null, - baseSpecification != null ? baseSpecification.sound() : null, - baseSpecification != null ? baseSpecification.pitch() : 1.0f - ); - } - ), - weight, - AmountProvider.fixed(1), - condition - )); + public Builder item(@NonNull String itemId, double weight) { + return item(itemId, 1, 1, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a registered item drop with default quantity (1) and custom catch quality feedback. + * + * @param itemId registered item identifier + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull String itemId, double weight, @NonNull FishingCatchQuality quality) { + return item(itemId, 1, 1, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a custom Blighted entity catch. + * Adds a registered item drop with default quantity (1), custom catch quality feedback, and selection condition. * - * @param blightedEntity Blighted entity to spawn - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param itemId registered item identifier + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addBlightedEntity( - BlightedEntity blightedEntity, + public Builder item( + @NonNull String itemId, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addBlightedEntity(blightedEntity, weight, quality, LootCondition.alwaysTrue()); + return item(itemId, 1, 1, weight, quality, condition); + } + + /** + * Adds a registered item drop with fixed quantity and common catch quality. + * + * @param itemId registered item identifier + * @param count fixed drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull String itemId, int count, double weight) { + return item(itemId, count, count, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a registered item drop with fixed quantity and custom catch quality feedback. + * + * @param itemId registered item identifier + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull String itemId, int count, double weight, @NonNull FishingCatchQuality quality) { + return item(itemId, count, count, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a custom Blighted entity catch with a selection condition. + * Adds a registered item drop with fixed quantity, custom catch quality feedback, and selection condition. * - * @param blightedEntity Blighted entity to spawn - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param condition condition required for eligibility + * @param itemId registered item identifier + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addBlightedEntity( - BlightedEntity blightedEntity, + public Builder item( + @NonNull String itemId, + int count, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addEntity(LootEntry.weighted( - new GenericFeedbackDecorator<>(EntityResult.blighted(blightedEntity), quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.fixed(1), - condition - )); + return item(itemId, count, count, weight, quality, condition); } /** - * Adds a vanilla material item catch with a variable quantity range. + * Adds a registered item drop with variable quantity range and common catch quality. * - * @param material material to drop - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param itemId registered item identifier + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull String itemId, int minAmount, int maxAmount, double weight) { + return item(itemId, minAmount, maxAmount, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a registered item drop with variable quantity range and custom catch quality feedback. + * + * @param itemId registered item identifier + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback * @return this builder */ - public Builder addItem( - Material material, - int minimumAmount, - int maximumAmount, + public Builder item( + @NonNull String itemId, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality ) { - return addItem(material, minimumAmount, maximumAmount, weight, quality, LootCondition.alwaysTrue()); + return item(itemId, minAmount, maxAmount, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a vanilla material item catch with a variable quantity range and selection condition. + * Adds a registered item drop with variable quantity range, custom catch quality feedback, and selection condition. * - * @param material material to drop - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param condition condition required for eligibility + * @param itemId registered item identifier + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - Material material, - int minimumAmount, - int maximumAmount, + public Builder item( + @NonNull String itemId, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(LootEntry.weighted( - new GenericFeedbackDecorator<>(ItemResult.of(material), quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.range(minimumAmount, maximumAmount), - condition - )); + Objects.requireNonNull(itemId, "itemId cannot be null"); + return registerItemEntry(ItemResult.of(itemId), minAmount, maxAmount, weight, quality, condition); } /** - * Adds a registered item catch with a variable quantity range. + * Adds a Blighted item drop with default quantity (1) and common catch quality. * - * @param itemId registry ID of item - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param item Blighted item definition + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull BlightedItem item, double weight) { + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), weight); + } + + /** + * Adds a Blighted item drop with default quantity (1) and custom catch quality feedback. + * + * @param item Blighted item definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull BlightedItem item, double weight, @NonNull FishingCatchQuality quality) { + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), weight, quality); + } + + /** + * Adds a Blighted item drop with default quantity (1), custom catch quality feedback, and selection condition. + * + * @param item Blighted item definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - String itemId, - int minimumAmount, - int maximumAmount, + public Builder item( + @NonNull BlightedItem item, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(itemId, minimumAmount, maximumAmount, weight, quality, LootCondition.alwaysTrue()); + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), weight, quality, condition); } /** - * Adds a registered item catch with a variable quantity range and selection condition. + * Adds a Blighted item drop with fixed quantity and common catch quality. * - * @param itemId registry ID of item - * @param minimumAmount minimum drop quantity - * @param maximumAmount maximum drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback - * @param condition condition required for eligibility + * @param item Blighted item definition + * @param count fixed drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull BlightedItem item, int count, double weight) { + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), count, weight); + } + + /** + * Adds a Blighted item drop with fixed quantity and custom catch quality feedback. + * + * @param item Blighted item definition + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull BlightedItem item, int count, double weight, @NonNull FishingCatchQuality quality) { + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), count, weight, quality); + } + + /** + * Adds a Blighted item drop with fixed quantity, custom catch quality feedback, and selection condition. + * + * @param item Blighted item definition + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - String itemId, - int minimumAmount, - int maximumAmount, + public Builder item( + @NonNull BlightedItem item, + int count, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(LootEntry.weighted( - new GenericFeedbackDecorator<>(ItemResult.of(itemId), quality, FISHING_FEEDBACK_MAPPER), - weight, - AmountProvider.range(minimumAmount, maximumAmount), - condition - )); + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), count, weight, quality, condition); } /** - * Adds a vanilla material item catch with a fixed quantity. + * Adds a Blighted item drop with variable quantity range and common catch quality. * - * @param material material to drop - * @param amount drop quantity - * @param weight selection weight - * @param quality catch quality tier for feedback + * @param item Blighted item definition + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull BlightedItem item, int minAmount, int maxAmount, double weight) { + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), minAmount, maxAmount, weight); + } + + /** + * Adds a Blighted item drop with variable quantity range and custom catch quality feedback. + * + * @param item Blighted item definition + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback * @return this builder */ - public Builder addItem( - Material material, - int amount, + public Builder item( + @NonNull BlightedItem item, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality + @NonNull FishingCatchQuality quality ) { - return addItem(material, amount, amount, weight, quality, LootCondition.alwaysTrue()); + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), minAmount, maxAmount, weight, quality); } /** - * Adds a vanilla material item catch with a fixed quantity and selection condition. + * Adds a Blighted item drop with variable quantity range, custom catch quality feedback, and selection condition. * - * @param material material to drop - * @param amount drop quantity + * @param item Blighted item definition + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity * @param weight selection weight * @param quality catch quality tier for feedback * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - Material material, - int amount, + public Builder item( + @NonNull BlightedItem item, + int minAmount, + int maxAmount, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(material, amount, amount, weight, quality, condition); + Objects.requireNonNull(item, "item cannot be null"); + return item(item.getItemId(), minAmount, maxAmount, weight, quality, condition); + } + + /** + * Adds a custom loot result item drop with default quantity (1) and common catch quality. + * + * @param result custom loot result + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull LootResult result, double weight) { + return item(result, 1, 1, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); } /** - * Adds a registered item catch with a fixed quantity. + * Adds a custom loot result item drop with default quantity (1) and custom catch quality feedback. * - * @param itemId registry ID of item - * @param amount drop quantity + * @param result custom loot result * @param weight selection weight * @param quality catch quality tier for feedback * @return this builder */ - public Builder addItem(String itemId, int amount, double weight, FishingCatchQuality quality) { - return addItem(itemId, amount, amount, weight, quality, LootCondition.alwaysTrue()); + public Builder item(@NonNull LootResult result, double weight, @NonNull FishingCatchQuality quality) { + return item(result, 1, 1, weight, quality, LootCondition.alwaysTrue()); } /** - * Adds a registered item catch with a fixed quantity and selection condition. + * Adds a custom loot result item drop with default quantity (1), custom catch quality feedback, and selection condition. * - * @param itemId registry ID of item - * @param amount drop quantity + * @param result custom loot result * @param weight selection weight * @param quality catch quality tier for feedback * @param condition condition required for eligibility * @return this builder */ - public Builder addItem( - String itemId, - int amount, + public Builder item( + @NonNull LootResult result, double weight, - FishingCatchQuality quality, - LootCondition condition + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition ) { - return addItem(itemId, amount, amount, weight, quality, condition); + return item(result, 1, 1, weight, quality, condition); } /** - * Constructs the configured {@link FishingLootTable}. + * Adds a custom loot result item drop with fixed quantity and common catch quality. * - * @return new fishing loot table + * @param result custom loot result + * @param count fixed drop quantity + * @param weight selection weight + * @return this builder */ - public FishingLootTable build() { - entityTableBuilder - .selectionStrategy(new WeightedSelectionStrategy()) - .rollChance(1.0); + public Builder item(@NonNull LootResult result, int count, double weight) { + return item(result, count, count, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } - itemTableBuilder - .selectionStrategy(new WeightedSelectionStrategy()) - .rollChance(1.0); + /** + * Adds a custom loot result item drop with fixed quantity and custom catch quality feedback. + * + * @param result custom loot result + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item(@NonNull LootResult result, int count, double weight, @NonNull FishingCatchQuality quality) { + return item(result, count, count, weight, quality, LootCondition.alwaysTrue()); + } + /** + * Adds a custom loot result item drop with fixed quantity, custom catch quality feedback, and selection condition. + * + * @param result custom loot result + * @param count fixed drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder item( + @NonNull LootResult result, + int count, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return item(result, count, count, weight, quality, condition); + } + + /** + * Adds a custom loot result item drop with variable quantity range and common catch quality. + * + * @param result custom loot result + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @return this builder + */ + public Builder item(@NonNull LootResult result, int minAmount, int maxAmount, double weight) { + return item(result, minAmount, maxAmount, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom loot result item drop with variable quantity range and custom catch quality feedback. + * + * @param result custom loot result + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder item( + @NonNull LootResult result, + int minAmount, + int maxAmount, + double weight, + @NonNull FishingCatchQuality quality + ) { + return item(result, minAmount, maxAmount, weight, quality, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom loot result item drop with variable quantity range, custom catch quality feedback, and selection condition. + * + * @param result custom loot result + * @param minAmount minimum drop quantity + * @param maxAmount maximum drop quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder item( + @NonNull LootResult result, + int minAmount, + int maxAmount, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(result, "result cannot be null"); + return registerItemEntry(result, minAmount, maxAmount, weight, quality, condition); + } + + /** + * Adds a fixed gem reward drop with common catch quality. + * + * @param gems gem quantity + * @param weight selection weight + * @return this builder + */ + public Builder gems(int gems, double weight) { + return gems(gems, gems, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a fixed gem reward drop with custom catch quality feedback. + * + * @param gems gem quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder gems(int gems, double weight, @NonNull FishingCatchQuality quality) { + return gems(gems, gems, weight, quality, LootCondition.alwaysTrue()); + } + + /** + * Adds a variable gem reward drop with common catch quality. + * + * @param minGems minimum gem quantity + * @param maxGems maximum gem quantity + * @param weight selection weight + * @return this builder + */ + public Builder gems(int minGems, int maxGems, double weight) { + return gems(minGems, maxGems, weight, FishingCatchQuality.COMMON, LootCondition.alwaysTrue()); + } + + /** + * Adds a variable gem reward drop with custom catch quality feedback. + * + * @param minGems minimum gem quantity + * @param maxGems maximum gem quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder gems(int minGems, int maxGems, double weight, @NonNull FishingCatchQuality quality) { + return gems(minGems, maxGems, weight, quality, LootCondition.alwaysTrue()); + } + + /** + * Adds a variable gem reward drop with custom catch quality feedback and selection condition. + * + * @param minGems minimum gem quantity + * @param maxGems maximum gem quantity + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder gems( + int minGems, + int maxGems, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(quality, "quality cannot be null"); + Objects.requireNonNull(condition, "condition cannot be null"); + return registerItemEntry(new GemsResult(), minGems, maxGems, weight, quality, condition); + } + + /** + * Adds a damaged item drop with randomized durability and common catch quality. + * + * @param material item material + * @param minPercentage minimum durability ratio remaining + * @param maxPercentage maximum durability ratio remaining + * @param weight selection weight + * @return this builder + */ + public Builder damagedItem( + @NonNull Material material, + double minPercentage, + double maxPercentage, + double weight + ) { + return damagedItem(material, minPercentage, maxPercentage, weight, FishingCatchQuality.COMMON); + } + + /** + * Adds a damaged item drop with randomized durability and custom catch quality feedback. + * + * @param material item material + * @param minPercentage minimum durability ratio remaining + * @param maxPercentage maximum durability ratio remaining + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder damagedItem( + @NonNull Material material, + double minPercentage, + double maxPercentage, + double weight, + @NonNull FishingCatchQuality quality + ) { + Objects.requireNonNull(material, "material cannot be null"); + Objects.requireNonNull(quality, "quality cannot be null"); + return registerItemEntry( + ItemResult.randomDurability(material, minPercentage, maxPercentage), + 1, 1, weight, quality, LootCondition.alwaysTrue() + ); + } + + /** + * Adds a randomized enchanted book drop with common catch quality. + * + * @param enchantments list of eligible enchantments + * @param minLevel minimum enchantment level + * @param maxLevel maximum enchantment level + * @param weight selection weight + * @return this builder + */ + public Builder enchantedBook( + @NonNull List enchantments, + int minLevel, + int maxLevel, + double weight + ) { + return enchantedBook(enchantments, minLevel, maxLevel, weight, FishingCatchQuality.COMMON); + } + + /** + * Adds a randomized enchanted book drop with custom catch quality feedback. + * + * @param enchantments list of eligible enchantments + * @param minLevel minimum enchantment level + * @param maxLevel maximum enchantment level + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder enchantedBook( + @NonNull List enchantments, + int minLevel, + int maxLevel, + double weight, + @NonNull FishingCatchQuality quality + ) { + Objects.requireNonNull(enchantments, "enchantments cannot be null"); + Objects.requireNonNull(quality, "quality cannot be null"); + return registerItemEntry( + ItemResult.randomEnchantedBook(enchantments, minLevel, maxLevel), + 1, 1, weight, quality, LootCondition.alwaysTrue() + ); + } + + /** + * Adds an enchanted book drop from a weighted enchantment pool with common catch quality. + * + * @param enchantmentPool map of enchantments and their levels + * @param weight selection weight + * @return this builder + */ + public Builder enchantedBook( + @NonNull Map enchantmentPool, + double weight + ) { + return enchantedBook(enchantmentPool, weight, FishingCatchQuality.COMMON); + } + + /** + * Adds an enchanted book drop from a weighted enchantment pool with custom catch quality feedback. + * + * @param enchantmentPool map of enchantments and their levels + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder enchantedBook( + @NonNull Map enchantmentPool, + double weight, + @NonNull FishingCatchQuality quality + ) { + Objects.requireNonNull(enchantmentPool, "enchantmentPool cannot be null"); + Objects.requireNonNull(quality, "quality cannot be null"); + return registerItemEntry( + ItemResult.randomEnchantedBook(enchantmentPool), + 1, 1, weight, quality, LootCondition.alwaysTrue() + ); + } + + /** + * Adds an entity drop with common catch quality. + * + * @param type entity type + * @param weight selection weight + * @return this builder + */ + public Builder entity(@NonNull EntityType type, double weight) { + return entity(type, weight, FishingCatchQuality.COMMON, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds an entity drop with custom catch quality feedback. + * + * @param type entity type + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder entity(@NonNull EntityType type, double weight, @NonNull FishingCatchQuality quality) { + return entity(type, weight, quality, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds an entity drop with custom catch quality feedback and selection condition. + * + * @param type entity type + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return entity(type, weight, quality, null, false, condition); + } + + /** + * Adds an entity drop with custom catch quality feedback and catch message. + * + * @param type entity type + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage + ) { + return entity(type, weight, quality, catchMessage, false, LootCondition.alwaysTrue()); + } + + /** + * Adds an entity drop with full customization options. + * + * @param type entity type + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @param suppressStandardText whether to suppress standard catch header prefix + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage, + boolean suppressStandardText, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(type, "type cannot be null"); + return registerEntityEntry( + EntityResult.vanilla(type), + weight, + quality, + catchMessage, + suppressStandardText, + condition + ); + } + + /** + * Adds a modified entity drop with common catch quality. + * + * @param type entity type + * @param modifier spawned entity modifier callback + * @param weight selection weight + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + @NonNull Consumer modifier, + double weight + ) { + return entity(type, modifier, weight, FishingCatchQuality.COMMON, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a modified entity drop with custom catch quality feedback. + * + * @param type entity type + * @param modifier spawned entity modifier callback + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + @NonNull Consumer modifier, + double weight, + @NonNull FishingCatchQuality quality + ) { + return entity(type, modifier, weight, quality, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a modified entity drop with custom catch quality feedback and selection condition. + * + * @param type entity type + * @param modifier spawned entity modifier callback + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + @NonNull Consumer modifier, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return entity(type, modifier, weight, quality, null, false, condition); + } + + /** + * Adds a modified entity drop with custom catch quality feedback and catch message. + * + * @param type entity type + * @param modifier spawned entity modifier callback + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + @NonNull Consumer modifier, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage + ) { + return entity(type, modifier, weight, quality, catchMessage, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a modified entity drop with full customization options. + * + * @param type entity type + * @param modifier spawned entity modifier callback + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @param suppressStandardText whether to suppress standard catch header prefix + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull EntityType type, + @NonNull Consumer modifier, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage, + boolean suppressStandardText, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(type, "type cannot be null"); + Objects.requireNonNull(modifier, "modifier cannot be null"); + return registerEntityEntry( + EntityResult.vanilla(type, modifier), + weight, + quality, + catchMessage, + suppressStandardText, + condition + ); + } + + /** + * Adds a Blighted entity drop with common catch quality. + * + * @param entity Blighted entity definition + * @param weight selection weight + * @return this builder + */ + public Builder entity(@NonNull BlightedEntity entity, double weight) { + return entity(entity, weight, FishingCatchQuality.COMMON, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a Blighted entity drop with custom catch quality feedback. + * + * @param entity Blighted entity definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder entity(@NonNull BlightedEntity entity, double weight, @NonNull FishingCatchQuality quality) { + return entity(entity, weight, quality, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a Blighted entity drop with custom catch quality feedback and selection condition. + * + * @param entity Blighted entity definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull BlightedEntity entity, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return entity(entity, weight, quality, null, false, condition); + } + + /** + * Adds a Blighted entity drop with custom catch quality feedback and catch message. + * + * @param entity Blighted entity definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @return this builder + */ + public Builder entity( + @NonNull BlightedEntity entity, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage + ) { + return entity(entity, weight, quality, catchMessage, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a Blighted entity drop with full customization options. + * + * @param entity Blighted entity definition + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @param suppressStandardText whether to suppress standard catch header prefix + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull BlightedEntity entity, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage, + boolean suppressStandardText, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(entity, "entity cannot be null"); + return registerEntityEntry( + EntityResult.blighted(entity), + weight, + quality, + catchMessage, + suppressStandardText, + condition + ); + } + + /** + * Adds a custom spawner entity drop with common catch quality. + * + * @param spawner custom spawner function + * @param weight selection weight + * @return this builder + */ + public Builder entity(@NonNull Function spawner, double weight) { + return entity(spawner, weight, FishingCatchQuality.COMMON, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom spawner entity drop with custom catch quality feedback. + * + * @param spawner custom spawner function + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder entity( + @NonNull Function spawner, + double weight, + @NonNull FishingCatchQuality quality + ) { + return entity(spawner, weight, quality, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom spawner entity drop with custom catch quality feedback and selection condition. + * + * @param spawner custom spawner function + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull Function spawner, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return entity(spawner, weight, quality, null, false, condition); + } + + /** + * Adds a custom spawner entity drop with custom catch quality feedback and catch message. + * + * @param spawner custom spawner function + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @return this builder + */ + public Builder entity( + @NonNull Function spawner, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage + ) { + return entity(spawner, weight, quality, catchMessage, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom spawner entity drop with full customization options. + * + * @param spawner custom spawner function + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @param suppressStandardText whether to suppress standard catch header prefix + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull Function spawner, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage, + boolean suppressStandardText, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(spawner, "spawner cannot be null"); + return registerEntityEntry( + EntityResult.custom(spawner), + weight, + quality, + catchMessage, + suppressStandardText, + condition + ); + } + + /** + * Adds a custom loot result entity drop with common catch quality. + * + * @param result custom loot result + * @param weight selection weight + * @return this builder + */ + public Builder entity(@NonNull LootResult result, double weight) { + return entity(result, weight, FishingCatchQuality.COMMON, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom loot result entity drop with custom catch quality feedback. + * + * @param result custom loot result + * @param weight selection weight + * @param quality catch quality tier for feedback + * @return this builder + */ + public Builder entity(@NonNull LootResult result, double weight, @NonNull FishingCatchQuality quality) { + return entity(result, weight, quality, null, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom loot result entity drop with custom catch quality feedback and selection condition. + * + * @param result custom loot result + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull LootResult result, + double weight, + @NonNull FishingCatchQuality quality, + @NonNull LootCondition condition + ) { + return entity(result, weight, quality, null, false, condition); + } + + /** + * Adds a custom loot result entity drop with custom catch quality feedback and catch message. + * + * @param result custom loot result + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @return this builder + */ + public Builder entity( + @NonNull LootResult result, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage + ) { + return entity(result, weight, quality, catchMessage, false, LootCondition.alwaysTrue()); + } + + /** + * Adds a custom loot result entity drop with full customization options. + * + * @param result custom loot result + * @param weight selection weight + * @param quality catch quality tier for feedback + * @param catchMessage custom catch message + * @param suppressStandardText whether to suppress standard catch header prefix + * @param condition condition required for eligibility + * @return this builder + */ + public Builder entity( + @NonNull LootResult result, + double weight, + @NonNull FishingCatchQuality quality, + @Nullable String catchMessage, + boolean suppressStandardText, + @NonNull LootCondition condition + ) { + Objects.requireNonNull(result, "result cannot be null"); + return registerEntityEntry(result, weight, quality, catchMessage, suppressStandardText, condition); + } + + private Builder registerItemEntry( + LootResult result, + int minAmount, + int maxAmount, + double weight, + FishingCatchQuality quality, + LootCondition condition + ) { + Objects.requireNonNull(quality, "quality cannot be null"); + Objects.requireNonNull(condition, "condition cannot be null"); + + AmountProvider amountProvider = (minAmount == maxAmount) + ? AmountProvider.fixed(minAmount) + : AmountProvider.range(minAmount, maxAmount); + + itemTableBuilder.addEntry( + LootEntry.weighted( + new GenericFeedbackDecorator<>(result, quality, FISHING_FEEDBACK_MAPPER), + weight, + amountProvider, + condition + ) + ); + return this; + } + + private Builder registerEntityEntry( + LootResult result, + double weight, + FishingCatchQuality quality, + String catchMessage, + boolean suppressStandardText, + LootCondition condition + ) { + Objects.requireNonNull(quality, "quality cannot be null"); + Objects.requireNonNull(condition, "condition cannot be null"); + + Function mapper; + if (catchMessage != null || suppressStandardText) { + mapper = catchQuality -> { + FeedbackSpecification base = suppressStandardText + ? FISHING_SOUND_MAPPER.apply(catchQuality) + : FISHING_FEEDBACK_MAPPER.apply(catchQuality); + return new FeedbackSpecification( + catchMessage, + suppressStandardText ? null : (base != null ? base.messagePrefix() : null), + base != null ? base.sound() : null, + base != null ? base.pitch() : 1.0f + ); + }; + } else { + mapper = FISHING_FEEDBACK_MAPPER; + } + + entityTableBuilder.addEntry( + LootEntry.weighted( + new GenericFeedbackDecorator<>(result, quality, mapper), + weight, + AmountProvider.fixed(1), + condition + ) + ); + return this; + } + + /** + * Constructs the configured {@link FishingLootTable}. + * + * @return new fishing loot table + */ + @NonNull + public FishingLootTable build() { return new FishingLootTable( - entityTableBuilder.build(), - itemTableBuilder.build(), + entityTableBuilder + .selectionStrategy(new WeightedSelectionStrategy()) + .rollChance(1.0) + .build(), + itemTableBuilder + .selectionStrategy(new WeightedSelectionStrategy()) + .rollChance(1.0) + .build(), entityRollChance ); } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/CustomFishingHook.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/CustomFishingHook.java new file mode 100644 index 00000000..52cc03f5 --- /dev/null +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/CustomFishingHook.java @@ -0,0 +1,68 @@ +package fr.moussax.blightedSMP.engine.fishing.hooks; + +import fr.moussax.blightedSMP.engine.items.ItemType; +import org.bukkit.Location; +import org.bukkit.entity.FishHook; +import org.bukkit.util.Vector; + +/** + * Common abstraction for custom BlightedMC fishing hooks (such as lava and void fishing). + */ +public interface CustomFishingHook { + + /** + * Attempts to reel in the custom hook. + * + * @return true if a catch was completed and rod durability should be consumed, false otherwise + */ + boolean reelIn(); + + /** + * Cancels any ongoing tracking tasks and cleans up internal references for this hook. + */ + void remove(); + + /** + * Gets the custom rod item type required to operate this hook. + * + * @return the required {@link ItemType} + */ + ItemType getRequiredRodType(); + + /** + * Finds any active custom fishing hook associated with the specified Bukkit hook. + * + * @param hook the Bukkit fish hook entity + * @return the associated {@link CustomFishingHook}, or null if none exists + */ + static CustomFishingHook get(FishHook hook) { + if (hook == null) return null; + CustomFishingHook lavaHook = LavaFishingHook.get(hook); + if (lavaHook != null) return lavaHook; + return VoidFishingHook.get(hook); + } + + /** + * Cleans up all active custom fishing hooks across all custom fishing types. + */ + static void cleanupAll() { + LavaFishingHook.cleanupAll(); + VoidFishingHook.cleanupAll(); + } + + /** + * Calculates the arc launch velocity for caught items or entities traveling from + * the hook location toward the player. + * + * @param origin the hook origin location + * @param destination the destination (player) location + * @return the velocity vector + */ + static Vector calculateLaunchVelocity(Location origin, Location destination) { + Vector velocity = destination.toVector().subtract(origin.toVector()); + double distance = velocity.length(); + velocity.multiply(0.08); + velocity.setY(velocity.getY() + (Math.sqrt(distance) * 0.05) + 0.15); + return velocity; + } +} diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/LavaFishingHook.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/LavaFishingHook.java index 54672167..3ade32bc 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/LavaFishingHook.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/LavaFishingHook.java @@ -8,6 +8,7 @@ import fr.moussax.blightedSMP.engine.fishing.registry.FishingLootRegistry; import fr.moussax.blightedSMP.engine.player.BlightedPlayer; import fr.moussax.bedrock.text.Messenger; +import fr.moussax.blightedSMP.engine.items.ItemType; import org.bukkit.*; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; @@ -21,7 +22,7 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; -public final class LavaFishingHook { +public final class LavaFishingHook implements CustomFishingHook { private static final Map ACTIVE_HOOKS = new HashMap<>(); private static final double FLOAT_TARGET_HIGH = 0.95; @@ -170,6 +171,7 @@ private void adjustHookFloat(double targetOffset) { hook.setVelocity(currentOffset < targetOffset ? FLOAT_UP : FLOAT_DOWN); } + @Override public boolean reelIn() { remove(); @@ -186,11 +188,7 @@ public boolean reelIn() { world.playSound(hookLocation, Sound.BLOCK_LAVA_EXTINGUISH, 1.0f, 1.0f); Location playerLocation = player.getLocation(); - Vector velocity = playerLocation.toVector().subtract(hookLocation.toVector()); - - double distance = velocity.length(); - velocity.multiply(0.08); - velocity.setY(velocity.getY() + (Math.sqrt(distance) * 0.05) + 0.15); + Vector velocity = CustomFishingHook.calculateLaunchVelocity(hookLocation, playerLocation); Location spawnLocation = hookLocation.add(0, 0.5, 0); @@ -209,6 +207,7 @@ public boolean reelIn() { return success; } + @Override public void remove() { ACTIVE_HOOKS.remove(hook.getUniqueId()); if (task != null && !task.isCancelled()) { @@ -217,6 +216,11 @@ public void remove() { } } + @Override + public ItemType getRequiredRodType() { + return ItemType.LAVA_FISHING_ROD; + } + public static LavaFishingHook get(FishHook hook) { return ACTIVE_HOOKS.get(hook.getUniqueId()); } diff --git a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/VoidFishingHook.java b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/VoidFishingHook.java index 499ecd06..d42c59bf 100644 --- a/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/VoidFishingHook.java +++ b/blighted-smp/src/main/java/fr/moussax/blightedSMP/engine/fishing/hooks/VoidFishingHook.java @@ -8,6 +8,7 @@ import fr.moussax.blightedSMP.engine.fishing.registry.FishingLootRegistry; import fr.moussax.blightedSMP.engine.player.BlightedPlayer; import fr.moussax.bedrock.text.Messenger; +import fr.moussax.blightedSMP.engine.items.ItemType; import org.bukkit.*; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; @@ -21,7 +22,7 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; -public final class VoidFishingHook { +public final class VoidFishingHook implements CustomFishingHook { private static final Map ACTIVE_HOOKS = new HashMap<>(); private static final double CENTRAL_ISLAND_RADIUS_SQUARED = 1000.0 * 1000.0; @@ -263,6 +264,7 @@ private boolean isInvalid() { return false; } + @Override public boolean reelIn() { remove(); @@ -280,11 +282,7 @@ public boolean reelIn() { player.playSound(player.getLocation(), Sound.ITEM_TRIDENT_RETURN, 0.6f, 0.7f); Location playerLocation = player.getLocation(); - Vector velocity = playerLocation.toVector().subtract(hookLocation.toVector()); - - double distance = velocity.length(); - velocity.multiply(0.08); - velocity.setY(velocity.getY() + (Math.sqrt(distance) * 0.05) + 0.15); + Vector velocity = CustomFishingHook.calculateLaunchVelocity(hookLocation, playerLocation); Location spawnLocation = hookLocation.add(0, 0.5, 0); @@ -315,6 +313,7 @@ private void spawnVoidCollapseBurst(World world, Location center) { world.spawnParticle(Particle.END_ROD, center, 8, 0.1, 0.3, 0.1, 0.02); } + @Override public void remove() { ACTIVE_HOOKS.remove(hook.getUniqueId()); if (task != null && !task.isCancelled()) { @@ -326,6 +325,11 @@ public void remove() { } } + @Override + public ItemType getRequiredRodType() { + return ItemType.VOID_FISHING_ROD; + } + public static VoidFishingHook get(FishHook hook) { return ACTIVE_HOOKS.get(hook.getUniqueId()); } diff --git a/blighted-smp/src/test/java/fr/moussax/blightedSMP/engine/fishing/FishingTest.java b/blighted-smp/src/test/java/fr/moussax/blightedSMP/engine/fishing/FishingTest.java new file mode 100644 index 00000000..7ddf7735 --- /dev/null +++ b/blighted-smp/src/test/java/fr/moussax/blightedSMP/engine/fishing/FishingTest.java @@ -0,0 +1,84 @@ +package fr.moussax.blightedSMP.engine.fishing; + +import fr.moussax.blightedSMP.engine.fishing.hooks.CustomFishingHook; +import fr.moussax.blightedSMP.engine.fishing.modifiers.FishingSpeedCalculator; +import org.bukkit.Location; +import org.bukkit.util.Vector; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FishingTest { + + @Test + @DisplayName("FishingComboTracker bonuses scale correctly with combo and cap at maximum") + void testFishingComboBonuses() { + assertEquals(0.0, FishingComboTracker.getSeaCreatureChanceBonus(0), 1e-6); + assertEquals(0.0125, FishingComboTracker.getSeaCreatureChanceBonus(5), 1e-6); + assertEquals(0.025, FishingComboTracker.getSeaCreatureChanceBonus(10), 1e-6); + assertEquals(0.0375, FishingComboTracker.getSeaCreatureChanceBonus(15), 1e-6); + assertEquals(0.05, FishingComboTracker.getSeaCreatureChanceBonus(20), 1e-6); + assertEquals(0.05, FishingComboTracker.getSeaCreatureChanceBonus(30), 1e-6); + + assertEquals(0, FishingComboTracker.getBonusExperience(0)); + assertEquals(0, FishingComboTracker.getBonusExperience(4)); + assertEquals(2, FishingComboTracker.getBonusExperience(5)); + assertEquals(4, FishingComboTracker.getBonusExperience(10)); + assertEquals(6, FishingComboTracker.getBonusExperience(15)); + assertEquals(8, FishingComboTracker.getBonusExperience(20)); + assertEquals(8, FishingComboTracker.getBonusExperience(30)); + } + + @Test + @DisplayName("FishingSpeedCalculator wait time reduction applies diminishing returns correctly") + void testFishingSpeedCalculatorWaitTicks() { + int baseTicks = 300; + + assertEquals(300, FishingSpeedCalculator.applyToWaitTicks(baseTicks, 0)); + assertEquals(273, FishingSpeedCalculator.applyToWaitTicks(baseTicks, 10)); // 300 * (100/110) = 272.72 -> 273 + assertEquals(200, FishingSpeedCalculator.applyToWaitTicks(baseTicks, 50)); // 300 * (100/150) = 200 + assertEquals(150, FishingSpeedCalculator.applyToWaitTicks(baseTicks, 100)); // 300 * (100/200) = 150 + assertEquals(1, FishingSpeedCalculator.applyToWaitTicks(1, 1000)); // Never drops below 1 tick + } + + @Test + @DisplayName("CustomFishingHook launch velocity calculates expected trajectory arc") + void testCustomFishingHookLaunchVelocity() { + Location hookLocation = new Location(null, 0.0, 60.0, 0.0); + Location playerLocation = new Location(null, 3.0, 64.0, 0.0); + + Vector velocity = CustomFishingHook.calculateLaunchVelocity(hookLocation, playerLocation); + + assertEquals(3.0 * 0.08, velocity.getX(), 1e-6); + assertEquals(0.0, velocity.getZ(), 1e-6); + + double distance = 5.0; // sqrt(3^2 + 4^2) = 5 + double expectedY = (4.0 * 0.08) + (Math.sqrt(distance) * 0.05) + 0.15; + assertEquals(expectedY, velocity.getY(), 1e-6); + assertTrue(velocity.getY() > 0.45, "Launch velocity must include upward arc boost"); + } + + @Test + @DisplayName("FishingLootTable.Builder constructs table successfully with rich drop helpers") + void testFishingLootTableBuilder() { + FishingLootTable table = FishingLootTable.builder() + .entityRollChance(0.25) + .entity(org.bukkit.entity.EntityType.ZOMBIE, 10.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GOOD_CATCH) + .entity(org.bukkit.entity.EntityType.SKELETON, 5.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GREAT_CATCH, fr.moussax.blightedSMP.engine.loot.LootCondition.alwaysTrue()) + .entity(org.bukkit.entity.EntityType.SQUID, 8.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.COMMON, "§b§lSPLASH!") + .entity(org.bukkit.entity.EntityType.TROPICAL_FISH, 4.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GOOD_CATCH, "§d§lCOLORFUL!", true, fr.moussax.blightedSMP.engine.loot.LootCondition.alwaysTrue()) + .entity(org.bukkit.entity.EntityType.SILVERFISH, entity -> {}, 2.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GREAT_CATCH) + .item(org.bukkit.Material.COD, 50.0) + .item(org.bukkit.Material.SALMON, 2, 30.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GOOD_CATCH) + .item(org.bukkit.Material.PUFFERFISH, 1, 3, 10.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GREAT_CATCH) + .gems(5, 50.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GOOD_CATCH) + .gems(10, 20, 25.0, fr.moussax.blightedSMP.engine.loot.decorators.FishingCatchQuality.GREAT_CATCH) + .damagedItem(org.bukkit.Material.FISHING_ROD, 0.2, 0.8, 15.0) + .build(); + + org.junit.jupiter.api.Assertions.assertNotNull(table, "Constructed FishingLootTable must not be null"); + assertEquals(0.25, table.getEntityRollChance(), 1e-6); + } +}