diff --git a/build.gradle.kts b/build.gradle.kts index f80468c61..b840da473 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,3 @@ -import org.gradle.api.artifacts.VersionCatalog -import org.gradle.api.artifacts.VersionCatalogsExtension -import org.gradle.kotlin.dsl.getByType - plugins { base java @@ -14,6 +10,14 @@ version = "1.0" val libsCatalog: VersionCatalog = extensions.getByType().named("libs") +repositories { + mavenCentral() + mavenLocal() + maven("https://repo.viaversion.com") + maven("https://jitpack.io") + maven("https://repo.lucko.me/") +} + subprojects { apply(plugin = "java") apply(plugin = "java-library") diff --git a/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java b/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java index ec8113c04..0021effb6 100644 --- a/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java +++ b/commons/src/generated/java/net/swofty/commons/skyblock/item/ItemType.java @@ -1,6 +1,8 @@ // AUTO-GENERATED FILE. DO NOT EDIT. package net.swofty.commons.skyblock.item; +import java.lang.Exception; +import java.lang.String; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import org.jetbrains.annotations.Nullable; @@ -136,6 +138,8 @@ public enum ItemType { ATTACK_SPEED_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), + AUGER_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + AUTOPET_RULES_2_PACK(Material.PLAYER_HEAD, Rarity.SPECIAL), AUTO_RECOMBOBULATOR(Material.PLAYER_HEAD, Rarity.COMMON), @@ -316,6 +320,8 @@ public enum ItemType { BLAZE_ROD_DISTILLATE(Material.PLAYER_HEAD, Rarity.RARE), + BLESSED_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + BLOCK_DATA_TOOL(Material.DEBUG_STICK, Rarity.ADMIN), BLOCK_ZAPPER(Material.FLINT, Rarity.COMMON), @@ -402,6 +408,12 @@ public enum ItemType { BRONZE_BOWL(Material.PLAYER_HEAD, Rarity.UNCOMMON), + BRONZE_SHIP_ENGINE(Material.PLAYER_HEAD, Rarity.RARE), + + BRONZE_SHIP_HELM(Material.PLAYER_HEAD, Rarity.RARE), + + BRONZE_SHIP_HULL(Material.PLAYER_HEAD, Rarity.RARE), + BROWN_BANNER(Material.BROWN_BANNER, Rarity.COMMON), BROWN_BED(Material.BROWN_BED, Rarity.COMMON), @@ -518,6 +530,8 @@ public enum ItemType { CARROT(Material.CARROT, Rarity.COMMON), + CARROT_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + CARROT_CRYSTAL(Material.PLAYER_HEAD, Rarity.COMMON), CARROT_MINION(Material.PLAYER_HEAD, Rarity.COMMON), @@ -550,8 +564,12 @@ public enum ItemType { CHAINMAIL_LEGGINGS(Material.CHAINMAIL_LEGGINGS, Rarity.COMMON), + CHALLENGE_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + CHAMPION(Material.ENCHANTED_BOOK, Rarity.COMMON), + CHAMP_ROD(Material.FISHING_ROD, Rarity.RARE), + CHARCOAL(Material.CHARCOAL, Rarity.COMMON), CHARLIE_TROUSERS(Material.LEATHER_LEGGINGS, Rarity.COMMON), @@ -620,6 +638,10 @@ public enum ItemType { CHUM(Material.PLAYER_HEAD, Rarity.UNCOMMON), + CHUM_ROD(Material.FISHING_ROD, Rarity.RARE), + + CHUM_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + CLAY_BALL(Material.CLAY_BALL, Rarity.COMMON), CLAY_MINION(Material.PLAYER_HEAD, Rarity.COMMON), @@ -654,6 +676,8 @@ public enum ItemType { COMBAT_EXP_BOOST(Material.IRON_SWORD, Rarity.COMMON), + COMMON_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + COMPACT(Material.ENCHANTED_BOOK, Rarity.COMMON), COMPACTED_MOONFLOWER(Material.BLUE_ORCHID, Rarity.COMMON), @@ -678,6 +702,8 @@ public enum ItemType { CORNFLOWER(Material.CORNFLOWER, Rarity.COMMON), + CORRUPTED_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + COW_MINION(Material.PLAYER_HEAD, Rarity.COMMON), CRACKED_PIGGY_BANK(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -770,6 +796,8 @@ public enum ItemType { DANDELION(Material.DANDELION, Rarity.COMMON), + DARK_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + DARK_OAK_BOAT(Material.DARK_OAK_BOAT, Rarity.COMMON), DARK_OAK_BUTTON(Material.DARK_OAK_BUTTON, Rarity.COMMON), @@ -910,6 +938,8 @@ public enum ItemType { DIRT(Material.DIRT, Rarity.COMMON), + DIRT_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + DISPENSER(Material.DISPENSER, Rarity.COMMON), DITTO_BLOB(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1294,6 +1324,8 @@ public enum ItemType { FANCY_TUXEDO_LEGGINGS(Material.LEATHER_LEGGINGS, Rarity.COMMON), + FARMER_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + FARMING_EXP_BOOST_COMMON(Material.IRON_HOE, Rarity.COMMON), FARMING_EXP_BOOST_RARE(Material.IRON_HOE, Rarity.COMMON), @@ -1324,6 +1356,8 @@ public enum ItemType { FEROCITY_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), + FESTIVE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + FIERY_KUUDRA_CORE(Material.PLAYER_HEAD, Rarity.EPIC), FIGSTONE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1366,6 +1400,8 @@ public enum ItemType { FISHING_ROD(Material.FISHING_ROD, Rarity.COMMON), + FISH_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + FLAMES(Material.BLAZE_POWDER, Rarity.COMMON), FLAWED_AMBER_GEM(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -1446,6 +1482,8 @@ public enum ItemType { FRIED_FROZEN_CHICKEN(Material.PLAYER_HEAD, Rarity.EPIC), + FROZEN_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + FROZEN_CHICKEN(Material.PLAYER_HEAD, Rarity.RARE), FTX_3070(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1472,6 +1510,8 @@ public enum ItemType { GHAST_TEAR(Material.GHAST_TEAR, Rarity.UNCOMMON), + GIANT_FISHING_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + GILL_MEMBRANE(Material.PLAYER_HEAD, Rarity.COMMON), GLACIAL_ARTIFACT(Material.PLAYER_HEAD, Rarity.RARE), @@ -1510,12 +1550,16 @@ public enum ItemType { GLOWSTONE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + GLOWY_CHUM_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + GOBLIN_EGG(Material.EGG, Rarity.COMMON), GOD_POTION(Material.PLAYER_HEAD, Rarity.COMMON), GOLDEN_AXE(Material.GOLDEN_AXE, Rarity.COMMON), + GOLDEN_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + GOLDEN_BOOTS(Material.GOLDEN_BOOTS, Rarity.COMMON), GOLDEN_CARROT(Material.GOLDEN_CARROT, Rarity.COMMON), @@ -1670,6 +1714,8 @@ public enum ItemType { HELIX(Material.PLAYER_HEAD, Rarity.COMMON), + HELLFIRE_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + HIGH_CLASS_ARCHFIEND_DICE(Material.PLAYER_HEAD, Rarity.LEGENDARY), HOLOGRAM(Material.PLAYER_HEAD, Rarity.COMMON), @@ -1686,6 +1732,14 @@ public enum ItemType { HORSEMAN_CANDLE(Material.PLAYER_HEAD, Rarity.RARE), + HOTSPOT_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + + HOTSPOT_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + + HOTSPOT_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + + HOT_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + HOT_POTATO_BOOK(Material.BOOK, Rarity.EPIC), HUB_CASTLE_TRAVEL_SCROLL(Material.PAPER, Rarity.UNCOMMON), @@ -1710,12 +1764,20 @@ public enum ItemType { ICE(Material.ICE, Rarity.COMMON), + ICE_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + ICE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + ICE_ROD(Material.FISHING_ROD, Rarity.RARE), + + ICY_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + INFERNAL_KUUDRA_CORE(Material.PLAYER_HEAD, Rarity.LEGENDARY), INFERNO_FUEL_BLOCK(Material.PLAYER_HEAD, Rarity.COMMON), + INFERNO_ROD(Material.FISHING_ROD, Rarity.EPIC), + INFINI_TORCH(Material.TORCH, Rarity.EPIC), INK_SAC(Material.INK_SAC, Rarity.COMMON), @@ -1830,6 +1892,8 @@ public enum ItemType { JUNK_RING(Material.PLAYER_HEAD, Rarity.UNCOMMON), + JUNK_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + JUNK_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), KAT_BOUQUET(Material.ROSE_BUSH, Rarity.COMMON), @@ -1912,10 +1976,14 @@ public enum ItemType { LEATHER_LEGGINGS(Material.LEATHER_LEGGINGS, Rarity.COMMON), + LEGEND_ROD(Material.FISHING_ROD, Rarity.EPIC), + LEVER(Material.LEVER, Rarity.COMMON), LIGHTER_BLUE_ABICASE(Material.PLAYER_HEAD, Rarity.COMMON), + LIGHT_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + LIGHT_BLUE_BANNER(Material.LIGHT_BLUE_BANNER, Rarity.COMMON), LIGHT_BLUE_BED(Material.LIGHT_BLUE_BED, Rarity.COMMON), @@ -2032,6 +2100,8 @@ public enum ItemType { MAGMA_CUBE_MINION(Material.PLAYER_HEAD, Rarity.COMMON), + MAGMA_ROD(Material.FISHING_ROD, Rarity.RARE), + MANA_DISINTEGRATOR(Material.PLAYER_HEAD, Rarity.RARE), MANGCORE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -2160,6 +2230,8 @@ public enum ItemType { MINION_STORAGE_EXPANDER(Material.PLAYER_HEAD, Rarity.COMMON), + MINNOW_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + MINOS_RELIC(Material.PLAYER_HEAD, Rarity.EPIC), MITHRIL(Material.PRISMARINE_CRYSTALS, Rarity.COMMON), @@ -2432,6 +2504,10 @@ public enum ItemType { PET_LUCK_POTION_1(Material.POTION, Rarity.COMMON), + PHANTOM_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + + PHANTOM_ROD(Material.FISHING_ROD, Rarity.LEGENDARY), + PICKONIMBUS_2000(Material.DIAMOND_PICKAXE, Rarity.COMMON), PIGGY_BANK(Material.PLAYER_HEAD, Rarity.UNCOMMON), @@ -2502,6 +2578,8 @@ public enum ItemType { POLISHED_PUMPKIN(Material.PLAYER_HEAD, Rarity.COMMON), + POLISHED_TOPAZ_ROD(Material.FISHING_ROD, Rarity.RARE), + POOCH_SWORD(Material.GOLDEN_SWORD, Rarity.LEGENDARY), POPPY(Material.POPPY, Rarity.COMMON), @@ -2548,8 +2626,12 @@ public enum ItemType { PRISMARINE_CRYSTALS(Material.PRISMARINE_CRYSTALS, Rarity.COMMON), + PRISMARINE_ROD(Material.FISHING_ROD, Rarity.COMMON), + PRISMARINE_SHARD(Material.PRISMARINE_SHARD, Rarity.COMMON), + PRISMARINE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + PROMISING_AXE(Material.IRON_AXE, Rarity.COMMON), PROMISING_PICKAXE(Material.IRON_PICKAXE, Rarity.UNCOMMON), @@ -2766,6 +2848,8 @@ public enum ItemType { ROBOTRON_REFLECTOR(Material.PLAYER_HEAD, Rarity.COMMON), + ROD_OF_THE_SEA(Material.FISHING_ROD, Rarity.LEGENDARY), + ROGUE_SWORD(Material.GOLDEN_SWORD, Rarity.COMMON), ROOKIE_AXE(Material.STONE_AXE, Rarity.COMMON), @@ -2824,6 +2908,8 @@ public enum ItemType { RUSTY_COIN(Material.PLAYER_HEAD, Rarity.UNCOMMON), + RUSTY_SHIP_ENGINE(Material.PLAYER_HEAD, Rarity.SPECIAL), + SAND(Material.SAND, Rarity.COMMON), SANDBOX_ITEM(Material.BLAZE_POWDER, Rarity.COMMON), @@ -2880,6 +2966,8 @@ public enum ItemType { SHARD_OF_THE_SHREDDED(Material.PLAYER_HEAD, Rarity.COMMON), + SHARK_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + SHARK_FIN(Material.PRISMARINE_SHARD, Rarity.RARE), SHARPENED_CLAWS(Material.PRISMARINE_SHARD, Rarity.COMMON), @@ -2892,6 +2980,8 @@ public enum ItemType { SHORT_GRASS(Material.SHORT_GRASS, Rarity.COMMON), + SHREDDED_LINE(Material.PLAYER_HEAD, Rarity.RARE), + SILVER_FANG(Material.IRON_SWORD, Rarity.UNCOMMON), SILVER_MAGMAFISH(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3026,6 +3116,10 @@ public enum ItemType { SOUL_STRING(Material.STRING, Rarity.COMMON), + SPEEDSTER_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + + SPEEDY_LINE(Material.PLAYER_HEAD, Rarity.RARE), + SPEED_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), SPEED_ENRICHMENT(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3056,8 +3150,16 @@ public enum ItemType { SPIDER_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), + SPIKED_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + SPONGE(Material.SPONGE, Rarity.COMMON), + SPONGE_ROD(Material.FISHING_ROD, Rarity.COMMON), + + SPONGE_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + + SPOOKY_BAIT(Material.PLAYER_HEAD, Rarity.COMMON), + SPOOKY_SHARD(Material.PLAYER_HEAD, Rarity.RARE), SPRUCE_BOAT(Material.SPRUCE_BOAT, Rarity.COMMON), @@ -3120,10 +3222,14 @@ public enum ItemType { STARLYN_PRIZE(Material.PLAYER_HEAD, Rarity.COMMON), + STARTER_LAVA_ROD(Material.FISHING_ROD, Rarity.UNCOMMON), + STICK(Material.STICK, Rarity.COMMON), STICKY_PISTON(Material.STICKY_PISTON, Rarity.COMMON), + STINGY_SINKER(Material.PLAYER_HEAD, Rarity.RARE), + STONE(Material.STONE, Rarity.COMMON), STONE_AXE(Material.STONE_AXE, Rarity.COMMON), @@ -3260,6 +3366,8 @@ public enum ItemType { TESSELLATED_ENDER_PEARL(Material.PLAYER_HEAD, Rarity.LEGENDARY), + THE_SHREDDER(Material.FISHING_ROD, Rarity.LEGENDARY), + TIGER_SHARK_TOOTH(Material.GHAST_TEAR, Rarity.EPIC), TIGHTLY_TIED_HAY_BALE(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3274,6 +3382,8 @@ public enum ItemType { TITANIUM_TALISMAN(Material.PLAYER_HEAD, Rarity.UNCOMMON), + TITAN_LINE(Material.PLAYER_HEAD, Rarity.RARE), + TNT(Material.TNT, Rarity.COMMON), TNT_MINECART(Material.TNT_MINECART, Rarity.COMMON), @@ -3290,6 +3400,10 @@ public enum ItemType { TREASURE_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), + TREASURE_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + + TREASURE_HOOK(Material.PLAYER_HEAD, Rarity.RARE), + TREASURE_RING(Material.PLAYER_HEAD, Rarity.COMMON), TREASURE_TALISMAN(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3380,6 +3494,8 @@ public enum ItemType { WET_WATER(Material.PLAYER_HEAD, Rarity.COMMON), + WHALE_BAIT(Material.PLAYER_HEAD, Rarity.RARE), + WHEAT(Material.WHEAT, Rarity.COMMON), WHEAT_CRYSTAL(Material.PLAYER_HEAD, Rarity.COMMON), @@ -3418,6 +3534,8 @@ public enum ItemType { WILSON_ENGINEERING_PLANS(Material.PAPER, Rarity.LEGENDARY), + WINTER_ROD(Material.FISHING_ROD, Rarity.RARE), + WISHING_COMPASS(Material.PLAYER_HEAD, Rarity.COMMON), WITHER_ARTIFACT(Material.PLAYER_HEAD, Rarity.EPIC), @@ -3438,6 +3556,8 @@ public enum ItemType { WOODEN_AXE(Material.WOODEN_AXE, Rarity.COMMON), + WOODEN_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + WOODEN_HOE(Material.WOODEN_HOE, Rarity.COMMON), WOODEN_PICKAXE(Material.WOODEN_PICKAXE, Rarity.COMMON), @@ -3446,6 +3566,8 @@ public enum ItemType { WOODEN_SWORD(Material.WOODEN_SWORD, Rarity.COMMON), + WORM_BAIT(Material.PLAYER_HEAD, Rarity.UNCOMMON), + WORM_MEMBRANE(Material.ROTTEN_FLESH, Rarity.COMMON), YELLOW_BANNER(Material.YELLOW_BANNER, Rarity.COMMON), @@ -3470,6 +3592,8 @@ public enum ItemType { YELLOW_WOOL(Material.YELLOW_WOOL, Rarity.COMMON), + YETI_ROD(Material.FISHING_ROD, Rarity.EPIC), + ZOMBIE_ARTIFACT(Material.PLAYER_HEAD, Rarity.COMMON), ZOMBIE_BRAIN_MIXIN(Material.PLAYER_HEAD, Rarity.COMMON), diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java new file mode 100644 index 000000000..1eb86bfcb --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingExpertiseKills extends ItemAttribute { + @Override + public String getKey() { + return "fishing_expertise_kills"; + } + + @Override + public Long getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return 0L; + } + + @Override + public Long loadFromString(String string) { + return Long.parseLong(string); + } + + @Override + public String saveIntoString() { + return String.valueOf(getValue()); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java new file mode 100644 index 000000000..704b574c7 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingHook extends ItemAttribute { + @Override + public String getKey() { + return "fishing_hook"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java new file mode 100644 index 000000000..bf6ca37ba --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingLine extends ItemAttribute { + @Override + public String getKey() { + return "fishing_line"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java new file mode 100644 index 000000000..daa12ee81 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java @@ -0,0 +1,27 @@ +package net.swofty.commons.skyblock.item.attribute.attributes; + +import net.swofty.commons.skyblock.item.attribute.ItemAttribute; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +public class ItemAttributeFishingSinker extends ItemAttribute { + @Override + public String getKey() { + return "fishing_sinker"; + } + + @Override + public String getDefaultValue(@Nullable ItemStatistics defaultStatistics) { + return "none"; + } + + @Override + public String loadFromString(String string) { + return string == null || string.isBlank() ? "none" : string; + } + + @Override + public String saveIntoString() { + return getValue() == null || getValue().isBlank() ? "none" : getValue(); + } +} diff --git a/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java b/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java index 2c9e75300..bf2f12a24 100644 --- a/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java +++ b/commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java @@ -80,6 +80,9 @@ public enum ItemStatistic { PET_LUCK("Pet Luck", "§a", "§d", false, "♣"), SEA_CREATURE_CHANCE("Sea Creature Chance", "§c", "§9", true, "α", 2D, 1D), FISHING_SPEED("Fishing Speed", "§a", "§b", false, "☂"), + TREASURE_CHANCE("Treasure Chance", "§a", "§6", true, "⛃"), + TROPHY_FISH_CHANCE("Trophy Fish Chance", "§a", "§6", true, "♔"), + DOUBLE_HOOK_CHANCE("Double Hook Chance", "§a", "§3", true, "⚓"), BONUS_PEST_CHANCE("Bonus Pest Chance", "§a", "§2", true, "ൠ"), HEAT_RESISTANCE("Heat Resistance","§a","§c",false,"♨"), COLD_RESISTANCE("Cold Resistance", "§a", "§b", false, "❄"), diff --git a/configuration/skyblock/fishing/hotspots.yml b/configuration/skyblock/fishing/hotspots.yml new file mode 100644 index 000000000..c266f0dc0 --- /dev/null +++ b/configuration/skyblock/fishing/hotspots.yml @@ -0,0 +1,19 @@ +hotspots: + - id: BAYOU_WATER_1 + medium: WATER + regions: + - BACKWATER_BAYOU + serverType: BACKWATER_BAYOU + durationSeconds: 120 + maxActive: 2 + buffs: + FISHING_SPEED: 15 + SEA_CREATURE_CHANCE: 5 + DOUBLE_HOOK_CHANCE: 2 + TROPHY_FISH_CHANCE: 5 + TREASURE_CHANCE: 1 + spawnPoints: + - serverType: BACKWATER_BAYOU + x: 100 + y: 50 + z: 100 diff --git a/configuration/skyblock/fishing/tables.yml b/configuration/skyblock/fishing/tables.yml new file mode 100644 index 000000000..a429e3b80 --- /dev/null +++ b/configuration/skyblock/fishing/tables.yml @@ -0,0 +1,206 @@ +tables: + - id: DEFAULT_WATER + regions: [ ] + mediums: + - WATER + items: + - itemId: RAW_FISH + chance: 36 + amount: 1 + skillXp: 5 + - itemId: RAW_SALMON + chance: 22 + amount: 1 + skillXp: 6 + - itemId: PUFFERFISH + chance: 10 + amount: 1 + skillXp: 7 + - itemId: INK_SAC + chance: 8 + amount: 1 + skillXp: 5 + - itemId: LILY_PAD + chance: 8 + amount: 1 + skillXp: 5 + - itemId: CLAY_BALL + chance: 6 + amount: 1 + skillXp: 5 + - itemId: PRISMARINE_CRYSTALS + chance: 4 + amount: 1 + skillXp: 6 + - itemId: PRISMARINE_SHARD + chance: 3 + amount: 1 + skillXp: 6 + - itemId: TROPICAL_FISH + chance: 2 + amount: 1 + skillXp: 8 + - itemId: SPONGE + chance: 1 + amount: 1 + skillXp: 10 + treasures: + - itemId: PRISMARINE_CRYSTALS + chance: 50 + amount: 2 + skillXp: 10 + - itemId: PRISMARINE_SHARD + chance: 35 + amount: 2 + skillXp: 10 + - itemId: SPONGE + chance: 15 + amount: 1 + skillXp: 12 + junk: [ ] + seaCreatures: + - seaCreatureId: SQUID + chance: 6 + - seaCreatureId: SEA_WALKER + chance: 4 + - seaCreatureId: NIGHT_SQUID + chance: 2 + - id: DEFAULT_LAVA + regions: [ ] + mediums: + - LAVA + items: + - itemId: MAGMAFISH + chance: 100 + amount: 1 + skillXp: 10 + treasures: + - itemId: MAGMAFISH + chance: 100 + amount: 2 + skillXp: 15 + junk: [ ] + seaCreatures: + - seaCreatureId: LAVA_BLAZE + chance: 5 + - id: BAYOU_WATERS + regions: + - BACKWATER_BAYOU + mediums: + - WATER + items: + - itemId: RAW_FISH + chance: 30 + amount: 1 + skillXp: 5 + - itemId: RAW_SALMON + chance: 20 + amount: 1 + skillXp: 6 + - itemId: PUFFERFISH + chance: 10 + amount: 1 + skillXp: 7 + - itemId: INK_SAC + chance: 8 + amount: 1 + skillXp: 5 + - itemId: LILY_PAD + chance: 8 + amount: 1 + skillXp: 5 + - itemId: CLAY_BALL + chance: 8 + amount: 1 + skillXp: 5 + - itemId: PRISMARINE_CRYSTALS + chance: 5 + amount: 1 + skillXp: 6 + - itemId: PRISMARINE_SHARD + chance: 4 + amount: 1 + skillXp: 6 + - itemId: TROPICAL_FISH + chance: 5 + amount: 1 + skillXp: 8 + - itemId: SPONGE + chance: 2 + amount: 1 + skillXp: 10 + treasures: + - itemId: PRISMARINE_CRYSTALS + chance: 40 + amount: 2 + skillXp: 10 + - itemId: PRISMARINE_SHARD + chance: 30 + amount: 2 + skillXp: 10 + - itemId: SPONGE + chance: 20 + amount: 1 + skillXp: 12 + - itemId: CLAY_BALL + chance: 10 + amount: 4 + skillXp: 8 + junk: + - itemId: RUSTY_COIN + chance: 50 + amount: 1 + skillXp: 2 + - itemId: BUSTED_BELT_BUCKLE + chance: 30 + amount: 1 + skillXp: 2 + - itemId: OLD_LEATHER_BOOT + chance: 20 + amount: 1 + skillXp: 2 + seaCreatures: + - seaCreatureId: ALLIGATOR + chance: 5 + - seaCreatureId: BANSHEE + chance: 3 + - seaCreatureId: BAYOU_SLUDGE + chance: 3 + - seaCreatureId: DUMPSTER_DIVER + chance: 2 + - seaCreatureId: TITANOBOA + chance: 1 + - seaCreatureId: TRASH_GOBBLER + chance: 1 + - id: CRIMSON_ISLE_LAVA + regions: + - CRIMSON_ISLE + - BLAZING_VOLCANO + mediums: + - LAVA + items: + - itemId: MAGMAFISH + chance: 100 + amount: 1 + skillXp: 10 + treasures: + - itemId: MAGMAFISH + chance: 75 + amount: 2 + skillXp: 15 + - itemId: SULPHUR + chance: 25 + amount: 2 + skillXp: 15 + junk: [ ] + seaCreatures: + - seaCreatureId: LAVA_BLAZE + chance: 3 + - seaCreatureId: FRIED_CHICKEN + chance: 2 + - seaCreatureId: FIREPROOF_WITCH + chance: 2 + - seaCreatureId: FIERY_SCUTTLER + chance: 1 + - seaCreatureId: RAGNAROK + chance: 1 diff --git a/configuration/skyblock/fishing/trophy_fish.yml b/configuration/skyblock/fishing/trophy_fish.yml new file mode 100644 index 000000000..229f74b3d --- /dev/null +++ b/configuration/skyblock/fishing/trophy_fish.yml @@ -0,0 +1,13 @@ +trophyFish: + - id: MAGMAFISH + displayName: Magmafish + catchChance: 18 + regions: [ ] + requiredFishingLevel: 0 + minimumCastTimeMs: 0 + requiresStarterRodWithoutEnchantments: false + specialGoldenFish: false + bronzeItemId: MAGMAFISH + silverItemId: SILVER_MAGMAFISH + goldItemId: GOLD_MAGMAFISH + diamondItemId: DIAMOND_MAGMAFISH diff --git a/configuration/skyblock/items/fishing/baits.yml b/configuration/skyblock/items/fishing/baits.yml new file mode 100644 index 000000000..cbc70be98 --- /dev/null +++ b/configuration/skyblock/items/fishing/baits.yml @@ -0,0 +1,171 @@ +items: + - id: MINNOW_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + texture: b8e749ba141c054bb0c125320b17677bdcb3a7e9807a57527c0877b94548a2e + + - id: FISH_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 45 + components: + - id: FISHING_BAIT + texture: 49e8dc9fdc9f00e1d17666a4787d34cca7cc6dc030f0dc686195546f81c6f22 + + - id: LIGHT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: e3bcc16f402342b4acd29aecac72d1d5a116e0abb478bb4960e734fd70686ba + + - id: DARK_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 7281618a5c8239078fd43fef8eae14ea00665f635bd56d4451cccd5d0fa11821 + + - id: SPIKED_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + SEA_CREATURE_CHANCE: 6 + components: + - id: FISHING_BAIT + texture: e42c436c6580fad217323b9f045daa23a9f88219ac26506637669eff20901f74 + + - id: SPOOKY_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + tag_bonuses: + SPOOKY: 15 + texture: 977eab558e6a90f7cedd72c2416c891f47d71eb4e7bdcc299a6335286f5cba98 + + - id: CARROT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b + + - id: CORRUPTED_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + texture: 4bbcddd45cd347865bceab3e3dc5d382723463963f85ecce81cdd61b53db14e4 + + - id: BLESSED_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + treasure_quality_bonus: 50 + texture: c2b910b5897cdb86b21ebfcba544afa470ae6d228bee3494427c9c7e8f33502b + + - id: ICE_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + tag_bonuses: + WINTER: 20 + texture: 609e161bdc325c71572a548a79bb15481c924d63e4fb821379d5dd6c8929f39f + + - id: SHARK_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + tag_bonuses: + SHARK: 20 + texture: edff904124efe486b3a54261dbb8072b0a4e11615ad8d7394d814e0e8c8ef9eb + + - id: GLOWY_CHUM_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 25 + SEA_CREATURE_CHANCE: 3 + components: + - id: FISHING_BAIT + texture: dfdc1eed684dd805eae96d132e3da53d64267d7361388d5e2c67f5969871e71d + + - id: HOT_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + trophy_fish_chance_bonus: 5 + texture: 213c6899d97109c6cacbbcdd01e8900abaf46432f197595baa15ad137d5fb9ba + + - id: WORM_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 60 + components: + - id: FISHING_BAIT + texture: df03ad96092f3f789902436709cdf69de6b727c121b3c2daef9ffa1ccaed186c + + - id: FROZEN_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + tag_bonuses: + WINTER: 35 + texture: 38dc68a97cefe92c8cdaa7cb1a7a4de8f16c161da736edf54f79b74beecd6513 + + - id: GOLDEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + treasure_chance_bonus: 4 + texture: 72e2908dbb112dcd0b367df43fafcc41a56d9cf803e90a367834b4911f84f391 + + - id: TREASURE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 10 + components: + - id: FISHING_BAIT + treasure_chance_bonus: 2 + texture: c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e + + - id: WOODEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + texture: 5b236a39e51a39dff9bced39333a73413984bc74db37c1318bfc4a4459f035d2 + + - id: HOTSPOT_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + tag_bonuses: + HOTSPOT: 50 + texture: de9b17db5c4cadef737e2fefb42a0123c32cbeaa1ca8932579eb2f05018612cd + + - id: WHALE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 30 + components: + - id: FISHING_BAIT + texture: 5b4fb49ae77cfcf0b8f62df9c69cc96b27096ad2737d6d0aa450b50664fb2303 diff --git a/configuration/skyblock/items/fishing/parts.yml b/configuration/skyblock/items/fishing/parts.yml new file mode 100644 index 000000000..5433e2fb1 --- /dev/null +++ b/configuration/skyblock/items/fishing/parts.yml @@ -0,0 +1,191 @@ +items: + - id: COMMON_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 5 + tag_bonuses: + COMMON: 25 + texture: d235388f091b7fd13397151fca580fdf9a41c2a0a297f887838710f629aa3fd6 + + - id: HOTSPOT_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 20 + tag_bonuses: + HOTSPOT: 100 + texture: 17415df9f4c8cdabdacd442da80826188e46a3d166f56fd1509bba26faac76dd + + - id: PHANTOM_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 21 + tag_bonuses: + SPOOKY: 100 + texture: c95eff1654366d5245238ddbfb65a7a7128468a9ce343861fe239e87c14c3f6d + + - id: TREASURE_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: HOOK + required_fishing_level: 25 + treasure_only: true + texture: 9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e + + - id: SPEEDY_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 10 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 5 + texture: 5cbac3c84e21e65ec88007604c4eba1da391e185544b90252fc16ca695c59b4b + + - id: SHREDDED_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + DAMAGE: 250 + FEROCITY: 50 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 20 + texture: f5424291868be6ae16512641666c5286a740f936e42f96e34987fb6f43d16e6e + + - id: TITAN_LINE + material: PLAYER_HEAD + rarity: RARE + default_statistics: + DOUBLE_HOOK_CHANCE: 2 + components: + - id: FISHING_ROD_PART + category: LINE + required_fishing_level: 35 + texture: 9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9 + + - id: JUNK_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + bayou_treasure_to_junk: true + texture: d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500 + + - id: PRISMARINE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: PRISMARINE_SHARD + texture: b9d2d0fe4c93fbc21309e93d985df37e1133d2ece58d2f96b6be5cffba53c181 + + - id: SPONGE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: SPONGE + texture: 8b24369807fcf3bd852e6da87ddeca9d38a04f32c78599f4c5823b9522278259 + + - id: CHUM_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_item_id: CHUM + texture: d02b855b4acc508086248ff468aaaaba0c0d8deaa2adc0321ed0809e416736ef + + - id: FESTIVE_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + materialized_chance: 0.05 + texture: 6f5840e5b76a2ed0de1c2280ae8be0edd90d83e5f8408af9f1e92f2db92e0383 + + - id: ICY_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + tag_bonuses: + WINTER: 200 + materialized_item_id: ICE + texture: 41dfb1861aa0dd49f7bd8a4ecb14fbda35055fbe9b06b4d7be5cdde0fc7cc60e + + - id: STINGY_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 5 + bait_preservation_chance: 10.0 + texture: e886d5cac32bd32fc07938908c552b7b27965d92065b3157dfc7ef849281ee9d + + - id: HOTSPOT_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + category: SINKER + required_fishing_level: 20 + hotspot_buff_multiplier: 2.0 + texture: 88891d33b55dd1572814527b9c027ec724909c26281a197d0309fbfa925cbce4 + + - id: RUSTY_SHIP_ENGINE + material: PLAYER_HEAD + rarity: SPECIAL + components: + - id: FISHING_SHIP_PART + slot: ENGINE + texture: 53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c + + - id: BRONZE_SHIP_ENGINE + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: ENGINE + texture: 9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925 + + - id: BRONZE_SHIP_HELM + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: HELM + texture: 646c5393c3c57742c992c56a7b7a8b98d267538de947c1096fe76341431008f2 + + - id: BRONZE_SHIP_HULL + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + slot: HULL + texture: a4a7254f1ad8448097d83ddfc790c9f02bc889acbd304b414cee5a13ceadc1e diff --git a/configuration/skyblock/items/fishing/rods.yml b/configuration/skyblock/items/fishing/rods.yml new file mode 100644 index 000000000..0129732bc --- /dev/null +++ b/configuration/skyblock/items/fishing/rods.yml @@ -0,0 +1,292 @@ +items: + - id: CHALLENGE_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 75 + STRENGTH: 75 + FISHING_SPEED: 35 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 10 + + - id: CHAMP_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 90 + STRENGTH: 80 + FISHING_SPEED: 90 + SEA_CREATURE_CHANCE: 4 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 15 + + - id: LEGEND_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 130 + STRENGTH: 120 + FISHING_SPEED: 105 + SEA_CREATURE_CHANCE: 6 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 20 + + - id: ROD_OF_THE_SEA + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 150 + STRENGTH: 150 + FISHING_SPEED: 80 + SEA_CREATURE_CHANCE: 8 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 24 + + - id: GIANT_FISHING_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 20 + STRENGTH: 10 + FISHING_SPEED: 20 + DOUBLE_HOOK_CHANCE: 10 + components: + - id: FISHING_ROD_METADATA + medium: WATER + + - id: DIRT_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 20 + components: + - id: FISHING_ROD_METADATA + medium: WATER + rod_parts_enabled: false + + - id: STARTER_LAVA_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 50 + STRENGTH: 50 + FISHING_SPEED: 10 + TROPHY_FISH_CHANCE: 5 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 10 + + - id: POLISHED_TOPAZ_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 100 + STRENGTH: 100 + FISHING_SPEED: 50 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 19 + extra_requirements: + - "❣ Requires Heart of the Mountain Tier 5." + + - id: MAGMA_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 150 + STRENGTH: 120 + FISHING_SPEED: 40 + SEA_CREATURE_CHANCE: 6 + TROPHY_FISH_CHANCE: 10 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 27 + + - id: INFERNO_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 210 + STRENGTH: 150 + FISHING_SPEED: 60 + SEA_CREATURE_CHANCE: 10 + TROPHY_FISH_CHANCE: 15 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 30 + + - id: HELLFIRE_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 225 + STRENGTH: 225 + FISHING_SPEED: 60 + SEA_CREATURE_CHANCE: 14 + TROPHY_FISH_CHANCE: 20 + components: + - id: FISHING_ROD_METADATA + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 35 + + - id: CHUM_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 55 + STRENGTH: 40 + FISHING_SPEED: 70 + SEA_CREATURE_CHANCE: 2 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 5 + legacy_conversion_target: CHALLENGE_ROD + + - id: PRISMARINE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 15 + STRENGTH: 10 + FISHING_SPEED: 15 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 3 + legacy_conversion_target: CHALLENGE_ROD + + - id: SPONGE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 20 + STRENGTH: 15 + FISHING_SPEED: 30 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 5 + legacy_conversion_target: CHALLENGE_ROD + + - id: SPEEDSTER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 30 + STRENGTH: 15 + FISHING_SPEED: 45 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 6 + legacy_conversion_target: CHALLENGE_ROD + + - id: FARMER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 50 + STRENGTH: 20 + FISHING_SPEED: 60 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 8 + legacy_conversion_target: CHALLENGE_ROD + + - id: ICE_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 30 + FISHING_SPEED: 15 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 3 + legacy_conversion_target: CHALLENGE_ROD + + - id: WINTER_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 50 + STRENGTH: 50 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 10 + legacy_conversion_target: CHALLENGE_ROD + + - id: YETI_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 150 + STRENGTH: 130 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 25 + legacy_conversion_target: CHALLENGE_ROD + + - id: THE_SHREDDER + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 120 + FEROCITY: 50 + FISHING_SPEED: 115 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 20 + legacy_conversion_target: CHALLENGE_ROD + + - id: PHANTOM_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 200 + STRENGTH: 125 + FISHING_SPEED: 100 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 21 + legacy_conversion_target: CHALLENGE_ROD + + - id: AUGER_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 135 + STRENGTH: 90 + FISHING_SPEED: 110 + components: + - id: FISHING_ROD_METADATA + medium: WATER + required_fishing_level: 25 + legacy_conversion_target: ROD_OF_THE_SEA diff --git a/configuration/skyblock/items/vanillaItems.yml b/configuration/skyblock/items/vanillaItems.yml index 11451d222..d0e55dec2 100644 --- a/configuration/skyblock/items/vanillaItems.yml +++ b/configuration/skyblock/items/vanillaItems.yml @@ -186,6 +186,11 @@ items: material: FISHING_ROD rarity: COMMON components: + - id: FISHING_ROD + - id: FISHING_ROD_METADATA + display_name: Fishing Rod + medium: WATER + rod_parts_enabled: true - id: DEFAULT_CRAFTABLE recipes: - type: SHAPED @@ -926,4 +931,3 @@ items: type: JUKEBOX amount: 1 - diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java index d4905f1ff..092c5d4ad 100644 --- a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/TypeBackwaterBayouLoader.java @@ -42,9 +42,7 @@ public void afterInitialize(MinecraftServer server) { @Override public LoaderValues getLoaderValues() { return new LoaderValues( - (type) -> switch (type) { - default -> new Pos(-12.5, 74, -10.5, -55, 0); - }, // Spawn position + (type) -> new Pos(-12.5, 74, -10.5, -55, 0), // Spawn position true // Announce death messages ); } diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java new file mode 100644 index 000000000..ce4ab913c --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIFishingRodParts extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIFishingRodParts { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java new file mode 100644 index 000000000..1abe3f435 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIHook extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIHookGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java new file mode 100644 index 000000000..35ee873cb --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java @@ -0,0 +1,461 @@ +package net.swofty.type.backwaterbayou.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +// TODO: use ShopView +public class GUIJunkerJoel extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Junker Joel", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + layout.slot(10, ItemStackCreator.getStackHead( + "§9Junk Sinker", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§7Grants §6+10⛃ Treasure Chance §7while", + "§7in the §2Backwater Bayou §7but replaces", + "§7all §6Treasure §7catches with §2Junk§7!", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Sinker §7to a", + "§7Fishing Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§610,000 Coins", + "", + "§eClick to trade!" + )); + layout.slot(11, ItemStackCreator.getStackHead( + "§9Treasure Bait §8x16", + "c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e", + 16, + "§8Fishing Bait", + "§8Consumes on Cast", + "", + "§7Grants §b+10☂ Fishing Speed§7 and §6+2⛃", + "§6Treasure Chance§7.", + "", + "§9§lRARE BAIT", + "", + "§7Cost", + "§aRusty Coin", + "", + "§eClick to trade!", + "§eRight-click for more trading options!" + )); + layout.slot(12, ItemStackCreator.getStack( + "§aChallenging Rod", + Material.FISHING_ROD, + 1, + "§7Damage: §c+75", + "§7Strength: §c+75", + "§7Fishing Speed: §b+35", + "§7Sea Creature Chance: §3+2%", + "", + "§9ථ Hook §8§lNONE", + "§9ꨃ Line §8§lNONE", + "§9࿉ Sinker §8§lNONE", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply parts to this rod.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON FISHING ROD", + "", + "§7Cost", + "§fFishing Rod", + "§aRusty Coin §8x16", + "", + "§eClick to trade!" + )); + layout.slot(13, ItemStackCreator.getStackHead( + "§aBackwater Helmet", + "f6f6c3ebab908a184d49a0f8c85edd3ed48a65d69213bc0367db67a7a1c0c3a7", + 1, + "§7Health: §c+30", + "§7Defense: §a+15", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON HELMET", + "", + "§7Cost", + "§fAngler Helmet", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(14, ItemStackCreator.getStack( + "§aBackwater Chestplate", + Material.LEATHER_CHESTPLATE, + 1, + "§7Health: §c+50", + "§7Defense: §a+25", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON CHESTPLATE", + "", + "§7Cost", + "§fAngler Chestplate", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(15, ItemStackCreator.getStack( + "§aBackwater Leggings", + Material.LEATHER_LEGGINGS, + 1, + "§7Health: §c+40", + "§7Defense: §a+20", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON LEGGINGS", + "", + "§7Cost", + "§fAngler Leggings", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(16, ItemStackCreator.getStack( + "§aBackwater Boots", + Material.LEATHER_BOOTS, + 1, + "§7Health: §c+20", + "§7Defense: §a+10", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON BOOTS", + "", + "§7Cost", + "§fAngler Boots", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(19, ItemStackCreator.getStackHead( + "§fJunk Talisman", + "d24c6d00c53b51685a6be7453d236228f9837f1c1e27a9175813983ca49c792f", + 1, + "§7Grants §6+2.5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§f§lCOMMON ACCESSORY", + "", + "§7Cost", + "§aRusty Coin §8x32", + "", + "§eClick to trade!" + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§aJunk Ring", + "4c920d3593ed4936defc894b88c43a2bb0b50c3a1e9a6dd8e859cb27bd3cabd", + 1, + "§7Grants §6+5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§a§lUNCOMMON ACCESSORY", + "", + "§7Cost", + "§fJunk Talisman", + "§9Busted Belt Buckle §8x4", + "", + "§eClick to trade!" + )); + layout.slot(21, ItemStackCreator.getStackHead( + "§9Junk Artifact", + "9727812f708dee1826bceecdadb9c7719e3d0f385a3b2515d00b5f665d8ba83e", + 1, + "§7Grants §6+7.5⛃ Treasure Chance §7while", + "§7on the §2Backwater Bayou§7.", + "", + "§8§oOne man's trash is another man's", + "§8§otreasure.", + "", + "§8Works while in Accessory Bag!", + "§9§lRARE ACCESSORY", + "", + "§7Cost", + "§aJunk Ring", + "§5Old Leather Boot", + "", + "§eClick to trade!" + )); + layout.slot(22, ItemStackCreator.getStackHead( + "§aBackwater Necklace", + "ab6f8eea74ca22c2ab64592bab2699df39c3e7c1db7d2c9fc687be0dc8c7f1ed", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON NECKLACE", + "", + "§7Cost", + "§fAngler Necklace", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(23, ItemStackCreator.getStackHead( + "§aBackwater Cloak", + "f2adeecbf20b58fd4cad8aaa3b4653d7165e07aa167be48a321b096d56a9fe35", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON CLOAK", + "", + "§7Cost", + "§fAngler Cloak", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(24, ItemStackCreator.getStackHead( + "§aBackwater Belt", + "3c150be849a39208a38a83c5605e79aef93a12b37072b931693990192cb77a19", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON BELT", + "", + "§7Cost", + "§fAngler Belt", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(25, ItemStackCreator.getStackHead( + "§aBackwater Gloves", + "9a6c887b86b2a59fdea5052413eab74d434c07f52231ce7ac33af5b395beded0", + 1, + "§7Fishing Speed: §b+2", + "§7Sea Creature Chance: §3+1%", + "§7Treasure Chance: §6+0.1%", + "", + "§8Tiered Bonus: Swamp Soldier (0/8)", + "§7Increases damage dealt to §3Sea", + "§3Creatures §7by §a5%§7.", + "", + "§8This item can be reforged!", + "§a§lUNCOMMON GLOVES", + "", + "§7Cost", + "§fAngler Bracelet", + "§aRusty Coin §8x4", + "", + "§eClick to trade!" + )); + layout.slot(28, ItemStackCreator.getStackHead( + "§7[Lvl 100] §fHermit Crab", + "26629dfa3fdfef04054024e0156d5e19da5401b1911f59b4bd3982685fe54c2c", + 1, + "§8Fishing Pet", + "", + "§7Defense: §a+20", + "§7Fishing Speed: §b+20", + "§7Sea Creature Chance: §3+2%", + "", + "§6Comfort Zone", + "§7Grants §b+20☂ Fishing Speed §7for §a30s", + "§7upon catching §6Treasure§7.", + "", + "§cThis is a preview of Lvl 100.", + "§cNew pets are lowest level!", + "", + "§7Cost", + "§aRusty Coin §8x32", + "", + "§eClick to trade!" + )); + layout.slot(29, ItemStackCreator.getStackHead( + "§9Stingy Sinker", + "e886d5cac32bd32fc07938908c552b7b27965d92065b3157dfc7ef849281ee9d", + 1, + "§7Grants a §a10% §7chance to not consume", + "§7Bait.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Sinker §7to a", + "§7Fishing Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§aRusty Coin §8x64", + "", + "§eClick to trade!" + )); + layout.slot(30, ItemStackCreator.getStackHead( + "§9Speedy Line", + "5cbac3c84e21e65ec88007604c4eba1da391e185544b90252fc16ca695c59b4b", + 1, + "§7Grants §b+10☂ Fishing Speed§7.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Line §7to a Fishing", + "§7Rod.", + "", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(31, ItemStackCreator.getStackHead( + "§9Bronze Ship Engine", + "9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925", + 1, + "§8Ship Part", + "", + "§7Bring this item to §6Captain Baha§7.", + "", + "§7Grants §3+0.5☯ Fishing Wisdom §7when", + "§7attached to your §6Ship§7.", + "", + "§8§l* Soulbound §l*", + "§9§lRARE", + "", + "§7Cost", + "§aRusty Coin §8x64", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(32, ItemStackCreator.getStackHead( + "§6Gold Bottle Cap", + "269698fd92fb14827af97e54a3f28f5e2685d7e94bd128c0c27f259df996717c", + 1, + "§8Combinable in Anvil", + "", + "§7When applied to a fishing rod,", + "§7increases its §9Luck of the Sea §7level", + "§7by §a1§7!", + "§8Can be applied once.", + "§8Requires Luck of the Sea VI!", + "", + "§8§oOne man's trash is, indeed, another", + "§8§oman's treasure.", + "", + "§6§lLEGENDARY", + "", + "§7Cost", + "§aRusty Coin §8x512", + "§9Busted Belt Buckle §8x64", + "§5Old Leather Boot §8x8", + "", + "§eClick to trade!" + )); + layout.slot(33, ItemStackCreator.getStackHead( + "§9Treasure Hook", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§7Only allows you to catch items and", + "§6Treasure§7.", + "", + "§7Talk to §2Roddy §7in the §2Backwater", + "§2Bayou §7to apply this §9Hook §7to a Fishing", + "§7Rod.", + "", + "§4❣ §cRequires §aFishing Skill 25§c.", + "§9§lRARE ROD PART", + "", + "§7Cost", + "§6Bayou Water Orb", + "§5Old Leather Boot §8x4", + "§9Busted Belt Buckle §8x32", + "§aRusty Coin §8x256", + "", + "§cNot unlocked!" + )); + layout.slot(34, ItemStackCreator.getStack( + "§9Travel Scroll to the Bayou", + Material.MAP, + 1, + "§7Consume this item to add its", + "§7destination to your Fast Travel", + "§7options.", + "", + "§7Island: §aBackwater Bayou", + "§7Teleport: §eSpawn", + "", + "§9§lRARE TRAVEL SCROLL", + "", + "§7Cost", + "§9Busted Belt Buckle §8x8", + "", + "§eClick to trade!" + )); + layout.slot(49, ItemStackCreator.getStack( + "§aSell Item", + Material.HOPPER, + 1, + "§7Click items in your inventory to sell", + "§7them to this Shop!" + )); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java new file mode 100644 index 000000000..3f9f8aa0e --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUILine extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUILineGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java new file mode 100644 index 000000000..6591d0734 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUIRodPartGuide extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIRodPartGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java new file mode 100644 index 000000000..07fc59d6b --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java @@ -0,0 +1,4 @@ +package net.swofty.type.backwaterbayou.gui; + +public class GUISinker extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUISinkerGuide { +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java new file mode 100644 index 000000000..8e232ac42 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java @@ -0,0 +1,75 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCCaptainBaha extends HypixelNPC { + + public NPCCaptainBaha() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6Captain Baha", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "A9Wh529RWV2HEMvVnPzQEPfvT7p8m2GU8IB5FowBVYRash8GUSC6OvO88v5eBXAsCJvAauOnCFkp0DrxNTHUTS6E8rcGpo5ieHTr+QYglXIlA8S+rgA5eGODgI3LEtOZucHJ6H64a23Bu41lNMpN2c+LzQbisqC9WBnfVBxYo6qrzgh5JBGsRDIg2h3UKmTnNgJPuhN2cwRDDlHG8/k+xES5ZqyEFvdjGn6O5HHL6xyMkCukjZN0E8s03NkpkKxZXEm1M/Eg8EWtwGqZIa3DHNmxchYok4mDPMst8iRy4pGRlJN+VBCmGLIV7pq4QZlGzuXWplrX/PAOb+B36Rg67SHvmIk23tpnu+7uvB3rw9NedWY1+xLp8W4gPKpynOobSCbKiJ6bX0mCQfURVh2svFT5nG/VnKCL0TE8CUiTxOuxJR8QWwWRI4BMRMJQfQxy0mofvPnR5g1XUnHzvGWr4m44dmooqyCgB4W9iysADAEgc9CVtizjroopAJLXCtfsxwIuioHaZsBKQU1NpvpH55bPqf//RI9FyJJwOXTgX7fbF49z0eAgjnRAyF9VE9VYI2hFZwa3BIFnvdGxlZhE63QPB+nmKQMT0WzTz15lm77lxvvpQsurkm2gKr6FlL9+SokbTUuQmisyzS84s2EocpRscgc9JF1Dv/NjK7T+3GU="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDQxOTU1NzI0NiwKICAicHJvZmlsZUlkIiA6ICIzY2I3YTA3YWY3ZjM0ZWZiYTlkNGI4ODQ3NDM4Mzc0ZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJBUkJVWklLMTIwMTMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzcxYzQ0YWQ0MDdjMDIxNzM3YWQ3ODkwN2I1MDY4ZDdiY2MwYzY1OGIyYTJmYmFiZjAxNzA2NTYzYmQ5NDQ3ZCIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(-22.5, 75, -8.5, -115, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_VISITED_BACKWATER_BAYOU)) { + setDialogue(player, "arrived").thenRun(() -> + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_VISITED_BACKWATER_BAYOU, true)); + return; + } + + setDialogue(player, "idle"); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("arrived").lines(new String[]{ + "Land ho! We have arrived at the §2Backwater Bayou§f!", + "You go on and explore! Come back to the §6Ship §fand set sail when you're done!" + }).build(), + DialogueSet.builder() + .key("idle").lines(new String[]{ + "The §6Ship Navigator §fis yours whenever you're ready to head back.", + "Don't keep the marsh waiting too long, though." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java new file mode 100644 index 000000000..10b6e5f33 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java @@ -0,0 +1,69 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.stream.Stream; + +public class NPCHattie extends HypixelNPC { + + public NPCHattie() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§dHattie", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "vQ5zgSiec5YR9aUfRwR+dZH29487jWT9Pr7PfdIx9pCuK07orJTg5/h8LQBsLFFiNNxQDnENw7/JeaRUP9JxZcxT/OjVLGnlR/P5fn+AET6tSok86mYS81JMDuFPFR2qhoEPBEmOnT0JDmMW4MCCVZtjBz5ENvHvVelZ3eDqy5KROz2u1qwjVBL6QToyT1pLravS8Y/juJDkmFEr4HW76cErnsXU73TOcJ8VeN0oV8KMeKyayLnFK6zZ0OMHZmBEDyQJ59tfoNo12jkdyEZ2rIo/Ix2inZ/VB4QYA+sODyFbTb+YGWSOBU50fkGngwLXsCsc51xm3nGNm3+fVvO5Y6MoVKsUk9G7pddppFdw0G/dOLuoyMTtcWVbuYPqvVhd+b47h5z3zG5767FmZbm2QwlR1VqKC6KqyZFSR5T8p6RdZxz5to+d6RGs1reK5tCGyyPwyVc0TW1hTXQ523uiMYmPKbRWUssjd2uypIAFSiytjVWRl9LI2K5QrRazyv4t8e4JIoDczELdgM8y2qxHrbb4rdMbkSS2/KQnYWDBZoR4xprZR0j4rOxbXVjwQ/lZsHhYV7SPbtun2sHyNd/nD+XvydM7V7Zjci1Zt48AvHpkHGn+4J/eTLpBHe4C4aKdDCnnfdwb1F3DPWyQKs5nsc/LSvTacfwYZwW7SQ6f+U0="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTczOTk4ODE2OTQyNCwKICAicHJvZmlsZUlkIiA6ICI0YWY1YmQ3NTdmZDE0MWEwOTczYmUxNTFkZWRjNmM5ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJjcmFzaGludG95b3VybW9tIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2E4NzQxZTFiZTdjY2VlN2E3YjY2ZDE5YWMwZjZmNDM2ZmFlNjhkNGFkZjNlNzVkMjBmNTk1MjIxYzIyOTMwMSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9"; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(17.5, 71, 14.5, -135, 20); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + if (isInDialogue(player)) { + return; + } + + setDialogue(player, "hotspots-" + (1 + (int) (Math.random() * 2))); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("hotspots-1").lines(new String[]{ + "Hotspots are temporary rings that appear above the water or lava.", + "Fish inside one and you'll get a bonus while your bobber stays in it.", + "The Bayou, Hub, Spider's Den, and Crimson Isle all have them. Keep your eyes open!" + }).build(), + DialogueSet.builder() + .key("hotspots-2").lines(new String[]{ + "Hotspots can boost your §bFishing Speed§f, §3Sea Creature Chance§f, §6Treasure Chance§f, or even §5Trophy Fish Chance§f.", + "Some creatures only show up when you're fishing inside one.", + "If the water starts glowing, don't waste the opportunity." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java new file mode 100644 index 000000000..d66c9ac7d --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java @@ -0,0 +1,64 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.backwaterbayou.gui.GUIJunkerJoel; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.stream.Stream; + +public class NPCJunkerJoel extends HypixelNPC { + + public NPCJunkerJoel() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§2Junker Joel", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "cuTJRxZ5c0tPjwo+PK4Wuzp8Gymj87qIm+p9QQHLfgQWj75RkXAigGjcbWcIpBol4eP9xQ1KpZwuCfoIToRc9Y1HMMNAzdm459KJfSkhiHWMXggJBbW8CFvdKVIhQHMVKBCA0cgVDQE/ozNScwS63TXSSIE7iyHMAbFxoOw6hZMd9oQuaujnFt2lYda0yLmOSq1CKR+xUbLOsDqOPtQRaKw7hdYL99QzX8rMu7CAdPJkbnvb8ki/r/hkzqj0HikoBM02XZycdArMHq9MQPT6M7XKgRur/1AfMkaIFMTTGDVcIMQiWBY10I7UGui/hWm2jnIBjJrI/bvN5VRBeTxeoSaFSxQfZ1YJpLfuGjBY4XitD1W7UL11Z6BTI63VVIdW6L7vYm/4pRek/AAEfwa/cmEQelM44pvj3Yk/9/RWoZ0J+Sb/v6VX96apDmHk30pRDSx0gWrBXf9DGW56VFtiklR2edZI7OgGtfNcu83S2fmVZoxYO5zCEejbNj9tI7W2eY8Qmoqwo7J6OlfJWc3Ng/ucHBqlVR/T3sxnsyOE24BjvqPM349eyas079dzGc8PlYyvMj6RXtjX/Jz9clFdAXw94zENzvUltPNxcJgj9Xt41/9L7oEcEn9okM5kCqzfJXIAvZQmiZSv3rxYNg6TEoCY1r+eVRwRJMDTgefOpcs="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDE1NjgzNjkxNCwKICAicHJvZmlsZUlkIiA6ICI2NDU4Mjc0MjEyNDg0MDY0YTRkMDBlNDdjZWM4ZjcyZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaDNtMXMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWE0NTAzZTdmMTYxOTg1ZDAyNzMxYTMwNjczNWFlOTRlNDA3Yzc5MGY1ZWI0N2I2MzExOTA3N2RkODgzNDc2YiIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(6.5, 72, 4.5, 135, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + if (isInDialogue(player)) { + return; + } + + setDialogue(player, "intro").thenRun(() -> player.openView(new GUIJunkerJoel())); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("intro").lines(new String[]{ + "People dump all sorts of junk in these waters, and I make sure none of it goes to waste.", + "Bring me your scraps and I'll trade you something useful.", + "If you're planning to fish up a mountain of junk, you'll want a §9Junk Sinker§f." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java new file mode 100644 index 000000000..3c26b83b3 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java @@ -0,0 +1,74 @@ +package net.swofty.type.backwaterbayou.npcs; + +import net.minestom.server.coordinate.Pos; +import net.swofty.type.backwaterbayou.gui.GUIFishingRodParts; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCRoddy extends HypixelNPC { + + public NPCRoddy() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6§lROD MECHANIC", "§2Roddy", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "m9YzKGb9O5Hs5mLECUJS6JmzLBDBQy9J768PK8lwNBEmF5a9J8Xdy93EWCAtCGCAFMar9CWRmyqt9Ees7u/3PHNtUVg9EkmvG27cPEIMUB2lqVir0U62pfNcR+5JkjjqaleDLhcOBgXdN9iVHJUcZq2tTY3t1eVX5OKI8K9SVjGvxgGMKxFmR1758eqwh9Krvb7AXI1/zRaRdFRsdXs2SgrvI/HcD4GN4vrjl6ZteOprTY4vB9oHZZSBLffkL28psxckC6JwvpiEahEtHKo1lS43qMpKtqKX9qwSs8WZ8/9A+/dXwB6g0+b1C/JSFWkyETFfFs1dUSdVsThkqGstRmt6c6Ko4xdvS61WQYLS4pbEbPN4kk0WapdqrWrrqNvjjcBUd94mnqNgvA0N+qPVOD/QkLGLvZDfXC5Iyv2BlpdeQHosTgn9ZPDjotESMwWrGwhm/uLLxNc2Z/rAGke5zTjz4v1JDSha7uyXT1yZ3oCckUqhbGFzmx5YOQoT/PbWr/mONQbYWTJ5GnSeWIIEs616Icwn+Rlw0qF+3EPUeR7QRO1bt5aqpmCUcZvrYoMyS1pvLDjS66MyuK5mEsQDEY5Uufux4iB3J0rrSGSgoC/XP1s6kGlz+jFRbDT9VPv/m72msPS35uAB6nCnI3o6uXKr0GrUGX9BiHB68Us0Pfs="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MTI3MjI2NDk0NiwKICAicHJvZmlsZUlkIiA6ICIzOWEzOTMzZWE4MjU0OGU3ODQwNzQ1YzBjNGY3MjU2ZCIsCiAgInByb2ZpbGVOYW1lIiA6ICJkZW1pbmVjcmFmdGVybG9sIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzE3Y2FkOWYyN2Q3NGRlM2U1OWYyYTUxN2QwNGEyODJlMmNmODZlNGM1ZTQwNjM5ZGFlY2E3YjFhYWU3ZjVhNzEiCiAgICB9CiAgfQp9"; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(21.5, 78, -23.5, 135, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_RODDY)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_RODDY, true); + player.openView(new GUIFishingRodParts()); + }); + return; + } + + player.openView(new GUIFishingRodParts()); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "If your rod's missing some punch, you've come to the right mechanic.", + "Hooks, lines, and sinkers can change what your rod is best at catching.", + "Put a §aFishing Rod §fin the slot and I'll show you what parts fit." + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java index 272e68144..f15c0ca1e 100644 --- a/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java +++ b/type.crimsonisle/src/main/java/net/swofty/type/crimsonisle/TypeCrimsonIsleLoader.java @@ -42,9 +42,7 @@ public void afterInitialize(MinecraftServer server) { @Override public LoaderValues getLoaderValues() { return new LoaderValues( - (type) -> switch (type) { - default -> new Pos(-360.5, 80, -430.5, -180, 0); - }, // Spawn position + (type) -> new Pos(-360.5, 80, -430.5, -180, 0), // Spawn position true // Announce death messages ); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java index 03b5d9d04..1d669f73b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java +++ b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java @@ -79,6 +79,8 @@ public enum ToggleType { HAS_SPOKEN_TO_TIA(false), HAS_SPOKEN_TO_LIFT_OPERATOR(false), HAS_SPOKEN_TO_LAZY_MINER(false), + HAS_SPOKEN_TO_BAKER(false), + HAS_SPOKEN_TO_FISHERMAN_GERALD(false), HAS_SPOKEN_TO_RUSTY(false), HAS_SPOKEN_TO_RUSTY_ABOUT_PICKAXE(false), HAS_SPOKEN_TO_RUSTY_ABOUT_ABIPHONE(false), @@ -117,6 +119,12 @@ public enum ToggleType { AUTO_ACCEPT_QUESTS(false), RUSTY_PURCHASE_CONFIRMATION(false), RUSTY_SORT_BY_RARITY(false), + HAS_SPOKEN_TO_FISHERWOMAN_ENID(false), + HAS_SPOKEN_TO_CAPTAIN_BAHA(false), + HAS_SPOKEN_TO_RODDY(false), + HAS_CAUGHT_FIRST_FISH(false), + HAS_UNLOCKED_SHIP(false), + HAS_VISITED_BACKWATER_BAYOU(false), ; private final boolean defaultValue; diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java new file mode 100644 index 000000000..2b97b2735 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java @@ -0,0 +1,4 @@ +package net.swofty.type.hub.gui.fishing; + +public class GUIGFishingShip extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUIFishingShip { +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java new file mode 100644 index 000000000..e85d9e93c --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java @@ -0,0 +1,4 @@ +package net.swofty.type.hub.gui.fishing; + +public class GUINavigator extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUINavigator { +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java new file mode 100644 index 000000000..58702288e --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java @@ -0,0 +1,116 @@ +package net.swofty.type.hub.npcs; + +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.generic.entity.npc.HypixelNPC; +import net.swofty.type.generic.entity.npc.NPCOption; +import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.fishing.GUIGFishingShip; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingShipService; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCCaptainBaha extends HypixelNPC { + + public NPCCaptainBaha() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§6Captain Baha", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "A9Wh529RWV2HEMvVnPzQEPfvT7p8m2GU8IB5FowBVYRash8GUSC6OvO88v5eBXAsCJvAauOnCFkp0DrxNTHUTS6E8rcGpo5ieHTr+QYglXIlA8S+rgA5eGODgI3LEtOZucHJ6H64a23Bu41lNMpN2c+LzQbisqC9WBnfVBxYo6qrzgh5JBGsRDIg2h3UKmTnNgJPuhN2cwRDDlHG8/k+xES5ZqyEFvdjGn6O5HHL6xyMkCukjZN0E8s03NkpkKxZXEm1M/Eg8EWtwGqZIa3DHNmxchYok4mDPMst8iRy4pGRlJN+VBCmGLIV7pq4QZlGzuXWplrX/PAOb+B36Rg67SHvmIk23tpnu+7uvB3rw9NedWY1+xLp8W4gPKpynOobSCbKiJ6bX0mCQfURVh2svFT5nG/VnKCL0TE8CUiTxOuxJR8QWwWRI4BMRMJQfQxy0mofvPnR5g1XUnHzvGWr4m44dmooqyCgB4W9iysADAEgc9CVtizjroopAJLXCtfsxwIuioHaZsBKQU1NpvpH55bPqf//RI9FyJJwOXTgX7fbF49z0eAgjnRAyF9VE9VYI2hFZwa3BIFnvdGxlZhE63QPB+nmKQMT0WzTz15lm77lxvvpQsurkm2gKr6FlL9+SokbTUuQmisyzS84s2EocpRscgc9JF1Dv/NjK7T+3GU="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDQxOTU1NzI0NiwKICAicHJvZmlsZUlkIiA6ICIzY2I3YTA3YWY3ZjM0ZWZiYTlkNGI4ODQ3NDM4Mzc0ZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJBUkJVWklLMTIwMTMiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzcxYzQ0YWQ0MDdjMDIxNzM3YWQ3ODkwN2I1MDY4ZDdiY2MwYzY1OGIyYTJmYmFiZjAxNzA2NTYzYmQ5NDQ3ZCIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(162.5, 69, -65.5, 105, 0); + } + + @Override + public boolean looking(HypixelPlayer player) { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) return; + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + new GUIGFishingShip().open(player); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_CAPTAIN_BAHA)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_CAPTAIN_BAHA, true); + }); + return; + } + + if (player.countItem(ItemType.RUSTY_SHIP_ENGINE) > 0) { + setDialogue(player, "rust-ship-engine").thenRun(() -> + NPCOption.sendOption(player, "captain_baha_engine", true, java.util.List.of( + NPCOption.Option.builder() + .key("yes") + .color(NamedTextColor.GREEN) + .bold(false) + .name("Yes!") + .action(ignored -> handleRustyShipEngine(player)) + .build() + ))); + return; + } + + setDialogue(player, "first-interaction"); + } + + private void handleRustyShipEngine(SkyBlockPlayer player) { + setDialogue(player, "dialogue-yes").thenRun(() -> { + var definition = FishingItemSupport.getShipPart(ItemType.RUSTY_SHIP_ENGINE.name()); + if (definition != null) { + FishingShipService.installPart(player, ItemType.RUSTY_SHIP_ENGINE.name(), definition); + } + player.takeItem(ItemType.RUSTY_SHIP_ENGINE, 1); + FishingShipService.unlockDestination(player, "BACKWATER_BAYOU"); + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP, true); + new GUIGFishingShip().open(player); + }); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "I was about to set sail, but this §6Ship §fis missing its §cengine§f!", + "Maybe §3Fisherman §fGerald knows where it is?", + }).build(), + DialogueSet.builder() + .key("rust-ship-engine").lines(new String[]{ + "Ahoy, is that the §cRusty Ship Engine§f?" + }).build(), + DialogueSet.builder() + .key("dialogue-yes").lines(new String[]{ + "Excellent! I'm the captain of this §6Ship§f, which means I oversee everything from repairs to navigation.", + "Apply that §cRusty Ship Engine §fin the §6Engine §fslot by clicking the engine in your inventory!" + }).build() + ).toArray(DialogueSet[]::new); + } +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java index b49e95aec..5be734429 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java @@ -1,6 +1,8 @@ package net.swofty.type.hub.npcs; import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; @@ -31,7 +33,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(118.500, 71.000, -32.500, 145, 0); + return new Pos(118.5, 71, -32.5, 180, 0); } @Override @@ -52,7 +54,29 @@ public void onClick(NPCInteractEvent event) { return; } - // TODO: finish this quest + if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERMAN_GERALD)) { + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERMAN_GERALD, true); + }); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + setDialogue(player, "talk-to-enid-again"); + return; + } + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + setDialogue(player, Math.random() < 0.5D ? "after-bringing-engine-to-baha" : "idle-" + (1 + (int) (Math.random() * 3))); + return; + } + + if (player.countItem(ItemType.RUSTY_SHIP_ENGINE) > 0 || "RUSTY_SHIP_ENGINE".equals(player.getShipState().getEngine())) { + setDialogue(player, "after-fishing-engine"); + return; + } + + setDialogue(player, "after-talking-to-enid"); } @Override @@ -69,7 +93,46 @@ protected DialogueSet[] dialogues(HypixelPlayer player) { "Keep the noise down, kid!", "If you want to learn about §aFishing§f, go talk to my wife, Fisherwoman Enid.", "She's fishing a bit §bupstream§f. Once she's shown you the ropes, come back and talk to me!", + }).build(), + DialogueSet.builder() + .key("talk-to-enid-again").lines(new String[]{ + "If you want to learn about §aFishing§f, go talk to my wife, Fisherwoman Enid.", + "She's fishing a bit §bupstream§f. Once she's shown you the ropes, come back and talk to me!" + }).build(), + DialogueSet.builder() + .key("after-talking-to-enid").lines(new String[]{ + "Can you fish up the §cRusty Ship Engine §ffor me?", + "It's somewhere in this pond here.", + "Once you fish it out, you can set sail to the §2Backwater Bayou§f!" + }).build(), + DialogueSet.builder() + .key("after-fishing-engine").lines(new String[]{ + "Ah! The §cRusty Ship Engine§f! Perfect!", + "Bring that to §6Captain Baha §fand he'll be able to help you set sail!", + "He's just behind the Fisherman's Hut, waiting by the §6Ship§f!", + "Just leave out the part about me dropping it, will ya?" + }).build(), + DialogueSet.builder() + .key("after-bringing-engine-to-baha").lines(new String[]{ + "Thanks for helping me find the §cRusty Ship Engine§f, " + (player == null ? "kid" : player.getUsername()) + "!", + "You can use the §6Ship Navigator §fto set sail to the §2Backwater Bayou§f!", + "Safe travels!" + }).build(), + DialogueSet.builder() + .key("idle-1").lines(new String[]{ + "Fishing is the family business.", + "Enid and I are thrilled that our two children love it as much as we do!" + }).build(), + DialogueSet.builder() + .key("idle-2").lines(new String[]{ + "I met Captain Baha when i was marooned on a distant pirate cove.", + "He saved my skin then, and I'm forever grateful to him." + }).build(), + DialogueSet.builder() + .key("idle-3").lines(new String[]{ + "I've only gone lava fishing a few times in my life.", + "I prefer the open water. More peaceful, less ghasts!" }).build() ).toArray(DialogueSet[]::new); } -} \ No newline at end of file +} diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java index 722208ae8..d9a35d276 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFisherwomanEnid.java @@ -1,10 +1,14 @@ package net.swofty.type.hub.npcs; import net.minestom.server.coordinate.Pos; +import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; public class NPCFisherwomanEnid extends HypixelNPC { @@ -39,6 +43,66 @@ public boolean looking(HypixelPlayer player) { @Override public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) { + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + setDialogue(player, "first-interaction").thenRun(() -> + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID, true)); + return; + } + + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH)) { + setDialogue(player, "first-interaction"); + return; + } + + if (player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + setDialogue(player, Math.random() < 0.5D ? "after-gerald" : "idle-" + (1 + (int) (Math.random() * 3))); + return; + } + setDialogue(player, "after-catching-fish"); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "To fish, cast your rod into the water and wait for a fish to bite!" + }).build(), + DialogueSet.builder() + .key("after-catching-fish").lines(new String[]{ + "This part of the hub is a popular area for fishing because of the Fishing Outpost!", + "If you follow the river that flows under the bridge downstream, you'll find your way to it.", + "And tell Gerald I won't be home tonight! I'm tired of him making salmon." + }).build(), + DialogueSet.builder() + .key("after-gerald").lines(new String[]{ + "If you like fishin', you'll love the Backwater Bayou!", + "You should go there sometime soon!" + }).build(), + DialogueSet.builder() + .key("idle-1").lines(new String[]{ + "Using Bait is important to get better results!", + "My favorite kind of bait is Dark Bait because I prefer fishing at night.", + "Angler Angus knows a lot more about Bait than I do. I think he's fishing somewhere along this river if you're interested in learning more." + }).build(), + DialogueSet.builder() + .key("idle-2").lines(new String[]{ + "I know that Gavin uses /scg instead of looking in his Fishing Skill menu.", + "He thinks he's being sneaky, but everyone knows about it.", + "Little does he know, I use it too!" + }).build(), + DialogueSet.builder() + .key("idle-3").lines(new String[]{ + "The Backwater Bayou has all sorts of wild Sea Creatures native to the area.", + "I've heard stories of Frog Man, but I've never quite worked out if he's a frog or a man.", + "Perhaps he is both, perhaps neither." + }).build() + ).toArray(DialogueSet[]::new); } } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java index 67d5ac678..49e07821c 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java @@ -30,7 +30,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(147.5, 69.9, -59.5, -90, 0); + return new Pos(161.5, 69.900, 43.5, 203, 17); } @Override @@ -46,7 +46,9 @@ public void onClick(NPCInteractEvent event) { if (isInDialogue(player)) return; if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN)) { - setDialogue(player, "first-interaction").thenRun(() -> player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN, true)); + setDialogue(player, "first-interaction").thenRun(() -> { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN, true); + }); return; } @@ -73,4 +75,4 @@ protected DialogueSet[] dialogues(HypixelPlayer player) { }).build() ).toArray(DialogueSet[]::new); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java index 39de664f6..29881c36e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java @@ -61,6 +61,7 @@ import net.swofty.type.skyblockgeneric.entity.mob.MobRegistry; import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob; import net.swofty.type.skyblockgeneric.event.value.SkyBlockValueEvent; +import net.swofty.type.skyblockgeneric.fishing.FishingRegistry; import net.swofty.type.skyblockgeneric.item.ItemConfigParser; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.CraftableComponent; @@ -177,6 +178,7 @@ public void initialize(MinecraftServer server) { } catch (IOException e) { Logger.error("Failed to scan for YAML files", e); } + FishingRegistry.loadAll(); /** * Register commands diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java index a3afeed4e..4f8493e28 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/SkyBlockDataHandler.java @@ -373,6 +373,12 @@ DatapointPetData.class, new DatapointPetData("pet_data")), QUIVER("quiver", false, false, false, DatapointQuiver.class, new DatapointQuiver("quiver")), + SHIP_STATE("ship_state", false, false, false, + DatapointShipState.class, new DatapointShipState("ship_state")), + + TROPHY_FISH("trophy_fish", false, false, false, + DatapointTrophyFish.class, new DatapointTrophyFish("trophy_fish")), + RACE_BEST_TIME("race_best_time", false, false, false, DatapointMapStringLong.class, new DatapointMapStringLong("race_best_time")), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java new file mode 100644 index 000000000..5f761ba50 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java @@ -0,0 +1,97 @@ +package net.swofty.type.skyblockgeneric.data.datapoints; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class DatapointShipState extends SkyBlockDatapoint { + private static final Serializer serializer = new Serializer<>() { + @Override + public String serialize(ShipState value) { + JSONObject object = new JSONObject(); + object.put("shipName", value.getShipName()); + object.put("helm", value.getHelm()); + object.put("engine", value.getEngine()); + object.put("hull", value.getHull()); + object.put("destinations", value.getUnlockedDestinations()); + return object.toString(); + } + + @Override + public ShipState deserialize(String json) { + if (json == null || json.isEmpty()) { + return new ShipState(); + } + + JSONObject object = new JSONObject(json); + List destinations = new ArrayList<>(); + JSONArray array = object.optJSONArray("destinations"); + if (array != null) { + for (Object entry : array) { + destinations.add(String.valueOf(entry)); + } + } + + return new ShipState( + object.optString("shipName", "Zephyr"), + object.optString("helm", "CRACKED_SHIP_HELM"), + emptyToNull(object.optString("engine", "")), + object.optString("hull", "RUSTY_SHIP_HULL"), + destinations + ); + } + + @Override + public ShipState clone(ShipState value) { + return new ShipState( + value.getShipName(), + value.getHelm(), + value.getEngine(), + value.getHull(), + new ArrayList<>(value.getUnlockedDestinations()) + ); + } + }; + + public DatapointShipState(String key, ShipState value) { + super(key, value, serializer); + } + + public DatapointShipState(String key) { + this(key, new ShipState()); + } + + private static String emptyToNull(String value) { + return value == null || value.isEmpty() ? null : value; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ShipState { + private String shipName = "Zephyr"; + private String helm = "CRACKED_SHIP_HELM"; + private String engine = null; + private String hull = "RUSTY_SHIP_HULL"; + private List unlockedDestinations = new ArrayList<>(); + + public boolean hasDestination(String destinationId) { + return unlockedDestinations.contains(destinationId); + } + + public void unlockDestination(String destinationId) { + if (!unlockedDestinations.contains(destinationId)) { + unlockedDestinations.add(destinationId); + } + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java new file mode 100644 index 000000000..395512ca5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java @@ -0,0 +1,144 @@ +package net.swofty.type.skyblockgeneric.data.datapoints; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDatapoint; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +public class DatapointTrophyFish extends SkyBlockDatapoint { + private static final Serializer serializer = new Serializer<>() { + @Override + public String serialize(TrophyFishData value) { + JSONObject object = new JSONObject(); + JSONObject fishObject = new JSONObject(); + value.getFish().forEach((fishId, progress) -> { + JSONObject progressObject = new JSONObject(); + progressObject.put("bronze", progress.getBronze()); + progressObject.put("silver", progress.getSilver()); + progressObject.put("gold", progress.getGold()); + progressObject.put("diamond", progress.getDiamond()); + progressObject.put("totalCatches", progress.getTotalCatches()); + progressObject.put("catchesSinceGoldPity", progress.getCatchesSinceGoldPity()); + progressObject.put("catchesSinceDiamondPity", progress.getCatchesSinceDiamondPity()); + fishObject.put(fishId, progressObject); + }); + object.put("fish", fishObject); + return object.toString(); + } + + @Override + public TrophyFishData deserialize(String json) { + TrophyFishData data = new TrophyFishData(); + if (json == null || json.isEmpty()) { + return data; + } + + JSONObject object = new JSONObject(json); + JSONObject fishObject = object.optJSONObject("fish"); + if (fishObject == null) { + return data; + } + + for (String fishId : fishObject.keySet()) { + JSONObject progressObject = fishObject.getJSONObject(fishId); + data.getFish().put(fishId, new FishProgress( + progressObject.optInt("bronze", 0), + progressObject.optInt("silver", 0), + progressObject.optInt("gold", 0), + progressObject.optInt("diamond", 0), + progressObject.optInt("totalCatches", 0), + progressObject.optInt("catchesSinceGoldPity", progressObject.optInt("totalCatches", 0)), + progressObject.optInt("catchesSinceDiamondPity", progressObject.optInt("totalCatches", 0)) + )); + } + return data; + } + + @Override + public TrophyFishData clone(TrophyFishData value) { + Map fish = new HashMap<>(); + value.getFish().forEach((fishId, progress) -> + fish.put(fishId, new FishProgress( + progress.getBronze(), + progress.getSilver(), + progress.getGold(), + progress.getDiamond(), + progress.getTotalCatches(), + progress.getCatchesSinceGoldPity(), + progress.getCatchesSinceDiamondPity() + ))); + return new TrophyFishData(fish); + } + }; + + public DatapointTrophyFish(String key, TrophyFishData value) { + super(key, value, serializer); + } + + public DatapointTrophyFish(String key) { + this(key, new TrophyFishData()); + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class TrophyFishData { + private Map fish = new HashMap<>(); + + public FishProgress getProgress(String fishId) { + return fish.computeIfAbsent(fishId, ignored -> new FishProgress()); + } + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class FishProgress { + private int bronze; + private int silver; + private int gold; + private int diamond; + private int totalCatches; + private int catchesSinceGoldPity; + private int catchesSinceDiamondPity; + + public void increment(String tier) { + switch (tier.toUpperCase()) { + case "DIAMOND" -> { + diamond++; + catchesSinceDiamondPity = 0; + catchesSinceGoldPity = 0; + } + case "GOLD" -> { + gold++; + catchesSinceGoldPity = 0; + catchesSinceDiamondPity++; + } + case "SILVER" -> silver++; + default -> bronze++; + } + if (!"GOLD".equalsIgnoreCase(tier) && !"DIAMOND".equalsIgnoreCase(tier)) { + catchesSinceGoldPity++; + catchesSinceDiamondPity++; + } + totalCatches++; + } + + public boolean hasTier(String tier) { + return switch (tier.toUpperCase()) { + case "DIAMOND" -> diamond > 0; + case "GOLD" -> gold > 0; + case "SILVER" -> silver > 0; + default -> bronze > 0; + }; + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java index f8e00c296..04ef2c121 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/EnchantmentType.java @@ -27,6 +27,21 @@ public enum EnchantmentType { GIANT_KILLER(EnchantmentGiantKiller.class), EXECUTE(EnchantmentExecute.class), IMPALING(EnchantmentImpaling.class), + CASTER(EnchantmentCaster.class), + CHARM(EnchantmentCharm.class), + ANGLER(EnchantmentAngler.class), + BLESSING(EnchantmentBlessing.class), + CORRUPTION(EnchantmentCorruption.class), + EXPERTISE(EnchantmentExpertise.class), + FLASH(EnchantmentFlash.class), + FRAIL(EnchantmentFrail.class), + LUCK_OF_THE_SEA(EnchantmentLuckOfTheSea.class), + LURE(EnchantmentLure.class), + MAGNET(EnchantmentMagnet.class), + PISCARY(EnchantmentPiscary.class), + QUICK_BITE(EnchantmentQuickBite.class), + SPIKED_HOOK(EnchantmentSpikedHook.class), + TABASCO(EnchantmentTabasco.class), BANE_OF_ARTHROPODS(EnchantmentBaneOfArthropods.class), CUBISM(EnchantmentCubism.class), FORTUNE(EnchantmentFortune.class), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java new file mode 100644 index 000000000..7b9fa0371 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java @@ -0,0 +1,58 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentAngler implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §3+" + level + "% Sea Creature Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.SEA_CREATURE_CHANCE, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java new file mode 100644 index 000000000..15f7600b1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentBlessing implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §a+" + (level * 5) + "%§7 chance for a better §6Treasure§7 quality outcome."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java new file mode 100644 index 000000000..57016d46b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCaster implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "§a" + (level * 5) + "%§7 chance to not consume bait."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 15, + 3, 20, + 4, 25, + 5, 30, + 6, 60 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 15, + 3, 20, + 4, 25, + 5, 30 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java new file mode 100644 index 000000000..0e771ba22 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java @@ -0,0 +1,34 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCharm implements Ench { + @Override + public String getDescription(int level) { + return "§7Increases the chance to receive higher-tiered Trophy Fish by §a" + (level * 2) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.ofEntries( + Map.entry(1, 10), + Map.entry(2, 20), + Map.entry(3, 30), + Map.entry(4, 40), + Map.entry(5, 50), + Map.entry(6, 100) + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java new file mode 100644 index 000000000..ba7a17de2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java @@ -0,0 +1,50 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentCorruption implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "§a" + (level * 10) + "%§7 chance to summon a §5Corrupted §7variant of a caught §3Sea Creature§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 5, + 2, 10, + 3, 15, + 4, 20, + 5, 50 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 5, + 2, 10, + 3, 15, + 4, 20, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 10; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java new file mode 100644 index 000000000..4a3bbd78a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentExpertise implements Ench { + private static final double[] SEA_CREATURE_CHANCE_BONUS = { + 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0 + }; + + @Override + public String getDescription(int level) { + return "Tracks §3Sea Creature §7kills on this rod. Every kill grants §b+0.1☂ Fishing Wisdom§7. " + + "Current tier grants §3+" + SEA_CREATURE_CHANCE_BONUS[level - 1] + "% Sea Creature Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder() + .withBase(ItemStatistic.SEA_CREATURE_CHANCE, SEA_CREATURE_CHANCE_BONUS[level - 1]) + .build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 50, + 2, 100, + 3, 200, + 4, 400, + 5, 800, + 6, 1600, + 7, 3200, + 8, 6400, + 9, 12800, + 10, 25600 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java new file mode 100644 index 000000000..12e0d1ec6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java @@ -0,0 +1,57 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentFlash implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + (level * 5) + "☂ Fishing Speed§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.FISHING_SPEED, level * 5.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 60, + 5, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 60, + 5, 100 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java new file mode 100644 index 000000000..aa9c437a8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentFrail implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Reduces the defense of §3Sea Creatures §7you hit by §a" + (level * 10) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java new file mode 100644 index 000000000..4ed33f8b0 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java @@ -0,0 +1,59 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentLuckOfTheSea implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + level + "✯ Magic Find§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.MAGIC_FIND, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java new file mode 100644 index 000000000..daaf8248e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java @@ -0,0 +1,58 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentLure implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §b+" + (level * 4) + "☂ Fishing Speed§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.FISHING_SPEED, level * 4.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java new file mode 100644 index 000000000..ec27affd3 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java @@ -0,0 +1,51 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentMagnet implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Instantly pulls nearby items to you within §a" + (level * 2) + " §7blocks."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java new file mode 100644 index 000000000..dd76b4ee5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java @@ -0,0 +1,59 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentPiscary implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §6+" + level + "% Trophy Fish Chance§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.TROPHY_FISH_CHANCE, (double) level).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java new file mode 100644 index 000000000..d2331abb3 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java @@ -0,0 +1,50 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentQuickBite implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Decreases the time for your hook to get a bite by §a" + (level * 5) + "%§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 60, + 4, 80, + 5, 100 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 60, + 4, 80, + 5, 100 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 5; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java new file mode 100644 index 000000000..719ee96e8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentSpikedHook implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Deals §a" + (level * 5) + "%§7 more damage to §3Sea Creatures§7."; + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50, + 6, 80, + 7, 120 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD, EnchantItemGroups.FISHING_WEAPON); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 10, + 2, 20, + 3, 30, + 4, 40, + 5, 50 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 0; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java new file mode 100644 index 000000000..2becbc3e5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java @@ -0,0 +1,53 @@ +package net.swofty.type.skyblockgeneric.enchantment.impl; + +import lombok.NonNull; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.abstr.Ench; +import net.swofty.type.skyblockgeneric.enchantment.abstr.EnchFromTable; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EnchantmentTabasco implements Ench, EnchFromTable { + @Override + public String getDescription(int level) { + return "Grants §6+" + (level * 5) + "% Trophy Fish Chance §7while fishing in §clava§7."; + } + + @Override + public ItemStatistics getStatistics(int level) { + return ItemStatistics.builder().withBase(ItemStatistic.TROPHY_FISH_CHANCE, level * 5.0).build(); + } + + @Override + public ApplyLevels getLevelsToApply(@NonNull SkyBlockPlayer player) { + return new ApplyLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 80 + ))); + } + + @Override + public List getGroups() { + return List.of(EnchantItemGroups.FISHING_ROD); + } + + @Override + public TableLevels getLevelsFromTableToApply(@NonNull SkyBlockPlayer player) { + return new TableLevels(new HashMap<>(Map.of( + 1, 20, + 2, 40, + 3, 80 + ))); + } + + @Override + public int getRequiredBookshelfPower() { + return 15; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java new file mode 100644 index 000000000..23d854b30 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java @@ -0,0 +1,340 @@ +package net.swofty.type.skyblockgeneric.entity; + +import lombok.Getter; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.metadata.other.FishingHookMeta; +import net.minestom.server.event.entity.EntityTickEvent; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.ParticlePacket; +import net.minestom.server.particle.Particle; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.timer.Scheduler; +import net.minestom.server.timer.Task; +import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.FishingService; +import net.swofty.type.skyblockgeneric.fishing.FishingSession; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class FishingHook { + + public static final List activeHooks = new ArrayList<>(); + private static final double INITIAL_SPEED_MULTIPLIER = 10.0; + private static final double BOB_SPEED = 0.1; + private static final double BOB_AMOUNT = 0.09; + private static final double SURFACE_OFFSET = -0.02; + private static final double MAX_PULL_DOWN = 0.3; + private static final double PULL_DOWN_RECOVERY_SPEED = 0.016666666666666666; + private static final double CONTROLLER_DRAG = 0.2; + private static final double WATER_CHECK_OFFSET = -0.2; + private static final long BITE_WINDOW_TICKS = 20L; + private final SkyBlockPlayer owner; + private final SkyBlockItem rod; + private final FishingMedium requiredMedium; + private final Entity hook; + private final Entity controller; + @Getter + private boolean isRemoved = false; + private double bobTick = 0; + private double pullDownOffset = 0; + private Double stableWaterY = null; + private Task nextBiteTask; + private Task biteExpiryTask; + private boolean sessionStarted = false; + + public FishingHook(SkyBlockPlayer owner, SkyBlockItem rod) { + this.owner = owner; + this.rod = rod; + String itemId = rod.getAttributeHandler().getPotentialType() == null ? null : rod.getAttributeHandler().getPotentialType().name(); + var rodMetadata = FishingItemSupport.getRodMetadata(itemId); + this.requiredMedium = rodMetadata == null ? FishingMedium.WATER : rodMetadata.getMedium(); + + this.hook = new Entity(EntityType.FISHING_BOBBER); + this.hook.editEntityMeta(FishingHookMeta.class, meta -> { + meta.setOwnerEntity(owner); + }); + + this.controller = new Entity(EntityType.TEXT_DISPLAY); + this.controller.setNoGravity(true); + + this.controller.eventNode().addListener(EntityTickEvent.class, + event -> tick(event.getEntity())); + } + + public static FishingHook getFishingHookForOwner(@NotNull SkyBlockPlayer owner) { + for (FishingHook fishingHook : activeHooks) { + if (fishingHook.owner.getUuid().equals(owner.getUuid())) { + return fishingHook; + } + } + return null; + } + + private static boolean blockMatchesMedium(@NotNull Block block, @NotNull FishingMedium medium) { + if (!block.isLiquid()) { + return false; + } + String blockName = block.name(); + return switch (medium) { + case WATER -> blockName.contains("water"); + case LAVA -> blockName.contains("lava"); + }; + } + + public void spawn(Instance instance) { + Pos spawnPos = owner.getPosition().add(0, owner.getEyeHeight(), 0); + spawn(instance, spawnPos); + } + + public void spawn(Instance instance, Pos pos) { + activeHooks.add(this); + this.controller.setInstance(instance, pos); + this.hook.setInstance(instance, pos); + this.controller.addPassenger(hook); + this.controller.setVelocity(owner.getPosition().direction().mul(INITIAL_SPEED_MULTIPLIER)); + float pitch = (float) 1/3 + (float) (Math.random() * (0.5 - 1.0 / 3.0)); + owner.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.throw")) + .source(Sound.Source.NEUTRAL) + .volume(0.5f) + .pitch(pitch) + .build() + ); + } + + private boolean shouldKeepExisting() { + // Checks if the user is still in the same instance as the hook + Instance instance = controller.getInstance(); + if (instance == null) return false; + if (owner.getInstance() != instance) return false; + // Checks if the owner is still holding a fishing rod + return owner.getItemInMainHand().material() == Material.FISHING_ROD; + } + + private void tick(@NotNull Entity controller) { + Instance instance = controller.getInstance(); + if (instance == null) return; + if (!shouldKeepExisting()) { + remove(); + return; + } + + Pos pos = controller.getPosition(); + if (notInWater()) { + stableWaterY = null; + controller.setNoGravity(false); // Re-enable gravity to fall/stop + return; + } + + FishingMedium mediumAtHook = getCurrentMedium(); + if (mediumAtHook == null) { + if (sessionStarted) { + FishingService.clearSession(owner.getUuid()); + sessionStarted = false; + } + stableWaterY = null; + cancelBiteTasks(); + controller.setNoGravity(false); + return; + } + + if (mediumAtHook != requiredMedium) { + remove(); + return; + } + + // Hook is in valid fishing liquid + controller.setNoGravity(true); + Block blockBelow = instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0)); + + if (stableWaterY == null) { + // First time hitting water, establish stable surface Y + stableWaterY = getWaterSurface(blockBelow, (int) Math.floor(pos.y() + WATER_CHECK_OFFSET)) + SURFACE_OFFSET; + bobTick = 0; + pullDownOffset = 0; + // show particles + instance.playSound(Sound.sound() + .type(SoundEvent.ENTITY_FISHING_BOBBER_SPLASH) + .source(Sound.Source.PLAYER) + .volume(0.25f) + .pitch(0.8f) // 0.6-1.4 in vanilla + .build() + ); + instance.sendGroupedPacket(new ParticlePacket( + Particle.SPLASH, + controller.getPosition(), + new Pos(0.1, 0.001, 0.1), + 0, 5 + )); + startFishingSession(); + } + + bobTick += BOB_SPEED; + double yBob = Math.sin(bobTick) * BOB_AMOUNT; + + pullDownOffset = Math.max(pullDownOffset - PULL_DOWN_RECOVERY_SPEED, 0); + Pos targetPos = new Pos(pos.x(), stableWaterY + yBob - pullDownOffset, pos.z()); + + controller.teleport(targetPos); + controller.setVelocity(controller.getVelocity().mul(CONTROLLER_DRAG)); + } + + + public boolean notInWater() { + Instance instance = controller.getInstance(); + Pos pos = controller.getPosition(); + return getMedium(instance.getBlock(pos)) == null + && getMedium(instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0))) == null; + } + + public void showBiteAnimation() { + Instance instance = controller.getInstance(); + if (instance == null) return; + + instance.playSound(Sound.sound() + .type(SoundEvent.ENTITY_FISHING_BOBBER_SPLASH) + .source(Sound.Source.PLAYER) + .build() + ); + instance.sendGroupedPacket(new ParticlePacket( + Particle.SPLASH, + controller.getPosition(), + new Pos(0.1, 0.001, 0.1), + 0, 20 + )); + + pullDownOffset = Math.min(pullDownOffset + 0.15, MAX_PULL_DOWN); + bobTick += Math.PI / 6; + } + + public void remove() { + activeHooks.remove(this); + if (this.isRemoved) return; + this.isRemoved = true; + cancelBiteTasks(); + FishingService.clearSession(owner.getUuid()); + hook.remove(); + controller.remove(); + } + + public void tryRetrieve(SkyBlockItem rodInHand) { + FishingSession session = FishingService.getSession(owner.getUuid()); + if (session == null || !session.biteReady() || System.currentTimeMillis() > session.biteWindowEndsAt()) { + return; + } + + FishingService.resolveCatch(owner, rodInHand, this); + } + + private double getWaterSurface(Block block, int blockY) { + if (!block.isLiquid()) return blockY + 1.0; + + String levelStr = block.getProperty("level"); + int level = (levelStr == null) ? 0 : Integer.parseInt(levelStr); + + return blockY + ((level == 0) ? 1.0 : (8 - level) / 8.0); + } + + public Scheduler getScheduler() { + return hook.scheduler(); + } + + public Instance getInstance() { + return controller.getInstance(); + } + + public Pos getSpawnPosition() { + return controller.getPosition(); + } + + private void startFishingSession() { + if (sessionStarted) { + return; + } + + FishingSession session = FishingService.beginCast(owner, rod, requiredMedium); + sessionStarted = true; + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); + long waitTicks = FishingService.computeWaitTicks(owner, rod, bait); + scheduleNextBite(waitTicks); + } + + private void scheduleNextBite(long delayTicks) { + cancelBiteTasks(); + nextBiteTask = hook.scheduler().buildTask(() -> { + if (isRemoved || notInWater()) { + return; + } + + FishingSession session = FishingService.getSession(owner.getUuid()); + if (session == null || session.resolved()) { + return; + } + + long now = System.currentTimeMillis(); + FishingService.updateSession(session.withBiteTiming(now, now + (BITE_WINDOW_TICKS * 50)).withBiteReady(true)); + showBiteAnimation(); + + biteExpiryTask = hook.scheduler().buildTask(() -> { + FishingSession activeSession = FishingService.getSession(owner.getUuid()); + if (activeSession == null || activeSession.resolved() || isRemoved) { + return; + } + + FishingService.updateSession(activeSession.withBiteReady(false)); + FishingBaitComponent bait = FishingItemSupport.getBait(activeSession.baitItemId()); + long nextDelay = FishingService.computeWaitTicks(owner, rod, bait); + scheduleNextBite(nextDelay); + }).delay(TaskSchedule.tick((int) BITE_WINDOW_TICKS)).schedule(); + }).delay(TaskSchedule.tick((int) delayTicks)).schedule(); + } + + private void cancelBiteTasks() { + if (nextBiteTask != null) { + nextBiteTask.cancel(); + nextBiteTask = null; + } + if (biteExpiryTask != null) { + biteExpiryTask.cancel(); + biteExpiryTask = null; + } + } + + private FishingMedium getCurrentMedium() { + Instance instance = controller.getInstance(); + if (instance == null) { + return null; + } + + Pos pos = controller.getPosition(); + FishingMedium current = getMedium(instance.getBlock(pos)); + if (current != null) { + return current; + } + return getMedium(instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0))); + } + + private FishingMedium getMedium(Block block) { + if (blockMatchesMedium(block, FishingMedium.WATER)) { + return FishingMedium.WATER; + } + if (blockMatchesMedium(block, FishingMedium.LAVA)) { + return FishingMedium.LAVA; + } + return null; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingBaitService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingBaitService.java new file mode 100644 index 000000000..a95eecec4 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingBaitService.java @@ -0,0 +1,55 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.minestom.server.item.ItemStack; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +public final class FishingBaitService { + private FishingBaitService() { + } + + public static @Nullable FishingBaitComponent getFirstAvailableBait(SkyBlockPlayer player, FishingMedium medium) { + for (int slot = 0; slot < 36; slot++) { + SkyBlockItem item = new SkyBlockItem(player.getInventory().getItemStack(slot)); + ItemType type = item.getAttributeHandler().getPotentialType(); + if (type == null) { + continue; + } + + FishingBaitComponent baitComponent = item.getComponent(FishingBaitComponent.class); + if (baitComponent == null) { + continue; + } + if (!baitComponent.getMediums().isEmpty() && !baitComponent.getMediums().contains(medium)) { + continue; + } + return baitComponent; + } + return null; + } + + public static boolean consumeOneBait(SkyBlockPlayer player, String baitItemId) { + for (int slot = 0; slot < 36; slot++) { + SkyBlockItem item = new SkyBlockItem(player.getInventory().getItemStack(slot)); + if (item.getAttributeHandler().getPotentialType() == null) { + continue; + } + if (!item.getAttributeHandler().getPotentialType().name().equals(baitItemId)) { + continue; + } + + if (item.getAmount() > 1) { + item.setAmount(item.getAmount() - 1); + player.getInventory().setItemStack(slot, PlayerItemUpdater.playerUpdate(player, item.getItemStack()).build()); + } else { + player.getInventory().setItemStack(slot, ItemStack.AIR); + } + return true; + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchKind.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchKind.java new file mode 100644 index 000000000..2ec736f53 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchKind.java @@ -0,0 +1,10 @@ +package net.swofty.type.skyblockgeneric.fishing; + +public enum FishingCatchKind { + ITEM, + TREASURE, + SEA_CREATURE, + TROPHY_FISH, + QUEST, + SPECIAL +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResolver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResolver.java new file mode 100644 index 000000000..f6a935071 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResolver.java @@ -0,0 +1,10 @@ +package net.swofty.type.skyblockgeneric.fishing; + +public final class FishingCatchResolver { + private FishingCatchResolver() { + } + + public static FishingCatchResult resolve(FishingContext context) { + return FishingLootResolver.resolve(context); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResult.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResult.java new file mode 100644 index 000000000..79d2ce265 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResult.java @@ -0,0 +1,15 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import org.jetbrains.annotations.Nullable; + +public record FishingCatchResult( + FishingCatchKind kind, + @Nullable String itemId, + @Nullable String seaCreatureId, + @Nullable String trophyFishId, + int amount, + double skillXp, + boolean corrupted, + @Nullable String message +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java new file mode 100644 index 000000000..232130275 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java @@ -0,0 +1,23 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +public record FishingContext( + SkyBlockPlayer player, + SkyBlockItem rod, + FishingMedium medium, + @Nullable FishingBaitComponent bait, + @Nullable FishingRodPartComponent hook, + @Nullable FishingRodPartComponent line, + @Nullable FishingRodPartComponent sinker, + @Nullable String regionId, + boolean hotspotActive, + ItemStatistics hotspotBuffs, + long castDurationMs +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingHotspotService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingHotspotService.java new file mode 100644 index 000000000..babc132cc --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingHotspotService.java @@ -0,0 +1,75 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public final class FishingHotspotService { + private static final double HOTSPOT_RADIUS_SQUARED = 25.0D; + + private FishingHotspotService() { + } + + public static boolean isBobberInHotspot(SkyBlockPlayer player, FishingMedium medium, Pos bobberPos) { + ItemStatistics buffs = getActiveHotspotBuffs(player, medium, bobberPos); + for (ItemStatistic statistic : ItemStatistic.values()) { + if (buffs.getOverall(statistic) != 0.0D) { + return true; + } + } + return false; + } + + public static ItemStatistics getActiveHotspotBuffs(SkyBlockPlayer player, FishingMedium medium, Pos bobberPos) { + String serverType = HypixelConst.getTypeLoader().getType().name(); + SkyBlockRegion playerRegion = player.getRegion(); + String regionId = playerRegion == null ? null : playerRegion.getType().name(); + double sinkerMultiplier = 1.0D; + if (player.getItemInMainHand() != null) { + var heldItem = new net.swofty.type.skyblockgeneric.item.SkyBlockItem(player.getItemInMainHand()); + var sinker = FishingRodPartService.getSinker(heldItem); + if (sinker != null && sinker.getHotspotBuffMultiplier() > 0) { + sinkerMultiplier = sinker.getHotspotBuffMultiplier(); + } + } + + ItemStatistics.Builder builder = ItemStatistics.builder(); + for (HotspotDefinition hotspot : FishingRegistry.getHotspots()) { + if (hotspot.medium() != medium) { + continue; + } + if (!hotspot.regions().isEmpty() && (regionId == null || !hotspot.regions().contains(regionId))) { + continue; + } + if (!matchesAnyPoint(serverType, bobberPos, hotspot)) { + continue; + } + + for (ItemStatistic statistic : ItemStatistic.values()) { + double value = hotspot.buffs().getOverall(statistic) * sinkerMultiplier; + if (value != 0.0D) { + builder.withBase(statistic, value); + } + } + } + return builder.build(); + } + + private static boolean matchesAnyPoint(String serverType, Pos bobberPos, HotspotDefinition hotspot) { + for (HotspotDefinition.SpawnPoint point : hotspot.spawnPoints()) { + if (point.serverType() != null && !point.serverType().equals(serverType)) { + continue; + } + double dx = bobberPos.x() - point.x(); + double dy = bobberPos.y() - point.y(); + double dz = bobberPos.z() - point.z(); + if ((dx * dx) + (dy * dy) + (dz * dz) <= HOTSPOT_RADIUS_SQUARED) { + return true; + } + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemSupport.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemSupport.java new file mode 100644 index 000000000..3b5f39fa5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemSupport.java @@ -0,0 +1,93 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.item.ConfigurableSkyBlockItem; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodMetadataComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingShipPartComponent; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public final class FishingItemSupport { + private FishingItemSupport() { + } + + public static @Nullable FishingRodMetadataComponent getRodMetadata(@Nullable String itemId) { + return getComponent(itemId, FishingRodMetadataComponent.class); + } + + public static @Nullable FishingBaitComponent getBait(@Nullable String itemId) { + return getComponent(itemId, FishingBaitComponent.class); + } + + public static @Nullable FishingRodPartComponent getRodPart(@Nullable String itemId) { + return getComponent(itemId, FishingRodPartComponent.class); + } + + public static @Nullable FishingShipPartComponent getShipPart(@Nullable String itemId) { + return getComponent(itemId, FishingShipPartComponent.class); + } + + public static @Nullable SkyBlockItem getItem(@Nullable String itemId) { + if (itemId == null || itemId.isBlank()) { + return null; + } + ItemType type = ItemType.get(itemId); + return type == null ? null : new SkyBlockItem(type); + } + + public static List getBaits() { + return getItemsWith(FishingBaitComponent.class); + } + + public static List getRodParts() { + return getItemsWith(FishingRodPartComponent.class); + } + + public static List getShipParts() { + return getItemsWith(FishingShipPartComponent.class); + } + + private static @Nullable T getComponent(@Nullable String itemId, Class componentClass) { + if (itemId == null || itemId.isBlank()) { + return null; + } + + ItemType type = ItemType.get(itemId); + if (type == null) { + return null; + } + + SkyBlockItem item = new SkyBlockItem(type); + if (!item.hasComponent(componentClass)) { + return null; + } + return item.getComponent(componentClass); + } + + private static List getItemsWith(Class componentClass) { + List items = new ArrayList<>(); + for (String id : ConfigurableSkyBlockItem.getIDs()) { + ItemType type = ItemType.get(id); + if (type == null) { + continue; + } + + SkyBlockItem item = new SkyBlockItem(type); + if (!item.hasComponent(componentClass)) { + continue; + } + items.add(item); + } + + items.sort(Comparator.comparingInt(item -> item.getAttributeHandler().getRarity().ordinal()) + .thenComparing(SkyBlockItem::getDisplayName)); + return List.copyOf(items); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingLootResolver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingLootResolver.java new file mode 100644 index 000000000..4a723c6e2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingLootResolver.java @@ -0,0 +1,264 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public final class FishingLootResolver { + private FishingLootResolver() { + } + + public static FishingCatchResult resolve(FishingContext context) { + FishingCatchResult questCatch = tryResolveQuestCatch(context); + if (questCatch != null) { + return questCatch; + } + + FishingCatchResult trophyFish = tryResolveTrophyFish(context); + if (trophyFish != null) { + return trophyFish; + } + + FishingCatchResult seaCreature = tryResolveSeaCreature(context); + if (seaCreature != null) { + return seaCreature; + } + + return resolveItem(context); + } + + private static FishingCatchResult tryResolveTrophyFish(FishingContext context) { + if (context.medium() != FishingMedium.LAVA) { + return null; + } + + double bonus = getTotalStatistic(context, ItemStatistic.TROPHY_FISH_CHANCE); + if (context.bait() != null) { + bonus += context.bait().getTrophyFishChanceBonus(); + } + + List eligible = new ArrayList<>(); + for (TrophyFishDefinition definition : FishingRegistry.getTrophyFish()) { + if (!definition.regions().isEmpty() && context.regionId() != null && !definition.regions().contains(context.regionId())) { + continue; + } + if (context.player().getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { + continue; + } + if (context.castDurationMs() < definition.minimumCastTimeMs()) { + continue; + } + eligible.add(definition); + } + + eligible.sort(Comparator.comparingDouble(TrophyFishDefinition::catchChance)); + for (TrophyFishDefinition definition : eligible) { + if (Math.random() * 100 <= definition.catchChance() + bonus) { + String tier = rollTrophyTier(context, definition); + String itemId = switch (tier) { + case "DIAMOND" -> definition.diamondItemId(); + case "GOLD" -> definition.goldItemId(); + case "SILVER" -> definition.silverItemId(); + default -> definition.bronzeItemId(); + }; + if (itemId == null) { + continue; + } + return new FishingCatchResult(FishingCatchKind.TROPHY_FISH, itemId, null, definition.id(), 1, 300.0D, false, null); + } + } + + return null; + } + + private static FishingCatchResult tryResolveQuestCatch(FishingContext context) { + if (context.medium() != FishingMedium.WATER) { + return null; + } + if (context.regionId() == null) { + return null; + } + if (!"FISHING_OUTPOST".equals(context.regionId()) && !"FISHERMANS_HUT".equals(context.regionId())) { + return null; + } + if (!context.player().getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_FISHERWOMAN_ENID)) { + return null; + } + if (context.player().getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_UNLOCKED_SHIP)) { + return null; + } + if (context.player().getShipState().getEngine() != null) { + return null; + } + if (context.player().countItem(ItemType.RUSTY_SHIP_ENGINE) > 0) { + return null; + } + if (Math.random() * 100 > 1.0D) { + return null; + } + + return new FishingCatchResult( + FishingCatchKind.QUEST, + ItemType.RUSTY_SHIP_ENGINE.name(), + null, + null, + 1, + 15.0D, + false, + "You fished up a Rusty Ship Engine!" + ); + } + + private static String rollTrophyTier(FishingContext context, TrophyFishDefinition definition) { + var progress = context.player().getTrophyFishData().getProgress(definition.id()); + if (progress.getTotalCatches() + 1 >= 600 && !progress.hasTier("DIAMOND")) { + return "DIAMOND"; + } + if (progress.getTotalCatches() + 1 >= 100 && !progress.hasTier("GOLD")) { + return "GOLD"; + } + + double charmBonus = 0.0D; + var charm = context.rod().getAttributeHandler().getEnchantment(net.swofty.type.skyblockgeneric.enchantment.EnchantmentType.CHARM); + if (charm != null) { + charmBonus = charm.level() * 2.0D; + } + + if (Math.random() <= (0.002D * (1 + charmBonus / 100D))) { + return "DIAMOND"; + } + if (Math.random() <= (0.02D * (1 + charmBonus / 100D))) { + return "GOLD"; + } + if (Math.random() <= (0.25D * (1 + charmBonus / 100D))) { + return "SILVER"; + } + return "BRONZE"; + } + + private static FishingCatchResult tryResolveSeaCreature(FishingContext context) { + FishingTableDefinition table = findTable(context); + if (table == null) { + return null; + } + + double seaCreatureChance = getTotalStatistic(context, ItemStatistic.SEA_CREATURE_CHANCE); + if (context.hook() != null && context.hook().isTreasureOnly()) { + return null; + } + + for (FishingTableDefinition.SeaCreatureRoll roll : table.seaCreatures()) { + SeaCreatureDefinition definition = FishingRegistry.getSeaCreature(roll.seaCreatureId()); + if (definition != null && context.player().getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { + continue; + } + double tagBonus = definition == null ? 0.0D : getTagBonus(context, definition.tags()); + if (Math.random() * 100 <= roll.chance() + seaCreatureChance + tagBonus) { + double skillXp = definition == null ? 0.0D : definition.skillXp(); + return new FishingCatchResult(FishingCatchKind.SEA_CREATURE, null, roll.seaCreatureId(), null, 1, skillXp, false, null); + } + } + return null; + } + + private static FishingCatchResult resolveItem(FishingContext context) { + FishingTableDefinition table = findTable(context); + if (table == null) { + return new FishingCatchResult(FishingCatchKind.ITEM, "RAW_FISH", null, null, 1, 5.0D, false, null); + } + + List pool = table.items(); + double treasureChance = getTotalStatistic(context, ItemStatistic.TREASURE_CHANCE); + if (context.bait() != null) { + treasureChance += context.bait().getTreasureChanceBonus(); + } + if (context.sinker() != null && context.sinker().isBayouTreasureToJunk()) { + treasureChance += 10.0D; + } + + if (!table.treasures().isEmpty() && Math.random() * 100 <= treasureChance) { + pool = context.sinker() != null && context.sinker().isBayouTreasureToJunk() ? table.junk() : table.treasures(); + return pick(pool, FishingCatchKind.TREASURE); + } + + FishingCatchResult result = pick(pool, FishingCatchKind.ITEM); + if (result != null) { + return result; + } + if (!table.junk().isEmpty()) { + return pick(table.junk(), FishingCatchKind.ITEM); + } + return new FishingCatchResult(FishingCatchKind.ITEM, "RAW_FISH", null, null, 1, 5.0D, false, null); + } + + private static FishingCatchResult pick(List pool, FishingCatchKind kind) { + double roll = Math.random() * 100; + double cursor = 0; + for (FishingTableDefinition.LootEntry entry : pool) { + cursor += entry.chance(); + if (roll <= cursor) { + return new FishingCatchResult(kind, entry.itemId(), null, null, entry.amount(), entry.skillXp(), false, null); + } + } + return pool.isEmpty() ? null : new FishingCatchResult(kind, pool.getFirst().itemId(), null, null, pool.getFirst().amount(), pool.getFirst().skillXp(), false, null); + } + + private static FishingTableDefinition findTable(FishingContext context) { + FishingTableDefinition fallback = null; + for (FishingTableDefinition definition : FishingRegistry.getTables()) { + if (!definition.mediums().isEmpty() && !definition.mediums().contains(context.medium())) { + continue; + } + if (context.regionId() != null && definition.regions().contains(context.regionId())) { + return definition; + } + if (definition.regions().isEmpty() && fallback == null) { + fallback = definition; + } + } + return fallback; + } + + private static double getTotalStatistic(FishingContext context, ItemStatistic statistic) { + double total = context.rod().getAttributeHandler().getStatistics().getOverall(statistic) + + FishingRodPartService.getStatistics(context.rod()).getOverall(statistic); + total += context.hotspotBuffs().getOverall(statistic); + if (context.bait() != null) { + SkyBlockItem baitItem = FishingItemSupport.getItem(context.bait().getItemId()); + if (baitItem != null) { + total += baitItem.getAttributeHandler().getStatistics().getOverall(statistic); + } + } + return total; + } + + private static double getTagBonus(FishingContext context, List tags) { + double total = 0.0D; + if (context.hook() != null) { + total += getTagBonus(context.hook().getTagBonuses(), tags); + } + if (context.line() != null) { + total += getTagBonus(context.line().getTagBonuses(), tags); + } + if (context.sinker() != null) { + total += getTagBonus(context.sinker().getTagBonuses(), tags); + } + if (context.bait() != null) { + total += getTagBonus(context.bait().getTagBonuses(), tags); + } + return total; + } + + private static double getTagBonus(java.util.Map bonuses, List tags) { + double total = 0.0D; + for (String tag : tags) { + total += bonuses.getOrDefault(tag, 0.0D); + } + return total; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java new file mode 100644 index 000000000..c9b135f64 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java @@ -0,0 +1,30 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.minestom.server.instance.block.Block; +import org.jetbrains.annotations.Nullable; + +public enum FishingMedium { + WATER, + LAVA; + + public boolean matches(Block block) { + if (block == null || !block.isLiquid()) { + return false; + } + + String blockName = block.name(); + return switch (this) { + case WATER -> blockName.contains("water"); + case LAVA -> blockName.contains("lava"); + }; + } + + public static @Nullable FishingMedium fromBlock(Block block) { + for (FishingMedium medium : values()) { + if (medium.matches(block)) { + return medium; + } + } + return null; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingPartCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingPartCategory.java new file mode 100644 index 000000000..36995d73c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingPartCategory.java @@ -0,0 +1,7 @@ +package net.swofty.type.skyblockgeneric.fishing; + +public enum FishingPartCategory { + HOOK, + LINE, + SINKER +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java new file mode 100644 index 000000000..cc9768e88 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java @@ -0,0 +1,393 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.ServerType; +import net.swofty.commons.YamlFileUtils; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; +import org.tinylog.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class FishingRegistry { + private static final File FISHING_DIR = new File("./configuration/skyblock/fishing"); + + private static final Map TABLES = new LinkedHashMap<>(); + private static final Map TROPHY_FISH = new LinkedHashMap<>(); + private static final Map SEA_CREATURES = new LinkedHashMap<>(); + private static final Map HOTSPOTS = new LinkedHashMap<>(); + + private FishingRegistry() { + } + + public static void loadAll() { + TABLES.clear(); + TROPHY_FISH.clear(); + SEA_CREATURES.clear(); + HOTSPOTS.clear(); + + if (!YamlFileUtils.ensureDirectoryExists(FISHING_DIR)) { + throw new IllegalStateException("Unable to create fishing configuration directory"); + } + + try { + loadTables(new File(FISHING_DIR, "tables.yml")); + loadTrophyFish(new File(FISHING_DIR, "trophy_fish.yml")); + loadSeaCreatures(new File(FISHING_DIR, "sea_creatures.yml")); + loadHotspots(new File(FISHING_DIR, "hotspots.yml")); + } catch (Exception exception) { + Logger.error(exception, "Failed to load fishing configuration"); + } + } + + public static @Nullable FishingTableDefinition getTable(String tableId) { + return TABLES.get(tableId); + } + + public static @Nullable TrophyFishDefinition getTrophyFish(String id) { + return TROPHY_FISH.get(id); + } + + public static @Nullable SeaCreatureDefinition getSeaCreature(String id) { + return SEA_CREATURES.get(id); + } + + + public static List getTables() { + return List.copyOf(TABLES.values()); + } + + public static List getHotspots() { + return List.copyOf(HOTSPOTS.values()); + } + + public static List getTrophyFish() { + return List.copyOf(TROPHY_FISH.values()); + } + + public static List getSeaCreatures() { + return List.copyOf(SEA_CREATURES.values()); + } + + + @SuppressWarnings("unchecked") + private static void loadTables(File file) throws IOException { + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("tables", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + TABLES.put(id, new FishingTableDefinition( + id, + stringList(entry.get("regions")), + parseMediums((List) entry.get("mediums")), + parseLootEntries((List>) entry.get("items")), + parseLootEntries((List>) entry.get("treasures")), + parseLootEntries((List>) entry.get("junk")), + parseSeaCreatureRolls((List>) entry.get("seaCreatures")) + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadTrophyFish(File file) throws IOException { + if (!file.exists()) { + return; + } + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("trophyFish", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + TROPHY_FISH.put(id, new TrophyFishDefinition( + id, + string(entry, "displayName"), + doubleValue(entry, "catchChance", 0.0D), + stringList(entry.get("regions")), + intValue(entry, "requiredFishingLevel", 0), + longValue(entry, "minimumCastTimeMs", 0L), + nullableString(entry, "requiredRodId"), + nullableDouble(entry.get("minimumMana")), + nullableDouble(entry.get("minimumBobberDepth")), + nullableDouble(entry.get("maximumPlayerDistance")), + booleanValue(entry, "requiresStarterRodWithoutEnchantments", false), + booleanValue(entry, "specialGoldenFish", false), + nullableString(entry, "bronzeItemId"), + nullableString(entry, "silverItemId"), + nullableString(entry, "goldItemId"), + nullableString(entry, "diamondItemId") + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadSeaCreatures(File file) throws IOException { + if (!file.exists()) { + return; + } + + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("seaCreatures", Collections.emptyList()); + for (Map entry : entries) { + String id = string(entry, "id"); + SEA_CREATURES.put(id, new SeaCreatureDefinition( + id, + intValue(entry, "requiredFishingLevel", 0), + doubleValue(entry, "skillXp", 0.0D), + stringList(entry.get("tags")) + )); + } + } + + @SuppressWarnings("unchecked") + private static void loadHotspots(File file) throws IOException { + if (!file.exists()) { + return; + } + + Map root = YamlFileUtils.loadYaml(file); + List> entries = (List>) root.getOrDefault("hotspots", Collections.emptyList()); + for (Map entry : entries) { + String serverType = normalizeServerType(nullableString(entry, "serverType")); + List> rawSpawnPoints = (List>) entry.get("spawnPoints"); + List spawnPoints = new ArrayList<>(); + if (rawSpawnPoints == null || rawSpawnPoints.isEmpty()) { + spawnPoints.add(new HotspotDefinition.SpawnPoint( + serverType, + doubleValue(entry.get("x"), 0.0D), + doubleValue(entry.get("y"), 0.0D), + doubleValue(entry.get("z"), 0.0D) + )); + } else { + for (Map spawnPoint : rawSpawnPoints) { + spawnPoints.add(new HotspotDefinition.SpawnPoint( + normalizeServerType(nullableString(spawnPoint, "serverType"), serverType), + doubleValue(spawnPoint.get("x"), 0.0D), + doubleValue(spawnPoint.get("y"), 0.0D), + doubleValue(spawnPoint.get("z"), 0.0D) + )); + } + } + + String id = nullableString(entry, "id"); + if (id == null || id.isBlank()) { + id = serverType + "_" + HOTSPOTS.size(); + } + + Map buffs = castMap(entry.get("buffs")); + HOTSPOTS.put(id, new HotspotDefinition( + id, + nullableString(entry, "displayName") == null ? "Hotspot" : nullableString(entry, "displayName"), + stringList(entry.get("regions")), + entry.containsKey("medium") ? FishingMedium.valueOf(String.valueOf(entry.get("medium")).toUpperCase()) : FishingMedium.WATER, + intValue(entry, "maxActive", defaultMaxActiveForServer(serverType)), + intValue(entry, "durationSeconds", 120), + parseStatistics(buffs, defaultHotspotBuffs()), + stringList(entry.get("seaCreatures")), + spawnPoints + )); + } + } + + + private static ItemStatistics parseStatistics(@Nullable Map values) { + return parseStatistics(values, Map.of()); + } + + private static ItemStatistics parseStatistics(@Nullable Map values, Map defaults) { + if (values == null || values.isEmpty()) { + if (defaults.isEmpty()) { + return ItemStatistics.empty(); + } + values = new LinkedHashMap<>(); + } + + Map mergedValues = new LinkedHashMap<>(); + defaults.forEach(mergedValues::put); + mergedValues.putAll(values); + + if (mergedValues.isEmpty()) { + return ItemStatistics.empty(); + } + + ItemStatistics.Builder builder = ItemStatistics.builder(); + for (Map.Entry entry : mergedValues.entrySet()) { + builder.withBase(ItemStatistic.valueOf(entry.getKey().toUpperCase()), doubleValue(entry.getValue(), 0.0D)); + } + return builder.build(); + } + + + private static List parseMediums(@Nullable List mediums) { + if (mediums == null || mediums.isEmpty()) { + return List.of(FishingMedium.WATER); + } + + List result = new ArrayList<>(); + for (Object value : mediums) { + result.add(FishingMedium.valueOf(String.valueOf(value).toUpperCase())); + } + return result; + } + + @SuppressWarnings("unchecked") + private static @Nullable Map castMap(@Nullable Object value) { + if (value instanceof Map map) { + return (Map) map; + } + return null; + } + + private static List stringList(@Nullable Object value) { + if (!(value instanceof List values) || values.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Object entry : values) { + result.add(String.valueOf(entry)); + } + return result; + } + + private static String string(Map values, String key) { + String value = nullableString(values, key); + if (value == null) { + throw new IllegalArgumentException("Missing fishing config key: " + key); + } + return value; + } + + private static @Nullable String nullableString(Map values, String key) { + return nullableString(values.get(key)); + } + + private static @Nullable String nullableString(@Nullable Object value) { + if (value == null) { + return null; + } + String stringValue = String.valueOf(value); + return stringValue.isBlank() ? null : stringValue; + } + + private static int intValue(Map values, String key, int defaultValue) { + return intValue(values.get(key), defaultValue); + } + + private static int intValue(@Nullable Object value, int defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).intValue(); + } + + private static long longValue(Map values, String key, long defaultValue) { + return longValue(values.get(key), defaultValue); + } + + private static long longValue(@Nullable Object value, long defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).longValue(); + } + + private static double doubleValue(Map values, String key, double defaultValue) { + return doubleValue(values.get(key), defaultValue); + } + + private static double doubleValue(@Nullable Object value, double defaultValue) { + if (value == null) { + return defaultValue; + } + return ((Number) value).doubleValue(); + } + + private static @Nullable Double nullableDouble(@Nullable Object value) { + if (value == null) { + return null; + } + return ((Number) value).doubleValue(); + } + + private static boolean booleanValue(Map values, String key, boolean defaultValue) { + return booleanValue(values.get(key), defaultValue); + } + + private static boolean booleanValue(@Nullable Object value, boolean defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Boolean bool) { + return bool; + } + return Boolean.parseBoolean(String.valueOf(value)); + } + + private static String normalizeServerType(@Nullable String serverType) { + return normalizeServerType(serverType, null); + } + + private static String normalizeServerType(@Nullable String serverType, @Nullable String fallback) { + String value = serverType == null || serverType.isEmpty() ? fallback : serverType; + if (value == null || value.isEmpty()) { + return ServerType.SKYBLOCK_HUB.name(); + } + return ServerType.getSkyblockServer(value).name(); + } + + private static int defaultMaxActiveForServer(String serverType) { + return switch (serverType) { + case "SKYBLOCK_HUB", "SKYBLOCK_BACKWATER_BAYOU" -> 2; + case "SKYBLOCK_SPIDERS_DEN" -> 1; + case "SKYBLOCK_CRIMSON_ISLE" -> 3; + default -> 1; + }; + } + + private static Map defaultHotspotBuffs() { + Map defaults = new LinkedHashMap<>(); + defaults.put("FISHING_SPEED", 15.0D); + defaults.put("SEA_CREATURE_CHANCE", 5.0D); + defaults.put("DOUBLE_HOOK_CHANCE", 2.0D); + defaults.put("TROPHY_FISH_CHANCE", 5.0D); + defaults.put("TREASURE_CHANCE", 1.0D); + return defaults; + } + + private static List parseLootEntries(@Nullable List> entries) { + if (entries == null || entries.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Map entry : entries) { + result.add(new FishingTableDefinition.LootEntry( + string(entry, "itemId"), + doubleValue(entry, "chance", 0.0D), + intValue(entry, "amount", 1), + doubleValue(entry, "skillXp", 0.0D) + )); + } + return result; + } + + private static List parseSeaCreatureRolls(@Nullable List> entries) { + if (entries == null || entries.isEmpty()) { + return List.of(); + } + + List result = new ArrayList<>(); + for (Map entry : entries) { + result.add(new FishingTableDefinition.SeaCreatureRoll( + string(entry, "seaCreatureId"), + doubleValue(entry, "chance", 0.0D) + )); + } + return result; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodLoreBuilder.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodLoreBuilder.java new file mode 100644 index 000000000..acdd1317b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodLoreBuilder.java @@ -0,0 +1,111 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.DefaultSoulboundComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodMetadataComponent; +import net.swofty.type.skyblockgeneric.item.components.GemstoneComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public final class FishingRodLoreBuilder { + private static final List STAT_ORDER = List.of( + ItemStatistic.DAMAGE, + ItemStatistic.STRENGTH, + ItemStatistic.FEROCITY, + ItemStatistic.FISHING_SPEED, + ItemStatistic.SEA_CREATURE_CHANCE, + ItemStatistic.DOUBLE_HOOK_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE + ); + + private FishingRodLoreBuilder() { + } + + public static @Nullable FishingRodLore build(SkyBlockItem item, @Nullable SkyBlockPlayer player) { + if (!item.hasComponent(FishingRodMetadataComponent.class)) { + return null; + } + + FishingRodMetadataComponent metadata = item.getComponent(FishingRodMetadataComponent.class); + List lore = new ArrayList<>(); + if (metadata.getSubtitle() != null && !metadata.getSubtitle().isBlank()) { + lore.add(metadata.getSubtitle()); + } + + for (ItemStatistic statistic : STAT_ORDER) { + double amount = item.getAttributeHandler().getStatistics().getOverall(statistic) + + FishingRodPartService.getStatistics(item).getOverall(statistic); + if (amount == 0.0D) { + continue; + } + lore.add(formatStatistic(statistic, amount)); + } + + if (item.hasComponent(GemstoneComponent.class)) { + lore.add(renderGemSlots(item.getComponent(GemstoneComponent.class))); + } + + lore.add(partLine("ථ Hook ", item.getAttributeHandler().getFishingHook())); + lore.add(partLine("ꨃ Line ", item.getAttributeHandler().getFishingLine())); + lore.add(partLine("࿉ Sinker ", item.getAttributeHandler().getFishingSinker())); + + if (metadata.getLegacyConversionTarget() != null) { + lore.add("Talk to Roddy in the Backwater"); + lore.add("Bayou to convert this rod."); + } else if (metadata.isRodPartsEnabled()) { + lore.add("Talk to Roddy in the Backwater"); + lore.add("Bayou to apply parts to this rod."); + } + + if (item.hasComponent(net.swofty.type.skyblockgeneric.item.components.ReforgableComponent.class)) { + lore.add("This item can be reforged!"); + } + if (metadata.getRequiredFishingLevel() > 0) { + lore.add("❣ Requires Fishing Skill " + metadata.getRequiredFishingLevel() + "."); + } + if (metadata.getExtraRequirements() != null) { + lore.addAll(metadata.getExtraRequirements()); + } + if (item.hasComponent(DefaultSoulboundComponent.class)) { + lore.add("* Co-op Soulbound *"); + } + + lore.add(item.getAttributeHandler().getRarity().getDisplay() + " FISHING ROD"); + return new FishingRodLore(item.getDisplayName(), lore); + } + + private static String renderGemSlots(GemstoneComponent gemstone) { + return gemstone.getSlots().stream() + .map(slot -> "[" + slot.slot().getSymbol() + "]") + .reduce((left, right) -> left + " " + right) + .orElse(""); + } + + private static String partLine(String prefix, @Nullable String itemId) { + if (itemId == null) { + return prefix + "NONE"; + } + ItemType type = ItemType.get(itemId); + return prefix + (type == null ? "NONE" : type.getDisplayName().replace("§", "")); + } + + private static String formatStatistic(ItemStatistic statistic, double amount) { + return statistic.getDisplayName() + ": " + statistic.getPrefix() + format(amount) + statistic.getSuffix(); + } + + private static String format(double value) { + if (Math.abs(value - Math.rint(value)) < 0.0001D) { + return String.valueOf((long) Math.rint(value)); + } + return StringUtility.decimalify(value, 1); + } + + public record FishingRodLore(String displayName, List lore) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodPartService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodPartService.java new file mode 100644 index 000000000..3c5ebb102 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodPartService.java @@ -0,0 +1,63 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import org.jetbrains.annotations.Nullable; + +public final class FishingRodPartService { + private FishingRodPartService() { + } + + public static @Nullable FishingRodPartComponent getHook(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingHook()); + } + + public static @Nullable FishingRodPartComponent getLine(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingLine()); + } + + public static @Nullable FishingRodPartComponent getSinker(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingSinker()); + } + + public static ItemStatistics getStatistics(SkyBlockItem rod) { + ItemStatistics.Builder builder = ItemStatistics.builder(); + append(builder, getHook(rod)); + append(builder, getLine(rod)); + append(builder, getSinker(rod)); + return builder.build(); + } + + public static void applyPart(SkyBlockItem rod, FishingRodPartComponent part) { + switch (part.getCategory()) { + case HOOK -> rod.getAttributeHandler().setFishingHook(part.getItemId()); + case LINE -> rod.getAttributeHandler().setFishingLine(part.getItemId()); + case SINKER -> rod.getAttributeHandler().setFishingSinker(part.getItemId()); + } + } + + public static void removePart(SkyBlockItem rod, FishingPartCategory category) { + switch (category) { + case HOOK -> rod.getAttributeHandler().setFishingHook(null); + case LINE -> rod.getAttributeHandler().setFishingLine(null); + case SINKER -> rod.getAttributeHandler().setFishingSinker(null); + } + } + + private static void append(ItemStatistics.Builder builder, @Nullable FishingRodPartComponent definition) { + if (definition == null) { + return; + } + SkyBlockItem item = FishingItemSupport.getItem(definition.getItemId()); + if (item == null) { + return; + } + for (var statistic : net.swofty.commons.skyblock.statistics.ItemStatistic.values()) { + double amount = item.getAttributeHandler().getStatistics().getOverall(statistic); + if (amount != 0) { + builder.withBase(statistic, amount); + } + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java new file mode 100644 index 000000000..fd0ba7fef --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java @@ -0,0 +1,163 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.type.generic.data.datapoints.DatapointToggles; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointCollection; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointTrophyFish; +import net.swofty.type.skyblockgeneric.entity.FishingHook; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; +import net.swofty.type.skyblockgeneric.region.SkyBlockRegion; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public final class FishingService { + private static final Map SESSIONS = new ConcurrentHashMap<>(); + + private FishingService() { + } + + public static FishingSession beginCast(SkyBlockPlayer player, SkyBlockItem rod, FishingMedium medium) { + FishingBaitComponent bait = FishingBaitService.getFirstAvailableBait(player, medium); + FishingSession session = new FishingSession( + player.getUuid(), + rod.getAttributeHandler().getPotentialType().name(), + medium, + bait == null ? null : bait.getItemId(), + System.currentTimeMillis(), + 0L, + 0L, + false, + false + ); + SESSIONS.put(player.getUuid(), session); + return session; + } + + public static @Nullable FishingSession getSession(UUID playerUuid) { + return SESSIONS.get(playerUuid); + } + + public static void updateSession(FishingSession session) { + SESSIONS.put(session.ownerUuid(), session); + } + + public static void clearSession(UUID playerUuid) { + SESSIONS.remove(playerUuid); + } + + public static long computeWaitTicks(SkyBlockPlayer player, SkyBlockItem rod, @Nullable FishingBaitComponent bait) { + double fishingSpeed = player.getStatistics().allStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED) + + rod.getAttributeHandler().getStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED) + + FishingRodPartService.getStatistics(rod).getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); + if (bait != null) { + SkyBlockItem baitItem = FishingItemSupport.getItem(bait.getItemId()); + if (baitItem != null) { + fishingSpeed += baitItem.getAttributeHandler().getStatistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); + } + if ("CORRUPTED_BAIT".equals(bait.getItemId())) { + fishingSpeed /= 2.0D; + } + } + long baseTicks = 80L; + return Math.max(20L, Math.round(baseTicks - Math.min(50D, fishingSpeed / 2D))); + } + + public static @Nullable FishingCatchResult resolveCatch(SkyBlockPlayer player, SkyBlockItem rod, FishingHook hook) { + FishingSession session = getSession(player.getUuid()); + if (session == null || session.resolved()) { + return null; + } + + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); + SkyBlockRegion region = player.getRegion(); + var hotspotBuffs = FishingHotspotService.getActiveHotspotBuffs(player, session.medium(), hook.getSpawnPosition()); + boolean hotspotActive = hasAnyBuffValue(hotspotBuffs); + FishingContext context = new FishingContext( + player, + rod, + session.medium(), + bait, + FishingRodPartService.getHook(rod), + FishingRodPartService.getLine(rod), + FishingRodPartService.getSinker(rod), + region == null ? null : region.getType().name(), + hotspotActive, + hotspotBuffs, + System.currentTimeMillis() - session.castAt() + ); + + FishingCatchResult result = FishingCatchResolver.resolve(context); + if (result == null) { + return null; + } + + if (session.baitItemId() != null) { + boolean preserve = false; + var caster = rod.getAttributeHandler().getEnchantment(net.swofty.type.skyblockgeneric.enchantment.EnchantmentType.CASTER); + if (caster != null) { + preserve |= Math.random() * 100 < caster.level(); + } + FishingRodPartComponent sinker = FishingRodPartService.getSinker(rod); + if (!preserve && sinker != null && sinker.getBaitPreservationChance() > 0) { + preserve = Math.random() * 100 < sinker.getBaitPreservationChance(); + } + if (!preserve) { + FishingBaitService.consumeOneBait(player, session.baitItemId()); + } + } + + awardCatch(player, rod, hook, result); + updateSession(session.withResolved(true)); + return result; + } + + private static void awardCatch(SkyBlockPlayer player, SkyBlockItem rod, FishingHook hook, FishingCatchResult result) { + if (!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH)) { + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_CAUGHT_FIRST_FISH, true); + } + + if (result.itemId() != null) { + player.addAndUpdateItem(net.swofty.commons.skyblock.item.ItemType.valueOf(result.itemId()), result.amount()); + player.getCollection().increase(net.swofty.commons.skyblock.item.ItemType.valueOf(result.itemId()), result.amount()); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COLLECTION, DatapointCollection.class).setValue(player.getCollection()); + } + + FishingRodPartComponent sinker = FishingRodPartService.getSinker(rod); + if (sinker != null && sinker.getMaterializedItemId() != null && Math.random() <= sinker.getMaterializedChance()) { + player.addAndUpdateItem(net.swofty.commons.skyblock.item.ItemType.valueOf(sinker.getMaterializedItemId())); + } + + if (result.trophyFishId() != null) { + String tier = result.itemId() != null && result.itemId().contains("_DIAMOND") ? "DIAMOND" : + result.itemId() != null && result.itemId().contains("_GOLD") ? "GOLD" : + result.itemId() != null && result.itemId().contains("_SILVER") ? "SILVER" : "BRONZE"; + DatapointTrophyFish.TrophyFishData data = player.getTrophyFishData(); + data.getProgress(result.trophyFishId()).increment(tier); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.TROPHY_FISH, DatapointTrophyFish.class).setValue(data); + } + + if (result.kind() != FishingCatchKind.SEA_CREATURE && result.skillXp() > 0) { + player.getSkills().increase(player, net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING, result.skillXp()); + } + + if (result.kind() == FishingCatchKind.SEA_CREATURE && result.seaCreatureId() != null) { + // TODO: sea creatures + } + player.setItemInHand(rod); + } + + private static boolean hasAnyBuffValue(net.swofty.commons.skyblock.statistics.ItemStatistics statistics) { + for (net.swofty.commons.skyblock.statistics.ItemStatistic statistic : net.swofty.commons.skyblock.statistics.ItemStatistic.values()) { + if (statistics.getOverall(statistic) != 0.0D) { + return true; + } + } + return false; + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java new file mode 100644 index 000000000..1b8c71a5b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java @@ -0,0 +1,29 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public record FishingSession( + UUID ownerUuid, + String rodItemId, + FishingMedium medium, + @Nullable String baitItemId, + long castAt, + long biteReadyAt, + long biteWindowEndsAt, + boolean biteReady, + boolean resolved +) { + public FishingSession withBiteTiming(long readyAt, long windowEndsAt) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, readyAt, windowEndsAt, biteReady, resolved); + } + + public FishingSession withBiteReady(boolean ready) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, biteReadyAt, biteWindowEndsAt, ready, resolved); + } + + public FishingSession withResolved(boolean nextResolved) { + return new FishingSession(ownerUuid, rodItemId, medium, baitItemId, castAt, biteReadyAt, biteWindowEndsAt, biteReady, nextResolved); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipPartSlot.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipPartSlot.java new file mode 100644 index 000000000..7a93807a5 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipPartSlot.java @@ -0,0 +1,7 @@ +package net.swofty.type.skyblockgeneric.fishing; + +public enum FishingShipPartSlot { + HELM, + ENGINE, + HULL +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java new file mode 100644 index 000000000..a2ae344c8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java @@ -0,0 +1,31 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.data.datapoints.DatapointShipState; +import net.swofty.type.skyblockgeneric.item.components.FishingShipPartComponent; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public final class FishingShipService { + private FishingShipService() { + } + + public static DatapointShipState.ShipState getState(SkyBlockPlayer player) { + return player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).getValue(); + } + + public static void installPart(SkyBlockPlayer player, String itemId, FishingShipPartComponent definition) { + DatapointShipState.ShipState state = getState(player); + switch (definition.getSlot()) { + case HELM -> state.setHelm(itemId); + case ENGINE -> state.setEngine(itemId); + case HULL -> state.setHull(itemId); + } + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).setValue(state); + } + + public static void unlockDestination(SkyBlockPlayer player, String destinationId) { + DatapointShipState.ShipState state = getState(player); + state.unlockDestination(destinationId); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).setValue(state); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingTableDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingTableDefinition.java new file mode 100644 index 000000000..13d287fbd --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingTableDefinition.java @@ -0,0 +1,19 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import java.util.List; + +public record FishingTableDefinition( + String id, + List regions, + List mediums, + List items, + List treasures, + List junk, + List seaCreatures +) { + public record LootEntry(String itemId, double chance, int amount, double skillXp) { + } + + public record SeaCreatureRoll(String seaCreatureId, double chance) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/HotspotDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/HotspotDefinition.java new file mode 100644 index 000000000..a3c48b9c0 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/HotspotDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; + +import java.util.List; + +public record HotspotDefinition( + String id, + String displayName, + List regions, + FishingMedium medium, + int maxActive, + int durationSeconds, + ItemStatistics buffs, + List seaCreatureIds, + List spawnPoints +) { + public record SpawnPoint( + String serverType, + double x, + double y, + double z + ) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/SeaCreatureDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/SeaCreatureDefinition.java new file mode 100644 index 000000000..d2ebd4041 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/SeaCreatureDefinition.java @@ -0,0 +1,11 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import java.util.List; + +public record SeaCreatureDefinition( + String id, + int requiredFishingLevel, + double skillXp, + List tags +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/TrophyFishDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/TrophyFishDefinition.java new file mode 100644 index 000000000..e3736b5ab --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/TrophyFishDefinition.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public record TrophyFishDefinition( + String id, + String displayName, + double catchChance, + List regions, + int requiredFishingLevel, + long minimumCastTimeMs, + @Nullable String requiredRodId, + @Nullable Double minimumMana, + @Nullable Double minimumBobberDepth, + @Nullable Double maximumPlayerDistance, + boolean requiresStarterRodWithoutEnchantments, + boolean specialGoldenFish, + @Nullable String bronzeItemId, + @Nullable String silverItemId, + @Nullable String goldItemId, + @Nullable String diamondItemId +) { +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java new file mode 100644 index 000000000..2857b9bd1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java @@ -0,0 +1,154 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.FishingBaitComponent; +import net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class FishingGuideStackFactory { + private static final List GUIDE_STAT_ORDER = List.of( + ItemStatistic.DAMAGE, + ItemStatistic.STRENGTH, + ItemStatistic.FEROCITY, + ItemStatistic.FISHING_SPEED, + ItemStatistic.SEA_CREATURE_CHANCE, + ItemStatistic.DOUBLE_HOOK_CHANCE, + ItemStatistic.TREASURE_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE, + ItemStatistic.MAGIC_FIND + ); + + private FishingGuideStackFactory() { + } + + public static net.minestom.server.item.ItemStack.Builder buildBaitStack(SkyBlockItem baitItem) { + FishingBaitComponent bait = baitItem.getComponent(FishingBaitComponent.class); + List lore = new ArrayList<>(); + lore.add("§8Fishing Bait"); + lore.add("§8Consumes on Cast"); + lore.add(""); + appendStatistics(lore, baitItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, bait.getTagBonuses()); + + if (bait.getTreasureChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTreasureChanceBonus()) + " Treasure Chance§7."); + } + if (bait.getTreasureQualityBonus() > 0) { + lore.add("§7Increases treasure quality by §a" + format(bait.getTreasureQualityBonus()) + "%§7."); + } + if (bait.getTrophyFishChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTrophyFishChanceBonus()) + " Trophy Fish Chance§7."); + } + if (bait.getDoubleHookChanceBonus() > 0) { + lore.add("§7Grants §9+" + format(bait.getDoubleHookChanceBonus()) + " Double Hook Chance§7."); + } + if (bait.getMediums().size() == 1) { + lore.add("§7Usable in " + (bait.getMediums().getFirst() == FishingMedium.WATER ? "§bWater" : "§cLava") + "§7."); + } + finishFooter(lore, bait.getItemId(), "BAIT"); + + return ItemStackCreator.getStackHead( + coloredName(bait.getItemId(), bait.getDisplayName()), + bait.getTexture(), + 1, + lore.toArray(String[]::new) + ); + } + + public static net.minestom.server.item.ItemStack.Builder buildRodPartStack(SkyBlockItem partItem) { + FishingRodPartComponent part = partItem.getComponent(FishingRodPartComponent.class); + List lore = new ArrayList<>(); + lore.add("§8" + StringUtility.toNormalCase(part.getCategory().name()) + " Rod Part"); + lore.add(""); + appendStatistics(lore, partItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, part.getTagBonuses()); + + if (part.isTreasureOnly()) { + lore.add("§7Only allows you to catch items and §6Treasure§7."); + } + if (part.isBayouTreasureToJunk()) { + lore.add("§7Replaces §6Treasure §7catches with §2Junk §7in the §2Backwater Bayou§7."); + } + if (part.getMaterializedItemId() != null) { + String itemName = ItemType.valueOf(part.getMaterializedItemId()).getDisplayName(); + if (part.getMaterializedChance() >= 1.0D) { + lore.add("§7Materializes §f" + itemName + " §7in your inventory whenever you catch something."); + } else { + lore.add("§7Has a §a" + format(part.getMaterializedChance() * 100.0D) + "% §7chance to materialize §f" + itemName + "§7."); + } + } + if (part.getBaitPreservationChance() > 0) { + lore.add("§7Grants a §a" + format(part.getBaitPreservationChance()) + "% §7chance to not consume Bait."); + } + if (part.getHotspotBuffMultiplier() > 1.0D) { + lore.add("§7Increases the bonuses of §dFishing Hotspots §7by §a" + format((part.getHotspotBuffMultiplier() - 1.0D) * 100.0D) + "%§7."); + } + if (part.getRequiredFishingLevel() > 0) { + lore.add(""); + lore.add("§4❣ §cRequires §aFishing Skill " + part.getRequiredFishingLevel() + "§c."); + } + finishFooter(lore, part.getItemId(), "ROD PART"); + + return ItemStackCreator.getStackHead( + coloredName(part.getItemId(), part.getDisplayName()), + part.getTexture(), + 1, + lore.toArray(String[]::new) + ); + } + + private static void appendStatistics(List lore, ItemStatistics statistics) { + for (ItemStatistic statistic : GUIDE_STAT_ORDER) { + double amount = statistics.getOverall(statistic); + if (amount == 0) { + continue; + } + lore.add("§7" + statistic.getDisplayName() + ": " + statistic.getLoreColor() + + statistic.getPrefix() + format(amount) + statistic.getSuffix()); + } + } + + private static void appendTagBonuses(List lore, Map bonuses) { + for (Map.Entry entry : bonuses.entrySet()) { + lore.add("§7Increases the chance to catch §e" + describeTag(entry.getKey()) + " §7by §a" + format(entry.getValue()) + "%§7."); + } + } + + private static void finishFooter(List lore, String itemId, String suffix) { + if (!lore.isEmpty() && !lore.getLast().isEmpty()) { + lore.add(""); + } + lore.add(ItemType.valueOf(itemId).rarity.getDisplay() + " " + suffix); + } + + private static String coloredName(String itemId, String displayName) { + return ItemType.valueOf(itemId).rarity.getColor() + displayName; + } + + private static String describeTag(String tag) { + return switch (tag.toUpperCase()) { + case "COMMON" -> "Common Sea Creatures"; + case "HOTSPOT" -> "Hotspot Sea Creatures"; + case "SPOOKY" -> "Spooky Sea Creatures"; + case "WINTER" -> "Winter Sea Creatures"; + case "SHARK" -> "Sharks"; + default -> StringUtility.toNormalCase(tag.toLowerCase().replace('_', ' ')); + }; + } + + private static String format(double value) { + if (Math.abs(value - Math.rint(value)) < 0.0001D) { + return String.valueOf((long) Math.rint(value)); + } + return StringUtility.decimalify(value, 1); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java new file mode 100644 index 000000000..8a2fae43d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java @@ -0,0 +1,645 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +// make these actually paginated views +public class GUI13SeaCreatureGuide extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("(1/3) Sea Creature Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§aSea Creature Guide", + Material.BOOK, + 1, + "§7Your guide to the creatures of the", + "§7deep! Can also be accessed with", + "§a/scg§7!", + "", + "§7Beware, Sea Creatures spawn much", + "§7less often on your private island.", + "", + "§7Your Fishing: §aLevel XVIII" + )); + layout.slot(10, ItemStackCreator.getStackHead( + "§7[Lvl 1] Squid (§f§lCommon§7)", + "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Ink Sac", + "§7- Lily Pad", + "", + "§cRequirements:", + "§7- §aFishing Skill 1", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b64" + )); + layout.slot(11, ItemStackCreator.getStackHead( + "§7[Lvl 4] Sea Walker (§f§lCommon§7)", + "d88ba8bb50b79e441e47b7e452764d5fff6693779d2dadd9f7f52f98d7ea0", + 1, + "§9⚓ Aquatic§7, §2༕ Undead", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Rotten Flesh", + "", + "§cRequirements:", + "§7- §aFishing Skill 1", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b64" + )); + layout.slot(12, ItemStackCreator.getStackHead( + "§7[Lvl 6] Night Squid (§f§lCommon§7)", + "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Ink Sac", + "§7- Lily Pad", + "§7- §aFishing Exp Boost", + "§7- §aSquid Boots", + "§7- §9Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 3", + "§7- §bWater", + "§7- Nighttime", + "§7- §fDark Bait" + )); + layout.slot(13, ItemStackCreator.getStackHead( + "§7[Lvl 10] Sea Guardian (§f§lCommon§7)", + "221025434045bda7025b3e514b316a4b770c6faa4ba9adb4be3809526db77f9d", + 1, + "§9⚓ Aquatic§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Prismarine Crystals", + "§7- Prismarine Shard", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b48" + )); + layout.slot(14, ItemStackCreator.getStackHead( + "§7[Lvl 10] Frog Man (§f§lCommon§7)", + "6157f19da077a3df49b2925fb6e8b400222ba6e559e86815f9b296d9e9667dd7", + 1, + "§9⚓ Aquatic§7, §a☮ Animal§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Tropical Fish", + "§7- §aHalf-Eaten Mushroom", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b28" + )); + layout.slot(15, ItemStackCreator.getStackHead( + "§7[Lvl 8] Trash Gobbler (§f§lCommon§7)", + "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + 1, + "§9⚓ Aquatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aCan of Worms", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b57" + )); + layout.slot(16, ItemStackCreator.getStackHead( + "§7[Lvl 10] Bogged (§f§lCommon§7)", + "a3b9003ba2d05562c75119b8a62185c67130e9282f7acbac4bc2824c21eb95d9", + 1, + "§f🦴 Skeletal§7, §9⚓ Aquatic", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Galatea" + )); + layout.slot(19, ItemStackCreator.getStackHead( + "§7[Lvl 7] Frozen Steve (§f§lCommon§7)", + "54690f5aa6d0e800f9b8d1890fc158b921819a81dfd7342a2170e7efc46b9ed7", + 1, + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- Ice", + "§7- Lily Pad", + "§7- Pufferfish", + "§7- Raw Cod", + "§7- Raw Salmon", + "§7- White Gift", + "§7- §aHunk of Ice", + "§7- §9Icy Sinker", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b9" + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§7[Lvl 15] Dumpster Diver (§a§lUncommon§7)", + "f5c5eb5ee072c06580986d12a029e28010c1290875534810c53140bc76dabfeb", + 1, + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- §aBronze Bowl", + "§7- §aOverflowing Trash Can", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b38" + )); + layout.slot(21, ItemStackCreator.getStackHead( + "§7[Lvl 6] Nurse Shark (§a§lUncommon§7)", + "2067ccefba5d811f47e3e18438556b704393aafcafccedd5d0981999286f598a", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §aNurse Shark Tooth", + "§7- §9Shark Fin", + "", + "§cRequirements:", + "§7- §aFishing Skill 5", + "§7- §bWater", + "§7- §bFishing Festival" + )); + layout.slot(22, ItemStackCreator.getStack( + "§7[Lvl 13] Frosty (§f§lCommon§7)", + Material.CARVED_PUMPKIN, + 1, + "§9⚓ Aquatic§7, §f☃ Frozen§7, ⚙ Construct", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- Carrot", + "§7- Ice", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Snow Block", + "§7- Sponge", + "§7- White Gift", + "§7- §aHunk of Ice", + "", + "§cRequirements:", + "§7- §aFishing Skill 6", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b9" + )); + layout.slot(23, ItemStackCreator.getStackHead( + "§7[Lvl 15] Mithril Grubber (§a§lUncommon§7)", + "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + 1, + "§9⚓ Aquatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §9Mithril Powder", + "§7- Mithril", + "§7- Raw Cod", + "§7- §9Enchanted Mithril", + "", + "§cRequirements:", + "§7- §aFishing Skill 6", + "§7- §bWater", + "§7- §2Abandoned Quarry" + )); + layout.slot(24, ItemStackCreator.getStackHead( + "§7[Lvl 18] Wetwing (§a§lUncommon§7)", + "dbc0f7c9e926c320ba472d4a88763ef932a660c470f786ac0c04c15a78fd505f", + 1, + "§9⚓ Aquatic§7, §2༕ Undead§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "§7- §aWet Water", + "§7- §9Enchanted Mangrove Log", + "", + "§cRequirements:", + "§7- §aFishing Skill 7", + "§7- §bWater", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(25, ItemStackCreator.getStackHead( + "§7[Lvl 15] Sea Witch (§a§lUncommon§7)", + "fce6604157fc4ab5591e4bcf507a749918ee9c41e357d47376e0ee7342074c90", + 1, + "§9⚓ Aquatic§7, §e✰ Humanoid§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Salmon", + "§7- Tropical Fish", + "§7- §9Fairy's Fedora", + "§7- §9Fairy's Galoshes", + "§7- §9Fairy's Polo", + "§7- §9Fairy's Trousers", + "", + "§cRequirements:", + "§7- §aFishing Skill 7", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b52" + )); + layout.slot(28, ItemStackCreator.getStack( + "§7[Lvl 9] Scarecrow (§f§lCommon§7)", + Material.CARVED_PUMPKIN, + 1, + "§9⚓ Aquatic§7, §6☽ Spooky", + "", + "§cDrops:", + "§7- Hay Bale", + "§7- Lily Pad", + "§7- §aGreen Candy", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "§7- §6Spooky Festival" + )); + layout.slot(29, ItemStackCreator.getStack( + "§7[Lvl 15] Sea Archer (§a§lUncommon§7)", + Material.SKELETON_SKULL, + 1, + "§9⚓ Aquatic§7, §f🦴 Skeletal", + "", + "§cDrops:", + "§7- Bone", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aEnchanted Bone", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b48" + )); + layout.slot(30, ItemStackCreator.getStackHead( + "§7[Lvl 8] Tadgang (§9§lRare§7)", + "1608d86ffb297bf93b7190d24bc3b2dc094f8086740f7541a752fbe661f175fc", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Mangrove Log", + "§7- Sea Lumies", + "§7- §aEnchanted Sea Lumies", + "§7- §aGill Membrane", + "§7- §9Enchanted Mangrove Log", + "", + "§cRequirements:", + "§7- §aFishing Skill 9", + "§7- §bWater", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(31, ItemStackCreator.getStackHead( + "§7[Lvl 10] Oasis Sheep (§a§lUncommon§7)", + "292df216ecd27624ac771bacfbfe006e1ed84a79e9270be0f88e9c8791d1ece4", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Mutton", + "§7- White Wool", + "§7- §aEnchanted Raw Mutton", + "§7- §9Enchanted Cooked Mutton", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bOasis" + )); + layout.slot(32, ItemStackCreator.getStackHead( + "§7[Lvl 10] Oasis Rabbit (§a§lUncommon§7)", + "b50459bcb08db5ce93e021079c1cfc038c9ebe7ad9a149516efe4d5ee8afb59f", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Rabbit Hide", + "§7- Rabbit's Foot", + "§7- Raw Rabbit", + "§7- §aEnchanted Raw Rabbit", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bOasis" + )); + layout.slot(33, ItemStackCreator.getStackHead( + "§7[Lvl 10] Banshee (§9§lRare§7)", + "30ccc3c9a06de657b98f881e23a57ecaeb252c364ddb7b92564f5ed2b8087e3b", + 1, + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Lily Pad", + "§7- Raw Salmon", + "§7- Tropical Fish", + "§7- §aEnchanted Clay Ball", + "§7- §aTorn Cloth", + "§7- §9Calcified Heart", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b22" + )); + layout.slot(34, ItemStackCreator.getStackHead( + "§7[Lvl 20] Blue Shark (§9§lRare§7)", + "381e1d06e5f0654a682a3264905b5dc4b8e7b613ab6697ac45f2e0da3bc9b4fd", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §9Blue Shark Tooth", + "§7- §9Shark Fin", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §bFishing Festival" + )); + layout.slot(37, ItemStackCreator.getStackHead( + "§7[Lvl 30] Snapping Turtle (§9§lRare§7)", + "e08fc1ae87a7035d32b0b0da58de4801463aaf8b238618024aacb0c515ae3bba", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Gold Ingot", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- §aEnchanted Gold Ingot", + "§7- §9Broken Radar", + "§7- §9Edible Seaweed", + "", + "§cRequirements:", + "§7- §aFishing Skill 10", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b5" + )); + layout.slot(38, ItemStackCreator.getStackHead( + "§7[Lvl 20] Rider of the Deep (§a§lUncommon§7)", + "cfb7dbbe002f69463768113c1e925848197f59b62694ce105792dd5a52dc17a1", + 1, + "§9⚓ Aquatic§7, §2༕ Undead§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Dark Bait", + "§7- Lily Pad", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Magnet VI)", + "§7- §aEnchanted Feather", + "§7- §aEnchanted Rotten Flesh", + "", + "§cRequirements:", + "§7- §aFishing Skill 11", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b36" + )); + layout.slot(39, ItemStackCreator.getStackHead( + "§7[Lvl 14] Ent (§5§lEpic§7)", + "30519f79e5829136c3df10b6bd727db255717c87e5c102892ef67e7f46929515", + 1, + "§2⸙ Woodland§7, §9⚓ Aquatic", + "", + "§cDrops:", + "§7- Sea Lumies", + "§7- §aEnchanted Sea Lumies", + "§7- §9Enchanted Mangrove Log", + "§7- §5Foraging Exp Boost", + "§7- §5Mangcore", + "", + "§cRequirements:", + "§7- §aFishing Skill 12", + "§7- §bWater", + "§7- §2Galatea" + )); + layout.slot(40, ItemStackCreator.getStackHead( + "§7[Lvl 21] Grinch (§a§lUncommon§7)", + "2508e4a2f88502c019652b2437b76c82fedff9091389d88118ecc673f628b547", + 1, + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §9Ice Essence", + "§7- White Gift", + "§7- §aGreen Gift", + "", + "§cRequirements:", + "§7- §aFishing Skill 13", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b2" + )); + layout.slot(41, ItemStackCreator.getStackHead( + "§7[Lvl 23] Catfish (§9§lRare§7)", + "e18f77331b2cab64e2b430fa8e4273e4db7f78fcdfa4b1a9a418af47375056eb", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Pufferfish", + "§7- Raw Cod", + "§7- Raw Salmon", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Frail VI)", + "", + "§cRequirements:", + "§7- §aFishing Skill 13", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b26" + )); + layout.slot(42, ItemStackCreator.getStack( + "§7[Lvl 30] Fried Chicken (§f§lCommon§7)", + Material.COOKED_CHICKEN, + 1, + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Raw Chicken", + "§7- §aEnchanted Raw Chicken", + "§7- §aFried Feather", + "§7- §9Magmafish", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle" + )); + layout.slot(43, ItemStackCreator.getStackHead( + "§7[Lvl 25] Carrot King (§9§lRare§7)", + "b50459bcb08db5ce93e021079c1cfc038c9ebe7ad9a149516efe4d5ee8afb59f", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Caster VI)", + "§7- §aEnchanted Carrot", + "§7- §aRabbit Hat", + "§7- §9Enchanted Rabbit Foot", + "§7- §5Lucky Clover Core", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §bWater", + "§7- §fCarrot Bait" + )); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Skill" + )); + layout.slot(50, ItemStackCreator.getStack( + "§aSort", + Material.HOPPER, + 1, + "", + "§b▶ Fishing Level Req", + "§7 Alphabetical", + "§7 Mob Level", + "§7 Killed Most", + "§7 Ascending Rarity", + "§7 Descending Rarity", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(51, ItemStackCreator.getStack( + "§aFilter", + Material.ENDER_EYE, + 1, + "", + "§f▶ All Sea Creatures", + "§7 Has Level Requirement", + "§7 Has Never Killed", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(52, ItemStackCreator.getStack( + "§aCategory", + Material.CAULDRON, + 1, + "", + "§a▶ Any Category", + "§7 Water", + "§7 Lava", + "§7 Winter", + "§7 Spooky", + "§7 Shark", + "§7 Oasis", + "§7 Bayou", + "§7 Hotspot", + "§7 Galatea", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(53, ItemStackCreator.getStack( + "§aNext Page", + Material.ARROW, + 1, + "§ePage 2" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java new file mode 100644 index 000000000..3a7c29f06 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java @@ -0,0 +1,574 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +// make these actually paginated views and data-driven +public class GUI23SeaCreatureGuide extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("(2/3) Sea Creature Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§aSea Creature Guide", + Material.BOOK, + 1, + "§7Your guide to the creatures of the", + "§7deep! Can also be accessed with", + "§a/scg§7!", + "", + "§7Beware, Sea Creatures spawn much", + "§7less often on your private island.", + "", + "§7Your Fishing: §aLevel XVIII" + )); + layout.slot(10, ItemStackCreator.getStackHead( + "§7[Lvl 24] Nightmare (§9§lRare§7)", + "578211e1b4d99d1c7bfda4838e48fc884c3eae376f58d932bc2f78b0a919f8e7", + 1, + "§9⚓ Aquatic§7, §6☽ Spooky§7, §2༕ Undead", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- §aEnchanted Rotten Flesh", + "§7- §aGreen Candy", + "§7- §aLucky Hoof", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 14", + "§7- §bWater", + "§7- §6Spooky Festival" + )); + layout.slot(11, ItemStackCreator.getStackHead( + "§7[Lvl 35] Agarimoo (§9§lRare§7)", + "3d597f77cde32c9ac9b06f82fcf7c9cb500facc14bff166222b24be39962f0ef", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Red Mushroom", + "§7- §9Agarimoo Tongue", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §aChumcap Bucket", + "§7- §bWater" + )); + layout.slot(12, ItemStackCreator.getStackHead( + "§7[Lvl 20] Water Worm (§9§lRare§7)", + "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + 1, + "§9⚓ Aquatic§7, §6⛏ Subterranean", + "", + "§cDrops:", + "§7- Hard Stone", + "§7- ⸕ Rough Amber Gemstone", + "§7- §aWorm Membrane", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §bWater", + "§7- §6Goblin Holdout" + )); + layout.slot(13, ItemStackCreator.getStackHead( + "§7[Lvl 25] Bayou Sludge (§5§lEpic§7)", + "895aeec6b842ada8669f846d65bc49762597824ab944f22f45bf3bbb941abe6c", + 1, + "§9⚓ Aquatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- Clay Ball", + "§7- Enchanted Book", + "§7 (Respite I)", + "§7- Lily Pad", + "§7- Slimeball", + "§7- §9Enchanted Book", + "§7 (Blessing VI)", + "§7- §aEnchanted Slimeball", + "§7- §aPoison Sample", + "§7- §9Enchanted Slime Block", + "", + "§cRequirements:", + "§7- §aFishing Skill 15", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b23" + )); + layout.slot(14, ItemStackCreator.getStackHead( + "§7[Lvl 30] Sea Leech (§9§lRare§7)", + "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Spiked Hook VI)", + "§7- §9Fishing Exp Boost", + "§7- §5Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 16", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b15" + )); + layout.slot(15, ItemStackCreator.getStackHead( + "§7[Lvl 75] Fireproof Witch (§9§lRare§7)", + "fce6604157fc4ab5591e4bcf507a749918ee9c41e357d47376e0ee7342074c90", + 1, + "§c♆ Magmatic§7, §e✰ Humanoid§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §9Enchanted Book", + "§7 (Fire Protection VI)", + "§7- §aEnchanted Glowstone", + "§7- §aEnchanted Glowstone Dust", + "§7- §aSinged Powder", + "§7- §9Magmafish", + "", + "§cRequirements:", + "§7- §aFishing Skill 16", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle" + )); + layout.slot(16, ItemStackCreator.getStackHead( + "§7[Lvl 21] Stridersurfer (§9§lRare§7)", + "620971f4dd71592a6065944487da2adf22987d5d0cccf6085dff7a6767d1b21a", + 1, + "§c♆ Magmatic§7, §2༕ Undead§7, §2⸙ Woodland", + "", + "§cDrops:", + "§7- §aGill Membrane", + "§7- §9Sturdy Bone", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §cLava", + "§7- §2Galatea", + "", + "§cStats", + "§7- Kills: §b8" + )); + layout.slot(19, ItemStackCreator.getStackHead( + "§7[Lvl 25] Poisoned Water Worm (§9§lRare§7)", + "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + 1, + "§9⚓ Aquatic§7, §6⛏ Subterranean§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- Hard Stone", + "§7- ⸕ Rough Amber Gemstone", + "§7- §aWorm Membrane", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "§7- §6Goblin Holdout" + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§7[Lvl 45] Guardian Defender (§5§lEpic§7)", + "221025434045bda7025b3e514b316a4b770c6faa4ba9adb4be3809526db77f9d", + 1, + "§9⚓ Aquatic§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Raw Cod", + "§7- Sponge", + "§7- §9Enchanted Book", + "§7 (Lure VI)", + "§7- §aEnchanted Prismarine Crystals", + "§7- §aEnchanted Prismarine Shard", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b12" + )); + layout.slot(21, ItemStackCreator.getStackHead( + "§7[Lvl 50] Werewolf (§5§lEpic§7)", + "ce4606c6d973a999aec1687c7e075f7d37db8185e88b844507f16b3e2b3eb690", + 1, + "§9⚓ Aquatic§7, §6☽ Spooky§7, §a☮ Animal", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- §aGreen Candy", + "§7- §9Werewolf Skin", + "§7- §5Deep Sea Orb", + "§7- §5Purple Candy", + "", + "§cRequirements:", + "§7- §aFishing Skill 17", + "§7- §bWater", + "§7- §6Spooky Festival" + )); + layout.slot(22, ItemStackCreator.getStackHead( + "§7[Lvl 50] Tiger Shark (§5§lEpic§7)", + "ea575977e6bd0c7add94e2d8fdcc2af77e36c44d6b4c67788862a94000be6399", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §aCarnival Ticket", + "§7- §9Shark Fin", + "§7- §5Megalodon Pet", + "§7- §5Tiger Shark Tooth", + "", + "§cRequirements:", + "§7- §aFishing Skill 18", + "§7- §bWater", + "§7- §bFishing Festival" + )); + layout.slot(23, ItemStackCreator.getStackHead( + "§7[Lvl 60] Deep Sea Protector (§5§lEpic§7)", + "22bcaceeb4162f400d44743315932ac820d3119ac8986a0161a726161ccc93fc", + 1, + "§9⚓ Aquatic§7, ⚙ Construct", + "", + "§cDrops:", + "§7- Lily Pad", + "§7- Sponge", + "§7- Tropical Fish", + "§7- §9Enchanted Book", + "§7 (Angler VI)", + "§7- §aEnchanted Iron Ingot", + "§7- §5Fishing Exp Boost", + "", + "§cRequirements:", + "§7- §aFishing Skill 18", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b7" + )); + layout.slot(24, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "811a1173af3bead305e6339f555662e990d5faadb87e07299fa68ca828a6d2fb", + 1, + "§c♆ Magmatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 19", + "§7- §cLava", + "§7- §bPrecursor Remnants" + )); + layout.slot(25, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "6d6bcd3bea0dff1f45d808e7a8550f95106af41b6d8d18a0793e19c9255ae845", + 1, + "§9⚓ Aquatic§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 19", + "§7- §bWater", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(28, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§5§lEpic§7)", + "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0", + 1, + "§c♆ Magmatic§7, §4♨ Infernal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §cLava", + "§7- §cMagma Fields" + )); + layout.slot(29, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "5cf6abfbc778b1fac0d6db161e74438a1b468323b6f93fa4d650e42cd0f5802a", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §bWater", + "§7- §2Backwater Bayou", + "", + "§cStats", + "§7- Kills: §b6" + )); + layout.slot(30, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "46c15b527e4872249c91797435521cb77651b567e57518304f5f131e49ded652", + 1, + "§9⚓ Aquatic§7, §f🦴 Skeletal§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 20", + "§7- §bWater", + "§7- §2Galatea" + )); + layout.slot(31, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "6c9bc01f299f98d565a27ba10a1293915ae8beeefb8a67845e2331dbe6fd6fd6", + 1, + "§9⚓ Aquatic§7, §6☽ Spooky§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 21", + "§7- §bWater", + "§7- §6Spooky Festival" + )); + layout.slot(32, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§5§lEpic§7)", + "74e9c6e98582ffd8ff8feb3322cd1849c43fb16b158abb11ca7b42eda7743eb", + 1, + "§c♆ Magmatic§7, §2༕ Undead", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 22", + "§7- §cLava", + "§7- §cMagma Fields" + )); + layout.slot(33, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "58be05cfae2c6a7d47da2ce88b3e00c72a145cc3218f041b3dd5bd5fa5ca827", + 1, + "§9⚓ Aquatic§7, §2༕ Undead§7, §6⛏ Subterranean", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 24", + "§7- §bWater", + "§7- §2Mithril Deposits", + "§7- §bPrecursor Remnants", + "§7- §2Jungle" + )); + layout.slot(34, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "de2e5865429dd2520bbc703e4a9f2f1abd5e1cc5d31b8a9acbf74b7a97c937aa", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 24", + "§7- §bWater", + "§7- §bFishing Festival" + )); + layout.slot(37, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "4dd2d3c6d01c276226c7b0d377122e1a647b2ffb5b9b54fa98eac37bb1d09d3a", + 1, + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 25", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(38, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "68a6194a5b217b9f5a3dfecce5f3efe6967405039b82fa0c4e8959175f32e75a", + 1, + "§9⚓ Aquatic§7, §6☽ Spooky§7, §5♃ Arcane", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 26", + "§7- §bWater", + "§7- §6Spooky Festival" + )); + layout.slot(39, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§a§lUncommon§7)", + "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429", + 1, + "§c♆ Magmatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 27", + "§7- §cLava", + "§7- §cCrimson Isle", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(40, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§a§lUncommon§7)", + "47f1bc3fa91cd86cf4ba7745586d67207b58e7cf27bdf7a717780843785bf9b5", + 1, + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 28", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(41, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "c2407e66c81b1443c2e7dfc4d6583eb19c622fa22f34fbf99fe6c45f76a", + 1, + "§9⚓ Aquatic§7, §f☃ Frozen§7, §e✰ Humanoid", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 28", + "§7- §bWater", + "§7- §cJerry's Workshop", + "", + "§cStats", + "§7- Kills: §b2" + )); + layout.slot(42, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "18ae7046da98dcb33f3ed42f1dc41d08ac8dfa5db3a3860de5b1b5c056804187", + 1, + "§c♆ Magmatic§7, §4Ж Arthropod", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 30", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(43, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "645f2c0bbfe3b8b19b7452072db69a5f59da38ff61415545156e5701e1be756d", + 1, + "§9⚓ Aquatic§7, §a☮ Animal§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 30", + "§7- §bWater", + "§7- §2Backwater Bayou" + )); + layout.slot(45, ItemStackCreator.getStack( + "§aPrevious Page", + Material.ARROW, + 1, + "§ePage 1" + )); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Skill" + )); + layout.slot(50, ItemStackCreator.getStack( + "§aSort", + Material.HOPPER, + 1, + "", + "§b▶ Fishing Level Req", + "§7 Alphabetical", + "§7 Mob Level", + "§7 Killed Most", + "§7 Ascending Rarity", + "§7 Descending Rarity", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(51, ItemStackCreator.getStack( + "§aFilter", + Material.ENDER_EYE, + 1, + "", + "§f▶ All Sea Creatures", + "§7 Has Level Requirement", + "§7 Has Never Killed", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(52, ItemStackCreator.getStack( + "§aCategory", + Material.CAULDRON, + 1, + "", + "§a▶ Any Category", + "§7 Water", + "§7 Lava", + "§7 Winter", + "§7 Spooky", + "§7 Shark", + "§7 Oasis", + "§7 Bayou", + "§7 Hotspot", + "§7 Galatea", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(53, ItemStackCreator.getStack( + "§aNext Page", + Material.ARROW, + 1, + "§ePage 3" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java new file mode 100644 index 000000000..8d484e0c1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java @@ -0,0 +1,272 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +// make these actually paginated views +public class GUI33SeaCreatureGuide extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("(3/3) Sea Creature Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§aSea Creature Guide", + Material.BOOK, + 1, + "§7Your guide to the creatures of the", + "§7deep! Can also be accessed with", + "§a/scg§7!", + "", + "§7Beware, Sea Creatures spawn much", + "§7less often on your private island.", + "", + "§7Your Fishing: §aLevel XVIII" + )); + layout.slot(10, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429", + 1, + "§c♆ Magmatic§7, §a⚂ Cubic", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 31", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(11, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "b78ef2e4cf2c41a2d14bfde9caff10219f5b1bf5b35a49eb51c6467882cb5f0", + 1, + "§c♆ Magmatic§7, §4♨ Infernal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 33", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(12, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§9§lRare§7)", + "c63704a7fc7d437f7b923e23e9a08ae3bbe28937df4dafa9e3e8725b2ce4afa5", + 1, + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 34", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(13, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§5§lEpic§7)", + "1642a06cd75ef307c1913ba7a224fb2082d8a2c5254fd1bf006125a087a9a868", + 1, + "§c♆ Magmatic§7, §e✰ Humanoid§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(14, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "b2b6074d0c9d6b89a494cf4f74158282a64ee23ba8a0725633ad70932ada1a8f", + 1, + "§9⚓ Aquatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §bWater", + "§7- §dFishing Hotspot", + "", + "§cStats", + "§7- Kills: §b1" + )); + layout.slot(15, ItemStackCreator.getStack( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + Material.DRAGON_EGG, + 1, + "§f☃ Frozen§7, §e⛨ Shielded§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 35", + "§7- §bWater", + "§7- §cJerry's Workshop" + )); + layout.slot(16, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "32581d564f01d712255125e1f101e534217f76e3599dab7f4ae0ffe328f729eb", + 1, + "§c♆ Magmatic§7, §d❃ Elusive§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 36", + "§7- §cLava", + "§7- §cCrimson Isle" + )); + layout.slot(19, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "a3f925d274ec65e002028c898e11aa9b76d6d67aa305ad9c7c69fe61cec5e664", + 1, + "§c♆ Magmatic§7, §5♃ Arcane§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 36", + "§7- §cLava", + "§7- §cCrimson Isle", + "§7- §cNovice Trophy Fisher" + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§6§lLegendary§7)", + "55b194025806687642e2bc239895d646a6d8c193d9253b61bfce908f6ce1b84a", + 1, + "§c♆ Magmatic§7, §a☮ Animal", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 37", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle" + )); + layout.slot(21, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "f3c802e580bfefc18c4af94cceb82968b5b4aeab0d832346a633a7473a41dfac", + 1, + "§9⚓ Aquatic§7, ⚙ Construct, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 40", + "§7- §bWater", + "§7- §dFishing Hotspot" + )); + layout.slot(22, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "22bcaceeb4162f400d44743315932ac820d3119ac8986a0161a726161ccc93fc", + 1, + "§c♆ Magmatic§7, ⚙ Construct, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 45", + "§7- §cLava", + "§7- §cCrimson Isle", + "§7- §cAdept Trophy Fisher" + )); + layout.slot(23, ItemStackCreator.getStackHead( + "§7[Lvl §k?] §k????? (§d§lMythic§7)", + "a8e1fe214b71f6ea69c541a861c64bafda7bf9b85de5dd17ab2b6ccd1d32b039", + 1, + "§c♆ Magmatic§7, §f🦴 Skeletal§7, §d❃ Elusive", + "", + "§cDrops:", + "§7- §k???????", + "", + "§cRequirements:", + "§7- §aFishing Skill 47", + "§7- §cLava", + "§7- §dFishing Hotspot", + "§7- §cCrimson Isle" + )); + layout.slot(45, ItemStackCreator.getStack( + "§aPrevious Page", + Material.ARROW, + 1, + "§ePage 2" + )); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Skill" + )); + layout.slot(50, ItemStackCreator.getStack( + "§aSort", + Material.HOPPER, + 1, + "", + "§b▶ Fishing Level Req", + "§7 Alphabetical", + "§7 Mob Level", + "§7 Killed Most", + "§7 Ascending Rarity", + "§7 Descending Rarity", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(51, ItemStackCreator.getStack( + "§aFilter", + Material.ENDER_EYE, + 1, + "", + "§f▶ All Sea Creatures", + "§7 Has Level Requirement", + "§7 Has Never Killed", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + layout.slot(52, ItemStackCreator.getStack( + "§aCategory", + Material.CAULDRON, + 1, + "", + "§a▶ Any Category", + "§7 Water", + "§7 Lava", + "§7 Winter", + "§7 Spooky", + "§7 Shark", + "§7 Oasis", + "§7 Bayou", + "§7 Hotspot", + "§7 Galatea", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java new file mode 100644 index 000000000..7b14e8009 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java @@ -0,0 +1,42 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; + +public class GUIBaitGuide extends StatelessView { + private static final int[] BAIT_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Bait Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§6Bait Guide", + Material.BOOK, + 1, + "§7View §6Baits§7 and the effects they add", + "§7to your fishing catches." + )); + + int index = 0; + for (var bait : FishingItemSupport.getBaits()) { + if (index >= BAIT_SLOTS.length) { + break; + } + layout.slot(BAIT_SLOTS[index++], FishingGuideStackFactory.buildBaitStack(bait)); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java new file mode 100644 index 000000000..6a8f4b2ed --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java @@ -0,0 +1,101 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.ViewSession; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUIFishingRodParts extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Fishing Rod Parts", InventoryType.CHEST_6_ROW); + } + + @Override + public void onClose(DefaultState state, ViewContext ctx, ViewSession.CloseReason reason) { + ItemStack rodItem = ctx.inventory().getItemStack(21); + if (!rodItem.isAir()) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + player.addAndUpdateItem(new SkyBlockItem(rodItem)); + ctx.inventory().setItemStack(21, ItemStack.AIR); + } + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.editable(21, (_, _) -> ItemStackCreator.createNamedItemStack( + Material.FISHING_ROD, + "§7Place your §aFishing Rod §7here!" + ), (_, oldItem, newItem, _) -> { + if (newItem.isAir()) { + return; + } + SkyBlockItem rod = new SkyBlockItem(newItem); + ItemType type = rod.getAttributeHandler().getPotentialType(); + var metadata = type == null ? null : FishingItemSupport.getRodMetadata(type.name()); + if (metadata == null || !metadata.isRodPartsEnabled() || metadata.getLegacyConversionTarget() != null) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + player.sendMessage("§cThat fishing rod does not support rod parts."); + ctx.inventory().setItemStack(21, oldItem); + if (!newItem.isAir()) { + player.addAndUpdateItem(new SkyBlockItem(newItem)); + } + } + }); + + layout.slot(22, ItemStackCreator.getStack( + "§9ථ Hook", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Hook§7!", + "", + "§eClick to browse Hooks!" + ), (_, viewCtx) -> viewCtx.push(new GUIHookGuide())); + + layout.slot(23, ItemStackCreator.getStack( + "§9ꨃ Line", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Line§7!", + "", + "§eClick to browse Lines!" + ), (_, viewCtx) -> viewCtx.push(new GUILineGuide())); + + layout.slot(24, ItemStackCreator.getStack( + "§9࿉ Sinker", + Material.LIGHT_BLUE_STAINED_GLASS_PANE, + 1, + "§7Place a §aFishing Rod §7in the slot to the", + "§7left to view and modify its §9Sinker§7!", + "", + "§eClick to browse Sinkers!" + ), (_, viewCtx) -> viewCtx.push(new GUISinkerGuide())); + + layout.slot(50, ItemStackCreator.getStack( + "§9Rod Part Guide", + Material.BOOK, + 1, + "§7View all of the §9Rod Parts §7that can be", + "§7applied to §aFishing Rods§7! Can also be", + "§7accessed with §a/rodparts§7!", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUIRodPartGuide())); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java new file mode 100644 index 000000000..0307a956b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java @@ -0,0 +1,155 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.inventory.item.GUIItem; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingShipService; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUIFishingShip extends HypixelInventoryGUI { + + public GUIFishingShip() { + super("{Fishing Ship}", InventoryType.CHEST_5_ROW); + } + + @Override + public void onOpen(InventoryGUIOpenEvent e) { + fill(FILLER_ITEM); + set(new GUIItem(4) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + var state = FishingShipService.getState(skyBlockPlayer); + return ItemStackCreator.getStack( + "§6{Fishing Ship}", + Material.OAK_BOAT, + 1, + "§7Your §6Ship §7will help you travel to", + "§7different §9fishing islands §7in SkyBlock.", + "", + "§7For now, it can only get you to the", + "§2Backwater Bayou§7.", + "", + "§7Helm: §f" + resolvePartName(state.getHelm(), "Cracked Ship Helm"), + "§7Engine: §f" + resolvePartName(state.getEngine(), "Missing Engine"), + "§7Hull: §f" + resolvePartName(state.getHull(), "Rusty Ship Hull") + ); + } + }); + set(new GUIItem(21) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getHelm(), + "Cracked Ship Helm", + "d8d4a54d1fcf47b2efc99ba4cc772250aee5c2f26ed1a19052213e0f3323ca1d", + "§7A cracked ship helm, incapable of", + "§7changing its heading which appears", + "§7due east." + ); + } + }); + set(new GUIItem(22) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getEngine(), + "Missing Engine", + "53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c", + "§7This ship still needs an engine before", + "§7it can get you anywhere." + ); + } + }); + set(new GUIItem(23) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return buildShipPartStack( + FishingShipService.getState(skyBlockPlayer).getHull(), + "Rusty Ship Hull", + "f42d53ca6e7d80a99a699c2036dcf6e233394feb9f46fb2ff9d9a819690894a9", + "§7A hull rusted and dilapidated beyond", + "§7repair. It's a miracle the ship", + "§7remains afloat." + ); + } + }); + set(new GUIClickableItem(31) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + boolean unlocked = FishingShipService.getState(skyBlockPlayer).hasDestination("BACKWATER_BAYOU"); + return ItemStackCreator.getStack( + unlocked ? "§aOpen Navigator" : "§cNavigator Locked", + Material.COMPASS, + 1, + "§7Choose where to set sail next.", + "", + unlocked ? "§eClick to browse destinations!" : "§cInstall an engine first." + ); + } + + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + if (!FishingShipService.getState(skyBlockPlayer).hasDestination("BACKWATER_BAYOU")) { + player.sendMessage("§cYour ship cannot travel anywhere yet."); + return; + } + skyBlockPlayer.openView(new GUINavigator()); + } + }); + set(new GUIItem(44) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + return ItemStackCreator.getStack( + "§aRename Ship", + Material.NAME_TAG, + 1, + "§7You may be going on long voyages", + "§7with your §6Ship§7, best to give it a name!", + "", + "§7Current Name: §6" + FishingShipService.getState(skyBlockPlayer).getShipName(), + "", + "§7Renaming is not implemented yet." + ); + } + }); + set(GUIClickableItem.getCloseItem(40)); + updateItemStacks(getInventory(), getPlayer()); + } + + @Override + public boolean allowHotkeying() { + return false; + } + + @Override + public void onBottomClick(InventoryPreClickEvent e) { + e.setCancelled(true); + } + + private static String resolvePartName(String itemId, String fallback) { + var definition = FishingItemSupport.getShipPart(itemId); + return definition == null ? fallback : definition.getDisplayName(); + } + + private static ItemStack.Builder buildShipPartStack(String itemId, String fallbackName, String fallbackTexture, String... fallbackLore) { + var definition = FishingItemSupport.getShipPart(itemId); + String name = definition == null ? fallbackName : definition.getDisplayName(); + String texture = definition == null || definition.getTexture() == null ? fallbackTexture : definition.getTexture(); + String[] lore = fallbackLore; + return ItemStackCreator.getStackHead("§f" + name, texture, 1, lore); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingSkillExampleRemoveThis.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingSkillExampleRemoveThis.java new file mode 100644 index 000000000..b0e02bcdf --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingSkillExampleRemoveThis.java @@ -0,0 +1,450 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +public class GUIFishingSkillExampleRemoveThis extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Fishing Skill", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(0, ItemStackCreator.getStack( + "§aFishing Skill", + Material.FISHING_ROD, + 1, + "§7Visit your local pond to fish and", + "§7earn Fishing XP!", + "", + "§7Progress to Level XIX: §e33.1%", + "§2§l§m §f§l§m §e33,082§6/§e100k", + "", + "§eTreasure Hunter XVIII", + " §fGrants §a+1.8§f §6⛃ Treasure Chance§f.", + "", + "§8Increase your Fishing Level to", + "§8unlock Perks, statistic bonuses, and", + "§8more!" + )); + layout.slot(2, ItemStackCreator.getStack( + "§aFishing Level VIII", + Material.LIME_STAINED_GLASS_PANE, + 8, + "§7Rewards:", + " §eTreasure Hunter VIII", + " §fGrants §a+§80.7➜§a0.8§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§64,000 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(3, ItemStackCreator.getStack( + "§aFishing Level IX", + Material.LIME_STAINED_GLASS_PANE, + 9, + "§7Rewards:", + " §fScarecrow§3 Sea Creature", + " §9Tadgang§3 Sea Creature", + " §aSea Archer§3 Sea Creature", + " §eTreasure Hunter IX", + " §fGrants §a+§80.8➜§a0.9§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§65,000 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(4, ItemStackCreator.getStack( + "§aFishing Level X", + Material.PRISMARINE, + 10, + "§7Rewards:", + " §9Banshee§3 Sea Creature", + " §aOasis Sheep§3 Sea Creature", + " §9Blue Shark§3 Sea Creature", + " §9Snapping Turtle§3 Sea Creature", + " §aOasis Rabbit§3 Sea Creature", + " §eTreasure Hunter X", + " §fGrants §a+§80.9➜§a1§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§67,500 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(6, ItemStackCreator.getStack( + "§aFishing Level XVIII", + Material.LIME_STAINED_GLASS_PANE, + 18, + "§7Rewards:", + " §5Tiger Shark§3 Sea Creature", + " §5Deep Sea Protector§3 Sea Creature", + " §eTreasure Hunter XVIII", + " §fGrants §a+§81.7➜§a1.8§f §6⛃ Treasure Chance§f.", + " §8+§a3 §c❤ Health", + " §8+§665,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(7, ItemStackCreator.getStack( + "§eFishing Level XIX", + Material.YELLOW_STAINED_GLASS_PANE, + 19, + "§7Rewards:", + " §6???§3 Sea Creature", + " §9???§3 Sea Creature", + " §eTreasure Hunter XIX", + " §fGrants §a+§81.8➜§a1.9§f §6⛃ Treasure Chance§f.", + " §8+§a3 §c❤ Health", + " §8+§680,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§7Progress: §e33.1%", + "§2§l§m §f§l§m §e33,082§6/§e100k" + )); + layout.slot(8, ItemStackCreator.getStack( + "§cFishing Level XX", + Material.RED_STAINED_GLASS_PANE, + 20, + "§7Rewards:", + " §6???§3 Sea Creature", + " §5???§3 Sea Creature", + " §6???§3 Sea Creature", + " §eTreasure Hunter XX", + " §fGrants §a+§81.9➜§a2§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6100,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + layout.slot(9, ItemStackCreator.getStack( + "§aFishing Level I", + Material.LIME_STAINED_GLASS_PANE, + 1, + "§7Rewards:", + " §fSquid§3 Sea Creature", + " §fSea Walker§3 Sea Creature", + " §eTreasure Hunter I", + " §fGrants §a+0.1§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§6100 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(11, ItemStackCreator.getStack( + "§aFishing Level VII", + Material.LIME_STAINED_GLASS_PANE, + 7, + "§7Rewards:", + " §aWetwing§3 Sea Creature", + " §aSea Witch§3 Sea Creature", + " §eTreasure Hunter VII", + " §fGrants §a+§80.6➜§a0.7§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§63,000 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(13, ItemStackCreator.getStack( + "§aFishing Level XI", + Material.LIME_STAINED_GLASS_PANE, + 11, + "§7Rewards:", + " §aRider of the Deep§3 Sea Creature", + " §eTreasure Hunter XI", + " §fGrants §a+§81➜§a1.1§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§610,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(15, ItemStackCreator.getStack( + "§aFishing Level XVII", + Material.LIME_STAINED_GLASS_PANE, + 17, + "§7Rewards:", + " §5Guardian Defender§3 Sea Creature", + " §5Werewolf§3 Sea Creature", + " §9Stridersurfer§3 Sea Creature", + " §9Poisoned Water Worm§3 Sea Creature", + " §eTreasure Hunter XVII", + " §fGrants §a+§81.6➜§a1.7§f §6⛃ Treasure Chance§f.", + " §8+§a3 §c❤ Health", + " §8+§650,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(17, ItemStackCreator.getStack( + "§cFishing Level XXI", + Material.RED_STAINED_GLASS_PANE, + 21, + "§7Rewards:", + " §6???§3 Sea Creature", + " §eTreasure Hunter XXI", + " §fGrants §a+§82➜§a2.1§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6125,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + layout.slot(18, ItemStackCreator.getStack( + "§aFishing Level II", + Material.LIME_STAINED_GLASS_PANE, + 2, + "§7Rewards:", + " §eTreasure Hunter II", + " §fGrants §a+§80.1➜§a0.2§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§6250 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(20, ItemStackCreator.getStack( + "§aFishing Level VI", + Material.LIME_STAINED_GLASS_PANE, + 6, + "§7Rewards:", + " §aMedium Mithril Grubber§3 Sea Creature", + " §aMithril Grubber§3 Sea Creature", + " §aBloated Mithril Grubber§3 Sea Creature", + " §aLarge Mithril Grubber§3 Sea Creature", + " §fFrosty§3 Sea Creature", + " §eTreasure Hunter VI", + " §fGrants §a+§80.5➜§a0.6§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§62,000 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(22, ItemStackCreator.getStack( + "§aFishing Level XII", + Material.LIME_STAINED_GLASS_PANE, + 12, + "§7Rewards:", + " §5Ent§3 Sea Creature", + " §eTreasure Hunter XII", + " §fGrants §a+§81.1➜§a1.2§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§615,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(24, ItemStackCreator.getStack( + "§aFishing Level XVI", + Material.LIME_STAINED_GLASS_PANE, + 16, + "§7Rewards:", + " §9Sea Leech§3 Sea Creature", + " §9Fireproof Witch§3 Sea Creature", + " §eTreasure Hunter XVI", + " §fGrants §a+§81.5➜§a1.6§f §6⛃ Treasure Chance§f.", + " §8+§a3 §c❤ Health", + " §8+§640,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(26, ItemStackCreator.getStack( + "§cFishing Level XXII", + Material.RED_STAINED_GLASS_PANE, + 22, + "§7Rewards:", + " §5???§3 Sea Creature", + " §eTreasure Hunter XXII", + " §fGrants §a+§82.1➜§a2.2§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6150,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + layout.slot(27, ItemStackCreator.getStack( + "§aFishing Level III", + Material.LIME_STAINED_GLASS_PANE, + 3, + "§7Rewards:", + " §fNight Squid§3 Sea Creature", + " §eTreasure Hunter III", + " §fGrants §a+§80.2➜§a0.3§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§6500 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(28, ItemStackCreator.getStack( + "§aFishing Level IV", + Material.LIME_STAINED_GLASS_PANE, + 4, + "§7Rewards:", + " §eTreasure Hunter IV", + " §fGrants §a+§80.3➜§a0.4§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§6750 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(29, ItemStackCreator.getStack( + "§aFishing Level V", + Material.PRISMARINE, + 5, + "§7Rewards:", + " §fSea Guardian§3 Sea Creature", + " §aDumpster Diver§3 Sea Creature", + " §fFrog Man§3 Sea Creature", + " §fTrash Gobbler§3 Sea Creature", + " §fBogged§3 Sea Creature", + " §aNurse Shark§3 Sea Creature", + " §fFrozen Steve§3 Sea Creature", + " §eTreasure Hunter V", + " §fGrants §a+§80.4➜§a0.5§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§61,000 §7Coins", + " §8+§b5 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(31, ItemStackCreator.getStack( + "§aFishing Level XIII", + Material.LIME_STAINED_GLASS_PANE, + 13, + "§7Rewards:", + " §9Catfish§3 Sea Creature", + " §aGrinch§3 Sea Creature", + " §eTreasure Hunter XIII", + " §fGrants §a+§81.2➜§a1.3§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§620,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(32, ItemStackCreator.getStack( + "§aFishing Level XIV", + Material.LIME_STAINED_GLASS_PANE, + 14, + "§7Rewards:", + " §fFried Chicken§3 Sea Creature", + " §9Carrot King§3 Sea Creature", + " §9Nightmare§3 Sea Creature", + " §eTreasure Hunter XIV", + " §fGrants §a+§81.3➜§a1.4§f §6⛃ Treasure Chance§f.", + " §8+§a2 §c❤ Health", + " §8+§625,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(33, ItemStackCreator.getStack( + "§aFishing Level XV", + Material.PRISMARINE, + 15, + "§7Rewards:", + " §9Agarimoo§3 Sea Creature", + " §9Water Worm§3 Sea Creature", + " §5Bayou Sludge§3 Sea Creature", + " §eTreasure Hunter XV", + " §fGrants §a+§81.4➜§a1.5§f §6⛃ Treasure Chance§f.", + " §8+§a3 §c❤ Health", + " §8+§630,000 §7Coins", + " §8+§b10 SkyBlock XP", + "", + "§a§lUNLOCKED" + )); + layout.slot(35, ItemStackCreator.getStack( + "§cFishing Level XXIII", + Material.RED_STAINED_GLASS_PANE, + 23, + "§7Rewards:", + " §eTreasure Hunter XXIII", + " §fGrants §a+§82.2➜§a2.3§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6175,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + layout.slot(39, ItemStackCreator.getStack( + "§6Bait Guide", + Material.BOOK, + 1, + "§7View §6Baits§7, their uses, and how to", + "§7obtain them! Can also be accessed", + "§7with §a/bait§7!", + "", + "§eClick to view!" + )); + layout.slot(40, ItemStackCreator.getStack( + "§aSea Creature Guide", + Material.BOOK, + 1, + "§7Your guide to the creatures of the", + "§7deep! Can also be accessed with", + "§a/scg§7!", + "", + "§7Beware, Sea Creatures spawn much", + "§7less often on your private island.", + "", + "§7Your Fishing: §aLevel XVIII", + "", + "§eClick to view!" + )); + layout.slot(41, ItemStackCreator.getStack( + "§9Rod Part Guide", + Material.BOOK, + 1, + "§7View all of the §9Rod Parts §7that can be", + "§7applied to §aFishing Rods§7! Can also be", + "§7accessed with §a/rodparts§7!", + "", + "§eClick to view!" + )); + layout.slot(44, ItemStackCreator.getStack( + "§cFishing Level XXIV", + Material.RED_STAINED_GLASS_PANE, + 24, + "§7Rewards:", + " §6???§3 Sea Creature", + " §6???§3 Sea Creature", + " §eTreasure Hunter XXIV", + " §fGrants §a+§82.3➜§a2.4§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6200,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Your Skills" + )); + layout.slot(53, ItemStackCreator.getStack( + "§cFishing Level XXV", + Material.RED_STAINED_GLASS_PANE, + 25, + "§7Rewards:", + " §6???§3 Sea Creature", + " §eTreasure Hunter XXV", + " §fGrants §a+§82.4➜§a2.5§f §6⛃ Treasure Chance§f.", + " §8+§a4 §c❤ Health", + " §8+§6225,000 §7Coins", + " §8+§b10 SkyBlock XP" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java new file mode 100644 index 000000000..3fa81e827 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingPartCategory; + +public class GUIHookGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Hook", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9ථ Hooks", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§9Hooks §7change what your rod is better at catching." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.HOOK || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java new file mode 100644 index 000000000..6d53c13d8 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingPartCategory; + +public class GUILineGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Line", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9ꨃ Lines", + "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", + 1, + "§9Lines §7grant stat bonuses to your rod everywhere." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.LINE || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java new file mode 100644 index 000000000..f47c10a82 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java @@ -0,0 +1,89 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.commons.ServerType; +import net.swofty.type.generic.HypixelConst; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.Layouts; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +public class GUINavigator extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Navigator", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + ServerType currentServer = HypixelConst.getTypeLoader().getType(); + boolean inBayou = currentServer == ServerType.SKYBLOCK_BACKWATER_BAYOU; + boolean unlocked = inBayou || player.getShipState().hasDestination("BACKWATER_BAYOU"); + + layout.slots(Layouts.row(0), (_, _) -> Components.FILLER); + layout.slots(Layouts.row(5), (_, _) -> Components.FILLER); + layout.slots(Layouts.rectangle(9, 45), (_, _) -> Components.FILLER.material(Material.BLUE_STAINED_GLASS_PANE)); + Components.close(layout, 49); + + if (inBayou) { + layout.slot(10, ItemStackCreator.getStackHead( + "§bFishing Outpost", + "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", + 1, + "§7Your base of operations.", + "", + "§eClick to travel!" + ), (_, viewCtx) -> ((SkyBlockPlayer) viewCtx.player()).sendTo(ServerType.SKYBLOCK_HUB)); + layout.slot(40, ItemStackCreator.getStackHead( + "§2Backwater Bayou", + "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", + 1, + "§7A small, marshy outlet in the middle", + "§7of nowhere. Due to its isolated", + "§7nature, people frequently come here", + "§7to dump their trash.", + "", + "§a§lYOU ARE HERE!" + )); + return; + } + + layout.slot(10, ItemStackCreator.getStackHead( + "§2Backwater Bayou", + "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", + 1, + "§7A small, marshy outlet in the middle", + "§7of nowhere. Due to its isolated", + "§7nature, people frequently come here", + "§7to dump their trash.", + "", + "§7Activities:", + "§8 ■ §7Fish up §2Junk §7and trade it with §2Junker", + " §2Joel §7for useful items!", + "§8 ■ §7Apply §9Rod Parts §7with §2Roddy§7.", + "§8 ■ §7Fish §2Bayou Sea Creatures§7.", + "§8 ■ §7Learn about §dFishing Hotspots §7from", + " §dHattie§7.", + "", + unlocked ? "§eClick to travel!" : "§cDestination Locked" + ), unlocked + ? (_, viewCtx) -> ((SkyBlockPlayer) viewCtx.player()).sendTo(ServerType.SKYBLOCK_BACKWATER_BAYOU) + : (_, viewCtx) -> viewCtx.player().sendMessage("§cYou have not unlocked this destination yet.")); + layout.slot(40, ItemStackCreator.getStackHead( + "§bFishing Outpost", + "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", + 1, + "§7Your base of operations.", + "", + "§a§lYOU ARE HERE!" + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java new file mode 100644 index 000000000..9dbeca20b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java @@ -0,0 +1,64 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +public class GUIRodPartGuide extends StatelessView { + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Rod Part Guide", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + + layout.slot(4, ItemStackCreator.getStack( + "§9Rod Part Guide", + Material.BOOK, + 1, + "§7View all §9Rod Parts §7that can be applied", + "§7to your upgraded fishing rods." + )); + layout.slot(20, ItemStackCreator.getStackHead( + "§9ථ Hooks", + "9809753cbab0380c7a1c18925faf9b51e44caadd1e5748542b0f23835f4ef64e", + 1, + "§9Hooks §7make you more likely to catch", + "§7certain things.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUIHookGuide())); + layout.slot(22, ItemStackCreator.getStackHead( + "§9ꨃ Lines", + "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", + 1, + "§9Lines §7grant you stat bonuses", + "§7everywhere.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUILineGuide())); + layout.slot(24, ItemStackCreator.getStackHead( + "§9࿉ Sinkers", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§9Sinkers §7add special fishing effects", + "§7to your rod.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUISinkerGuide())); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Rod Parts" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java new file mode 100644 index 000000000..420f50b1c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java @@ -0,0 +1,47 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.fishing; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingPartCategory; + +public class GUISinkerGuide extends StatelessView { + private static final int[] PART_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Sinker", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + layout.slot(4, ItemStackCreator.getStackHead( + "§9࿉ Sinkers", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§9Sinkers §7add special fishing effects to your rod." + )); + + int index = 0; + for (var part : FishingItemSupport.getRodParts()) { + if (part.getComponent(net.swofty.type.skyblockgeneric.item.components.FishingRodPartComponent.class).getCategory() != FishingPartCategory.SINKER || index >= PART_SLOTS.length) { + continue; + } + layout.slot(PART_SLOTS[index++], FishingGuideStackFactory.buildRodPartStack(part)); + } + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Rod Part Guide" + ), (_, viewCtx) -> viewCtx.pop()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java index da84784c6..ab2cc5494 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java @@ -85,6 +85,41 @@ public void setRuneData(ItemAttributeRuneInfusedWith.RuneData data) { ((ItemAttributeRuneInfusedWith) item.getAttribute("rune_infused_with")).setValue(data); } + public @Nullable String getFishingHook() { + String value = ((ItemAttributeFishingHook) item.getAttribute("fishing_hook")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingHook(@Nullable String hookId) { + item.getAttribute("fishing_hook").setValue(hookId == null ? "none" : hookId); + } + + public @Nullable String getFishingLine() { + String value = ((ItemAttributeFishingLine) item.getAttribute("fishing_line")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingLine(@Nullable String lineId) { + item.getAttribute("fishing_line").setValue(lineId == null ? "none" : lineId); + } + + public @Nullable String getFishingSinker() { + String value = ((ItemAttributeFishingSinker) item.getAttribute("fishing_sinker")).getValue(); + return value == null || value.equalsIgnoreCase("none") ? null : value; + } + + public void setFishingSinker(@Nullable String sinkerId) { + item.getAttribute("fishing_sinker").setValue(sinkerId == null ? "none" : sinkerId); + } + + public long getFishingExpertiseKills() { + return ((ItemAttributeFishingExpertiseKills) item.getAttribute("fishing_expertise_kills")).getValue(); + } + + public void setFishingExpertiseKills(long kills) { + item.getAttribute("fishing_expertise_kills").setValue(kills); + } + public boolean isPet() { return item.hasComponent(PetComponent.class); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java index 329980e18..f1cef59c0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java @@ -11,6 +11,9 @@ import net.swofty.commons.skyblock.item.reforge.ReforgeType; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.FishingPartCategory; +import net.swofty.type.skyblockgeneric.fishing.FishingShipPartSlot; import net.swofty.type.skyblockgeneric.gems.GemRarity; import net.swofty.type.skyblockgeneric.gems.Gemstone; import net.swofty.type.skyblockgeneric.item.components.*; @@ -162,6 +165,74 @@ yield new EnchantableComponent( showLores ); } + case "FISHING_ROD" -> new FishingRodComponent(); + case "FISHING_ROD_METADATA" -> { + FishingMedium medium = safeConfig.containsKey("medium") + ? safeConfig.getEnum("medium", FishingMedium.class) + : FishingMedium.WATER; + int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); + boolean rodPartsEnabled = safeConfig.getBoolean("rod_parts_enabled", true); + String legacyConversionTarget = safeConfig.getString("legacy_conversion_target", null); + String subtitle = safeConfig.getString("subtitle", null); + List extraRequirements = safeConfig.getList("extra_requirements", String.class); + yield new FishingRodMetadataComponent( + medium, + requiredFishingLevel, + rodPartsEnabled, + legacyConversionTarget, + subtitle, + extraRequirements + ); + } + case "FISHING_ROD_PART" -> { + String displayName = safeConfig.getString("display_name"); + FishingPartCategory category = safeConfig.getEnum("category", FishingPartCategory.class); + int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); + Map tagBonuses = new java.util.LinkedHashMap<>(); + for (Map.Entry entry : safeConfig.getMap("tag_bonuses").entrySet()) { + tagBonuses.put(entry.getKey(), ((Number) entry.getValue()).doubleValue()); + } + yield new FishingRodPartComponent( + itemId, + displayName, + category, + requiredFishingLevel, + tagBonuses, + safeConfig.getBoolean("treasure_only", false), + safeConfig.getBoolean("bayou_treasure_to_junk", false), + safeConfig.getString("materialized_item_id", null), + safeConfig.getDouble("materialized_chance", 1.0), + safeConfig.getDouble("bait_preservation_chance", 0.0), + safeConfig.getDouble("hotspot_buff_multiplier", 1.0), + safeConfig.getString("texture", null) + ); + } + case "FISHING_BAIT" -> { + String displayName = safeConfig.getString("display_name"); + Map tagBonuses = new java.util.LinkedHashMap<>(); + for (Map.Entry entry : safeConfig.getMap("tag_bonuses").entrySet()) { + tagBonuses.put(entry.getKey(), ((Number) entry.getValue()).doubleValue()); + } + List mediums = safeConfig.containsKey("mediums") + ? safeConfig.getList("mediums", String.class).stream().map(value -> FishingMedium.valueOf(value.toUpperCase())).toList() + : List.of(FishingMedium.WATER, FishingMedium.LAVA); + yield new FishingBaitComponent( + itemId, + displayName, + tagBonuses, + safeConfig.getDouble("treasure_chance_bonus", 0.0), + safeConfig.getDouble("treasure_quality_bonus", 0.0), + safeConfig.getDouble("trophy_fish_chance_bonus", 0.0), + safeConfig.getDouble("double_hook_chance_bonus", 0.0), + mediums, + safeConfig.getString("texture", null) + ); + } + case "FISHING_SHIP_PART" -> { + String displayName = safeConfig.getString("display_name"); + FishingShipPartSlot slot = safeConfig.getEnum("slot", FishingShipPartSlot.class); + yield new FishingShipPartComponent(itemId, displayName, slot, safeConfig.getString("texture", null)); + } case "ENCHANTED" -> { if (safeConfig.containsKey("recipes")) { List> recipeConfigs = safeConfig.getMapList("recipes"); @@ -663,4 +734,4 @@ private static List parseGemstoneEntries(List 3 && !parts[3].isBlank()) { + getAttributeHandler().setFishingExpertiseKills(Long.parseLong(parts[3])); + } + } + + private @Nullable String readLegacyFishingPart(String[] parts, int index) { + if (index >= parts.length) { + return null; + } + String value = parts[index]; + return value == null || value.isBlank() || value.equalsIgnoreCase("none") ? null : value; + } + public ItemStack.Builder getDisplayItem() { ItemStack.Builder builder; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java new file mode 100644 index 000000000..30328eed6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java @@ -0,0 +1,54 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; + +import java.util.List; +import java.util.Map; + +@Getter +public class FishingBaitComponent extends SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final Map tagBonuses; + private final double treasureChanceBonus; + private final double treasureQualityBonus; + private final double trophyFishChanceBonus; + private final double doubleHookChanceBonus; + private final List mediums; + private final String texture; + + public FishingBaitComponent( + String itemId, + String displayName, + Map tagBonuses, + double treasureChanceBonus, + double treasureQualityBonus, + double trophyFishChanceBonus, + double doubleHookChanceBonus, + List mediums, + String texture + ) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.tagBonuses = Map.copyOf(tagBonuses); + this.treasureChanceBonus = treasureChanceBonus; + this.treasureQualityBonus = treasureQualityBonus; + this.trophyFishChanceBonus = trophyFishChanceBonus; + this.doubleHookChanceBonus = doubleHookChanceBonus; + this.mediums = List.copyOf(mediums); + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + addInheritedComponent(new ExtraUnderNameComponent(List.of("Fishing Bait", "Consumes on Cast"))); + addInheritedComponent(new ExtraRarityComponent("BAIT")); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java new file mode 100644 index 000000000..c7dba0d77 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java @@ -0,0 +1,43 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.swofty.type.skyblockgeneric.entity.FishingHook; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; +import net.swofty.type.skyblockgeneric.fishing.FishingService; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; + +public class FishingRodComponent extends SkyBlockItemComponent { + + public FishingRodComponent() { + addInheritedComponent(new InteractableComponent( + null, + (player, item) -> { + FishingHook hook = FishingHook.getFishingHookForOwner(player); + if (hook != null) { + hook.tryRetrieve(item); + hook.remove(); + FishingService.clearSession(player.getUuid()); + float pitch = 0.8f + (float) (Math.random() * 0.4f); + player.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.retrieve")) + .source(Sound.Source.NEUTRAL) + .volume(1f) + .pitch(pitch) + .build() + ); + } else { + String itemId = item.getAttributeHandler().getPotentialType() == null ? null : item.getAttributeHandler().getPotentialType().name(); + var metadata = FishingItemSupport.getRodMetadata(itemId); + if (metadata != null && metadata.getLegacyConversionTarget() != null) { + return; + } + new FishingHook(player, item).spawn(player.getInstance()); + } + }, + null + )); + } + +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java new file mode 100644 index 000000000..ccb7f8c8c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java @@ -0,0 +1,42 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.reforge.ReforgeType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@Getter +public class FishingRodMetadataComponent extends SkyBlockItemComponent { + private final FishingMedium medium; + private final int requiredFishingLevel; + private final boolean rodPartsEnabled; + private final @Nullable String legacyConversionTarget; + private final @Nullable String subtitle; + private final List extraRequirements; + + public FishingRodMetadataComponent( + FishingMedium medium, + int requiredFishingLevel, + boolean rodPartsEnabled, + @Nullable String legacyConversionTarget, + @Nullable String subtitle, + List extraRequirements + ) { + this.medium = medium; + this.requiredFishingLevel = requiredFishingLevel; + this.rodPartsEnabled = rodPartsEnabled; + this.legacyConversionTarget = legacyConversionTarget; + this.subtitle = subtitle; + this.extraRequirements = List.copyOf(extraRequirements); + addInheritedComponent(new FishingRodComponent()); + addInheritedComponent(new EnchantableComponent(List.of(EnchantItemGroups.FISHING_ROD), true)); + addInheritedComponent(new ReforgableComponent(ReforgeType.FISHING_RODS)); + addInheritedComponent(new DefaultSoulboundComponent(true)); + addInheritedComponent(new ExtraRarityComponent("FISHING ROD")); + addInheritedComponent(new LoreUpdateComponent("FISHING_ROD", true)); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java new file mode 100644 index 000000000..1cc4f105e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java @@ -0,0 +1,60 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.FishingPartCategory; + +import java.util.Map; + +@Getter +public class FishingRodPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final FishingPartCategory category; + private final int requiredFishingLevel; + private final Map tagBonuses; + private final boolean treasureOnly; + private final boolean bayouTreasureToJunk; + private final String materializedItemId; + private final double materializedChance; + private final double baitPreservationChance; + private final double hotspotBuffMultiplier; + private final String texture; + + public FishingRodPartComponent( + String itemId, + String displayName, + FishingPartCategory category, + int requiredFishingLevel, + Map tagBonuses, + boolean treasureOnly, + boolean bayouTreasureToJunk, + String materializedItemId, + double materializedChance, + double baitPreservationChance, + double hotspotBuffMultiplier, + String texture + ) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.category = category; + this.requiredFishingLevel = requiredFishingLevel; + this.tagBonuses = Map.copyOf(tagBonuses); + this.treasureOnly = treasureOnly; + this.bayouTreasureToJunk = bayouTreasureToJunk; + this.materializedItemId = materializedItemId; + this.materializedChance = materializedChance; + this.baitPreservationChance = baitPreservationChance; + this.hotspotBuffMultiplier = hotspotBuffMultiplier; + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + addInheritedComponent(new ExtraRarityComponent("ROD PART")); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java new file mode 100644 index 000000000..3ef56d3d2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java @@ -0,0 +1,28 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.skyblockgeneric.fishing.FishingShipPartSlot; + +@Getter +public class FishingShipPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String itemId; + private final String displayName; + private final FishingShipPartSlot slot; + private final String texture; + + public FishingShipPartComponent(String itemId, String displayName, FishingShipPartSlot slot, String texture) { + this.itemId = itemId; + ItemType type = ItemType.get(itemId); + this.displayName = displayName == null || displayName.isBlank() + ? (type == null ? itemId : type.getDisplayName()) + : displayName; + this.slot = slot; + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java index 432c0a787..1b4a8bcde 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/lore/LoreRegistry.java @@ -3,9 +3,15 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.PotatoType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; +import net.swofty.type.skyblockgeneric.fishing.FishingRodLoreBuilder; import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class LoreRegistry { @@ -70,6 +76,16 @@ public class LoreRegistry { "§eClick to open!" ), (item, player) -> "§aSkyBlock Menu §7(Click)")); register("HOT_POTATO_BOOK", new LoreConfig((item, player) -> PotatoType.allLores(), null)); + register("FISHING_ROD", new LoreConfig( + (item, player) -> { + var lore = FishingRodLoreBuilder.build(item, player); + return lore == null ? List.of() : lore.lore(); + }, + (item, player) -> { + var lore = FishingRodLoreBuilder.build(item, player); + return lore == null ? item.getDisplayName() : lore.displayName(); + } + )); register("MIDAS_SWORD", new LoreConfig((item, player) -> { List lore = new ArrayList<>(); long pricePaid = item.getAttributeHandler().getDarkAuctionPrice(); @@ -115,4 +131,4 @@ public static void register(String id, LoreConfig handler) { public static LoreConfig getHandler(String id) { return REGISTERED_HANDLERS.get(id); } -} \ No newline at end of file +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java index f7eb978a2..429c4e9de 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/region/RegionType.java @@ -132,6 +132,17 @@ public enum RegionType { MURKWATER_SHALLOWS("Murkwater Shallows", "§3"), NORTH_WETLANDS("North Wetlands", "§2"), + // Backwater Bayou + BACKWATER_BAYOU("Backwater Bayou", "§2"), + CRIMSON_ISLE("Crimson Isle", "§c"), + BLAZING_VOLCANO("Blazing Volcano", "§4"), + DOJO("Dojo", "§6"), + MYSTIC_MARSH("Mystic Marsh", "§2"), + SCARLETON("Scarleton", "§c"), + BURNING_DESERT("Burning Desert", "§6"), + DRAGONTAIL("Dragontail", "§4"), + STRONGHOLD("Stronghold", "§4"), + DWARVEN_VILLAGE("Dwarven Village", DwarvenMinesConfiguration.class), DWARVEN_MINES("Dwarven Mines", "§2", DwarvenMinesConfiguration.class), GOBLIN_BURROWS("Goblin Burrows", DwarvenMinesConfiguration.class), diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java index 82ce85395..16a8a0d87 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/user/SkyBlockPlayer.java @@ -19,8 +19,8 @@ import net.minestom.server.network.packet.server.play.UpdateHealthPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.tag.Tag; import net.swofty.commons.StringUtility; +import net.minestom.server.tag.Tag; import net.swofty.commons.skyblock.PlayerShopData; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; import net.swofty.commons.skyblock.item.ItemType; @@ -553,6 +553,14 @@ public DatapointQuiver.PlayerQuiver getQuiver() { return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.QUIVER, DatapointQuiver.class).getValue(); } + public DatapointShipState.ShipState getShipState() { + return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).getValue(); + } + + public DatapointTrophyFish.TrophyFishData getTrophyFishData() { + return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.TROPHY_FISH, DatapointTrophyFish.class).getValue(); + } + public DatapointAccessoryBag.PlayerAccessoryBag getAccessoryBag() { return getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ACCESSORY_BAG, DatapointAccessoryBag.class).getValue(); }