From 1f353f844fead0b9c11bce7696e612ab2b199c84 Mon Sep 17 00:00:00 2001 From: AriDev <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 20 Dec 2025 16:56:42 +0200 Subject: [PATCH 1/7] feat: partial fishing hook --- configuration/skyblock/items/vanillaItems.yml | 1 + .../skyblockgeneric/entity/FishingHook.java | 211 +++++ .../item/ItemConfigParser.java | 892 +++++++++--------- .../item/components/FishingRodComponent.java | 33 + 4 files changed, 692 insertions(+), 445 deletions(-) create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java diff --git a/configuration/skyblock/items/vanillaItems.yml b/configuration/skyblock/items/vanillaItems.yml index 5df04acb6..0da9213bc 100644 --- a/configuration/skyblock/items/vanillaItems.yml +++ b/configuration/skyblock/items/vanillaItems.yml @@ -183,6 +183,7 @@ items: material: FISHING_ROD rarity: COMMON components: + - id: FISHING_ROD - id: DEFAULT_CRAFTABLE recipes: - type: SHAPED 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..1fb323cc3 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/entity/FishingHook.java @@ -0,0 +1,211 @@ +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.Player; +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 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 final Player owner; + 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; + + public FishingHook(Player owner) { + this.owner = owner; + + 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 Player owner) { + for (FishingHook fishingHook : activeHooks) { + if (fishingHook.owner.getUuid().equals(owner.getUuid())) { + return fishingHook; + } + } + return null; + } + + private static boolean isNotWater(@NotNull Block block) { + return !block.isLiquid() || !block.name().contains("water"); + } + + 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)); + owner.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.throw")) + .source(Sound.Source.NEUTRAL) + .volume(0.5f) + .pitch((float) 1 / 3) // the pitch is 1/3-0.5 + .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; + } + + // Hook is in water + 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 + )); + } + + 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(); + // Check the block at the entity's precise location + Block currentBlock = instance.getBlock(pos); + + // Check the block slightly below the entity's location + Block blockBelow = instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0)); + + // The hook is considered "in water" if either its current block OR + // the block directly below it is water. + return isNotWater(currentBlock) && isNotWater(blockBelow); + } + + 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; + hook.remove(); + controller.remove(); + } + + 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(); + } +} \ No newline at end of file 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 73b2b7d17..1644bee55 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 @@ -27,449 +27,451 @@ import java.util.Map; public class ItemConfigParser { - public static ConfigurableSkyBlockItem parseItem(Map config) { - String id = (String) config.get("id"); - // Clean up the ID - id = id.replaceAll("[^a-zA-Z0-9_]", ""); - - Material material = Material.values().stream().filter(loopedMaterial -> { - return loopedMaterial.key().value().equalsIgnoreCase((String) config.get("material")); - }).findFirst().orElse(Material.AIR); - - List lore = (List) config.get("lore"); - Map statistics = new HashMap<>(); - - if (config.containsKey("default_statistics")) { - // Convert all the objects to doubles, noting they may be integers - for (Map.Entry entry : ((Map) config.get("default_statistics")).entrySet()) { - statistics.put(entry.getKey(), Double.parseDouble(entry.getValue().toString())); - } - } - - ConfigurableSkyBlockItem item = new ConfigurableSkyBlockItem(id, material, lore, statistics); - - List> components = (List>) config.get("components"); - if (components == null) components = new ArrayList<>(); - for (Map componentConfig : components) { - String componentId = (String) componentConfig.get("id"); - SkyBlockItemComponent component = parseComponent(id, componentId, componentConfig); - if (component != null) { - // Mark all components from YAML as explicit - item.addComponent(component, true); - } - } - - item.register(); - return item; - } - - private static @Nullable SkyBlockItemComponent parseComponent(String itemId, String id, Map config) { - return switch (id.toUpperCase()) { - case "ABILITY" -> { - List abilities = (List) config.get("abilities"); - yield new AbilityComponent(abilities); - } - case "TALISMAN", "ACCESSORY" -> new AccessoryComponent(); - case "ANVIL_COMBINABLE" -> { - String handlerId = (String) config.get("handler_id"); - yield new AnvilCombinableComponent(handlerId); - } - case "ARMOR" -> new ArmorComponent(); - case "ARROW" -> new ArrowComponent(); - case "AUCTION_CATEGORY" -> { - String category = (String) config.get("category"); - yield new AuctionCategoryComponent(category); - } - case "AXE" -> new AxeComponent(); - case "BACKPACK" -> { - int rows = (int) config.get("rows"); - String skullTexture = (String) config.get("skull-texture"); - yield new BackpackComponent(rows, skullTexture); - } - case "BOW" -> { - String handlerId = (String) config.get("handler_id"); - boolean shouldBeArrow = (boolean) config.getOrDefault("should-be-arrow", true); - yield new BowComponent(handlerId, shouldBeArrow); - } - case "CONSTANT_STATISTICS" -> new ConstantStatisticsComponent(); - case "DEFAULT_CRAFTABLE" -> { - List> recipes = (List>) config.get("recipes"); - boolean defaultCraftable = true; - if (config.containsKey("default-craftable")) { - defaultCraftable = (boolean) config.get("default-craftable"); - } - CraftableComponent component = new CraftableComponent(recipes); - component.setDefaultCraftable(defaultCraftable); - yield component; - } - case "CUSTOM_DISPLAY_NAME" -> new CustomDisplayNameComponent((item) -> config.get("display_name").toString()); - case "DECORATION_HEAD" -> { - String texture = (String) config.get("texture"); - yield new DecorationHeadComponent(texture); - } - case "DEFAULT_SOULBOUND" -> { - boolean coopAllowed = (boolean) config.get("coop_allowed"); - yield new DefaultSoulboundComponent(coopAllowed); - } - case "DISABLE_ANIMATION" -> { - List animations = (List) config.get("disabled_animations"); - yield new DisableAnimationComponent(animations); - } - case "DRILL" -> new DrillComponent(); - case "ENCHANTABLE" -> { - List groups = (List) config.getOrDefault("enchant_groups", List.of()); - boolean showLores = (boolean) config.getOrDefault("show_lores", true); - yield new EnchantableComponent( - groups.stream().map(EnchantItemGroups::valueOf).toList(), - showLores - ); - } - case "ENCHANTED" -> { - if (config.containsKey("recipe_type") && config.containsKey("item_id")) { - SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.valueOf((String) config.get("recipe_type")); - String baseMaterial = (String) config.get("item_id"); - yield new EnchantedComponent(type, itemId, baseMaterial); - } - yield new EnchantedComponent(); - } - case "EXTRA_RARITY" -> { - String display = (String) config.get("display"); - yield new ExtraRarityComponent(display); - } - case "DUNGEON_ITEM" -> new ExtraRarityComponent("DUNGEON ITEM"); - case "EXTRA_UNDER_NAME" -> { - if (config.containsKey("displays")) { - List displays = (List) config.get("displays"); - yield new ExtraUnderNameComponent(displays); - } else { - String display = (String) config.get("display"); - yield new ExtraUnderNameComponent(display); - } - } - case "GEMSTONE" -> { - List gemstones = (List) config.get("gemstones"); - yield new GemstoneComponent(gemstones); - } - case "GEMSTONE_IMPL" -> { - GemRarity rarity = GemRarity.valueOf((String) config.get("rarity")); - Gemstone gemstone = Gemstone.valueOf((String) config.get("gemstone")); - String texture = (String) config.get("skull_texture"); - yield new GemstoneImplComponent(rarity, gemstone, texture); - } - case "HOT_POTATO" -> { - String type = (String) config.get("potato_type"); - - if (config.containsKey("appliable_items")) { - var appliableItems = (List) config.get("appliable_items"); - HashMap appliable = new HashMap<>(); - - for (var item : appliableItems) { - var split = item.split(":"); - - if (split.length != 2) - continue; - - appliable.put(ItemType.valueOf(split[0]), Integer.parseInt(split[1])); - } - - yield new HotPotatoableComponent(PotatoType.valueOf(type), appliable); - } - - yield new HotPotatoableComponent(PotatoType.valueOf(type)); - } - case "INTERACTABLE" -> { - String handlerId = (String) config.get("handler_id"); - try { - yield new InteractableComponent(handlerId); - } catch (Exception e) { - Logger.error("Failed to parse InteractableComponent for " + handlerId); - yield null; - } - } - case "KAT" -> { - int reducedDays = (int) config.get("reduced_days"); - yield new KatComponent(reducedDays); - } - case "LEATHER_COLOR" -> { - String r = (String) config.get("r"); - String g = (String) config.get("g"); - String b = (String) config.get("b"); - - Color color = new Color(Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b)); - yield new LeatherColorComponent(color); - } - case "MINION" -> { - String minionType = (String) config.get("minion_type"); - String baseItem = (String) config.get("base_item"); - boolean isByDefaultCraftable = (boolean) config.get("default_craftable"); - - List ingredients = (List) config.get("ingredients"); - List ingredientsMap = new ArrayList<>(); - - for (String ingredient : ingredients) { - String[] ingredientParts = ingredient.split(":"); - ingredientsMap.add(new MinionIngredient( - ItemType.valueOf(ingredientParts[0]), - Integer.parseInt(ingredientParts[1]) - )); - } - - yield new MinionComponent(minionType,baseItem, isByDefaultCraftable, ingredientsMap); - } - case "MINION_FUEL" -> { - double percentage = (double) config.get("fuel_percentage"); - long lastTime = (int) config.get("last_time_ms"); - yield new MinionFuelComponent(percentage, lastTime); - } - case "MINION_SHIPPING" -> { - double percentage = (double) config.get("percentage"); - yield new MinionShippingComponent(percentage); - } - case "MINION_SKIN" -> { - String skinName = (String) config.get("name"); - Map helmetConfig = (Map) config.get("helmet"); - Map chestplateConfig = (Map) config.get("chestplate"); - Map leggingsConfig = (Map) config.get("leggings"); - Map bootsConfig = (Map) config.get("boots"); - - MinionSkinComponent.MinionArmorPiece helmet = helmetConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(helmetConfig) : - new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); - MinionSkinComponent.MinionArmorPiece chestplate = chestplateConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(chestplateConfig) : - new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); - MinionSkinComponent.MinionArmorPiece leggings = leggingsConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(leggingsConfig) : - new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); - MinionSkinComponent.MinionArmorPiece boots = bootsConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(bootsConfig) : - new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); - - yield new MinionSkinComponent(skinName, helmet, chestplate, leggings, boots); - } - case "MINION_UPGRADE" -> { - double speedIncrease = (double) config.get("speed_increase"); - yield new MinionUpgradeComponent(speedIncrease); - } - case "MUSEUM" -> { - String category = (String) config.get("museum_category"); - yield new MuseumComponent(category); - } - case "NOT_FINISHED_YET" -> new NotFinishedYetComponent(); - case "LORE_UPDATE" -> { - boolean isAbsolute = (boolean) config.getOrDefault("is_absolute", false); - yield new LoreUpdateComponent(config.get("handler_id").toString(), isAbsolute); - } - case "PET_ITEM" -> new PetItemComponent(); - case "PICKAXE" -> new PickaxeComponent(); - case "PLACEABLE" -> { - String blockType = (String) config.get("block_type"); - yield new PlaceableComponent(blockType); - } - case "PLACE_EVENT" -> { - String handlerId = (String) config.get("handler_id"); - yield new PlaceEventComponent(handlerId); - } - case "POWER_STONE" -> new PowerStoneComponent(); - case "QUIVER_DISPLAY" -> { - boolean shouldBeArrow = (boolean) config.get("should_be_arrow"); - yield new QuiverDisplayComponent(shouldBeArrow); - } - case "REFORGABLE" -> { - String type = (String) config.get("reforge_type"); - yield new ReforgableComponent(ReforgeType.valueOf(type)); - } - case "RIGHT_CLICK_RECIPE" -> { - String recipeItem = (String) config.get("recipe_item"); - yield new RightClickRecipeComponent(recipeItem); - } - case "RUNEABLE" -> { - String applicableTo = (String) config.get("applicable_to"); - yield new RuneableComponent(RuneableComponent.RuneApplicableTo.valueOf(applicableTo)); - } - case "CUSTOM_DROP" -> { - List> rulesConfig = (List>) config.get("rules"); - List rules = new ArrayList<>(); - - for (Map ruleConfig : rulesConfig) { - // Parse conditions - Map conditionsConfig = (Map) ruleConfig.get("conditions"); - CustomDropComponent.DropConditions conditions = CustomDropComponent.parseDropConditions(conditionsConfig); - - // Parse drops - List> dropsConfig = (List>) ruleConfig.get("drops"); - List drops = new ArrayList<>(); - - for (Map dropConfig : dropsConfig) { - String itemName = (String) dropConfig.get("item"); - ItemType itemType = ItemType.valueOf(itemName); - double chance = ((Number) dropConfig.get("chance")).doubleValue(); - String amount = dropConfig.get("amount").toString(); - - drops.add(new CustomDropComponent.Drop(itemType, chance, amount)); - } - - rules.add(new CustomDropComponent.DropRule(conditions, drops)); - } - - yield new CustomDropComponent(rules); - } - case "RUNE" -> { - int level = (int) config.get("required_level"); - String color = (String) config.get("color"); - String applicableTo = (String) config.get("applicable_to"); - String texture = (String) config.get("skull_texture"); - yield new RuneComponent(level, color, applicableTo, texture); - } - case "SACK" -> { - List items = (List) config.get("valid_items"); - int capacity = (int) config.get("max_capacity"); - yield new SackComponent(items, capacity); - } - case "SELLABLE" -> { - Object value = config.get("value"); - if (value instanceof Double) { - yield new SellableComponent((double) value); - } else if (value instanceof Integer) { - yield new SellableComponent((int) value); - } - yield new SellableComponent(1); - } - case "SERVER_ORB" -> { - String handlerId = (String) config.get("handler_id"); - List blockStrings = ((List) config.getOrDefault("valid_blocks", List.of())).stream().map( - String::toLowerCase - ).toList(); - List materials = Material.values().stream() - .filter(material -> blockStrings.contains(material.key().value().toLowerCase())) - .toList(); - - yield new ServerOrbComponent(handlerId, materials); - } - case "SHORT_BOW" -> { - String handlerId = (String) config.get("handler_id"); - float cooldown = (float) config.get("cooldown"); - boolean shouldBeArrow = (boolean) config.getOrDefault("should-be-arrow", true); - yield new ShortBowComponent(cooldown, handlerId, shouldBeArrow); - } - case "SHOVEL" -> new ShovelComponent(); - case "SKILLABLE_MINE" -> { - String category = (String) config.get("category"); - double value = (double) config.get("mining_value"); - yield new SkillableMineComponent(category, value); - } - case "SKULL_HEAD" -> new SkullHeadComponent((item) -> config.get("texture").toString()); - case "STANDARD_ITEM" -> { - String type = (String) config.get("standard_item_type"); - yield new StandardItemComponent(type); - } - case "CUSTOM_STATISTICS" -> { - String handlerId = (String) config.get("handler_id"); - yield new CustomStatisticsComponent(handlerId); - } - case "TIERED_TALISMAN" -> { - ItemType baseTier = ItemType.valueOf((String) config.get("base_tier")); - int tier = (int) config.get("tier"); - yield new TieredTalismanComponent(baseTier, tier); - } - case "TRACKED_UNIQUE" -> new TrackedUniqueComponent(); - case "TRAVEL_SCROLL" -> { - String scrollType = (String) config.get("scroll_type"); - yield new TravelScrollComponent(scrollType); - } - case "PET" -> { - String petName = (String) config.get("pet_name"); - - // Parse george price - Map georgePriceMap = (Map) config.get("george_price"); - RarityValue georgePrice = new RarityValue<>( - georgePriceMap.get("common"), - georgePriceMap.get("uncommon"), - georgePriceMap.get("rare"), - georgePriceMap.get("epic"), - georgePriceMap.get("legendary"), - georgePriceMap.get("rest") - ); - - // Parse kat upgrades if present - RarityValue katUpgrades = null; - if (config.containsKey("kat_upgrades")) { - Map> katUpgradeMap = (Map>) config.get("kat_upgrades"); - katUpgrades = new RarityValue<>( - parseKatUpgrade(katUpgradeMap.get("common")), - parseKatUpgrade(katUpgradeMap.get("uncommon")), - parseKatUpgrade(katUpgradeMap.get("rare")), - parseKatUpgrade(katUpgradeMap.get("epic")), - parseKatUpgrade(katUpgradeMap.get("legendary")), - parseKatUpgrade(katUpgradeMap.get("rest")) - ); - } - - // Parse base statistics - Map baseStatsMap = (Map) config.get("base_statistics"); - ItemStatistics.Builder baseBuilder = ItemStatistics.builder(); - baseStatsMap.forEach((stat, value) -> - baseBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), value) - ); - ItemStatistics baseStatistics = baseBuilder.build(); - - // Parse per level statistics - Map perLevelStatsMap = (Map) config.get("per_level_statistics"); - Map perLevelStatistics = new HashMap<>(); - for (Map.Entry entry : perLevelStatsMap.entrySet()) { - String rarity = entry.getKey(); - ItemStatistics.Builder rarityBuilder = ItemStatistics.builder(); - try { - Map rarityStatsMap = (Map) entry.getValue(); - rarityBuilder = ItemStatistics.builder(); - for (Map.Entry e : rarityStatsMap.entrySet()) { - String stat = e.getKey(); - Double value = e.getValue(); - rarityBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), value); - } - } catch (ClassCastException e) { - // Per level statistics is a map with an Integer, so we need to convert it to a double - Map rarityStatsMap = (Map) entry.getValue(); - rarityBuilder = ItemStatistics.builder(); - for (Map.Entry mapEntry : rarityStatsMap.entrySet()) { - String stat = mapEntry.getKey(); - Integer value = mapEntry.getValue(); - rarityBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), Double.valueOf(value)); - } - } - perLevelStatistics.put(Rarity.valueOf(rarity.toUpperCase()), rarityBuilder.build()); - } - - // Parse other fields - Particle particleId = Particle.fromId((Integer) config.get("particle")); - String skillCategory = (String) config.get("skill_category"); - String skullTexture = (String) config.get("skull_texture"); - String handlerId = (String) config.get("handler_id"); - - yield new PetComponent( - petName, - georgePrice, - katUpgrades, - baseStatistics, - perLevelStatistics, - particleId, - skillCategory, - skullTexture, - handlerId - ); - } - default -> throw new IllegalArgumentException("Unknown component type: " + id); - }; - } - - private static KatUpgrade parseKatUpgrade(Map config) { - if (config == null) return null; - - Long time = ((Number) config.get("time")).longValue(); - Integer coins = (Integer) config.get("coins"); - - if (config.containsKey("item")) { - String item = (String) config.get("item"); - Integer amount = (Integer) config.get("amount"); - return KatUpgrade.WithItem(time, coins, ItemType.valueOf(item), amount); - } - - return KatUpgrade.OnlyCoins(time, coins); - } + public static ConfigurableSkyBlockItem parseItem(Map config) { + String id = (String) config.get("id"); + // Clean up the ID + id = id.replaceAll("[^a-zA-Z0-9_]", ""); + + Material material = Material.values().stream().filter(loopedMaterial -> { + return loopedMaterial.key().value().equalsIgnoreCase((String) config.get("material")); + }).findFirst().orElse(Material.AIR); + + List lore = (List) config.get("lore"); + Map statistics = new HashMap<>(); + + if (config.containsKey("default_statistics")) { + // Convert all the objects to doubles, noting they may be integers + for (Map.Entry entry : ((Map) config.get("default_statistics")).entrySet()) { + statistics.put(entry.getKey(), Double.parseDouble(entry.getValue().toString())); + } + } + + ConfigurableSkyBlockItem item = new ConfigurableSkyBlockItem(id, material, lore, statistics); + + List> components = (List>) config.get("components"); + if (components == null) components = new ArrayList<>(); + for (Map componentConfig : components) { + String componentId = (String) componentConfig.get("id"); + SkyBlockItemComponent component = parseComponent(id, componentId, componentConfig); + if (component != null) { + // Mark all components from YAML as explicit + item.addComponent(component, true); + } + } + + item.register(); + return item; + } + + private static @Nullable SkyBlockItemComponent parseComponent(String itemId, String id, Map config) { + return switch (id.toUpperCase()) { + case "ABILITY" -> { + List abilities = (List) config.get("abilities"); + yield new AbilityComponent(abilities); + } + case "TALISMAN", "ACCESSORY" -> new AccessoryComponent(); + case "ANVIL_COMBINABLE" -> { + String handlerId = (String) config.get("handler_id"); + yield new AnvilCombinableComponent(handlerId); + } + case "ARMOR" -> new ArmorComponent(); + case "ARROW" -> new ArrowComponent(); + case "AUCTION_CATEGORY" -> { + String category = (String) config.get("category"); + yield new AuctionCategoryComponent(category); + } + case "AXE" -> new AxeComponent(); + case "BACKPACK" -> { + int rows = (int) config.get("rows"); + String skullTexture = (String) config.get("skull-texture"); + yield new BackpackComponent(rows, skullTexture); + } + case "BOW" -> { + String handlerId = (String) config.get("handler_id"); + boolean shouldBeArrow = (boolean) config.getOrDefault("should-be-arrow", true); + yield new BowComponent(handlerId, shouldBeArrow); + } + case "CONSTANT_STATISTICS" -> new ConstantStatisticsComponent(); + case "DEFAULT_CRAFTABLE" -> { + List> recipes = (List>) config.get("recipes"); + boolean defaultCraftable = true; + if (config.containsKey("default-craftable")) { + defaultCraftable = (boolean) config.get("default-craftable"); + } + CraftableComponent component = new CraftableComponent(recipes); + component.setDefaultCraftable(defaultCraftable); + yield component; + } + case "CUSTOM_DISPLAY_NAME" -> + new CustomDisplayNameComponent((item) -> config.get("display_name").toString()); + case "DECORATION_HEAD" -> { + String texture = (String) config.get("texture"); + yield new DecorationHeadComponent(texture); + } + case "DEFAULT_SOULBOUND" -> { + boolean coopAllowed = (boolean) config.get("coop_allowed"); + yield new DefaultSoulboundComponent(coopAllowed); + } + case "DISABLE_ANIMATION" -> { + List animations = (List) config.get("disabled_animations"); + yield new DisableAnimationComponent(animations); + } + case "DRILL" -> new DrillComponent(); + case "ENCHANTABLE" -> { + List groups = (List) config.getOrDefault("enchant_groups", List.of()); + boolean showLores = (boolean) config.getOrDefault("show_lores", true); + yield new EnchantableComponent( + groups.stream().map(EnchantItemGroups::valueOf).toList(), + showLores + ); + } + case "FISHING_ROD" -> new FishingRodComponent(); + case "ENCHANTED" -> { + if (config.containsKey("recipe_type") && config.containsKey("item_id")) { + SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.valueOf((String) config.get("recipe_type")); + String baseMaterial = (String) config.get("item_id"); + yield new EnchantedComponent(type, itemId, baseMaterial); + } + yield new EnchantedComponent(); + } + case "EXTRA_RARITY" -> { + String display = (String) config.get("display"); + yield new ExtraRarityComponent(display); + } + case "DUNGEON_ITEM" -> new ExtraRarityComponent("DUNGEON ITEM"); + case "EXTRA_UNDER_NAME" -> { + if (config.containsKey("displays")) { + List displays = (List) config.get("displays"); + yield new ExtraUnderNameComponent(displays); + } else { + String display = (String) config.get("display"); + yield new ExtraUnderNameComponent(display); + } + } + case "GEMSTONE" -> { + List gemstones = (List) config.get("gemstones"); + yield new GemstoneComponent(gemstones); + } + case "GEMSTONE_IMPL" -> { + GemRarity rarity = GemRarity.valueOf((String) config.get("rarity")); + Gemstone gemstone = Gemstone.valueOf((String) config.get("gemstone")); + String texture = (String) config.get("skull_texture"); + yield new GemstoneImplComponent(rarity, gemstone, texture); + } + case "HOT_POTATO" -> { + String type = (String) config.get("potato_type"); + + if (config.containsKey("appliable_items")) { + var appliableItems = (List) config.get("appliable_items"); + HashMap appliable = new HashMap<>(); + + for (var item : appliableItems) { + var split = item.split(":"); + + if (split.length != 2) + continue; + + appliable.put(ItemType.valueOf(split[0]), Integer.parseInt(split[1])); + } + + yield new HotPotatoableComponent(PotatoType.valueOf(type), appliable); + } + + yield new HotPotatoableComponent(PotatoType.valueOf(type)); + } + case "INTERACTABLE" -> { + String handlerId = (String) config.get("handler_id"); + try { + yield new InteractableComponent(handlerId); + } catch (Exception e) { + Logger.error("Failed to parse InteractableComponent for " + handlerId); + yield null; + } + } + case "KAT" -> { + int reducedDays = (int) config.get("reduced_days"); + yield new KatComponent(reducedDays); + } + case "LEATHER_COLOR" -> { + String r = (String) config.get("r"); + String g = (String) config.get("g"); + String b = (String) config.get("b"); + + Color color = new Color(Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b)); + yield new LeatherColorComponent(color); + } + case "MINION" -> { + String minionType = (String) config.get("minion_type"); + String baseItem = (String) config.get("base_item"); + boolean isByDefaultCraftable = (boolean) config.get("default_craftable"); + + List ingredients = (List) config.get("ingredients"); + List ingredientsMap = new ArrayList<>(); + + for (String ingredient : ingredients) { + String[] ingredientParts = ingredient.split(":"); + ingredientsMap.add(new MinionIngredient( + ItemType.valueOf(ingredientParts[0]), + Integer.parseInt(ingredientParts[1]) + )); + } + + yield new MinionComponent(minionType, baseItem, isByDefaultCraftable, ingredientsMap); + } + case "MINION_FUEL" -> { + double percentage = (double) config.get("fuel_percentage"); + long lastTime = (int) config.get("last_time_ms"); + yield new MinionFuelComponent(percentage, lastTime); + } + case "MINION_SHIPPING" -> { + double percentage = (double) config.get("percentage"); + yield new MinionShippingComponent(percentage); + } + case "MINION_SKIN" -> { + String skinName = (String) config.get("name"); + Map helmetConfig = (Map) config.get("helmet"); + Map chestplateConfig = (Map) config.get("chestplate"); + Map leggingsConfig = (Map) config.get("leggings"); + Map bootsConfig = (Map) config.get("boots"); + + MinionSkinComponent.MinionArmorPiece helmet = helmetConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(helmetConfig) : + new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); + MinionSkinComponent.MinionArmorPiece chestplate = chestplateConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(chestplateConfig) : + new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); + MinionSkinComponent.MinionArmorPiece leggings = leggingsConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(leggingsConfig) : + new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); + MinionSkinComponent.MinionArmorPiece boots = bootsConfig != null ? MinionSkinComponent.MinionArmorPiece.fromConfig(bootsConfig) : + new MinionSkinComponent.MinionArmorPiece(Material.AIR, null, null); + + yield new MinionSkinComponent(skinName, helmet, chestplate, leggings, boots); + } + case "MINION_UPGRADE" -> { + double speedIncrease = (double) config.get("speed_increase"); + yield new MinionUpgradeComponent(speedIncrease); + } + case "MUSEUM" -> { + String category = (String) config.get("museum_category"); + yield new MuseumComponent(category); + } + case "NOT_FINISHED_YET" -> new NotFinishedYetComponent(); + case "LORE_UPDATE" -> { + boolean isAbsolute = (boolean) config.getOrDefault("is_absolute", false); + yield new LoreUpdateComponent(config.get("handler_id").toString(), isAbsolute); + } + case "PET_ITEM" -> new PetItemComponent(); + case "PICKAXE" -> new PickaxeComponent(); + case "PLACEABLE" -> { + String blockType = (String) config.get("block_type"); + yield new PlaceableComponent(blockType); + } + case "PLACE_EVENT" -> { + String handlerId = (String) config.get("handler_id"); + yield new PlaceEventComponent(handlerId); + } + case "POWER_STONE" -> new PowerStoneComponent(); + case "QUIVER_DISPLAY" -> { + boolean shouldBeArrow = (boolean) config.get("should_be_arrow"); + yield new QuiverDisplayComponent(shouldBeArrow); + } + case "REFORGABLE" -> { + String type = (String) config.get("reforge_type"); + yield new ReforgableComponent(ReforgeType.valueOf(type)); + } + case "RIGHT_CLICK_RECIPE" -> { + String recipeItem = (String) config.get("recipe_item"); + yield new RightClickRecipeComponent(recipeItem); + } + case "RUNEABLE" -> { + String applicableTo = (String) config.get("applicable_to"); + yield new RuneableComponent(RuneableComponent.RuneApplicableTo.valueOf(applicableTo)); + } + case "CUSTOM_DROP" -> { + List> rulesConfig = (List>) config.get("rules"); + List rules = new ArrayList<>(); + + for (Map ruleConfig : rulesConfig) { + // Parse conditions + Map conditionsConfig = (Map) ruleConfig.get("conditions"); + CustomDropComponent.DropConditions conditions = CustomDropComponent.parseDropConditions(conditionsConfig); + + // Parse drops + List> dropsConfig = (List>) ruleConfig.get("drops"); + List drops = new ArrayList<>(); + + for (Map dropConfig : dropsConfig) { + String itemName = (String) dropConfig.get("item"); + ItemType itemType = ItemType.valueOf(itemName); + double chance = ((Number) dropConfig.get("chance")).doubleValue(); + String amount = dropConfig.get("amount").toString(); + + drops.add(new CustomDropComponent.Drop(itemType, chance, amount)); + } + + rules.add(new CustomDropComponent.DropRule(conditions, drops)); + } + + yield new CustomDropComponent(rules); + } + case "RUNE" -> { + int level = (int) config.get("required_level"); + String color = (String) config.get("color"); + String applicableTo = (String) config.get("applicable_to"); + String texture = (String) config.get("skull_texture"); + yield new RuneComponent(level, color, applicableTo, texture); + } + case "SACK" -> { + List items = (List) config.get("valid_items"); + int capacity = (int) config.get("max_capacity"); + yield new SackComponent(items, capacity); + } + case "SELLABLE" -> { + Object value = config.get("value"); + if (value instanceof Double) { + yield new SellableComponent((double) value); + } else if (value instanceof Integer) { + yield new SellableComponent((int) value); + } + yield new SellableComponent(1); + } + case "SERVER_ORB" -> { + String handlerId = (String) config.get("handler_id"); + List blockStrings = ((List) config.getOrDefault("valid_blocks", List.of())).stream().map( + String::toLowerCase + ).toList(); + List materials = Material.values().stream() + .filter(material -> blockStrings.contains(material.key().value().toLowerCase())) + .toList(); + + yield new ServerOrbComponent(handlerId, materials); + } + case "SHORT_BOW" -> { + String handlerId = (String) config.get("handler_id"); + float cooldown = (float) config.get("cooldown"); + boolean shouldBeArrow = (boolean) config.getOrDefault("should-be-arrow", true); + yield new ShortBowComponent(cooldown, handlerId, shouldBeArrow); + } + case "SHOVEL" -> new ShovelComponent(); + case "SKILLABLE_MINE" -> { + String category = (String) config.get("category"); + double value = (double) config.get("mining_value"); + yield new SkillableMineComponent(category, value); + } + case "SKULL_HEAD" -> new SkullHeadComponent((item) -> config.get("texture").toString()); + case "STANDARD_ITEM" -> { + String type = (String) config.get("standard_item_type"); + yield new StandardItemComponent(type); + } + case "CUSTOM_STATISTICS" -> { + String handlerId = (String) config.get("handler_id"); + yield new CustomStatisticsComponent(handlerId); + } + case "TIERED_TALISMAN" -> { + ItemType baseTier = ItemType.valueOf((String) config.get("base_tier")); + int tier = (int) config.get("tier"); + yield new TieredTalismanComponent(baseTier, tier); + } + case "TRACKED_UNIQUE" -> new TrackedUniqueComponent(); + case "TRAVEL_SCROLL" -> { + String scrollType = (String) config.get("scroll_type"); + yield new TravelScrollComponent(scrollType); + } + case "PET" -> { + String petName = (String) config.get("pet_name"); + + // Parse george price + Map georgePriceMap = (Map) config.get("george_price"); + RarityValue georgePrice = new RarityValue<>( + georgePriceMap.get("common"), + georgePriceMap.get("uncommon"), + georgePriceMap.get("rare"), + georgePriceMap.get("epic"), + georgePriceMap.get("legendary"), + georgePriceMap.get("rest") + ); + + // Parse kat upgrades if present + RarityValue katUpgrades = null; + if (config.containsKey("kat_upgrades")) { + Map> katUpgradeMap = (Map>) config.get("kat_upgrades"); + katUpgrades = new RarityValue<>( + parseKatUpgrade(katUpgradeMap.get("common")), + parseKatUpgrade(katUpgradeMap.get("uncommon")), + parseKatUpgrade(katUpgradeMap.get("rare")), + parseKatUpgrade(katUpgradeMap.get("epic")), + parseKatUpgrade(katUpgradeMap.get("legendary")), + parseKatUpgrade(katUpgradeMap.get("rest")) + ); + } + + // Parse base statistics + Map baseStatsMap = (Map) config.get("base_statistics"); + ItemStatistics.Builder baseBuilder = ItemStatistics.builder(); + baseStatsMap.forEach((stat, value) -> + baseBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), value) + ); + ItemStatistics baseStatistics = baseBuilder.build(); + + // Parse per level statistics + Map perLevelStatsMap = (Map) config.get("per_level_statistics"); + Map perLevelStatistics = new HashMap<>(); + for (Map.Entry entry : perLevelStatsMap.entrySet()) { + String rarity = entry.getKey(); + ItemStatistics.Builder rarityBuilder = ItemStatistics.builder(); + try { + Map rarityStatsMap = (Map) entry.getValue(); + rarityBuilder = ItemStatistics.builder(); + for (Map.Entry e : rarityStatsMap.entrySet()) { + String stat = e.getKey(); + Double value = e.getValue(); + rarityBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), value); + } + } catch (ClassCastException e) { + // Per level statistics is a map with an Integer, so we need to convert it to a double + Map rarityStatsMap = (Map) entry.getValue(); + rarityBuilder = ItemStatistics.builder(); + for (Map.Entry mapEntry : rarityStatsMap.entrySet()) { + String stat = mapEntry.getKey(); + Integer value = mapEntry.getValue(); + rarityBuilder.withBase(ItemStatistic.valueOf(stat.toUpperCase()), Double.valueOf(value)); + } + } + perLevelStatistics.put(Rarity.valueOf(rarity.toUpperCase()), rarityBuilder.build()); + } + + // Parse other fields + Particle particleId = Particle.fromId((Integer) config.get("particle")); + String skillCategory = (String) config.get("skill_category"); + String skullTexture = (String) config.get("skull_texture"); + String handlerId = (String) config.get("handler_id"); + + yield new PetComponent( + petName, + georgePrice, + katUpgrades, + baseStatistics, + perLevelStatistics, + particleId, + skillCategory, + skullTexture, + handlerId + ); + } + default -> throw new IllegalArgumentException("Unknown component type: " + id); + }; + } + + private static KatUpgrade parseKatUpgrade(Map config) { + if (config == null) return null; + + Long time = ((Number) config.get("time")).longValue(); + Integer coins = (Integer) config.get("coins"); + + if (config.containsKey("item")) { + String item = (String) config.get("item"); + Integer amount = (Integer) config.get("amount"); + return KatUpgrade.WithItem(time, coins, ItemType.valueOf(item), amount); + } + + return KatUpgrade.OnlyCoins(time, coins); + } } \ No newline at end of file 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..0493b516a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodComponent.java @@ -0,0 +1,33 @@ +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.item.SkyBlockItemComponent; + +public class FishingRodComponent extends SkyBlockItemComponent { + + public FishingRodComponent() { + addInheritedComponent(new InteractableComponent( + null, + (player, item) -> { + FishingHook hook = FishingHook.getFishingHookForOwner(player); + if (hook != null) { + hook.remove(); + player.playSound( + Sound.sound() + .type(Key.key("entity.fishing_bobber.retrieve")) + .source(Sound.Source.NEUTRAL) + .volume(1f) + .pitch(0.8f) // the pitch is 0.8-1.2 + .build() + ); + } else { + new FishingHook(player).spawn(player.getInstance()); + } + }, + null + )); + } + +} From 0de4b09d02911a34c70f2a130a02b39535ce312e Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:57:22 +0200 Subject: [PATCH 2/7] feat: unfinished fishing quests --- .../data/datapoints/DatapointToggles.java | 2 + .../swofty/type/hub/gui/GUIGFishingShip.java | 133 ++++++++++++++++++ .../swofty/type/hub/npcs/NPCCaptainBaha.java | 77 ++++++++++ .../type/hub/npcs/NPCFishermanGerald.java | 82 +++++++++++ .../net/swofty/type/hub/npcs/NPCGavin.java | 77 ++++++++++ .../skyblockgeneric/entity/FishingHook.java | 3 +- .../item/components/FishingRodComponent.java | 3 +- 7 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java create mode 100644 type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java create mode 100644 type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java create mode 100644 type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java 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 86d7e7324..df8c8c565 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 @@ -75,6 +75,8 @@ public enum ToggleType { HAS_SPOKEN_TO_LIFT_OPERATOR(false), HAS_SPOKEN_TO_LAZY_MINER(false), HAS_SPOKEN_TO_BAKER(false), + HAS_SPOKEN_TO_GAVIN(false), + HAS_SPOKEN_TO_FISHERMAN_GERALD(false), HAS_SPOKEN_TO_RUSTY(false), HAS_SPOKEN_TO_RUSTY_ABOUT_PICKAXE(false), HAS_SPOKEN_TO_CURATOR(false), diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java new file mode 100644 index 000000000..5886b6a03 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java @@ -0,0 +1,133 @@ +package net.swofty.type.hub.gui; + +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; + +// TOOD: Fishing ship name can be changed. And the parts can be changed +public class GUIGFishingShip extends HypixelInventoryGUI { + + public GUIGFishingShip() { + 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) { + 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: §fCracked Ship Helm", + "§7Engine: §fRusty Ship Engine", + "§7Hull: §fRusty Ship Hull" + ); + } + }); + set(new GUIItem(21) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStackHead( + "§fCracked Ship Helm", + "d8d4a54d1fcf47b2efc99ba4cc772250aee5c2f26ed1a19052213e0f3323ca1d", + 1, + "§7A cracked ship helm, incapable of", + "§7changing its heading which appears", + "§7due east.", + "", + "§6§lUPGRADE TO §8➜ §9Bronze Ship Helm", + "§7Crafted from §aBronze Bowls§7, which", + "§7are rarely dropped by §cDumpster", + "§cDivers §7in the §2Backwater Bayou§7.", + "", + "§eClick a Ship Part in your inventory to", + "§eupgrade this part!" + ); + } + }); + // TODO: this is "missing" by default, need to implement that state + set(new GUIItem(22) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStackHead( + "§fRusty Ship Engine", + "53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c", + 1, + "§7Rusted by the waters, but it seems to", + "§7be able to run...for now.", + "", + "§6§lUPGRADE TO §8➜ §9Bronze Ship Engine", + "§7Purchased from §2Junker Joel §7in the", + "§2Backwater Bayou§7.", + "", + "§eClick a Ship Part in your inventory to", + "§eupgrade this part!" + ); + } + }); + set(new GUIItem(23) { + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStackHead( + "§fRusty Ship Hull", + "f42d53ca6e7d80a99a699c2036dcf6e233394feb9f46fb2ff9d9a819690894a9", + 1, + "§7A hull rusted and dilapidated beyond", + "§7repair. It's a miracle the ship", + "§7remains afloat.", + "", + "§6§lUPGRADE TO §8➜ §9Bronze Ship Hull", + "§7Crafted from §aTorn Cloth§7, which is", + "§7rarely dropped by §cBanshees §7in the", + "§2Backwater Bayou§7.", + "", + "§eClick a Ship Part in your inventory to", + "§eupgrade this part!" + ); + } + }); + set(new GUIItem(44) { + @Override + public ItemStack.Builder getItem(HypixelPlayer 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: §6Zephyr", + "", + "§eClick to rename!" + ); + } + }); + set(GUIClickableItem.getCloseItem(40)); + updateItemStacks(getInventory(), getPlayer()); + } + + @Override + public boolean allowHotkeying() { + return false; + } + + @Override + public void onBottomClick(InventoryPreClickEvent e) { + e.setCancelled(true); + } +} 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..985de6655 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java @@ -0,0 +1,77 @@ +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.user.HypixelPlayer; + +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(179.500, 69.000, 55.500, 105, 0); + } + + @Override + public boolean looking() { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + 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); + }); + return; + } + + setDialogue(player, "idle-" + (int)(Math.random() * 2 + 1)); + // TODO: new GUIFishingShip().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 new file mode 100644 index 000000000..c6f8fcd62 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java @@ -0,0 +1,82 @@ +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.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.skill.SkillCategories; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.stream.Stream; + +public class NPCFishermanGerald extends HypixelNPC { + + public NPCFishermanGerald() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§3Fisherman Gerald", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "oJ24ajDV0/I3NFdHBh7D71v+jboQFJlaFxxu47bWeSmUXhLl6z1Vk9aksUE8qqTNs9EVUWFpSjAe7i/w57nkh4AAH+GvplyzZANEhHf9SJhBdwjCpIDVJZ453hs9xMYbyvp4KiZkia+jbLKrQfQOFOa9aWt1mmhhOneNgzx4it5Bo1qzDoPvbgFu5uL7rbyzdOl9ZW5wEobb2Ns4TbqPdT+NjZurw7rkpRpdLhAbHZoD2NEw0BX3VHTvtlY8zh14//YV7Vo5+xUUWGTrt0UjudIxDdJI8R9ZiWgCgl9N1ElzokFh/h0aHg0vL0QSG1Y5bHY5ea+E2+3tLDiEvQO7Soh/VV1/yySjmkt/JbUiEFmCv6vkjm4bgbAZAm42GxlvkAyFpZoFZijmCaw8ObJivZlwJNUjY4D0PBEm4rnVSVFjjWBGaGXyFG2/KtUL8nYZE81ABqrL3xSHFeEUIBePNsBq84eI88aNGYCjU9Ct4bfAhbdZMWM84PzBqAa5jH6NNqb/5aV2jmEp0OcoF80W+pcaR/uNPOo9Gjy5HkUYMpLJ775SqC//m/Rrh7RypdNcVUIanmUqP+hP7oz1SI3L6glv4+CGlGprr67QHP9d9PcZzVgF1YHOfOKW4muqJNjgpKYFZRiz4yWmOdURKomqUuz4tyKDxu0drx5eHfQ+3mw="; + } + + @Override + public String texture(HypixelPlayer player) { + return "eyJ0aW1lc3RhbXAiOjE1NTk1NzQ0MjU3OTEsInByb2ZpbGVJZCI6ImZkNjBmMzZmNTg2MTRmMTJiM2NkNDdjMmQ4NTUyOTlhIiwicHJvZmlsZU5hbWUiOiJSZWFkIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9hNjc1ZjA3MWVmYjBjZjI3YmYxNjA4MWUzZjgyZjliNWY4YWU4OGVjYTllZTk1MjNiNjIxNmU2MTdmNmY0NWM5In19fQ=="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(153.500, 68.500, 55.500, -60, 0); + } + + @Override + public boolean looking() { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + if (isInDialogue(player)) return; + + boolean belowFive = player.getSkills().getCurrentLevel(SkillCategories.FISHING) < 5; + if (belowFive) { + setDialogue(player, "below-fishing-5"); + return; + } + + 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; + } + + // TODO: finish this quest + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("below-fishing-5").lines(new String[]{ + "Hmm, you're not quite ready yet.", + "Go talk to the §eFish Merchant §fin the §bFishing Outpost§f, get geared up, and get fishin'!", + "Come back once you've reached §aFishing Skill V §fand I'll tell you how you can get to a §anew island§f!", + }).build(), + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "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() + ).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 new file mode 100644 index 000000000..019f86891 --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java @@ -0,0 +1,77 @@ +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.user.HypixelPlayer; + +import java.util.stream.Stream; + +public class NPCGavin extends HypixelNPC { + + public NPCGavin() { + super(new HumanConfiguration() { + @Override + public String[] holograms(HypixelPlayer player) { + return new String[]{"§bGavin", "§e§lCLICK"}; + } + + @Override + public String signature(HypixelPlayer player) { + return "qwNSHj1b7UwXoeP6/Vs/1EGb0pyfO+DGOVUQ9DJ7DY0ZPn6VwQv1Ej1W39wANDGJI1p8eQKRqMLKH0Xj4WkSwnMnj0e7DZU2VROO9xi3th5IhJg/7SzpMt2vMvYUN3u6HI1EzhYHuLL1oHF1eGK/5lZZp6xvb2X4ZuOvX8oASvrgQFPcxR2WMn4nwS4bKRp5CDFGg+fCHCMuHHQAjZpJAHqbfxD2DWXq7CbuyOQJlIybhGDY30syWVKH1aZsp5Nmm8fOeSysqyZL+F49zBbxPUBaX/gmxsBR8cRyU37gBzT39aTeybFsZrQSOz3raFX7H4pRC8xf9dKQzTYxCvi14ljjp8q+IH1AWYSZJSZkxA6k03gxVH6Oxbs8XjHWxYQIu4uPhTV3LRShkSRz1WTLYHqu+I/fhmAsAN7YJQHYNFJGkLSBVYRCkSPCQ3efj7TDX455KlojZ23waaqEvH0d9gUMEScRc3Qpq1Tf3X63CNvd5BBO6apiN9Vfq3TZ3YKdhGLQLXBsu3QewCH2qcf6jbU37in6FltyncRsrd84pFsl2ryquOYhwj2slnVNIyhG7zAguRM9p7zvZOPYlgSplcMgW8sQ3Isv25PBGZ+B6Qhwdl4yYpUnc/n7EyxMuthGyID/nhwTBq4f51L3+RNDYnFz9ED26E3IcW/dQdgxPNA="; + } + + @Override + public String texture(HypixelPlayer player) { + return "ewogICJ0aW1lc3RhbXAiIDogMTc0MDA3MTUzNTE3NCwKICAicHJvZmlsZUlkIiA6ICI1ODc5MjNlNDkxMzM0ZDMzYWE4ZjQ3ZWJkZTljOTc3MiIsCiAgInByb2ZpbGVOYW1lIiA6ICJFbGV2ZW5mb3VyMTAiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZlMzc1NmQ4Y2ZhYzU0MDU1YmNkNTUyNWQyYTNhYmVmZTZjZWY3NzkyNGY4YTk5ODQ2YmVhMmZlZmY3NjExNCIKICAgIH0KICB9Cn0="; + } + + @Override + public Pos position(HypixelPlayer player) { + return new Pos(161.500, 69.900, 43.500, 203, 17); + } + + @Override + public boolean looking() { + return true; + } + }); + } + + @Override + public void onClick(NPCInteractEvent event) { + HypixelPlayer player = event.player(); + 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); + }); + return; + } + + setDialogue(player, "idle-" + (int)(Math.random() * 2 + 1)); + } + + @Override + protected DialogueSet[] dialogues(HypixelPlayer player) { + return Stream.of( + DialogueSet.builder() + .key("first-interaction").lines(new String[]{ + "At the end of each year I bake cakes for everyone in town to celebrate the year.", + "I made one especially for you, here you go.", + "I've recently added a §dNew Year Cake Bag §fto my inventory. Sadly, it's not free! Click me again to open my shop!", + }).build(), + DialogueSet.builder() + .key("idle-1").lines(new String[]{ + "You can open your §aSea Creature Guide §fthrough your §aFishing Skill §fmenu, or with §d/scg§f!" + }).build(), + DialogueSet.builder() + .key("idle-2").lines(new String[]{ + "I'd rather be out there fishing for §6Treasure§f.", + "But mum insists I finish my studies first." + }).build() + ).toArray(DialogueSet[]::new); + } +} 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 index 1fb323cc3..93033b42f 100644 --- 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 @@ -80,12 +80,13 @@ public void spawn(Instance instance, Pos 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((float) 1 / 3) // the pitch is 1/3-0.5 + .pitch(pitch) .build() ); } 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 index 0493b516a..2cbed8e14 100644 --- 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 @@ -14,12 +14,13 @@ public FishingRodComponent() { FishingHook hook = FishingHook.getFishingHookForOwner(player); if (hook != null) { hook.remove(); + 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(0.8f) // the pitch is 0.8-1.2 + .pitch(pitch) .build() ); } else { From 04bdea1263f91e10add48dbde1f51de061aa32da Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:26:12 +0200 Subject: [PATCH 3/7] fix: import after merge --- .../src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java | 1 + .../main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java | 1 + type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java | 1 + 3 files changed, 3 insertions(+) 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 index 985de6655..e41346ea4 100644 --- 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 @@ -4,6 +4,7 @@ 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 java.util.stream.Stream; 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 c6f8fcd62..399d73784 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 @@ -4,6 +4,7 @@ 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.skill.SkillCategories; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; 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 019f86891..8195ba1fd 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 @@ -4,6 +4,7 @@ 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 java.util.stream.Stream; From 52785c845cc1fc3fe7213f9b08ce30007afcf319 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 30 Dec 2025 01:17:08 +0200 Subject: [PATCH 4/7] feat: add HypixelPlayer method signature to overriden HypixelNPC#looking methods --- .../src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java | 2 +- .../main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java | 2 +- type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index e41346ea4..4bf4cd26c 100644 --- 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 @@ -34,7 +34,7 @@ public Pos position(HypixelPlayer player) { } @Override - public boolean looking() { + public boolean looking(HypixelPlayer player) { return true; } }); 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 399d73784..0c919476b 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 @@ -36,7 +36,7 @@ public Pos position(HypixelPlayer player) { } @Override - public boolean looking() { + public boolean looking(HypixelPlayer player) { return true; } }); 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 8195ba1fd..0ef94e224 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 @@ -34,7 +34,7 @@ public Pos position(HypixelPlayer player) { } @Override - public boolean looking() { + public boolean looking(HypixelPlayer player) { return true; } }); From a24c1cefe0603c3014a9f5986e29bd36c561ec8c Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 30 Dec 2025 01:22:11 +0200 Subject: [PATCH 5/7] refactor: remove extra 0s on positions --- .../src/main/java/net/swofty/type/hub/npcs/NPCCaptainBaha.java | 2 +- .../main/java/net/swofty/type/hub/npcs/NPCFishermanGerald.java | 2 +- type.hub/src/main/java/net/swofty/type/hub/npcs/NPCGavin.java | 2 +- .../missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java | 2 +- .../missions/thepark/birchpark/MissionTalkToCharlie.java | 2 +- .../missions/thepark/birchpark/MissionTalkToCharlieAgain.java | 2 +- .../thepark/darkthicket/MissionGiveRyanDarkOakLogs.java | 2 +- .../missions/thepark/darkthicket/MissionSneakUpOnRyan.java | 2 +- .../mission/missions/thepark/darkthicket/MissionTalkToRyan.java | 2 +- .../mission/missions/thepark/jungle/MissionTalkToMolbert.java | 2 +- .../mission/missions/thepark/savanna/MissionCheckOnMelody.java | 2 +- .../missions/thepark/savanna/MissionGiveMelodyAcaciaLogs.java | 2 +- .../mission/missions/thepark/spruce/MissionFindKelly.java | 2 +- .../missions/thepark/spruce/MissionGiveKellySpruceLogs.java | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) 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 index 4bf4cd26c..d5ade58e1 100644 --- 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 @@ -30,7 +30,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(179.500, 69.000, 55.500, 105, 0); + return new Pos(179.5, 69, 55.5, 105, 0); } @Override 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 0c919476b..a0cb82351 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 @@ -32,7 +32,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(153.500, 68.500, 55.500, -60, 0); + return new Pos(153.5, 68.5, 55.5, -60, 0); } @Override 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 0ef94e224..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(161.500, 69.900, 43.500, 203, 17); + return new Pos(161.5, 69.900, 43.5, 203, 17); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java index d796dc2ba..70a517d61 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java @@ -44,6 +44,6 @@ public Set getValidRegions() { @Override public Pos getLocation() { - return new Pos(-277.5, 80, -17.500); + return new Pos(-277.5, 80, -17.5); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlie.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlie.java index ef062d1f5..a0e35b5b0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlie.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlie.java @@ -40,6 +40,6 @@ public Set getValidRegions() { @Override public Pos getLocation() { - return new Pos(-277.5, 80, -17.500); + return new Pos(-277.5, 80, -17.5); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java index f8c7ba560..fac3eb988 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java @@ -45,6 +45,6 @@ public Set getValidRegions() { @Override public Pos getLocation() { - return new Pos(-277.5, 80, -17.500); + return new Pos(-277.5, 80, -17.5); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java index 42ec99156..4b7c983fd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java @@ -22,7 +22,7 @@ public class MissionGiveRyanDarkOakLogs extends SkyBlockMission implements Locat @Override public Pos getLocation() { - return new Pos(-364.5, 102.5, -90.500); + return new Pos(-364.5, 102.5, -90.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionSneakUpOnRyan.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionSneakUpOnRyan.java index d4971f034..6acbbb650 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionSneakUpOnRyan.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionSneakUpOnRyan.java @@ -14,7 +14,7 @@ public class MissionSneakUpOnRyan extends SkyBlockMission implements LocationAss @Override public Pos getLocation() { - return new Pos(-364.5, 102.5, -90.500); + return new Pos(-364.5, 102.5, -90.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionTalkToRyan.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionTalkToRyan.java index 8f6f02b65..62136e8d3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionTalkToRyan.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionTalkToRyan.java @@ -14,7 +14,7 @@ public class MissionTalkToRyan extends SkyBlockMission implements LocationAssoci @Override public Pos getLocation() { - return new Pos(-364.5, 102.5, -90.500); + return new Pos(-364.5, 102.5, -90.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionTalkToMolbert.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionTalkToMolbert.java index f29d22c30..60bf01d1c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionTalkToMolbert.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/jungle/MissionTalkToMolbert.java @@ -14,7 +14,7 @@ public class MissionTalkToMolbert extends SkyBlockMission implements LocationAss @Override public Pos getLocation() { - return new Pos(-447.5, 120, -63.500); + return new Pos(-447.5, 120, -63.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCheckOnMelody.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCheckOnMelody.java index 4ab4fbc35..b14c2813f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCheckOnMelody.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionCheckOnMelody.java @@ -40,6 +40,6 @@ public Set getValidRegions() { @Override public Pos getLocation() { - return new Pos(-411.5, 109, 71.500); + return new Pos(-411.5, 109, 71.5); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionGiveMelodyAcaciaLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionGiveMelodyAcaciaLogs.java index 2072491f5..3efc71140 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionGiveMelodyAcaciaLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/savanna/MissionGiveMelodyAcaciaLogs.java @@ -21,7 +21,7 @@ public class MissionGiveMelodyAcaciaLogs extends SkyBlockMission implements Loca @Override public Pos getLocation() { - return new Pos(-411.5, 109, 71.500); + return new Pos(-411.5, 109, 71.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionFindKelly.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionFindKelly.java index de04e80a7..5cc574129 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionFindKelly.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionFindKelly.java @@ -14,7 +14,7 @@ public class MissionFindKelly extends SkyBlockMission implements LocationAssocia @Override public Pos getLocation() { - return new Pos(-350.5, 94, 33.500); + return new Pos(-350.5, 94, 33.5); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionGiveKellySpruceLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionGiveKellySpruceLogs.java index 471cd78cc..f5e79f5dd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionGiveKellySpruceLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/spruce/MissionGiveKellySpruceLogs.java @@ -15,7 +15,7 @@ public class MissionGiveKellySpruceLogs extends SkyBlockMission implements Locat @Override public Pos getLocation() { - return new Pos(-350.5, 94, 33.500); + return new Pos(-350.5, 94, 33.5); } @Override From eb262b2483511c4a5ed82cc4af0387f4e5add0e6 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Mon, 16 Mar 2026 23:35:45 +0200 Subject: [PATCH 6/7] feat: slop --- build.gradle.kts | 12 +- .../commons/skyblock/item/ItemType.java | 124 +++ .../ItemAttributeFishingExpertiseKills.java | 27 + .../attributes/ItemAttributeFishingHook.java | 27 + .../attributes/ItemAttributeFishingLine.java | 27 + .../ItemAttributeFishingSinker.java | 27 + .../skyblock/statistics/ItemStatistic.java | 3 + configuration/skyblock/fishing/hotspots.yml | 5 + configuration/skyblock/fishing/tables.yml | 206 +++++ .../skyblock/fishing/trophy_fish.yml | 13 + .../skyblock/items/fishing/fishingContent.yml | 735 ++++++++++++++++++ .../TypeBackwaterBayouLoader.java | 4 +- .../gui/GUIFishingRodParts.java | 100 +++ .../type/backwaterbayou/gui/GUIHook.java | 48 ++ .../backwaterbayou/gui/GUIJunkerJoel.java | 461 +++++++++++ .../type/backwaterbayou/gui/GUILine.java | 48 ++ .../backwaterbayou/gui/GUIRodPartGuide.java | 64 ++ .../type/backwaterbayou/gui/GUISinker.java | 48 ++ .../backwaterbayou/npcs/NPCCaptainBaha.java | 75 ++ .../type/backwaterbayou/npcs/NPCHattie.java | 69 ++ .../backwaterbayou/npcs/NPCJunkerJoel.java | 64 ++ .../type/backwaterbayou/npcs/NPCRoddy.java | 74 ++ .../crimsonisle/TypeCrimsonIsleLoader.java | 4 +- .../data/datapoints/DatapointToggles.java | 6 + .../gui/{ => fishing}/GUIGFishingShip.java | 2 +- .../type/hub/gui/fishing/GUINavigator.java | 57 ++ .../swofty/type/hub/npcs/NPCCaptainBaha.java | 51 +- .../type/hub/npcs/NPCFishermanGerald.java | 59 +- .../type/hub/npcs/NPCFisherwomanEnid.java | 64 ++ .../SkyBlockGenericLoader.java | 2 + .../data/SkyBlockDataHandler.java | 23 +- .../data/datapoints/DatapointShipState.java | 97 +++ .../data/datapoints/DatapointTrophyFish.java | 124 +++ .../enchantment/EnchantmentType.java | 15 + .../enchantment/impl/EnchantmentAngler.java | 58 ++ .../enchantment/impl/EnchantmentBlessing.java | 51 ++ .../enchantment/impl/EnchantmentCaster.java | 51 ++ .../enchantment/impl/EnchantmentCharm.java | 34 + .../impl/EnchantmentCorruption.java | 50 ++ .../impl/EnchantmentExpertise.java | 52 ++ .../enchantment/impl/EnchantmentFlash.java | 57 ++ .../enchantment/impl/EnchantmentFrail.java | 52 ++ .../impl/EnchantmentLuckOfTheSea.java | 59 ++ .../enchantment/impl/EnchantmentLure.java | 58 ++ .../enchantment/impl/EnchantmentMagnet.java | 51 ++ .../enchantment/impl/EnchantmentPiscary.java | 59 ++ .../impl/EnchantmentQuickBite.java | 50 ++ .../impl/EnchantmentSpikedHook.java | 52 ++ .../enchantment/impl/EnchantmentTabasco.java | 53 ++ .../skyblockgeneric/entity/FishingHook.java | 162 +++- .../fishing/BaitDefinition.java | 22 + .../fishing/FishingBaitService.java | 54 ++ .../fishing/FishingCatchKind.java | 10 + .../fishing/FishingCatchResolver.java | 10 + .../fishing/FishingCatchResult.java | 15 + .../fishing/FishingContext.java | 21 + .../fishing/FishingHotspotService.java | 69 ++ .../fishing/FishingItemBootstrap.java | 25 + .../fishing/FishingItemCatalog.java | 160 ++++ .../fishing/FishingLootResolver.java | 259 ++++++ .../fishing/FishingMedium.java | 30 + .../fishing/FishingRegistry.java | 438 +++++++++++ .../fishing/FishingRodDefinition.java | 23 + .../fishing/FishingRodLoreBuilder.java | 222 ++++++ .../fishing/FishingRodPartService.java | 62 ++ .../fishing/FishingService.java | 158 ++++ .../fishing/FishingSession.java | 29 + .../fishing/FishingShipService.java | 30 + .../fishing/FishingTableDefinition.java | 19 + .../fishing/HotspotDefinition.java | 20 + .../fishing/RodPartDefinition.java | 30 + .../fishing/SeaCreatureDefinition.java | 14 + .../fishing/ShipPartDefinition.java | 19 + .../fishing/TrophyFishDefinition.java | 25 + .../fishing/FishingGuideStackFactory.java | 151 ++++ .../fishing/GUI13SeaCreatureGuide.java | 645 +++++++++++++++ .../fishing/GUI23SeaCreatureGuide.java | 574 ++++++++++++++ .../fishing/GUI33SeaCreatureGuide.java | 272 +++++++ .../gui/inventories/fishing/GUIBaitGuide.java | 42 + .../GUIFishingSkillExampleRemoveThis.java | 450 +++++++++++ .../item/ItemAttributeHandler.java | 48 +- .../item/ItemConfigParser.java | 73 ++ .../skyblockgeneric/item/SkyBlockItem.java | 28 + .../item/components/FishingBaitComponent.java | 46 ++ .../item/components/FishingRodComponent.java | 11 +- .../FishingRodMetadataComponent.java | 52 ++ .../components/FishingRodPartComponent.java | 53 ++ .../components/FishingShipPartComponent.java | 22 + .../skyblockgeneric/region/RegionType.java | 11 + .../skyblockgeneric/user/SkyBlockPlayer.java | 23 +- 90 files changed, 7933 insertions(+), 46 deletions(-) create mode 100644 commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingExpertiseKills.java create mode 100644 commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingHook.java create mode 100644 commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingLine.java create mode 100644 commons/src/main/java/net/swofty/commons/skyblock/item/attribute/attributes/ItemAttributeFishingSinker.java create mode 100644 configuration/skyblock/fishing/hotspots.yml create mode 100644 configuration/skyblock/fishing/tables.yml create mode 100644 configuration/skyblock/fishing/trophy_fish.yml create mode 100644 configuration/skyblock/items/fishing/fishingContent.yml create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIJunkerJoel.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCCaptainBaha.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCHattie.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCJunkerJoel.java create mode 100644 type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/npcs/NPCRoddy.java rename type.hub/src/main/java/net/swofty/type/hub/gui/{ => fishing}/GUIGFishingShip.java (99%) create mode 100644 type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointShipState.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentAngler.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentBlessing.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCaster.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCharm.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentCorruption.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentExpertise.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFlash.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentFrail.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLuckOfTheSea.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentLure.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentMagnet.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentPiscary.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentQuickBite.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentSpikedHook.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/enchantment/impl/EnchantmentTabasco.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingBaitService.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchKind.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResolver.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingCatchResult.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingHotspotService.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingLootResolver.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingMedium.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodLoreBuilder.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodPartService.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingSession.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingTableDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/HotspotDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/SeaCreatureDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/TrophyFishDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI13SeaCreatureGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI23SeaCreatureGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUI33SeaCreatureGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIBaitGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingSkillExampleRemoveThis.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java 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..0168a99cc --- /dev/null +++ b/configuration/skyblock/fishing/hotspots.yml @@ -0,0 +1,5 @@ +hotspots: + - x: 100 + y: 50 + z: 100 + serverType: BACKWATER_BAYOU 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/fishingContent.yml b/configuration/skyblock/items/fishing/fishingContent.yml new file mode 100644 index 000000000..2d93a58d0 --- /dev/null +++ b/configuration/skyblock/items/fishing/fishingContent.yml @@ -0,0 +1,735 @@ +items: + - id: CHALLENGE_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 75 + STRENGTH: 75 + FISHING_SPEED: 40 + SEA_CREATURE_CHANCE: 7 + TREASURE_CHANCE: 2.5 + components: + - id: FISHING_ROD_METADATA + display_name: Challenging Rod + medium: WATER + required_fishing_level: 10 + rod_parts_enabled: true + enchantments: + ANGLER: 5 + CASTER: 5 + FRAIL: 5 + IMPALING: 3 + LOOTING: 3 + LUCK_OF_THE_SEA: 5 + LURE: 5 + MAGNET: 5 + PISCARY: 5 + SPIKED_HOOK: 5 + - id: CHAMP_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 100 + STRENGTH: 100 + FISHING_SPEED: 55 + SEA_CREATURE_CHANCE: 10 + TREASURE_CHANCE: 3.0 + components: + - id: FISHING_ROD_METADATA + display_name: Rod of Champions + medium: WATER + required_fishing_level: 15 + rod_parts_enabled: true + enchantments: + ANGLER: 6 + CASTER: 5 + CHARM: 3 + FRAIL: 6 + IMPALING: 4 + LOOTING: 4 + LUCK_OF_THE_SEA: 6 + LURE: 6 + MAGNET: 5 + PISCARY: 5 + SPIKED_HOOK: 6 + - id: LEGEND_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 125 + STRENGTH: 125 + FISHING_SPEED: 70 + SEA_CREATURE_CHANCE: 14 + TREASURE_CHANCE: 3.5 + components: + - id: FISHING_ROD_METADATA + display_name: Rod of Legends + medium: WATER + required_fishing_level: 20 + rod_parts_enabled: true + enchantments: + ANGLER: 6 + CASTER: 6 + CHARM: 4 + FRAIL: 7 + IMPALING: 5 + LOOTING: 4 + LUCK_OF_THE_SEA: 7 + LURE: 6 + MAGNET: 6 + PISCARY: 6 + SPIKED_HOOK: 7 + - id: ROD_OF_THE_SEA + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 150 + STRENGTH: 150 + FISHING_SPEED: 95 + SEA_CREATURE_CHANCE: 20 + TREASURE_CHANCE: 3.5 + components: + - id: FISHING_ROD_METADATA + display_name: Rod of the Sea + medium: WATER + required_fishing_level: 24 + rod_parts_enabled: true + enchantments: + FLASH: 5 + ANGLER: 6 + BLESSING: 6 + CASTER: 6 + CHARM: 6 + CORRUPTION: 5 + EXPERTISE: 10 + FRAIL: 7 + IMPALING: 5 + LOOTING: 4 + LUCK_OF_THE_SEA: 7 + LURE: 6 + MAGNET: 6 + PISCARY: 7 + QUICK_BITE: 5 + SPIKED_HOOK: 7 + TABASCO: 3 + - 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 + display_name: Giant Fishing Rod + medium: WATER + rod_parts_enabled: true + - id: DIRT_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 20 + components: + - id: FISHING_ROD_METADATA + display_name: Dirt Rod + 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 + display_name: Starter Lava Rod + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 10 + rod_parts_enabled: true + - id: POLISHED_TOPAZ_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 80 + STRENGTH: 80 + FISHING_SPEED: 30 + TROPHY_FISH_CHANCE: 8 + components: + - id: FISHING_ROD_METADATA + display_name: Topaz Rod + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 14 + rod_parts_enabled: true + - id: MAGMA_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 110 + STRENGTH: 110 + FISHING_SPEED: 50 + TROPHY_FISH_CHANCE: 12 + components: + - id: FISHING_ROD_METADATA + display_name: Magma Rod + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 18 + rod_parts_enabled: true + - id: INFERNO_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 140 + STRENGTH: 140 + FISHING_SPEED: 70 + TROPHY_FISH_CHANCE: 16 + components: + - id: FISHING_ROD_METADATA + display_name: Inferno Rod + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 22 + rod_parts_enabled: true + - id: HELLFIRE_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 175 + STRENGTH: 175 + FISHING_SPEED: 95 + TROPHY_FISH_CHANCE: 22 + components: + - id: FISHING_ROD_METADATA + display_name: Hellfire Rod + subtitle: Lava Rod + medium: LAVA + required_fishing_level: 26 + rod_parts_enabled: true + - id: CHUM_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 20 + STRENGTH: 10 + FISHING_SPEED: 30 + components: + - id: FISHING_ROD_METADATA + display_name: Chum Rod + medium: WATER + required_fishing_level: 4 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: CHUM_SINKER + - id: PRISMARINE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 10 + FISHING_SPEED: 10 + components: + - id: FISHING_ROD_METADATA + display_name: Prismarine Rod + medium: WATER + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: PRISMARINE_SINKER + - id: SPONGE_ROD + material: FISHING_ROD + rarity: COMMON + default_statistics: + DAMAGE: 10 + FISHING_SPEED: 10 + components: + - id: FISHING_ROD_METADATA + display_name: Sponge Rod + medium: WATER + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: SPONGE_SINKER + - id: SPEEDSTER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 30 + STRENGTH: 15 + FISHING_SPEED: 45 + components: + - id: FISHING_ROD_METADATA + display_name: Speedster Rod + medium: WATER + required_fishing_level: 6 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: SPEEDY_LINE + - id: FARMER_ROD + material: FISHING_ROD + rarity: UNCOMMON + default_statistics: + DAMAGE: 50 + STRENGTH: 20 + FISHING_SPEED: 60 + components: + - id: FISHING_ROD_METADATA + display_name: Farmer's Rod + medium: WATER + required_fishing_level: 8 + rod_parts_enabled: false + 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 + display_name: Ice Rod + medium: WATER + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: ICY_SINKER + - id: WINTER_ROD + material: FISHING_ROD + rarity: RARE + default_statistics: + DAMAGE: 50 + STRENGTH: 50 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + display_name: Winter Rod + medium: WATER + required_fishing_level: 10 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: FESTIVE_SINKER + - id: YETI_ROD + material: FISHING_ROD + rarity: EPIC + default_statistics: + DAMAGE: 150 + STRENGTH: 130 + FISHING_SPEED: 75 + components: + - id: FISHING_ROD_METADATA + display_name: Yeti Rod + medium: WATER + required_fishing_level: 25 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: ICY_SINKER + - id: THE_SHREDDER + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 120 + STRENGTH: 15 + FEROCITY: 50 + FISHING_SPEED: 115 + components: + - id: FISHING_ROD_METADATA + display_name: Shredder + medium: WATER + required_fishing_level: 20 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: SHREDDED_LINE + - id: PHANTOM_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 200 + STRENGTH: 125 + FISHING_SPEED: 100 + components: + - id: FISHING_ROD_METADATA + display_name: Phantom Rod + medium: WATER + required_fishing_level: 21 + rod_parts_enabled: false + legacy_conversion_target: CHALLENGE_ROD + legacy_conversion_part: PHANTOM_HOOK + - id: AUGER_ROD + material: FISHING_ROD + rarity: LEGENDARY + default_statistics: + DAMAGE: 135 + STRENGTH: 90 + FISHING_SPEED: 110 + components: + - id: FISHING_ROD_METADATA + display_name: Auger Rod + medium: WATER + required_fishing_level: 25 + rod_parts_enabled: false + legacy_conversion_target: ROD_OF_THE_SEA + legacy_conversion_part: ICY_SINKER + - id: COMMON_HOOK + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + display_name: Common Hook + 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 + display_name: Hotspot Hook + 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 + display_name: Phantom Hook + 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 + display_name: Treasure Hook + 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 + display_name: Speedy Line + 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 + display_name: Shredded Line + 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 + display_name: Titan Line + category: LINE + required_fishing_level: 35 + texture: 9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9 + - id: JUNK_SINKER + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_ROD_PART + display_name: Junk Sinker + 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 + display_name: Prismarine Sinker + 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 + display_name: Sponge Sinker + 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 + display_name: Chum Sinker + 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 + display_name: Festive Sinker + 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 + display_name: Icy Sinker + 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 + display_name: Stingy Sinker + 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 + display_name: Hotspot Sinker + category: SINKER + required_fishing_level: 20 + hotspot_buff_multiplier: 2.0 + texture: 88891d33b55dd1572814527b9c027ec724909c26281a197d0309fbfa925cbce4 + - id: MINNOW_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + display_name: Minnow Bait + texture: b8e749ba141c054bb0c125320b17677bdcb3a7e9807a57527c0877b94548a2e + - id: FISH_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 45 + components: + - id: FISHING_BAIT + display_name: Fish Bait + texture: 49e8dc9fdc9f00e1d17666a4787d34cca7cc6dc030f0dc686195546f81c6f22 + - id: LIGHT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + display_name: Light Bait + texture: e3bcc16f402342b4acd29aecac72d1d5a116e0abb478bb4960e734fd70686ba + - id: DARK_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + display_name: Dark Bait + texture: 7281618a5c8239078fd43fef8eae14ea00665f635bd56d4451cccd5d0fa11821 + - id: SPIKED_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + SEA_CREATURE_CHANCE: 6 + components: + - id: FISHING_BAIT + display_name: Spiked Bait + texture: e42c436c6580fad217323b9f045daa23a9f88219ac26506637669eff20901f74 + - id: SPOOKY_BAIT + material: PLAYER_HEAD + rarity: COMMON + default_statistics: + FISHING_SPEED: 25 + components: + - id: FISHING_BAIT + display_name: Spooky Bait + tag_bonuses: + SPOOKY: 15 + texture: 977eab558e6a90f7cedd72c2416c891f47d71eb4e7bdcc299a6335286f5cba98 + - id: CARROT_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + display_name: Carrot Bait + texture: 4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b + - id: CORRUPTED_BAIT + material: PLAYER_HEAD + rarity: COMMON + components: + - id: FISHING_BAIT + display_name: Corrupted Bait + texture: 4bbcddd45cd347865bceab3e3dc5d382723463963f85ecce81cdd61b53db14e4 + - id: BLESSED_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + display_name: Blessed Bait + treasure_quality_bonus: 50 + texture: c2b910b5897cdb86b21ebfcba544afa470ae6d228bee3494427c9c7e8f33502b + - id: ICE_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + display_name: Ice Bait + tag_bonuses: + WINTER: 20 + texture: 609e161bdc325c71572a548a79bb15481c924d63e4fb821379d5dd6c8929f39f + - id: SHARK_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + display_name: Shark 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 + display_name: Glowy Chum Bait + texture: dfdc1eed684dd805eae96d132e3da53d64267d7361388d5e2c67f5969871e71d + - id: HOT_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + default_statistics: + FISHING_SPEED: 15 + components: + - id: FISHING_BAIT + display_name: Hot 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 + display_name: Worm Bait + texture: df03ad96092f3f789902436709cdf69de6b727c121b3c2daef9ffa1ccaed186c + - id: FROZEN_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + display_name: Frozen Bait + tag_bonuses: + WINTER: 35 + texture: 38dc68a97cefe92c8cdaa7cb1a7a4de8f16c161da736edf54f79b74beecd6513 + - id: GOLDEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + display_name: Golden Bait + treasure_chance_bonus: 4 + texture: 72e2908dbb112dcd0b367df43fafcc41a56d9cf803e90a367834b4911f84f391 + - id: TREASURE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 10 + components: + - id: FISHING_BAIT + display_name: Treasure Bait + treasure_chance_bonus: 2 + texture: c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e + - id: WOODEN_BAIT + material: PLAYER_HEAD + rarity: UNCOMMON + components: + - id: FISHING_BAIT + display_name: Wooden Bait + texture: 5b236a39e51a39dff9bced39333a73413984bc74db37c1318bfc4a4459f035d2 + - id: HOTSPOT_BAIT + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_BAIT + display_name: Hotspot Bait + tag_bonuses: + HOTSPOT: 50 + texture: de9b17db5c4cadef737e2fefb42a0123c32cbeaa1ca8932579eb2f05018612cd + - id: WHALE_BAIT + material: PLAYER_HEAD + rarity: RARE + default_statistics: + FISHING_SPEED: 30 + components: + - id: FISHING_BAIT + display_name: Whale Bait + texture: 5b4fb49ae77cfcf0b8f62df9c69cc96b27096ad2737d6d0aa450b50664fb2303 + - id: RUSTY_SHIP_ENGINE + material: PLAYER_HEAD + rarity: SPECIAL + components: + - id: FISHING_SHIP_PART + display_name: Rusty Ship Engine + slot: ENGINE + texture: 53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c + - id: BRONZE_SHIP_ENGINE + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + display_name: Bronze Ship Engine + slot: ENGINE + texture: 9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925 + - id: BRONZE_SHIP_HELM + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + display_name: Bronze Ship Helm + slot: HELM + texture: 646c5393c3c57742c992c56a7b7a8b98d267538de947c1096fe76341431008f2 + - id: BRONZE_SHIP_HULL + material: PLAYER_HEAD + rarity: RARE + components: + - id: FISHING_SHIP_PART + display_name: Bronze Ship Hull + slot: HULL + texture: a4a7254f1ad8448097d83ddfc790c9f02bc889acbd304b414cee5a13ceadc1e 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..135a02aa8 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIFishingRodParts.java @@ -0,0 +1,100 @@ +package net.swofty.type.backwaterbayou.gui; + +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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.FishingRodDefinition; +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(); + FishingRodDefinition def = type == null ? null : FishingItemCatalog.getRod(type.name()); + if (def == null || !def.rodPartsEnabled()) { + 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 GUIHook())); + + 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 GUILine())); + + 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 GUISinker())); + + 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.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..5dfd61149 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIHook.java @@ -0,0 +1,48 @@ +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.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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; + +public class GUIHook 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { + if (part.category() != RodPartDefinition.PartCategory.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.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..0572d1b34 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java @@ -0,0 +1,48 @@ +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.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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; + +public class GUILine 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { + if (part.category() != RodPartDefinition.PartCategory.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.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..a1b29cff4 --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUIRodPartGuide.java @@ -0,0 +1,64 @@ +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.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 GUIHook())); + layout.slot(22, ItemStackCreator.getStackHead( + "§9ꨃ Lines", + "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", + 1, + "§9Lines §7grant you stat bonuses", + "§7everywhere.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUILine())); + layout.slot(24, ItemStackCreator.getStackHead( + "§9࿉ Sinkers", + "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", + 1, + "§9Sinkers §7add special fishing effects", + "§7to your rod.", + "", + "§eClick to view!" + ), (_, viewCtx) -> viewCtx.push(new GUISinker())); + layout.slot(48, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Fishing Rod Parts" + ), (_, viewCtx) -> viewCtx.pop()); + } +} 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..cbe71b12f --- /dev/null +++ b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUISinker.java @@ -0,0 +1,48 @@ +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.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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; + +public class GUISinker 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { + if (part.category() != RodPartDefinition.PartCategory.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.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 7b2503008..325191e64 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 @@ -118,6 +118,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/GUIGFishingShip.java b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java similarity index 99% rename from type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java rename to type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java index 5886b6a03..5a8eebfb6 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIGFishingShip.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUIGFishingShip.java @@ -1,4 +1,4 @@ -package net.swofty.type.hub.gui; +package net.swofty.type.hub.gui.fishing; import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; 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..7ffca738b --- /dev/null +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/fishing/GUINavigator.java @@ -0,0 +1,57 @@ +package net.swofty.type.hub.gui.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.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; + +public class GUINavigator extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Navigator", InventoryType.CHEST_6_ROW); + } + + // todo: make this work with the mission + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + 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); + + 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.", + "", + "§eClick to travel!" + )); + layout.slot(40, ItemStackCreator.getStackHead( + "§bFishing Outpost", + "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", + 1, + "§7Your base of operations.", + "", + "§a§lYOU ARE HERE!" + )); + } +} 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 index d5ade58e1..4e86e12fd 100644 --- 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 @@ -1,11 +1,19 @@ 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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.FishingShipService; +import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.stream.Stream; @@ -30,7 +38,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(179.5, 69, 55.5, 105, 0); + return new Pos(162.5, 69, -65.5, 105, 0); } @Override @@ -42,18 +50,49 @@ public boolean looking(HypixelPlayer player) { @Override public void onClick(NPCInteractEvent event) { - HypixelPlayer player = event.player(); + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); if (isInDialogue(player)) return; - if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_GAVIN)) { + 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_GAVIN, true); + player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_CAPTAIN_BAHA, true); }); return; } - setDialogue(player, "idle-" + (int)(Math.random() * 2 + 1)); - // TODO: new GUIFishingShip().open(player); + 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(() -> { + ShipPartDefinition definition = FishingItemCatalog.getShipPart(ItemType.RUSTY_SHIP_ENGINE.name()); + if (definition != null) { + FishingShipService.installPart(player, 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 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 012fab80e..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,7 @@ 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; @@ -32,7 +33,7 @@ public String texture(HypixelPlayer player) { @Override public Pos position(HypixelPlayer player) { - return new Pos(153.5, 68.5, 55.5, -60, 0); + return new Pos(118.5, 71, -32.5, 180, 0); } @Override @@ -60,7 +61,22 @@ public void onClick(NPCInteractEvent event) { return; } - // TODO: finish this quest + 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 @@ -77,6 +93,45 @@ 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); } 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.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/SkyBlockGenericLoader.java index 9c1f868e7..2b3c82676 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 @@ -60,6 +60,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; @@ -174,6 +175,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 4b01c28b0..d55a4c4dc 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 @@ -11,7 +11,14 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.data.DataHandler; import net.swofty.type.generic.data.Datapoint; -import net.swofty.type.generic.data.datapoints.*; +import net.swofty.type.generic.data.datapoints.DatapointBoolean; +import net.swofty.type.generic.data.datapoints.DatapointDouble; +import net.swofty.type.generic.data.datapoints.DatapointInteger; +import net.swofty.type.generic.data.datapoints.DatapointLong; +import net.swofty.type.generic.data.datapoints.DatapointMapStringLong; +import net.swofty.type.generic.data.datapoints.DatapointPresentYear; +import net.swofty.type.generic.data.datapoints.DatapointString; +import net.swofty.type.generic.data.datapoints.DatapointStringList; import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.user.HypixelPlayer; @@ -30,7 +37,11 @@ import org.tinylog.Logger; import tools.jackson.core.JacksonException; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.Function; @@ -362,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")), @@ -512,4 +529,4 @@ public static void startRepeatSetValueLoop() { return TaskSchedule.nextTick(); }); } -} \ No newline at end of file +} 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..4193ff3bf --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/data/datapoints/DatapointTrophyFish.java @@ -0,0 +1,124 @@ +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()); + 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) + )); + } + 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() + ))); + 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; + + public void increment(String tier) { + switch (tier.toUpperCase()) { + case "DIAMOND" -> diamond++; + case "GOLD" -> gold++; + case "SILVER" -> silver++; + default -> bronze++; + } + 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 index 93033b42f..1686e8a5d 100644 --- 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 @@ -6,7 +6,6 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityType; -import net.minestom.server.entity.Player; import net.minestom.server.entity.metadata.other.FishingHookMeta; import net.minestom.server.event.entity.EntityTickEvent; import net.minestom.server.instance.Instance; @@ -16,6 +15,15 @@ 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.BaitDefinition; +import net.swofty.type.skyblockgeneric.fishing.FishingItemCatalog; +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.user.SkyBlockPlayer; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -32,7 +40,10 @@ public class FishingHook { 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 final Player owner; + 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 @@ -40,9 +51,16 @@ public class FishingHook { private double bobTick = 0; private double pullDownOffset = 0; private Double stableWaterY = null; + private Task nextBiteTask; + private Task biteExpiryTask; + private boolean sessionStarted = false; - public FishingHook(Player owner) { + public FishingHook(SkyBlockPlayer owner, SkyBlockItem rod) { this.owner = owner; + this.rod = rod; + String itemId = rod.getAttributeHandler().getPotentialType() == null ? null : rod.getAttributeHandler().getPotentialType().name(); + var rodDefinition = FishingItemCatalog.getRod(itemId); + this.requiredMedium = rodDefinition == null ? FishingMedium.WATER : rodDefinition.medium(); this.hook = new Entity(EntityType.FISHING_BOBBER); this.hook.editEntityMeta(FishingHookMeta.class, meta -> { @@ -56,7 +74,7 @@ public FishingHook(Player owner) { event -> tick(event.getEntity())); } - public static FishingHook getFishingHookForOwner(@NotNull Player owner) { + public static FishingHook getFishingHookForOwner(@NotNull SkyBlockPlayer owner) { for (FishingHook fishingHook : activeHooks) { if (fishingHook.owner.getUuid().equals(owner.getUuid())) { return fishingHook; @@ -65,8 +83,15 @@ public static FishingHook getFishingHookForOwner(@NotNull Player owner) { return null; } - private static boolean isNotWater(@NotNull Block block) { - return !block.isLiquid() || !block.name().contains("water"); + 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) { @@ -115,7 +140,24 @@ private void tick(@NotNull Entity controller) { return; } - // Hook is in water + 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)); @@ -138,6 +180,7 @@ private void tick(@NotNull Entity controller) { new Pos(0.1, 0.001, 0.1), 0, 5 )); + startFishingSession(); } bobTick += BOB_SPEED; @@ -154,15 +197,8 @@ private void tick(@NotNull Entity controller) { public boolean notInWater() { Instance instance = controller.getInstance(); Pos pos = controller.getPosition(); - // Check the block at the entity's precise location - Block currentBlock = instance.getBlock(pos); - - // Check the block slightly below the entity's location - Block blockBelow = instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0)); - - // The hook is considered "in water" if either its current block OR - // the block directly below it is water. - return isNotWater(currentBlock) && isNotWater(blockBelow); + return getMedium(instance.getBlock(pos)) == null + && getMedium(instance.getBlock(pos.add(0, WATER_CHECK_OFFSET, 0))) == null; } public void showBiteAnimation() { @@ -189,10 +225,21 @@ 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; @@ -209,4 +256,85 @@ public Scheduler getScheduler() { public Instance getInstance() { return controller.getInstance(); } -} \ No newline at end of file + + public Pos getSpawnPosition() { + return controller.getPosition(); + } + + private void startFishingSession() { + if (sessionStarted) { + return; + } + + FishingSession session = FishingService.beginCast(owner, rod, requiredMedium); + sessionStarted = true; + BaitDefinition bait = FishingItemCatalog.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)); + BaitDefinition bait = FishingItemCatalog.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/BaitDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java new file mode 100644 index 000000000..a3266fd4c --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java @@ -0,0 +1,22 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public record BaitDefinition( + String itemId, + String displayName, + ItemStatistics statistics, + List lore, + Map tagBonuses, + double treasureChanceBonus, + double treasureQualityBonus, + double trophyFishChanceBonus, + double doubleHookChanceBonus, + List mediums, + @Nullable String texture +) { +} 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..3a0f8e48d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingBaitService.java @@ -0,0 +1,54 @@ +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.updater.PlayerItemUpdater; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +public final class FishingBaitService { + private FishingBaitService() { + } + + public static @Nullable BaitDefinition 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; + } + + BaitDefinition bait = FishingItemCatalog.getBait(type.name()); + if (bait == null) { + continue; + } + if (!bait.mediums().isEmpty() && !bait.mediums().contains(medium)) { + continue; + } + return bait; + } + 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..9525d40df --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingContext.java @@ -0,0 +1,21 @@ +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.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +public record FishingContext( + SkyBlockPlayer player, + SkyBlockItem rod, + FishingMedium medium, + @Nullable BaitDefinition bait, + @Nullable RodPartDefinition hook, + @Nullable RodPartDefinition line, + @Nullable RodPartDefinition 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..7fb4a1a1b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingHotspotService.java @@ -0,0 +1,69 @@ +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(); + + 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); + 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/FishingItemBootstrap.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java new file mode 100644 index 000000000..f2fd40efa --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java @@ -0,0 +1,25 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; + +public final class FishingItemBootstrap { + private FishingItemBootstrap() { + } + + public static void applyDefaults(SkyBlockItem item) { + if (item.getAttributeHandler().getPotentialType() == null) { + return; + } + + FishingRodDefinition definition = FishingItemCatalog.getRod(item.getAttributeHandler().getPotentialType().name()); + if (definition == null) { + return; + } + + if (item.getAttributeHandler().getEnchantments().findAny().isEmpty()) { + definition.enchantments().forEach((type, level) -> + item.getAttributeHandler().addEnchantment(new SkyBlockEnchantment(type, level))); + } + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java new file mode 100644 index 000000000..2942d7f7e --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java @@ -0,0 +1,160 @@ +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.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.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +public final class FishingItemCatalog { + private FishingItemCatalog() { + } + + public static @Nullable FishingRodDefinition getRod(@Nullable String itemId) { + if (itemId == null) { + return null; + } + + ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); + if (item == null || !item.hasComponent(FishingRodMetadataComponent.class)) { + return null; + } + + FishingRodMetadataComponent component = item.getComponent(FishingRodMetadataComponent.class); + return new FishingRodDefinition( + itemId, + component.getDisplayName(), + component.getSubtitle(), + component.getMedium(), + component.getRequiredFishingLevel(), + item.getDefaultStatistics(), + component.getEnchantments(), + item.getLore(), + component.getLegacyConversionTarget(), + component.getLegacyConversionPart(), + component.isRodPartsEnabled() + ); + } + + public static @Nullable RodPartDefinition getRodPart(@Nullable String itemId) { + if (itemId == null) { + return null; + } + + ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); + if (item == null || !item.hasComponent(FishingRodPartComponent.class)) { + return null; + } + + FishingRodPartComponent component = item.getComponent(FishingRodPartComponent.class); + return new RodPartDefinition( + itemId, + component.getDisplayName(), + component.getCategory(), + component.getRequiredFishingLevel(), + item.getDefaultStatistics(), + item.getLore(), + component.getTagBonuses(), + component.isTreasureOnly(), + component.isBayouTreasureToJunk(), + component.getMaterializedItemId(), + component.getMaterializedChance(), + component.getBaitPreservationChance(), + component.getHotspotBuffMultiplier(), + component.getTexture() + ); + } + + public static @Nullable BaitDefinition getBait(@Nullable String itemId) { + if (itemId == null) { + return null; + } + + ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); + if (item == null || !item.hasComponent(FishingBaitComponent.class)) { + return null; + } + + FishingBaitComponent component = item.getComponent(FishingBaitComponent.class); + return new BaitDefinition( + itemId, + component.getDisplayName(), + item.getDefaultStatistics(), + item.getLore(), + component.getTagBonuses(), + component.getTreasureChanceBonus(), + component.getTreasureQualityBonus(), + component.getTrophyFishChanceBonus(), + component.getDoubleHookChanceBonus(), + component.getMediums(), + component.getTexture() + ); + } + + public static @Nullable ShipPartDefinition getShipPart(@Nullable String itemId) { + if (itemId == null) { + return null; + } + + ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); + if (item == null || !item.hasComponent(FishingShipPartComponent.class)) { + return null; + } + + FishingShipPartComponent component = item.getComponent(FishingShipPartComponent.class); + return new ShipPartDefinition( + itemId, + component.getDisplayName(), + component.getSlot(), + item.getLore(), + component.getTexture() + ); + } + + public static List getRods() { + return Arrays.stream(ItemType.values()) + .map(ItemType::name) + .map(FishingItemCatalog::getRod) + .filter(Objects::nonNull) + .sorted(Comparator.comparingInt(FishingRodDefinition::requiredFishingLevel) + .thenComparing(FishingRodDefinition::displayName)) + .toList(); + } + + public static List getRodParts() { + return Arrays.stream(ItemType.values()) + .map(ItemType::name) + .map(FishingItemCatalog::getRodPart) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(RodPartDefinition::category) + .thenComparingInt(RodPartDefinition::requiredFishingLevel) + .thenComparing(RodPartDefinition::displayName)) + .toList(); + } + + public static List getBaits() { + return Arrays.stream(ItemType.values()) + .map(ItemType::name) + .map(FishingItemCatalog::getBait) + .filter(Objects::nonNull) + .sorted(Comparator.comparing((BaitDefinition bait) -> ItemType.valueOf(bait.itemId()).rarity.ordinal()) + .thenComparing(BaitDefinition::displayName)) + .toList(); + } + + public static List getShipParts() { + return Arrays.stream(ItemType.values()) + .map(ItemType::name) + .map(FishingItemCatalog::getShipPart) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(ShipPartDefinition::slot).thenComparing(ShipPartDefinition::displayName)) + .toList(); + } +} \ No newline at end of file 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..24152bfc6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingLootResolver.java @@ -0,0 +1,259 @@ +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 java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public final class FishingLootResolver { + private FishingLootResolver() { + } + + public static FishingCatchResult resolve(FishingContext context) { + FishingCatchResult trophyFish = tryResolveTrophyFish(context); + if (trophyFish != null) { + return trophyFish; + } + + FishingCatchResult questCatch = tryResolveQuestCatch(context); + if (questCatch != null) { + return questCatch; + } + + 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().trophyFishChanceBonus(); + } + + 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(); + } + + 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().treasureOnly()) { + 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().treasureChanceBonus(); + } + if (context.sinker() != null && context.sinker().bayouTreasureToJunk()) { + treasureChance += 10.0D; + } + + if (!table.treasures().isEmpty() && Math.random() * 100 <= treasureChance) { + pool = context.sinker() != null && context.sinker().bayouTreasureToJunk() ? 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) { + for (FishingTableDefinition definition : FishingRegistry.getTables()) { + if (!definition.mediums().isEmpty() && !definition.mediums().contains(context.medium())) { + continue; + } + if (definition.regions().isEmpty()) { + return definition; + } + if (context.regionId() != null && definition.regions().contains(context.regionId())) { + return definition; + } + } + return null; + } + + 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) { + total += context.bait().statistics().getOverall(statistic); + } + return total; + } + + private static double getTagBonus(FishingContext context, List tags) { + double total = 0.0D; + if (context.hook() != null) { + total += getTagBonus(context.hook().tagBonuses(), tags); + } + if (context.line() != null) { + total += getTagBonus(context.line().tagBonuses(), tags); + } + if (context.sinker() != null) { + total += getTagBonus(context.sinker().tagBonuses(), tags); + } + if (context.bait() != null) { + total += getTagBonus(context.bait().tagBonuses(), 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/FishingRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java new file mode 100644 index 000000000..0befec050 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRegistry.java @@ -0,0 +1,438 @@ +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 net.swofty.type.skyblockgeneric.entity.mob.MobType; +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 SEA_CREATURES = new LinkedHashMap<>(); + private static final Map TROPHY_FISH = new LinkedHashMap<>(); + private static final Map HOTSPOTS = new LinkedHashMap<>(); + + private FishingRegistry() { + } + + public static void loadAll() { + TABLES.clear(); + SEA_CREATURES.clear(); + TROPHY_FISH.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")); + loadSeaCreatures(new File(FISHING_DIR, "sea_creatures.yml")); + loadTrophyFish(new File(FISHING_DIR, "trophy_fish.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 { + 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, + string(entry, "displayName"), + intValue(entry, "requiredFishingLevel", 0), + doubleValue(entry, "skillXp", 0.0D), + stringList(entry.get("tags")), + nullableString(entry, "corruptedVariantId") + )); + } + } + + @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()); + int generatedId = 1; + for (Map entry : entries) { + if (entry.containsKey("x") && entry.containsKey("y") && entry.containsKey("z")) { + String serverType = normalizeServerType(nullableString(entry, "serverType")); + String region = nullableString(entry, "region"); + HOTSPOTS.put("POSITION_" + generatedId, new HotspotDefinition( + "POSITION_" + generatedId, + "Hotspot", + region == null ? List.of() : List.of(region.toUpperCase()), + enumValue(entry, "medium", FishingMedium.class, FishingMedium.WATER), + intValue(entry, "maxActive", defaultMaxActiveForServer(serverType)), + intValue(entry, "durationSeconds", 120), + parseStatistics((Map) entry.get("buffs"), defaultHotspotBuffs()), + stringList(entry.get("seaCreatures")), + List.of(new HotspotDefinition.SpawnPoint( + doubleValue(entry.get("x"), 0), + doubleValue(entry.get("y"), 0), + doubleValue(entry.get("z"), 0), + serverType + )) + )); + generatedId++; + continue; + } + + String id = string(entry, "id"); + HOTSPOTS.put(id, new HotspotDefinition( + id, + string(entry, "displayName"), + stringList(entry.get("regions")), + enumValue(entry, "medium", FishingMedium.class, FishingMedium.WATER), + intValue(entry, "maxActive", 1), + intValue(entry, "durationSeconds", 120), + parseStatistics((Map) entry.get("buffs"), defaultHotspotBuffs()), + stringList(entry.get("seaCreatures")), + parseHotspotSpawnPoints((List>) entry.get("positions"), nullableString(entry, "serverType")) + )); + } + } + + + 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; + } + + private static List parseMobTypes(@Nullable List values) { + if (values == null || values.isEmpty()) { + return List.of(); + } + + List mobTypes = new ArrayList<>(); + for (Object value : values) { + mobTypes.add(MobType.valueOf(String.valueOf(value).toUpperCase())); + } + return mobTypes; + } + + private static List parseHotspotSpawnPoints(@Nullable List> entries, @Nullable String fallbackServerType) { + if (entries == null || entries.isEmpty()) { + return List.of(); + } + + List points = new ArrayList<>(); + for (Map entry : entries) { + points.add(new HotspotDefinition.SpawnPoint( + doubleValue(entry.get("x"), 0), + doubleValue(entry.get("y"), 0), + doubleValue(entry.get("z"), 0), + normalizeServerType(nullableString(entry, "serverType"), fallbackServerType) + )); + } + return points; + } + + 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; + } + + private static Map parseStringDoubleMap(@Nullable Map values) { + if (values == null || values.isEmpty()) { + return Map.of(); + } + + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : values.entrySet()) { + result.put(entry.getKey(), doubleValue(entry.getValue(), 0.0D)); + } + return result; + } + + private static String string(Map entry, String key) { + Object value = entry.get(key); + if (value == null) { + throw new IllegalArgumentException("Missing fishing config key: " + key); + } + return String.valueOf(value); + } + + private static @Nullable String nullableString(Map entry, String key) { + Object value = entry.get(key); + if (value == null) { + return null; + } + String stringValue = String.valueOf(value); + return stringValue.isEmpty() ? null : stringValue; + } + + private static List stringList(@Nullable Object raw) { + if (!(raw instanceof List list)) { + return List.of(); + } + List values = new ArrayList<>(); + for (Object entry : list) { + values.add(String.valueOf(entry)); + } + return values; + } + + private static int intValue(Map entry, String key, int defaultValue) { + return intValue(entry.get(key), defaultValue); + } + + private static int intValue(@Nullable Object value, int defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Number number) { + return number.intValue(); + } + return Integer.parseInt(String.valueOf(value)); + } + + private static long longValue(Map entry, String key, long defaultValue) { + return longValue(entry.get(key), defaultValue); + } + + private static long longValue(@Nullable Object value, long defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Number number) { + return number.longValue(); + } + return Long.parseLong(String.valueOf(value)); + } + + private static double doubleValue(Map entry, String key, double defaultValue) { + return doubleValue(entry.get(key), defaultValue); + } + + private static double doubleValue(@Nullable Object value, double defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Number number) { + return number.doubleValue(); + } + return Double.parseDouble(String.valueOf(value)); + } + + private static @Nullable Double nullableDouble(@Nullable Object value) { + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.doubleValue(); + } + String stringValue = String.valueOf(value); + return stringValue.isEmpty() ? null : Double.parseDouble(stringValue); + } + + private static boolean booleanValue(Map entry, String key, boolean defaultValue) { + Object value = entry.get(key); + if (value == null) { + return defaultValue; + } + if (value instanceof Boolean bool) { + return bool; + } + return Boolean.parseBoolean(String.valueOf(value)); + } + + private static > T enumValue(Map entry, String key, Class type, T defaultValue) { + Object value = entry.get(key); + if (value == null) { + return defaultValue; + } + return Enum.valueOf(type, String.valueOf(value).toUpperCase()); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java new file mode 100644 index 000000000..38d102af1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java @@ -0,0 +1,23 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public record FishingRodDefinition( + String itemId, + String displayName, + @Nullable String subtitle, + FishingMedium medium, + int requiredFishingLevel, + ItemStatistics statistics, + Map enchantments, + List lore, + @Nullable String legacyConversionTarget, + @Nullable String legacyConversionPart, + boolean rodPartsEnabled +) { +} 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..d108ad7bc --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodLoreBuilder.java @@ -0,0 +1,222 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.commons.skyblock.item.Rarity; +import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeHotPotatoBookData; +import net.swofty.commons.skyblock.item.reforge.Reforge; +import net.swofty.commons.skyblock.statistics.ItemStatistic; +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +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.TREASURE_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE, + ItemStatistic.MAGIC_FIND + ); + + private FishingRodLoreBuilder() { + } + + public static @Nullable FishingRodLore build(SkyBlockItem item, @Nullable SkyBlockPlayer player) { + ItemType itemType = item.getAttributeHandler().getPotentialType(); + if (itemType == null) { + return null; + } + + FishingRodDefinition definition = FishingItemCatalog.getRod(itemType.name()); + if (definition == null) { + return null; + } + + var handler = item.getAttributeHandler(); + Rarity rarity = handler.isRecombobulated() ? handler.getRarity().upgrade() : handler.getRarity(); + + String displayName = definition.displayName(); + Reforge reforge = handler.getReforge(); + if (reforge != null) { + displayName = reforge.getPrefix() + " " + displayName; + } + displayName = rarity.getColor() + displayName; + + List lore = new ArrayList<>(); + if (definition.subtitle() != null) { + lore.add("§8" + definition.subtitle()); + lore.add(""); + } + + for (ItemStatistic statistic : STAT_ORDER) { + String line = buildStatLine(item, definition, rarity, statistic); + if (line != null) { + lore.add(line); + } + } + + lore.addAll(definition.lore()); + if (!lore.isEmpty() && !lore.getLast().isEmpty()) { + lore.add(""); + } + + List enchantLines = buildEnchantLines(item, rarity); + lore.addAll(enchantLines); + if (!enchantLines.isEmpty()) { + lore.add(""); + } + + if (definition.rodPartsEnabled()) { + RodPartDefinition hook = FishingRodPartService.getHook(item); + RodPartDefinition line = FishingRodPartService.getLine(item); + RodPartDefinition sinker = FishingRodPartService.getSinker(item); + + lore.add(renderPartHeader("ථ", "Hook", hook)); + if (hook != null) { + lore.addAll(renderAppliedPartLore(hook, player)); + } + lore.add(renderPartHeader("ꨃ", "Line", line)); + if (line != null) { + lore.addAll(renderAppliedPartLore(line, player)); + } + lore.add(renderPartHeader("࿉", "Sinker", sinker)); + if (sinker != null) { + lore.addAll(renderAppliedPartLore(sinker, player)); + } + lore.add(""); + lore.add("§7Talk to §2Roddy §7in the §2Backwater"); + lore.add("§2Bayou §7to apply parts to this rod."); + lore.add(""); + } else if (definition.legacyConversionTarget() != null) { + lore.add("§7§cThis rod is broken and cannot be"); + lore.add("§cused to fish."); + lore.add(""); + lore.add("§7Bring it to §2Roddy §7in the §2Backwater"); + lore.add("§2Bayou §7to convert it into a §anew rod§7!"); + lore.add(""); + } + + lore.add("§8This item can be reforged!"); + + if (handler.getFishingExpertiseKills() > 0) { + lore.add("§fKills: §6" + StringUtility.commaify(handler.getFishingExpertiseKills())); + } + + if (handler.getSoulBoundData() != null) { + lore.add("§8§l* Co-op Soulbound §l*"); + } + + if (definition.requiredFishingLevel() > 0 && player != null && + player.getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { + lore.add("§4❣ §cRequires §aFishing Skill " + definition.requiredFishingLevel() + "§c."); + } + + String footer = rarity.getDisplay() + " FISHING ROD"; + if (handler.isRecombobulated()) { + footer = rarity.getColor() + "§l§ka §l" + rarity.name() + " FISHING ROD §l§ka"; + } + lore.add(footer); + + return new FishingRodLore(displayName, lore); + } + + private static @Nullable String buildStatLine(SkyBlockItem item, FishingRodDefinition definition, Rarity rarity, ItemStatistic statistic) { + double base = definition.statistics().getOverall(statistic); + double reforge = 0.0D; + if (item.getAttributeHandler().getReforge() != null) { + reforge = item.getAttributeHandler().getReforge().getAfterCalculation(ItemStatistics.empty(), rarity.ordinal() + 1).getOverall(statistic); + } + + double part = FishingRodPartService.getStatistics(item).getOverall(statistic); + double dynamic = item.getAttributeHandler().getExtraDynamicStatistics().getOverall(statistic); + double hpb = getHotPotatoContribution(item, statistic); + double total = base + reforge + part + dynamic + hpb; + + if (total == 0) { + return null; + } + + String line = "§7" + statistic.getDisplayName() + ": " + statistic.getLoreColor() + + statistic.getPrefix() + formatNumber(total) + statistic.getSuffix(); + if (hpb != 0) { + line += " §e(" + (hpb > 0 ? "+" : "") + formatNumber(hpb) + ")"; + } + if (part != 0) { + line += " §d(" + (part > 0 ? "+" : "") + formatNumber(part) + ")"; + } else if (reforge != 0) { + line += " §9(" + (reforge > 0 ? "+" : "") + formatNumber(reforge) + ")"; + } + return line; + } + + private static double getHotPotatoContribution(SkyBlockItem item, ItemStatistic statistic) { + ItemAttributeHotPotatoBookData.HotPotatoBookData data = item.getAttributeHandler().getHotPotatoBookData(); + if (!data.hasAppliedItem()) { + return 0.0D; + } + + double total = 0.0D; + for (Map.Entry entry : data.getPotatoType().stats.entrySet()) { + if (entry.getKey() == statistic) { + total += entry.getValue(); + } + } + return total; + } + + private static List buildEnchantLines(SkyBlockItem item, Rarity rarity) { + List enchantments = item.getAttributeHandler().getEnchantments() + .sorted(Comparator.comparing(enchantment -> enchantment.type().getName())) + .toList(); + if (enchantments.isEmpty()) { + return List.of(); + } + + String enchantColor = rarity == Rarity.MYTHIC ? "§d" : "§9"; + String joined = enchantments.stream() + .map(enchantment -> enchantColor + enchantment.type().getName() + " " + StringUtility.getAsRomanNumeral(enchantment.level())) + .reduce((left, right) -> left + ", " + right) + .orElse(""); + return StringUtility.splitByWordAndLength(joined, 34); + } + + private static String renderPartHeader(String symbol, String label, @Nullable RodPartDefinition part) { + if (part == null) { + return "§9" + symbol + " " + label + " §8§lNONE"; + } + return ItemType.valueOf(part.itemId()).rarity.getColor() + symbol + " " + part.displayName(); + } + + private static List renderAppliedPartLore(RodPartDefinition part, @Nullable SkyBlockPlayer player) { + List lines = new ArrayList<>(); + for (String line : part.lore()) { + lines.add("§7" + line); + } + if (part.requiredFishingLevel() > 0 && player != null && + player.getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < part.requiredFishingLevel()) { + lines.add("§4❣ §cRequires §aFishing Skill " + part.requiredFishingLevel() + "§c."); + } + return lines; + } + + private static String formatNumber(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..87ac626a1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodPartService.java @@ -0,0 +1,62 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import org.jetbrains.annotations.Nullable; + +public final class FishingRodPartService { + private FishingRodPartService() { + } + + public static @Nullable RodPartDefinition getHook(SkyBlockItem rod) { + return getPart(FishingItemCatalog.getRodPart(rod.getAttributeHandler().getFishingHook())); + } + + public static @Nullable RodPartDefinition getLine(SkyBlockItem rod) { + return getPart(FishingItemCatalog.getRodPart(rod.getAttributeHandler().getFishingLine())); + } + + public static @Nullable RodPartDefinition getSinker(SkyBlockItem rod) { + return getPart(FishingItemCatalog.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, RodPartDefinition part) { + switch (part.category()) { + case HOOK -> rod.getAttributeHandler().setFishingHook(part.itemId()); + case LINE -> rod.getAttributeHandler().setFishingLine(part.itemId()); + case SINKER -> rod.getAttributeHandler().setFishingSinker(part.itemId()); + } + } + + public static void removePart(SkyBlockItem rod, RodPartDefinition.PartCategory category) { + switch (category) { + case HOOK -> rod.getAttributeHandler().setFishingHook(null); + case LINE -> rod.getAttributeHandler().setFishingLine(null); + case SINKER -> rod.getAttributeHandler().setFishingSinker(null); + } + } + + private static @Nullable RodPartDefinition getPart(@Nullable RodPartDefinition definition) { + return definition; + } + + private static void append(ItemStatistics.Builder builder, @Nullable RodPartDefinition definition) { + if (definition == null) { + return; + } + for (var statistic : net.swofty.commons.skyblock.statistics.ItemStatistic.values()) { + double amount = definition.statistics().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..235e2a63a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingService.java @@ -0,0 +1,158 @@ +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.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) { + BaitDefinition bait = FishingBaitService.getFirstAvailableBait(player, medium); + FishingSession session = new FishingSession( + player.getUuid(), + rod.getAttributeHandler().getPotentialType().name(), + medium, + bait == null ? null : bait.itemId(), + 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 BaitDefinition 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) { + fishingSpeed += bait.statistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); + if ("CORRUPTED_BAIT".equals(bait.itemId())) { + 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; + } + + BaitDefinition bait = FishingItemCatalog.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(); + } + RodPartDefinition sinker = FishingRodPartService.getSinker(rod); + if (!preserve && sinker != null && sinker.baitPreservationChance() > 0) { + preserve = Math.random() * 100 < sinker.baitPreservationChance(); + } + 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()); + } + + RodPartDefinition sinker = FishingRodPartService.getSinker(rod); + if (sinker != null && sinker.materializedItemId() != null && Math.random() <= sinker.materializedChance()) { + player.addAndUpdateItem(net.swofty.commons.skyblock.item.ItemType.valueOf(sinker.materializedItemId())); + } + + 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/FishingShipService.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java new file mode 100644 index 000000000..aa9167c0b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipService.java @@ -0,0 +1,30 @@ +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.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, ShipPartDefinition definition) { + DatapointShipState.ShipState state = getState(player); + switch (definition.slot()) { + case HELM -> state.setHelm(definition.itemId()); + case ENGINE -> state.setEngine(definition.itemId()); + case HULL -> state.setHull(definition.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..de0af4eb1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/HotspotDefinition.java @@ -0,0 +1,20 @@ +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(double x, double y, double z, String serverType) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java new file mode 100644 index 000000000..fbd19e56a --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java @@ -0,0 +1,30 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import net.swofty.commons.skyblock.statistics.ItemStatistics; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public record RodPartDefinition( + String itemId, + String displayName, + PartCategory category, + int requiredFishingLevel, + ItemStatistics statistics, + List lore, + Map tagBonuses, + boolean treasureOnly, + boolean bayouTreasureToJunk, + @Nullable String materializedItemId, + double materializedChance, + double baitPreservationChance, + double hotspotBuffMultiplier, + @Nullable String texture +) { + public enum PartCategory { + HOOK, + LINE, + SINKER + } +} 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..e9ceb5727 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/SeaCreatureDefinition.java @@ -0,0 +1,14 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import java.util.List; + +public record SeaCreatureDefinition( + String id, + String displayName, + int requiredFishingLevel, + double skillXp, + List tags, + String corruptedVariantId +) { +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java new file mode 100644 index 000000000..60667cf38 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java @@ -0,0 +1,19 @@ +package net.swofty.type.skyblockgeneric.fishing; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public record ShipPartDefinition( + String itemId, + String displayName, + ShipPartSlot slot, + List lore, + @Nullable String texture +) { + public enum ShipPartSlot { + HELM, + ENGINE, + HULL + } +} 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..d8d9b39e6 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/FishingGuideStackFactory.java @@ -0,0 +1,151 @@ +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.BaitDefinition; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; + +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(BaitDefinition bait) { + List lore = new ArrayList<>(); + lore.add("§8Fishing Bait"); + lore.add("§8Consumes on Cast"); + lore.add(""); + appendStatistics(lore, bait.statistics()); + appendTagBonuses(lore, bait.tagBonuses()); + + if (bait.treasureChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.treasureChanceBonus()) + " Treasure Chance§7."); + } + if (bait.treasureQualityBonus() > 0) { + lore.add("§7Increases treasure quality by §a" + format(bait.treasureQualityBonus()) + "%§7."); + } + if (bait.trophyFishChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.trophyFishChanceBonus()) + " Trophy Fish Chance§7."); + } + if (bait.doubleHookChanceBonus() > 0) { + lore.add("§7Grants §9+" + format(bait.doubleHookChanceBonus()) + " Double Hook Chance§7."); + } + if (bait.mediums().size() == 1) { + lore.add("§7Usable in §" + (bait.mediums().getFirst() == FishingMedium.WATER ? "bWater" : "cLava") + "§7."); + } + finishFooter(lore, bait.itemId(), "BAIT"); + + return ItemStackCreator.getStackHead( + coloredName(bait.itemId(), bait.displayName()), + bait.texture(), + 1, + lore.toArray(String[]::new) + ); + } + + public static net.minestom.server.item.ItemStack.Builder buildRodPartStack(RodPartDefinition part) { + List lore = new ArrayList<>(); + lore.add("§8" + StringUtility.toNormalCase(part.category().name()) + " Rod Part"); + lore.add(""); + appendStatistics(lore, part.statistics()); + appendTagBonuses(lore, part.tagBonuses()); + + if (part.treasureOnly()) { + lore.add("§7Only allows you to catch items and §6Treasure§7."); + } + if (part.bayouTreasureToJunk()) { + lore.add("§7Replaces §6Treasure §7catches with §2Junk §7in the §2Backwater Bayou§7."); + } + if (part.materializedItemId() != null) { + String itemName = ItemType.valueOf(part.materializedItemId()).getDisplayName(); + if (part.materializedChance() >= 1.0D) { + lore.add("§7Materializes §f" + itemName + " §7in your inventory whenever you catch something."); + } else { + lore.add("§7Has a §a" + format(part.materializedChance() * 100.0D) + "% §7chance to materialize §f" + itemName + "§7."); + } + } + if (part.baitPreservationChance() > 0) { + lore.add("§7Grants a §a" + format(part.baitPreservationChance()) + "% §7chance to not consume Bait."); + } + if (part.hotspotBuffMultiplier() > 1.0D) { + lore.add("§7Increases the bonuses of §dFishing Hotspots §7by §a" + format((part.hotspotBuffMultiplier() - 1.0D) * 100.0D) + "%§7."); + } + if (part.requiredFishingLevel() > 0) { + lore.add(""); + lore.add("§4❣ §cRequires §aFishing Skill " + part.requiredFishingLevel() + "§c."); + } + finishFooter(lore, part.itemId(), "ROD PART"); + + return ItemStackCreator.getStackHead( + coloredName(part.itemId(), part.displayName()), + part.texture(), + 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); + } +} \ No newline at end of file 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..5dd5df60a --- /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.FishingItemCatalog; + +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 : FishingItemCatalog.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/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/item/ItemAttributeHandler.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemAttributeHandler.java index 1b92de105..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 @@ -2,20 +2,27 @@ import net.minestom.server.color.Color; import net.swofty.commons.ServiceType; +import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocolObject; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.item.attribute.attributes.*; -import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeExtraDynamicStatistics; import net.swofty.commons.skyblock.item.reforge.Reforge; import net.swofty.commons.skyblock.item.reforge.ReforgeLoader; -import net.swofty.commons.protocol.objects.itemtracker.TrackedItemUpdateProtocolObject; import net.swofty.commons.skyblock.statistics.ItemStatistics; import net.swofty.proxyapi.ProxyService; import net.swofty.type.skyblockgeneric.abiphone.AbiphoneNPC; import net.swofty.type.skyblockgeneric.abiphone.AbiphoneRegistry; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.item.components.*; +import net.swofty.type.skyblockgeneric.item.components.BackpackComponent; +import net.swofty.type.skyblockgeneric.item.components.DefaultSoulboundComponent; +import net.swofty.type.skyblockgeneric.item.components.EnchantedComponent; +import net.swofty.type.skyblockgeneric.item.components.GemstoneComponent; +import net.swofty.type.skyblockgeneric.item.components.LeatherColorComponent; +import net.swofty.type.skyblockgeneric.item.components.MinionComponent; +import net.swofty.type.skyblockgeneric.item.components.PetComponent; +import net.swofty.type.skyblockgeneric.item.components.PetItemComponent; +import net.swofty.type.skyblockgeneric.item.components.RuneableComponent; import net.swofty.type.skyblockgeneric.minion.MinionRegistry; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import org.jetbrains.annotations.Nullable; @@ -78,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 a65be2a27..cc4015e79 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,10 @@ 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.enchantment.EnchantmentType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; import net.swofty.type.skyblockgeneric.gems.GemRarity; import net.swofty.type.skyblockgeneric.gems.Gemstone; import net.swofty.type.skyblockgeneric.item.components.*; @@ -163,6 +167,75 @@ yield new EnchantableComponent( ); } case "FISHING_ROD" -> new FishingRodComponent(); + case "FISHING_ROD_METADATA" -> { + String displayName = safeConfig.getString("display_name"); + String subtitle = safeConfig.getString("subtitle", null); + FishingMedium medium = safeConfig.containsKey("medium") + ? safeConfig.getEnum("medium", FishingMedium.class) + : FishingMedium.WATER; + int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); + Map enchantments = new java.util.EnumMap<>(EnchantmentType.class); + for (Map.Entry entry : safeConfig.getMap("enchantments").entrySet()) { + enchantments.put(EnchantmentType.valueOf(entry.getKey().toUpperCase()), ((Number) entry.getValue()).intValue()); + } + yield new FishingRodMetadataComponent( + displayName, + subtitle, + medium, + requiredFishingLevel, + enchantments, + safeConfig.getString("legacy_conversion_target", null), + safeConfig.getString("legacy_conversion_part", null), + safeConfig.getBoolean("rod_parts_enabled", true) + ); + } + case "FISHING_ROD_PART" -> { + String displayName = safeConfig.getString("display_name"); + RodPartDefinition.PartCategory category = safeConfig.getEnum("category", RodPartDefinition.PartCategory.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( + 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( + 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"); + ShipPartDefinition.ShipPartSlot slot = safeConfig.getEnum("slot", ShipPartDefinition.ShipPartSlot.class); + yield new FishingShipPartComponent(displayName, slot, safeConfig.getString("texture", null)); + } case "ENCHANTED" -> { if (safeConfig.containsKey("recipes")) { List> recipeConfigs = safeConfig.getMapList("recipes"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/SkyBlockItem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/SkyBlockItem.java index a823d800d..bfd3f5ae2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/SkyBlockItem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/SkyBlockItem.java @@ -18,6 +18,7 @@ import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeType; import net.swofty.commons.skyblock.statistics.ItemStatistics; import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.skyblockgeneric.fishing.FishingItemBootstrap; import net.swofty.type.skyblockgeneric.item.components.EnchantedComponent; import net.swofty.type.skyblockgeneric.item.components.SkullHeadComponent; import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; @@ -124,6 +125,8 @@ private void loadAsItemType(ItemType type) { ItemAttributeStatistics statisticsAttribute = (ItemAttributeStatistics) getAttribute("statistics"); statisticsAttribute.setValue(statistics.clone()); } + + FishingItemBootstrap.applyDefaults(this); } private void loadAsMaterial(Material material) { @@ -180,12 +183,37 @@ private void loadAsStack(ItemStack item) { } } + migrateLegacyFishingRodState(item); + if (config != null) { ItemAttributeStatistics statisticsAttribute = (ItemAttributeStatistics) getAttribute("statistics"); statisticsAttribute.setValue(config.getDefaultStatistics()); } } + private void migrateLegacyFishingRodState(ItemStack item) { + String legacy = item.getTag(Tag.String("fishing_rod_state")); + if (legacy == null || legacy.isBlank()) { + return; + } + + String[] parts = legacy.split(";", -1); + getAttributeHandler().setFishingHook(readLegacyFishingPart(parts, 0)); + getAttributeHandler().setFishingLine(readLegacyFishingPart(parts, 1)); + getAttributeHandler().setFishingSinker(readLegacyFishingPart(parts, 2)); + if (parts.length > 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..29b78a3e4 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingBaitComponent.java @@ -0,0 +1,46 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; + +import java.util.List; +import java.util.Map; + +@Getter +public class FishingBaitComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + 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 displayName, + Map tagBonuses, + double treasureChanceBonus, + double treasureQualityBonus, + double trophyFishChanceBonus, + double doubleHookChanceBonus, + List mediums, + String texture + ) { + this.displayName = 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 -> 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")); + } +} \ No newline at end of file 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 index 2cbed8e14..7fdad90bb 100644 --- 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 @@ -3,6 +3,8 @@ 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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.FishingService; import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; public class FishingRodComponent extends SkyBlockItemComponent { @@ -13,7 +15,9 @@ public FishingRodComponent() { (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() @@ -24,7 +28,12 @@ public FishingRodComponent() { .build() ); } else { - new FishingHook(player).spawn(player.getInstance()); + String itemId = item.getAttributeHandler().getPotentialType() == null ? null : item.getAttributeHandler().getPotentialType().name(); + var definition = FishingItemCatalog.getRod(itemId); + if (definition != null && definition.legacyConversionTarget() != 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..81a9b6faf --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodMetadataComponent.java @@ -0,0 +1,52 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.commons.skyblock.item.reforge.ReforgeType; +import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; +import net.swofty.type.skyblockgeneric.fishing.FishingMedium; +import net.swofty.type.skyblockgeneric.utility.groups.EnchantItemGroups; + +import java.util.List; +import java.util.Map; + +@Getter +public class FishingRodMetadataComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String displayName; + private final String subtitle; + private final FishingMedium medium; + private final int requiredFishingLevel; + private final Map enchantments; + private final String legacyConversionTarget; + private final String legacyConversionPart; + private final boolean rodPartsEnabled; + + public FishingRodMetadataComponent( + String displayName, + String subtitle, + FishingMedium medium, + int requiredFishingLevel, + Map enchantments, + String legacyConversionTarget, + String legacyConversionPart, + boolean rodPartsEnabled + ) { + this.displayName = displayName; + this.subtitle = subtitle; + this.medium = medium; + this.requiredFishingLevel = requiredFishingLevel; + this.enchantments = Map.copyOf(enchantments); + this.legacyConversionTarget = legacyConversionTarget; + this.legacyConversionPart = legacyConversionPart; + this.rodPartsEnabled = rodPartsEnabled; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> displayName)); + if (subtitle != null && !subtitle.isBlank()) { + addInheritedComponent(new ExtraUnderNameComponent(subtitle)); + } + 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")); + } +} \ No newline at end of file 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..16f6f2403 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingRodPartComponent.java @@ -0,0 +1,53 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; + +import java.util.Map; + +@Getter +public class FishingRodPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String displayName; + private final RodPartDefinition.PartCategory 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 displayName, + RodPartDefinition.PartCategory category, + int requiredFishingLevel, + Map tagBonuses, + boolean treasureOnly, + boolean bayouTreasureToJunk, + String materializedItemId, + double materializedChance, + double baitPreservationChance, + double hotspotBuffMultiplier, + String texture + ) { + this.displayName = 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 -> displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + addInheritedComponent(new ExtraRarityComponent("ROD PART")); + } +} \ No newline at end of file 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..3a2aef7dd --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/FishingShipPartComponent.java @@ -0,0 +1,22 @@ +package net.swofty.type.skyblockgeneric.item.components; + +import lombok.Getter; +import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; + +@Getter +public class FishingShipPartComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { + private final String displayName; + private final ShipPartDefinition.ShipPartSlot slot; + private final String texture; + + public FishingShipPartComponent(String displayName, ShipPartDefinition.ShipPartSlot slot, String texture) { + this.displayName = displayName; + this.slot = slot; + this.texture = texture; + + addInheritedComponent(new CustomDisplayNameComponent(ignored -> displayName)); + if (texture != null && !texture.isBlank()) { + addInheritedComponent(new SkullHeadComponent(ignored -> texture)); + } + } +} \ 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 9c3fb7d69..d092d6dd8 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 @@ -131,6 +131,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 17aca8a03..0f860ed9f 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 @@ -16,16 +16,21 @@ 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.swofty.commons.StringUtility; import net.swofty.commons.skyblock.PlayerShopData; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; -import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.item.UnderstandableSkyBlockItem; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.data.HypixelDataHandler; -import net.swofty.type.generic.data.datapoints.*; +import net.swofty.type.generic.data.datapoints.DatapointBoolean; +import net.swofty.type.generic.data.datapoints.DatapointDouble; +import net.swofty.type.generic.data.datapoints.DatapointInteger; +import net.swofty.type.generic.data.datapoints.DatapointLong; +import net.swofty.type.generic.data.datapoints.DatapointRank; +import net.swofty.type.generic.data.datapoints.DatapointString; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skyblockgeneric.SkyBlockGenericLoader; @@ -61,7 +66,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -521,6 +530,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(); } From 3ccfd40761befc17307bb176734dc80250a96c8a Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:06:52 +0200 Subject: [PATCH 7/7] feat: fishing stuff --- configuration/skyblock/fishing/hotspots.yml | 20 +- .../skyblock/items/fishing/baits.yml | 171 ++++ .../skyblock/items/fishing/fishingContent.yml | 735 ------------------ .../skyblock/items/fishing/parts.yml | 191 +++++ configuration/skyblock/items/fishing/rods.yml | 292 +++++++ configuration/skyblock/items/vanillaItems.yml | 5 +- .../gui/GUIFishingRodParts.java | 98 +-- .../type/backwaterbayou/gui/GUIHook.java | 46 +- .../type/backwaterbayou/gui/GUILine.java | 46 +- .../backwaterbayou/gui/GUIRodPartGuide.java | 62 +- .../type/backwaterbayou/gui/GUISinker.java | 46 +- .../type/hub/gui/fishing/GUIGFishingShip.java | 131 +--- .../type/hub/gui/fishing/GUINavigator.java | 55 +- .../swofty/type/hub/npcs/NPCCaptainBaha.java | 7 +- .../data/datapoints/DatapointTrophyFish.java | 28 +- .../skyblockgeneric/entity/FishingHook.java | 12 +- .../fishing/BaitDefinition.java | 22 - .../fishing/FishingBaitService.java | 11 +- .../fishing/FishingContext.java | 10 +- .../fishing/FishingHotspotService.java | 12 +- .../fishing/FishingItemBootstrap.java | 25 - .../fishing/FishingItemCatalog.java | 160 ---- .../fishing/FishingItemSupport.java | 93 +++ .../fishing/FishingLootResolver.java | 45 +- .../fishing/FishingPartCategory.java | 7 + .../fishing/FishingRegistry.java | 283 +++---- .../fishing/FishingRodDefinition.java | 23 - .../fishing/FishingRodLoreBuilder.java | 205 ++--- .../fishing/FishingRodPartService.java | 37 +- .../fishing/FishingService.java | 29 +- .../fishing/FishingShipPartSlot.java | 7 + .../fishing/FishingShipService.java | 11 +- .../fishing/HotspotDefinition.java | 7 +- .../fishing/RodPartDefinition.java | 30 - .../fishing/SeaCreatureDefinition.java | 5 +- .../fishing/ShipPartDefinition.java | 19 - .../fishing/FishingGuideStackFactory.java | 79 +- .../gui/inventories/fishing/GUIBaitGuide.java | 4 +- .../fishing/GUIFishingRodParts.java | 101 +++ .../inventories/fishing/GUIFishingShip.java | 155 ++++ .../gui/inventories/fishing/GUIHookGuide.java | 47 ++ .../gui/inventories/fishing/GUILineGuide.java | 47 ++ .../gui/inventories/fishing/GUINavigator.java | 89 +++ .../inventories/fishing/GUIRodPartGuide.java | 64 ++ .../inventories/fishing/GUISinkerGuide.java | 47 ++ .../item/ItemConfigParser.java | 35 +- .../type/skyblockgeneric/item/ItemLore.java | 14 +- .../skyblockgeneric/item/SkyBlockItem.java | 2 - .../item/components/FishingBaitComponent.java | 16 +- .../item/components/FishingRodComponent.java | 6 +- .../FishingRodMetadataComponent.java | 40 +- .../components/FishingRodPartComponent.java | 19 +- .../components/FishingShipPartComponent.java | 18 +- .../item/handlers/lore/LoreRegistry.java | 20 +- 54 files changed, 1778 insertions(+), 2011 deletions(-) create mode 100644 configuration/skyblock/items/fishing/baits.yml delete mode 100644 configuration/skyblock/items/fishing/fishingContent.yml create mode 100644 configuration/skyblock/items/fishing/parts.yml create mode 100644 configuration/skyblock/items/fishing/rods.yml delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemSupport.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingPartCategory.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingShipPartSlot.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingRodParts.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIFishingShip.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIHookGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUILineGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUINavigator.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUIRodPartGuide.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/fishing/GUISinkerGuide.java diff --git a/configuration/skyblock/fishing/hotspots.yml b/configuration/skyblock/fishing/hotspots.yml index 0168a99cc..c266f0dc0 100644 --- a/configuration/skyblock/fishing/hotspots.yml +++ b/configuration/skyblock/fishing/hotspots.yml @@ -1,5 +1,19 @@ hotspots: - - x: 100 - y: 50 - z: 100 + - 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/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/fishingContent.yml b/configuration/skyblock/items/fishing/fishingContent.yml deleted file mode 100644 index 2d93a58d0..000000000 --- a/configuration/skyblock/items/fishing/fishingContent.yml +++ /dev/null @@ -1,735 +0,0 @@ -items: - - id: CHALLENGE_ROD - material: FISHING_ROD - rarity: UNCOMMON - default_statistics: - DAMAGE: 75 - STRENGTH: 75 - FISHING_SPEED: 40 - SEA_CREATURE_CHANCE: 7 - TREASURE_CHANCE: 2.5 - components: - - id: FISHING_ROD_METADATA - display_name: Challenging Rod - medium: WATER - required_fishing_level: 10 - rod_parts_enabled: true - enchantments: - ANGLER: 5 - CASTER: 5 - FRAIL: 5 - IMPALING: 3 - LOOTING: 3 - LUCK_OF_THE_SEA: 5 - LURE: 5 - MAGNET: 5 - PISCARY: 5 - SPIKED_HOOK: 5 - - id: CHAMP_ROD - material: FISHING_ROD - rarity: RARE - default_statistics: - DAMAGE: 100 - STRENGTH: 100 - FISHING_SPEED: 55 - SEA_CREATURE_CHANCE: 10 - TREASURE_CHANCE: 3.0 - components: - - id: FISHING_ROD_METADATA - display_name: Rod of Champions - medium: WATER - required_fishing_level: 15 - rod_parts_enabled: true - enchantments: - ANGLER: 6 - CASTER: 5 - CHARM: 3 - FRAIL: 6 - IMPALING: 4 - LOOTING: 4 - LUCK_OF_THE_SEA: 6 - LURE: 6 - MAGNET: 5 - PISCARY: 5 - SPIKED_HOOK: 6 - - id: LEGEND_ROD - material: FISHING_ROD - rarity: EPIC - default_statistics: - DAMAGE: 125 - STRENGTH: 125 - FISHING_SPEED: 70 - SEA_CREATURE_CHANCE: 14 - TREASURE_CHANCE: 3.5 - components: - - id: FISHING_ROD_METADATA - display_name: Rod of Legends - medium: WATER - required_fishing_level: 20 - rod_parts_enabled: true - enchantments: - ANGLER: 6 - CASTER: 6 - CHARM: 4 - FRAIL: 7 - IMPALING: 5 - LOOTING: 4 - LUCK_OF_THE_SEA: 7 - LURE: 6 - MAGNET: 6 - PISCARY: 6 - SPIKED_HOOK: 7 - - id: ROD_OF_THE_SEA - material: FISHING_ROD - rarity: LEGENDARY - default_statistics: - DAMAGE: 150 - STRENGTH: 150 - FISHING_SPEED: 95 - SEA_CREATURE_CHANCE: 20 - TREASURE_CHANCE: 3.5 - components: - - id: FISHING_ROD_METADATA - display_name: Rod of the Sea - medium: WATER - required_fishing_level: 24 - rod_parts_enabled: true - enchantments: - FLASH: 5 - ANGLER: 6 - BLESSING: 6 - CASTER: 6 - CHARM: 6 - CORRUPTION: 5 - EXPERTISE: 10 - FRAIL: 7 - IMPALING: 5 - LOOTING: 4 - LUCK_OF_THE_SEA: 7 - LURE: 6 - MAGNET: 6 - PISCARY: 7 - QUICK_BITE: 5 - SPIKED_HOOK: 7 - TABASCO: 3 - - 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 - display_name: Giant Fishing Rod - medium: WATER - rod_parts_enabled: true - - id: DIRT_ROD - material: FISHING_ROD - rarity: UNCOMMON - default_statistics: - FISHING_SPEED: 20 - components: - - id: FISHING_ROD_METADATA - display_name: Dirt Rod - 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 - display_name: Starter Lava Rod - subtitle: Lava Rod - medium: LAVA - required_fishing_level: 10 - rod_parts_enabled: true - - id: POLISHED_TOPAZ_ROD - material: FISHING_ROD - rarity: RARE - default_statistics: - DAMAGE: 80 - STRENGTH: 80 - FISHING_SPEED: 30 - TROPHY_FISH_CHANCE: 8 - components: - - id: FISHING_ROD_METADATA - display_name: Topaz Rod - subtitle: Lava Rod - medium: LAVA - required_fishing_level: 14 - rod_parts_enabled: true - - id: MAGMA_ROD - material: FISHING_ROD - rarity: RARE - default_statistics: - DAMAGE: 110 - STRENGTH: 110 - FISHING_SPEED: 50 - TROPHY_FISH_CHANCE: 12 - components: - - id: FISHING_ROD_METADATA - display_name: Magma Rod - subtitle: Lava Rod - medium: LAVA - required_fishing_level: 18 - rod_parts_enabled: true - - id: INFERNO_ROD - material: FISHING_ROD - rarity: EPIC - default_statistics: - DAMAGE: 140 - STRENGTH: 140 - FISHING_SPEED: 70 - TROPHY_FISH_CHANCE: 16 - components: - - id: FISHING_ROD_METADATA - display_name: Inferno Rod - subtitle: Lava Rod - medium: LAVA - required_fishing_level: 22 - rod_parts_enabled: true - - id: HELLFIRE_ROD - material: FISHING_ROD - rarity: LEGENDARY - default_statistics: - DAMAGE: 175 - STRENGTH: 175 - FISHING_SPEED: 95 - TROPHY_FISH_CHANCE: 22 - components: - - id: FISHING_ROD_METADATA - display_name: Hellfire Rod - subtitle: Lava Rod - medium: LAVA - required_fishing_level: 26 - rod_parts_enabled: true - - id: CHUM_ROD - material: FISHING_ROD - rarity: RARE - default_statistics: - DAMAGE: 20 - STRENGTH: 10 - FISHING_SPEED: 30 - components: - - id: FISHING_ROD_METADATA - display_name: Chum Rod - medium: WATER - required_fishing_level: 4 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: CHUM_SINKER - - id: PRISMARINE_ROD - material: FISHING_ROD - rarity: COMMON - default_statistics: - DAMAGE: 10 - FISHING_SPEED: 10 - components: - - id: FISHING_ROD_METADATA - display_name: Prismarine Rod - medium: WATER - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: PRISMARINE_SINKER - - id: SPONGE_ROD - material: FISHING_ROD - rarity: COMMON - default_statistics: - DAMAGE: 10 - FISHING_SPEED: 10 - components: - - id: FISHING_ROD_METADATA - display_name: Sponge Rod - medium: WATER - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: SPONGE_SINKER - - id: SPEEDSTER_ROD - material: FISHING_ROD - rarity: UNCOMMON - default_statistics: - DAMAGE: 30 - STRENGTH: 15 - FISHING_SPEED: 45 - components: - - id: FISHING_ROD_METADATA - display_name: Speedster Rod - medium: WATER - required_fishing_level: 6 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: SPEEDY_LINE - - id: FARMER_ROD - material: FISHING_ROD - rarity: UNCOMMON - default_statistics: - DAMAGE: 50 - STRENGTH: 20 - FISHING_SPEED: 60 - components: - - id: FISHING_ROD_METADATA - display_name: Farmer's Rod - medium: WATER - required_fishing_level: 8 - rod_parts_enabled: false - 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 - display_name: Ice Rod - medium: WATER - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: ICY_SINKER - - id: WINTER_ROD - material: FISHING_ROD - rarity: RARE - default_statistics: - DAMAGE: 50 - STRENGTH: 50 - FISHING_SPEED: 75 - components: - - id: FISHING_ROD_METADATA - display_name: Winter Rod - medium: WATER - required_fishing_level: 10 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: FESTIVE_SINKER - - id: YETI_ROD - material: FISHING_ROD - rarity: EPIC - default_statistics: - DAMAGE: 150 - STRENGTH: 130 - FISHING_SPEED: 75 - components: - - id: FISHING_ROD_METADATA - display_name: Yeti Rod - medium: WATER - required_fishing_level: 25 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: ICY_SINKER - - id: THE_SHREDDER - material: FISHING_ROD - rarity: LEGENDARY - default_statistics: - DAMAGE: 120 - STRENGTH: 15 - FEROCITY: 50 - FISHING_SPEED: 115 - components: - - id: FISHING_ROD_METADATA - display_name: Shredder - medium: WATER - required_fishing_level: 20 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: SHREDDED_LINE - - id: PHANTOM_ROD - material: FISHING_ROD - rarity: LEGENDARY - default_statistics: - DAMAGE: 200 - STRENGTH: 125 - FISHING_SPEED: 100 - components: - - id: FISHING_ROD_METADATA - display_name: Phantom Rod - medium: WATER - required_fishing_level: 21 - rod_parts_enabled: false - legacy_conversion_target: CHALLENGE_ROD - legacy_conversion_part: PHANTOM_HOOK - - id: AUGER_ROD - material: FISHING_ROD - rarity: LEGENDARY - default_statistics: - DAMAGE: 135 - STRENGTH: 90 - FISHING_SPEED: 110 - components: - - id: FISHING_ROD_METADATA - display_name: Auger Rod - medium: WATER - required_fishing_level: 25 - rod_parts_enabled: false - legacy_conversion_target: ROD_OF_THE_SEA - legacy_conversion_part: ICY_SINKER - - id: COMMON_HOOK - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_ROD_PART - display_name: Common Hook - 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 - display_name: Hotspot Hook - 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 - display_name: Phantom Hook - 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 - display_name: Treasure Hook - 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 - display_name: Speedy Line - 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 - display_name: Shredded Line - 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 - display_name: Titan Line - category: LINE - required_fishing_level: 35 - texture: 9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9 - - id: JUNK_SINKER - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_ROD_PART - display_name: Junk Sinker - 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 - display_name: Prismarine Sinker - 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 - display_name: Sponge Sinker - 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 - display_name: Chum Sinker - 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 - display_name: Festive Sinker - 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 - display_name: Icy Sinker - 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 - display_name: Stingy Sinker - 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 - display_name: Hotspot Sinker - category: SINKER - required_fishing_level: 20 - hotspot_buff_multiplier: 2.0 - texture: 88891d33b55dd1572814527b9c027ec724909c26281a197d0309fbfa925cbce4 - - id: MINNOW_BAIT - material: PLAYER_HEAD - rarity: COMMON - default_statistics: - FISHING_SPEED: 25 - components: - - id: FISHING_BAIT - display_name: Minnow Bait - texture: b8e749ba141c054bb0c125320b17677bdcb3a7e9807a57527c0877b94548a2e - - id: FISH_BAIT - material: PLAYER_HEAD - rarity: COMMON - default_statistics: - FISHING_SPEED: 45 - components: - - id: FISHING_BAIT - display_name: Fish Bait - texture: 49e8dc9fdc9f00e1d17666a4787d34cca7cc6dc030f0dc686195546f81c6f22 - - id: LIGHT_BAIT - material: PLAYER_HEAD - rarity: COMMON - components: - - id: FISHING_BAIT - display_name: Light Bait - texture: e3bcc16f402342b4acd29aecac72d1d5a116e0abb478bb4960e734fd70686ba - - id: DARK_BAIT - material: PLAYER_HEAD - rarity: COMMON - components: - - id: FISHING_BAIT - display_name: Dark Bait - texture: 7281618a5c8239078fd43fef8eae14ea00665f635bd56d4451cccd5d0fa11821 - - id: SPIKED_BAIT - material: PLAYER_HEAD - rarity: COMMON - default_statistics: - SEA_CREATURE_CHANCE: 6 - components: - - id: FISHING_BAIT - display_name: Spiked Bait - texture: e42c436c6580fad217323b9f045daa23a9f88219ac26506637669eff20901f74 - - id: SPOOKY_BAIT - material: PLAYER_HEAD - rarity: COMMON - default_statistics: - FISHING_SPEED: 25 - components: - - id: FISHING_BAIT - display_name: Spooky Bait - tag_bonuses: - SPOOKY: 15 - texture: 977eab558e6a90f7cedd72c2416c891f47d71eb4e7bdcc299a6335286f5cba98 - - id: CARROT_BAIT - material: PLAYER_HEAD - rarity: COMMON - components: - - id: FISHING_BAIT - display_name: Carrot Bait - texture: 4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b - - id: CORRUPTED_BAIT - material: PLAYER_HEAD - rarity: COMMON - components: - - id: FISHING_BAIT - display_name: Corrupted Bait - texture: 4bbcddd45cd347865bceab3e3dc5d382723463963f85ecce81cdd61b53db14e4 - - id: BLESSED_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - components: - - id: FISHING_BAIT - display_name: Blessed Bait - treasure_quality_bonus: 50 - texture: c2b910b5897cdb86b21ebfcba544afa470ae6d228bee3494427c9c7e8f33502b - - id: ICE_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - components: - - id: FISHING_BAIT - display_name: Ice Bait - tag_bonuses: - WINTER: 20 - texture: 609e161bdc325c71572a548a79bb15481c924d63e4fb821379d5dd6c8929f39f - - id: SHARK_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - components: - - id: FISHING_BAIT - display_name: Shark 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 - display_name: Glowy Chum Bait - texture: dfdc1eed684dd805eae96d132e3da53d64267d7361388d5e2c67f5969871e71d - - id: HOT_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - default_statistics: - FISHING_SPEED: 15 - components: - - id: FISHING_BAIT - display_name: Hot 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 - display_name: Worm Bait - texture: df03ad96092f3f789902436709cdf69de6b727c121b3c2daef9ffa1ccaed186c - - id: FROZEN_BAIT - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_BAIT - display_name: Frozen Bait - tag_bonuses: - WINTER: 35 - texture: 38dc68a97cefe92c8cdaa7cb1a7a4de8f16c161da736edf54f79b74beecd6513 - - id: GOLDEN_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - components: - - id: FISHING_BAIT - display_name: Golden Bait - treasure_chance_bonus: 4 - texture: 72e2908dbb112dcd0b367df43fafcc41a56d9cf803e90a367834b4911f84f391 - - id: TREASURE_BAIT - material: PLAYER_HEAD - rarity: RARE - default_statistics: - FISHING_SPEED: 10 - components: - - id: FISHING_BAIT - display_name: Treasure Bait - treasure_chance_bonus: 2 - texture: c1695c80854447b5db5a0ee6d57ef0a7d91d815bd7e6318c516a39d12fe0639e - - id: WOODEN_BAIT - material: PLAYER_HEAD - rarity: UNCOMMON - components: - - id: FISHING_BAIT - display_name: Wooden Bait - texture: 5b236a39e51a39dff9bced39333a73413984bc74db37c1318bfc4a4459f035d2 - - id: HOTSPOT_BAIT - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_BAIT - display_name: Hotspot Bait - tag_bonuses: - HOTSPOT: 50 - texture: de9b17db5c4cadef737e2fefb42a0123c32cbeaa1ca8932579eb2f05018612cd - - id: WHALE_BAIT - material: PLAYER_HEAD - rarity: RARE - default_statistics: - FISHING_SPEED: 30 - components: - - id: FISHING_BAIT - display_name: Whale Bait - texture: 5b4fb49ae77cfcf0b8f62df9c69cc96b27096ad2737d6d0aa450b50664fb2303 - - id: RUSTY_SHIP_ENGINE - material: PLAYER_HEAD - rarity: SPECIAL - components: - - id: FISHING_SHIP_PART - display_name: Rusty Ship Engine - slot: ENGINE - texture: 53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c - - id: BRONZE_SHIP_ENGINE - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_SHIP_PART - display_name: Bronze Ship Engine - slot: ENGINE - texture: 9172c1e729e0ca00193ab5d43e893fabedf5a80fc647258176e8502432885925 - - id: BRONZE_SHIP_HELM - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_SHIP_PART - display_name: Bronze Ship Helm - slot: HELM - texture: 646c5393c3c57742c992c56a7b7a8b98d267538de947c1096fe76341431008f2 - - id: BRONZE_SHIP_HULL - material: PLAYER_HEAD - rarity: RARE - components: - - id: FISHING_SHIP_PART - display_name: Bronze Ship Hull - slot: HULL - texture: a4a7254f1ad8448097d83ddfc790c9f02bc889acbd304b414cee5a13ceadc1e 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 523aebce3..d0e55dec2 100644 --- a/configuration/skyblock/items/vanillaItems.yml +++ b/configuration/skyblock/items/vanillaItems.yml @@ -187,6 +187,10 @@ items: 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 @@ -927,4 +931,3 @@ items: type: JUKEBOX amount: 1 - 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 index 135a02aa8..ce4ab913c 100644 --- 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 @@ -1,100 +1,4 @@ package net.swofty.type.backwaterbayou.gui; -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.FishingItemCatalog; -import net.swofty.type.skyblockgeneric.fishing.FishingRodDefinition; -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(); - FishingRodDefinition def = type == null ? null : FishingItemCatalog.getRod(type.name()); - if (def == null || !def.rodPartsEnabled()) { - 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 GUIHook())); - - 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 GUILine())); - - 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 GUISinker())); - - 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())); - } +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 index 5dfd61149..1abe3f435 100644 --- 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 @@ -1,48 +1,4 @@ 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.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.FishingItemCatalog; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; -import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; - -public class GUIHook 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { - if (part.category() != RodPartDefinition.PartCategory.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()); - } +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/GUILine.java b/type.backwaterbayou/src/main/java/net/swofty/type/backwaterbayou/gui/GUILine.java index 0572d1b34..3f9f8aa0e 100644 --- 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 @@ -1,48 +1,4 @@ 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.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.FishingItemCatalog; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; -import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; - -public class GUILine 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { - if (part.category() != RodPartDefinition.PartCategory.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()); - } +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 index a1b29cff4..6591d0734 100644 --- 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 @@ -1,64 +1,4 @@ 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.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 GUIHook())); - layout.slot(22, ItemStackCreator.getStackHead( - "§9ꨃ Lines", - "9a850a4f721bc150bb72b067e5074c8251058a6b9111691da315b393467c1aa9", - 1, - "§9Lines §7grant you stat bonuses", - "§7everywhere.", - "", - "§eClick to view!" - ), (_, viewCtx) -> viewCtx.push(new GUILine())); - layout.slot(24, ItemStackCreator.getStackHead( - "§9࿉ Sinkers", - "d24892a3142d2e130e5feb88b805b83de905489d2ccd1d031b9d7a2922b96500", - 1, - "§9Sinkers §7add special fishing effects", - "§7to your rod.", - "", - "§eClick to view!" - ), (_, viewCtx) -> viewCtx.push(new GUISinker())); - layout.slot(48, ItemStackCreator.getStack( - "§aGo Back", - Material.ARROW, - 1, - "§7To Fishing Rod Parts" - ), (_, viewCtx) -> viewCtx.pop()); - } +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 index cbe71b12f..07fc59d6b 100644 --- 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 @@ -1,48 +1,4 @@ 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.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.FishingItemCatalog; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; -import net.swofty.type.skyblockgeneric.gui.inventories.fishing.FishingGuideStackFactory; - -public class GUISinker 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 (RodPartDefinition part : FishingItemCatalog.getRodParts()) { - if (part.category() != RodPartDefinition.PartCategory.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()); - } +public class GUISinker extends net.swofty.type.skyblockgeneric.gui.inventories.fishing.GUISinkerGuide { } 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 index 5a8eebfb6..2b97b2735 100644 --- 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 @@ -1,133 +1,4 @@ package net.swofty.type.hub.gui.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; - -// TOOD: Fishing ship name can be changed. And the parts can be changed -public class GUIGFishingShip extends HypixelInventoryGUI { - - public GUIGFishingShip() { - 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) { - 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: §fCracked Ship Helm", - "§7Engine: §fRusty Ship Engine", - "§7Hull: §fRusty Ship Hull" - ); - } - }); - set(new GUIItem(21) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStackHead( - "§fCracked Ship Helm", - "d8d4a54d1fcf47b2efc99ba4cc772250aee5c2f26ed1a19052213e0f3323ca1d", - 1, - "§7A cracked ship helm, incapable of", - "§7changing its heading which appears", - "§7due east.", - "", - "§6§lUPGRADE TO §8➜ §9Bronze Ship Helm", - "§7Crafted from §aBronze Bowls§7, which", - "§7are rarely dropped by §cDumpster", - "§cDivers §7in the §2Backwater Bayou§7.", - "", - "§eClick a Ship Part in your inventory to", - "§eupgrade this part!" - ); - } - }); - // TODO: this is "missing" by default, need to implement that state - set(new GUIItem(22) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStackHead( - "§fRusty Ship Engine", - "53e84793917c890f7f8a2c4078a29e8ba939790498727af9342c2b6f6ac43c9c", - 1, - "§7Rusted by the waters, but it seems to", - "§7be able to run...for now.", - "", - "§6§lUPGRADE TO §8➜ §9Bronze Ship Engine", - "§7Purchased from §2Junker Joel §7in the", - "§2Backwater Bayou§7.", - "", - "§eClick a Ship Part in your inventory to", - "§eupgrade this part!" - ); - } - }); - set(new GUIItem(23) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStackHead( - "§fRusty Ship Hull", - "f42d53ca6e7d80a99a699c2036dcf6e233394feb9f46fb2ff9d9a819690894a9", - 1, - "§7A hull rusted and dilapidated beyond", - "§7repair. It's a miracle the ship", - "§7remains afloat.", - "", - "§6§lUPGRADE TO §8➜ §9Bronze Ship Hull", - "§7Crafted from §aTorn Cloth§7, which is", - "§7rarely dropped by §cBanshees §7in the", - "§2Backwater Bayou§7.", - "", - "§eClick a Ship Part in your inventory to", - "§eupgrade this part!" - ); - } - }); - set(new GUIItem(44) { - @Override - public ItemStack.Builder getItem(HypixelPlayer 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: §6Zephyr", - "", - "§eClick to rename!" - ); - } - }); - set(GUIClickableItem.getCloseItem(40)); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } +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 index 7ffca738b..e85d9e93c 100644 --- 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 @@ -1,57 +1,4 @@ package net.swofty.type.hub.gui.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.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; - -public class GUINavigator extends StatelessView { - - @Override - public ViewConfiguration configuration() { - return new ViewConfiguration<>("Navigator", InventoryType.CHEST_6_ROW); - } - - // todo: make this work with the mission - @Override - public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { - 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); - - 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.", - "", - "§eClick to travel!" - )); - layout.slot(40, ItemStackCreator.getStackHead( - "§bFishing Outpost", - "d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8", - 1, - "§7Your base of operations.", - "", - "§a§lYOU ARE HERE!" - )); - } +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 index 4e86e12fd..58702288e 100644 --- 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 @@ -10,9 +10,8 @@ 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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; import net.swofty.type.skyblockgeneric.fishing.FishingShipService; -import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.stream.Stream; @@ -84,9 +83,9 @@ public void onClick(NPCInteractEvent event) { private void handleRustyShipEngine(SkyBlockPlayer player) { setDialogue(player, "dialogue-yes").thenRun(() -> { - ShipPartDefinition definition = FishingItemCatalog.getShipPart(ItemType.RUSTY_SHIP_ENGINE.name()); + var definition = FishingItemSupport.getShipPart(ItemType.RUSTY_SHIP_ENGINE.name()); if (definition != null) { - FishingShipService.installPart(player, definition); + FishingShipService.installPart(player, ItemType.RUSTY_SHIP_ENGINE.name(), definition); } player.takeItem(ItemType.RUSTY_SHIP_ENGINE, 1); FishingShipService.unlockDestination(player, "BACKWATER_BAYOU"); 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 index 4193ff3bf..395512ca5 100644 --- 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 @@ -24,6 +24,8 @@ public String serialize(TrophyFishData value) { 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); @@ -50,7 +52,9 @@ public TrophyFishData deserialize(String json) { progressObject.optInt("silver", 0), progressObject.optInt("gold", 0), progressObject.optInt("diamond", 0), - progressObject.optInt("totalCatches", 0) + progressObject.optInt("totalCatches", 0), + progressObject.optInt("catchesSinceGoldPity", progressObject.optInt("totalCatches", 0)), + progressObject.optInt("catchesSinceDiamondPity", progressObject.optInt("totalCatches", 0)) )); } return data; @@ -65,7 +69,9 @@ public TrophyFishData clone(TrophyFishData value) { progress.getSilver(), progress.getGold(), progress.getDiamond(), - progress.getTotalCatches() + progress.getTotalCatches(), + progress.getCatchesSinceGoldPity(), + progress.getCatchesSinceDiamondPity() ))); return new TrophyFishData(fish); } @@ -101,14 +107,28 @@ public static class FishProgress { 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++; - case "GOLD" -> gold++; + 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++; } 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 index 1686e8a5d..23d854b30 100644 --- 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 @@ -17,12 +17,12 @@ import net.minestom.server.timer.Scheduler; import net.minestom.server.timer.Task; import net.minestom.server.timer.TaskSchedule; -import net.swofty.type.skyblockgeneric.fishing.BaitDefinition; -import net.swofty.type.skyblockgeneric.fishing.FishingItemCatalog; +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; @@ -59,8 +59,8 @@ public FishingHook(SkyBlockPlayer owner, SkyBlockItem rod) { this.owner = owner; this.rod = rod; String itemId = rod.getAttributeHandler().getPotentialType() == null ? null : rod.getAttributeHandler().getPotentialType().name(); - var rodDefinition = FishingItemCatalog.getRod(itemId); - this.requiredMedium = rodDefinition == null ? FishingMedium.WATER : rodDefinition.medium(); + 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 -> { @@ -268,7 +268,7 @@ private void startFishingSession() { FishingSession session = FishingService.beginCast(owner, rod, requiredMedium); sessionStarted = true; - BaitDefinition bait = FishingItemCatalog.getBait(session.baitItemId()); + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); long waitTicks = FishingService.computeWaitTicks(owner, rod, bait); scheduleNextBite(waitTicks); } @@ -296,7 +296,7 @@ private void scheduleNextBite(long delayTicks) { } FishingService.updateSession(activeSession.withBiteReady(false)); - BaitDefinition bait = FishingItemCatalog.getBait(activeSession.baitItemId()); + FishingBaitComponent bait = FishingItemSupport.getBait(activeSession.baitItemId()); long nextDelay = FishingService.computeWaitTicks(owner, rod, bait); scheduleNextBite(nextDelay); }).delay(TaskSchedule.tick((int) BITE_WINDOW_TICKS)).schedule(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java deleted file mode 100644 index a3266fd4c..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/BaitDefinition.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.swofty.type.skyblockgeneric.fishing; - -import net.swofty.commons.skyblock.statistics.ItemStatistics; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; - -public record BaitDefinition( - String itemId, - String displayName, - ItemStatistics statistics, - List lore, - Map tagBonuses, - double treasureChanceBonus, - double treasureQualityBonus, - double trophyFishChanceBonus, - double doubleHookChanceBonus, - List mediums, - @Nullable String texture -) { -} 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 index 3a0f8e48d..a95eecec4 100644 --- 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 @@ -3,6 +3,7 @@ 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; @@ -11,7 +12,7 @@ public final class FishingBaitService { private FishingBaitService() { } - public static @Nullable BaitDefinition getFirstAvailableBait(SkyBlockPlayer player, FishingMedium medium) { + 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(); @@ -19,14 +20,14 @@ private FishingBaitService() { continue; } - BaitDefinition bait = FishingItemCatalog.getBait(type.name()); - if (bait == null) { + FishingBaitComponent baitComponent = item.getComponent(FishingBaitComponent.class); + if (baitComponent == null) { continue; } - if (!bait.mediums().isEmpty() && !bait.mediums().contains(medium)) { + if (!baitComponent.getMediums().isEmpty() && !baitComponent.getMediums().contains(medium)) { continue; } - return bait; + return baitComponent; } return null; } 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 index 9525d40df..232130275 100644 --- 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 @@ -2,6 +2,8 @@ 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; @@ -9,10 +11,10 @@ public record FishingContext( SkyBlockPlayer player, SkyBlockItem rod, FishingMedium medium, - @Nullable BaitDefinition bait, - @Nullable RodPartDefinition hook, - @Nullable RodPartDefinition line, - @Nullable RodPartDefinition sinker, + @Nullable FishingBaitComponent bait, + @Nullable FishingRodPartComponent hook, + @Nullable FishingRodPartComponent line, + @Nullable FishingRodPartComponent sinker, @Nullable String regionId, boolean hotspotActive, ItemStatistics hotspotBuffs, 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 index 7fb4a1a1b..babc132cc 100644 --- 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 @@ -27,6 +27,14 @@ public static ItemStatistics getActiveHotspotBuffs(SkyBlockPlayer player, Fishin 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()) { @@ -41,7 +49,7 @@ public static ItemStatistics getActiveHotspotBuffs(SkyBlockPlayer player, Fishin } for (ItemStatistic statistic : ItemStatistic.values()) { - double value = hotspot.buffs().getOverall(statistic); + double value = hotspot.buffs().getOverall(statistic) * sinkerMultiplier; if (value != 0.0D) { builder.withBase(statistic, value); } @@ -65,5 +73,3 @@ private static boolean matchesAnyPoint(String serverType, Pos bobberPos, Hotspot return false; } } - - diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java deleted file mode 100644 index f2fd40efa..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemBootstrap.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.swofty.type.skyblockgeneric.fishing; - -import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; - -public final class FishingItemBootstrap { - private FishingItemBootstrap() { - } - - public static void applyDefaults(SkyBlockItem item) { - if (item.getAttributeHandler().getPotentialType() == null) { - return; - } - - FishingRodDefinition definition = FishingItemCatalog.getRod(item.getAttributeHandler().getPotentialType().name()); - if (definition == null) { - return; - } - - if (item.getAttributeHandler().getEnchantments().findAny().isEmpty()) { - definition.enchantments().forEach((type, level) -> - item.getAttributeHandler().addEnchantment(new SkyBlockEnchantment(type, level))); - } - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java deleted file mode 100644 index 2942d7f7e..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingItemCatalog.java +++ /dev/null @@ -1,160 +0,0 @@ -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.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.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -public final class FishingItemCatalog { - private FishingItemCatalog() { - } - - public static @Nullable FishingRodDefinition getRod(@Nullable String itemId) { - if (itemId == null) { - return null; - } - - ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); - if (item == null || !item.hasComponent(FishingRodMetadataComponent.class)) { - return null; - } - - FishingRodMetadataComponent component = item.getComponent(FishingRodMetadataComponent.class); - return new FishingRodDefinition( - itemId, - component.getDisplayName(), - component.getSubtitle(), - component.getMedium(), - component.getRequiredFishingLevel(), - item.getDefaultStatistics(), - component.getEnchantments(), - item.getLore(), - component.getLegacyConversionTarget(), - component.getLegacyConversionPart(), - component.isRodPartsEnabled() - ); - } - - public static @Nullable RodPartDefinition getRodPart(@Nullable String itemId) { - if (itemId == null) { - return null; - } - - ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); - if (item == null || !item.hasComponent(FishingRodPartComponent.class)) { - return null; - } - - FishingRodPartComponent component = item.getComponent(FishingRodPartComponent.class); - return new RodPartDefinition( - itemId, - component.getDisplayName(), - component.getCategory(), - component.getRequiredFishingLevel(), - item.getDefaultStatistics(), - item.getLore(), - component.getTagBonuses(), - component.isTreasureOnly(), - component.isBayouTreasureToJunk(), - component.getMaterializedItemId(), - component.getMaterializedChance(), - component.getBaitPreservationChance(), - component.getHotspotBuffMultiplier(), - component.getTexture() - ); - } - - public static @Nullable BaitDefinition getBait(@Nullable String itemId) { - if (itemId == null) { - return null; - } - - ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); - if (item == null || !item.hasComponent(FishingBaitComponent.class)) { - return null; - } - - FishingBaitComponent component = item.getComponent(FishingBaitComponent.class); - return new BaitDefinition( - itemId, - component.getDisplayName(), - item.getDefaultStatistics(), - item.getLore(), - component.getTagBonuses(), - component.getTreasureChanceBonus(), - component.getTreasureQualityBonus(), - component.getTrophyFishChanceBonus(), - component.getDoubleHookChanceBonus(), - component.getMediums(), - component.getTexture() - ); - } - - public static @Nullable ShipPartDefinition getShipPart(@Nullable String itemId) { - if (itemId == null) { - return null; - } - - ConfigurableSkyBlockItem item = ConfigurableSkyBlockItem.getFromID(itemId); - if (item == null || !item.hasComponent(FishingShipPartComponent.class)) { - return null; - } - - FishingShipPartComponent component = item.getComponent(FishingShipPartComponent.class); - return new ShipPartDefinition( - itemId, - component.getDisplayName(), - component.getSlot(), - item.getLore(), - component.getTexture() - ); - } - - public static List getRods() { - return Arrays.stream(ItemType.values()) - .map(ItemType::name) - .map(FishingItemCatalog::getRod) - .filter(Objects::nonNull) - .sorted(Comparator.comparingInt(FishingRodDefinition::requiredFishingLevel) - .thenComparing(FishingRodDefinition::displayName)) - .toList(); - } - - public static List getRodParts() { - return Arrays.stream(ItemType.values()) - .map(ItemType::name) - .map(FishingItemCatalog::getRodPart) - .filter(Objects::nonNull) - .sorted(Comparator.comparing(RodPartDefinition::category) - .thenComparingInt(RodPartDefinition::requiredFishingLevel) - .thenComparing(RodPartDefinition::displayName)) - .toList(); - } - - public static List getBaits() { - return Arrays.stream(ItemType.values()) - .map(ItemType::name) - .map(FishingItemCatalog::getBait) - .filter(Objects::nonNull) - .sorted(Comparator.comparing((BaitDefinition bait) -> ItemType.valueOf(bait.itemId()).rarity.ordinal()) - .thenComparing(BaitDefinition::displayName)) - .toList(); - } - - public static List getShipParts() { - return Arrays.stream(ItemType.values()) - .map(ItemType::name) - .map(FishingItemCatalog::getShipPart) - .filter(Objects::nonNull) - .sorted(Comparator.comparing(ShipPartDefinition::slot).thenComparing(ShipPartDefinition::displayName)) - .toList(); - } -} \ No newline at end of file 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 index 24152bfc6..4a723c6e2 100644 --- 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 @@ -3,6 +3,7 @@ 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; @@ -13,16 +14,16 @@ private FishingLootResolver() { } public static FishingCatchResult resolve(FishingContext context) { - FishingCatchResult trophyFish = tryResolveTrophyFish(context); - if (trophyFish != null) { - return trophyFish; - } - 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; @@ -38,7 +39,7 @@ private static FishingCatchResult tryResolveTrophyFish(FishingContext context) { double bonus = getTotalStatistic(context, ItemStatistic.TROPHY_FISH_CHANCE); if (context.bait() != null) { - bonus += context.bait().trophyFishChanceBonus(); + bonus += context.bait().getTrophyFishChanceBonus(); } List eligible = new ArrayList<>(); @@ -125,7 +126,7 @@ private static String rollTrophyTier(FishingContext context, TrophyFishDefinitio double charmBonus = 0.0D; var charm = context.rod().getAttributeHandler().getEnchantment(net.swofty.type.skyblockgeneric.enchantment.EnchantmentType.CHARM); if (charm != null) { - charmBonus = charm.level(); + charmBonus = charm.level() * 2.0D; } if (Math.random() <= (0.002D * (1 + charmBonus / 100D))) { @@ -147,7 +148,7 @@ private static FishingCatchResult tryResolveSeaCreature(FishingContext context) } double seaCreatureChance = getTotalStatistic(context, ItemStatistic.SEA_CREATURE_CHANCE); - if (context.hook() != null && context.hook().treasureOnly()) { + if (context.hook() != null && context.hook().isTreasureOnly()) { return null; } @@ -174,14 +175,14 @@ private static FishingCatchResult resolveItem(FishingContext context) { List pool = table.items(); double treasureChance = getTotalStatistic(context, ItemStatistic.TREASURE_CHANCE); if (context.bait() != null) { - treasureChance += context.bait().treasureChanceBonus(); + treasureChance += context.bait().getTreasureChanceBonus(); } - if (context.sinker() != null && context.sinker().bayouTreasureToJunk()) { + if (context.sinker() != null && context.sinker().isBayouTreasureToJunk()) { treasureChance += 10.0D; } if (!table.treasures().isEmpty() && Math.random() * 100 <= treasureChance) { - pool = context.sinker() != null && context.sinker().bayouTreasureToJunk() ? table.junk() : table.treasures(); + pool = context.sinker() != null && context.sinker().isBayouTreasureToJunk() ? table.junk() : table.treasures(); return pick(pool, FishingCatchKind.TREASURE); } @@ -208,18 +209,19 @@ private static FishingCatchResult pick(List po } 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 (definition.regions().isEmpty()) { - return definition; - } if (context.regionId() != null && definition.regions().contains(context.regionId())) { return definition; } + if (definition.regions().isEmpty() && fallback == null) { + fallback = definition; + } } - return null; + return fallback; } private static double getTotalStatistic(FishingContext context, ItemStatistic statistic) { @@ -227,7 +229,10 @@ private static double getTotalStatistic(FishingContext context, ItemStatistic st + FishingRodPartService.getStatistics(context.rod()).getOverall(statistic); total += context.hotspotBuffs().getOverall(statistic); if (context.bait() != null) { - total += context.bait().statistics().getOverall(statistic); + SkyBlockItem baitItem = FishingItemSupport.getItem(context.bait().getItemId()); + if (baitItem != null) { + total += baitItem.getAttributeHandler().getStatistics().getOverall(statistic); + } } return total; } @@ -235,16 +240,16 @@ private static double getTotalStatistic(FishingContext context, ItemStatistic st private static double getTagBonus(FishingContext context, List tags) { double total = 0.0D; if (context.hook() != null) { - total += getTagBonus(context.hook().tagBonuses(), tags); + total += getTagBonus(context.hook().getTagBonuses(), tags); } if (context.line() != null) { - total += getTagBonus(context.line().tagBonuses(), tags); + total += getTagBonus(context.line().getTagBonuses(), tags); } if (context.sinker() != null) { - total += getTagBonus(context.sinker().tagBonuses(), tags); + total += getTagBonus(context.sinker().getTagBonuses(), tags); } if (context.bait() != null) { - total += getTagBonus(context.bait().tagBonuses(), tags); + total += getTagBonus(context.bait().getTagBonuses(), tags); } return total; } 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 index 0befec050..cc9768e88 100644 --- 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 @@ -4,7 +4,6 @@ import net.swofty.commons.YamlFileUtils; import net.swofty.commons.skyblock.statistics.ItemStatistic; import net.swofty.commons.skyblock.statistics.ItemStatistics; -import net.swofty.type.skyblockgeneric.entity.mob.MobType; import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; @@ -20,8 +19,8 @@ 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 SEA_CREATURES = 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() { @@ -29,8 +28,8 @@ private FishingRegistry() { public static void loadAll() { TABLES.clear(); - SEA_CREATURES.clear(); TROPHY_FISH.clear(); + SEA_CREATURES.clear(); HOTSPOTS.clear(); if (!YamlFileUtils.ensureDirectoryExists(FISHING_DIR)) { @@ -39,8 +38,8 @@ public static void loadAll() { try { loadTables(new File(FISHING_DIR, "tables.yml")); - loadSeaCreatures(new File(FISHING_DIR, "sea_creatures.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"); @@ -97,6 +96,9 @@ private static void loadTables(File file) throws IOException { @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) { @@ -134,11 +136,9 @@ private static void loadSeaCreatures(File file) throws IOException { String id = string(entry, "id"); SEA_CREATURES.put(id, new SeaCreatureDefinition( id, - string(entry, "displayName"), intValue(entry, "requiredFishingLevel", 0), doubleValue(entry, "skillXp", 0.0D), - stringList(entry.get("tags")), - nullableString(entry, "corruptedVariantId") + stringList(entry.get("tags")) )); } } @@ -151,42 +151,44 @@ private static void loadHotspots(File file) throws IOException { Map root = YamlFileUtils.loadYaml(file); List> entries = (List>) root.getOrDefault("hotspots", Collections.emptyList()); - int generatedId = 1; for (Map entry : entries) { - if (entry.containsKey("x") && entry.containsKey("y") && entry.containsKey("z")) { - String serverType = normalizeServerType(nullableString(entry, "serverType")); - String region = nullableString(entry, "region"); - HOTSPOTS.put("POSITION_" + generatedId, new HotspotDefinition( - "POSITION_" + generatedId, - "Hotspot", - region == null ? List.of() : List.of(region.toUpperCase()), - enumValue(entry, "medium", FishingMedium.class, FishingMedium.WATER), - intValue(entry, "maxActive", defaultMaxActiveForServer(serverType)), - intValue(entry, "durationSeconds", 120), - parseStatistics((Map) entry.get("buffs"), defaultHotspotBuffs()), - stringList(entry.get("seaCreatures")), - List.of(new HotspotDefinition.SpawnPoint( - doubleValue(entry.get("x"), 0), - doubleValue(entry.get("y"), 0), - doubleValue(entry.get("z"), 0), - serverType - )) + 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) )); - generatedId++; - continue; + } 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 = string(entry, "id"); + 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, - string(entry, "displayName"), + nullableString(entry, "displayName") == null ? "Hotspot" : nullableString(entry, "displayName"), stringList(entry.get("regions")), - enumValue(entry, "medium", FishingMedium.class, FishingMedium.WATER), - intValue(entry, "maxActive", 1), + entry.containsKey("medium") ? FishingMedium.valueOf(String.valueOf(entry.get("medium")).toUpperCase()) : FishingMedium.WATER, + intValue(entry, "maxActive", defaultMaxActiveForServer(serverType)), intValue(entry, "durationSeconds", 120), - parseStatistics((Map) entry.get("buffs"), defaultHotspotBuffs()), + parseStatistics(buffs, defaultHotspotBuffs()), stringList(entry.get("seaCreatures")), - parseHotspotSpawnPoints((List>) entry.get("positions"), nullableString(entry, "serverType")) + spawnPoints )); } } @@ -232,33 +234,98 @@ private static List parseMediums(@Nullable List mediums) return result; } - private static List parseMobTypes(@Nullable List values) { - if (values == null || values.isEmpty()) { + @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 mobTypes = new ArrayList<>(); - for (Object value : values) { - mobTypes.add(MobType.valueOf(String.valueOf(value).toUpperCase())); + List result = new ArrayList<>(); + for (Object entry : values) { + result.add(String.valueOf(entry)); } - return mobTypes; + return result; } - private static List parseHotspotSpawnPoints(@Nullable List> entries, @Nullable String fallbackServerType) { - if (entries == null || entries.isEmpty()) { - return List.of(); + 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; + } - List points = new ArrayList<>(); - for (Map entry : entries) { - points.add(new HotspotDefinition.SpawnPoint( - doubleValue(entry.get("x"), 0), - doubleValue(entry.get("y"), 0), - doubleValue(entry.get("z"), 0), - normalizeServerType(nullableString(entry, "serverType"), fallbackServerType) - )); + 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; } - return points; + 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) { @@ -323,116 +390,4 @@ private static List parseSeaCreatureRoll } return result; } - - private static Map parseStringDoubleMap(@Nullable Map values) { - if (values == null || values.isEmpty()) { - return Map.of(); - } - - Map result = new LinkedHashMap<>(); - for (Map.Entry entry : values.entrySet()) { - result.put(entry.getKey(), doubleValue(entry.getValue(), 0.0D)); - } - return result; - } - - private static String string(Map entry, String key) { - Object value = entry.get(key); - if (value == null) { - throw new IllegalArgumentException("Missing fishing config key: " + key); - } - return String.valueOf(value); - } - - private static @Nullable String nullableString(Map entry, String key) { - Object value = entry.get(key); - if (value == null) { - return null; - } - String stringValue = String.valueOf(value); - return stringValue.isEmpty() ? null : stringValue; - } - - private static List stringList(@Nullable Object raw) { - if (!(raw instanceof List list)) { - return List.of(); - } - List values = new ArrayList<>(); - for (Object entry : list) { - values.add(String.valueOf(entry)); - } - return values; - } - - private static int intValue(Map entry, String key, int defaultValue) { - return intValue(entry.get(key), defaultValue); - } - - private static int intValue(@Nullable Object value, int defaultValue) { - if (value == null) { - return defaultValue; - } - if (value instanceof Number number) { - return number.intValue(); - } - return Integer.parseInt(String.valueOf(value)); - } - - private static long longValue(Map entry, String key, long defaultValue) { - return longValue(entry.get(key), defaultValue); - } - - private static long longValue(@Nullable Object value, long defaultValue) { - if (value == null) { - return defaultValue; - } - if (value instanceof Number number) { - return number.longValue(); - } - return Long.parseLong(String.valueOf(value)); - } - - private static double doubleValue(Map entry, String key, double defaultValue) { - return doubleValue(entry.get(key), defaultValue); - } - - private static double doubleValue(@Nullable Object value, double defaultValue) { - if (value == null) { - return defaultValue; - } - if (value instanceof Number number) { - return number.doubleValue(); - } - return Double.parseDouble(String.valueOf(value)); - } - - private static @Nullable Double nullableDouble(@Nullable Object value) { - if (value == null) { - return null; - } - if (value instanceof Number number) { - return number.doubleValue(); - } - String stringValue = String.valueOf(value); - return stringValue.isEmpty() ? null : Double.parseDouble(stringValue); - } - - private static boolean booleanValue(Map entry, String key, boolean defaultValue) { - Object value = entry.get(key); - if (value == null) { - return defaultValue; - } - if (value instanceof Boolean bool) { - return bool; - } - return Boolean.parseBoolean(String.valueOf(value)); - } - - private static > T enumValue(Map entry, String key, Class type, T defaultValue) { - Object value = entry.get(key); - if (value == null) { - return defaultValue; - } - return Enum.valueOf(type, String.valueOf(value).toUpperCase()); - } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java deleted file mode 100644 index 38d102af1..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/FishingRodDefinition.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.swofty.type.skyblockgeneric.fishing; - -import net.swofty.commons.skyblock.statistics.ItemStatistics; -import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; - -public record FishingRodDefinition( - String itemId, - String displayName, - @Nullable String subtitle, - FishingMedium medium, - int requiredFishingLevel, - ItemStatistics statistics, - Map enchantments, - List lore, - @Nullable String legacyConversionTarget, - @Nullable String legacyConversionPart, - boolean rodPartsEnabled -) { -} 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 index d108ad7bc..acdd1317b 100644 --- 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 @@ -2,20 +2,16 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.commons.skyblock.item.Rarity; -import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeHotPotatoBookData; -import net.swofty.commons.skyblock.item.reforge.Reforge; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.commons.skyblock.statistics.ItemStatistics; -import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; 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.Comparator; import java.util.List; -import java.util.Map; public final class FishingRodLoreBuilder { private static final List STAT_ORDER = List.of( @@ -24,193 +20,86 @@ public final class FishingRodLoreBuilder { ItemStatistic.FEROCITY, ItemStatistic.FISHING_SPEED, ItemStatistic.SEA_CREATURE_CHANCE, - ItemStatistic.TREASURE_CHANCE, - ItemStatistic.TROPHY_FISH_CHANCE, - ItemStatistic.MAGIC_FIND + ItemStatistic.DOUBLE_HOOK_CHANCE, + ItemStatistic.TROPHY_FISH_CHANCE ); private FishingRodLoreBuilder() { } public static @Nullable FishingRodLore build(SkyBlockItem item, @Nullable SkyBlockPlayer player) { - ItemType itemType = item.getAttributeHandler().getPotentialType(); - if (itemType == null) { + if (!item.hasComponent(FishingRodMetadataComponent.class)) { return null; } - FishingRodDefinition definition = FishingItemCatalog.getRod(itemType.name()); - if (definition == null) { - return null; - } - - var handler = item.getAttributeHandler(); - Rarity rarity = handler.isRecombobulated() ? handler.getRarity().upgrade() : handler.getRarity(); - - String displayName = definition.displayName(); - Reforge reforge = handler.getReforge(); - if (reforge != null) { - displayName = reforge.getPrefix() + " " + displayName; - } - displayName = rarity.getColor() + displayName; - + FishingRodMetadataComponent metadata = item.getComponent(FishingRodMetadataComponent.class); List lore = new ArrayList<>(); - if (definition.subtitle() != null) { - lore.add("§8" + definition.subtitle()); - lore.add(""); + if (metadata.getSubtitle() != null && !metadata.getSubtitle().isBlank()) { + lore.add(metadata.getSubtitle()); } for (ItemStatistic statistic : STAT_ORDER) { - String line = buildStatLine(item, definition, rarity, statistic); - if (line != null) { - lore.add(line); + double amount = item.getAttributeHandler().getStatistics().getOverall(statistic) + + FishingRodPartService.getStatistics(item).getOverall(statistic); + if (amount == 0.0D) { + continue; } + lore.add(formatStatistic(statistic, amount)); } - lore.addAll(definition.lore()); - if (!lore.isEmpty() && !lore.getLast().isEmpty()) { - lore.add(""); - } - - List enchantLines = buildEnchantLines(item, rarity); - lore.addAll(enchantLines); - if (!enchantLines.isEmpty()) { - lore.add(""); + if (item.hasComponent(GemstoneComponent.class)) { + lore.add(renderGemSlots(item.getComponent(GemstoneComponent.class))); } - if (definition.rodPartsEnabled()) { - RodPartDefinition hook = FishingRodPartService.getHook(item); - RodPartDefinition line = FishingRodPartService.getLine(item); - RodPartDefinition sinker = FishingRodPartService.getSinker(item); + lore.add(partLine("ථ Hook ", item.getAttributeHandler().getFishingHook())); + lore.add(partLine("ꨃ Line ", item.getAttributeHandler().getFishingLine())); + lore.add(partLine("࿉ Sinker ", item.getAttributeHandler().getFishingSinker())); - lore.add(renderPartHeader("ථ", "Hook", hook)); - if (hook != null) { - lore.addAll(renderAppliedPartLore(hook, player)); - } - lore.add(renderPartHeader("ꨃ", "Line", line)); - if (line != null) { - lore.addAll(renderAppliedPartLore(line, player)); - } - lore.add(renderPartHeader("࿉", "Sinker", sinker)); - if (sinker != null) { - lore.addAll(renderAppliedPartLore(sinker, player)); - } - lore.add(""); - lore.add("§7Talk to §2Roddy §7in the §2Backwater"); - lore.add("§2Bayou §7to apply parts to this rod."); - lore.add(""); - } else if (definition.legacyConversionTarget() != null) { - lore.add("§7§cThis rod is broken and cannot be"); - lore.add("§cused to fish."); - lore.add(""); - lore.add("§7Bring it to §2Roddy §7in the §2Backwater"); - lore.add("§2Bayou §7to convert it into a §anew rod§7!"); - lore.add(""); + 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."); } - lore.add("§8This item can be reforged!"); - - if (handler.getFishingExpertiseKills() > 0) { - lore.add("§fKills: §6" + StringUtility.commaify(handler.getFishingExpertiseKills())); + if (item.hasComponent(net.swofty.type.skyblockgeneric.item.components.ReforgableComponent.class)) { + lore.add("This item can be reforged!"); } - - if (handler.getSoulBoundData() != null) { - lore.add("§8§l* Co-op Soulbound §l*"); + if (metadata.getRequiredFishingLevel() > 0) { + lore.add("❣ Requires Fishing Skill " + metadata.getRequiredFishingLevel() + "."); } - - if (definition.requiredFishingLevel() > 0 && player != null && - player.getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < definition.requiredFishingLevel()) { - lore.add("§4❣ §cRequires §aFishing Skill " + definition.requiredFishingLevel() + "§c."); + if (metadata.getExtraRequirements() != null) { + lore.addAll(metadata.getExtraRequirements()); } - - String footer = rarity.getDisplay() + " FISHING ROD"; - if (handler.isRecombobulated()) { - footer = rarity.getColor() + "§l§ka §l" + rarity.name() + " FISHING ROD §l§ka"; + if (item.hasComponent(DefaultSoulboundComponent.class)) { + lore.add("* Co-op Soulbound *"); } - lore.add(footer); - return new FishingRodLore(displayName, lore); + lore.add(item.getAttributeHandler().getRarity().getDisplay() + " FISHING ROD"); + return new FishingRodLore(item.getDisplayName(), lore); } - private static @Nullable String buildStatLine(SkyBlockItem item, FishingRodDefinition definition, Rarity rarity, ItemStatistic statistic) { - double base = definition.statistics().getOverall(statistic); - double reforge = 0.0D; - if (item.getAttributeHandler().getReforge() != null) { - reforge = item.getAttributeHandler().getReforge().getAfterCalculation(ItemStatistics.empty(), rarity.ordinal() + 1).getOverall(statistic); - } - - double part = FishingRodPartService.getStatistics(item).getOverall(statistic); - double dynamic = item.getAttributeHandler().getExtraDynamicStatistics().getOverall(statistic); - double hpb = getHotPotatoContribution(item, statistic); - double total = base + reforge + part + dynamic + hpb; - - if (total == 0) { - return null; - } - - String line = "§7" + statistic.getDisplayName() + ": " + statistic.getLoreColor() - + statistic.getPrefix() + formatNumber(total) + statistic.getSuffix(); - if (hpb != 0) { - line += " §e(" + (hpb > 0 ? "+" : "") + formatNumber(hpb) + ")"; - } - if (part != 0) { - line += " §d(" + (part > 0 ? "+" : "") + formatNumber(part) + ")"; - } else if (reforge != 0) { - line += " §9(" + (reforge > 0 ? "+" : "") + formatNumber(reforge) + ")"; - } - return line; - } - - private static double getHotPotatoContribution(SkyBlockItem item, ItemStatistic statistic) { - ItemAttributeHotPotatoBookData.HotPotatoBookData data = item.getAttributeHandler().getHotPotatoBookData(); - if (!data.hasAppliedItem()) { - return 0.0D; - } - - double total = 0.0D; - for (Map.Entry entry : data.getPotatoType().stats.entrySet()) { - if (entry.getKey() == statistic) { - total += entry.getValue(); - } - } - return total; - } - - private static List buildEnchantLines(SkyBlockItem item, Rarity rarity) { - List enchantments = item.getAttributeHandler().getEnchantments() - .sorted(Comparator.comparing(enchantment -> enchantment.type().getName())) - .toList(); - if (enchantments.isEmpty()) { - return List.of(); - } - - String enchantColor = rarity == Rarity.MYTHIC ? "§d" : "§9"; - String joined = enchantments.stream() - .map(enchantment -> enchantColor + enchantment.type().getName() + " " + StringUtility.getAsRomanNumeral(enchantment.level())) - .reduce((left, right) -> left + ", " + right) + private static String renderGemSlots(GemstoneComponent gemstone) { + return gemstone.getSlots().stream() + .map(slot -> "[" + slot.slot().getSymbol() + "]") + .reduce((left, right) -> left + " " + right) .orElse(""); - return StringUtility.splitByWordAndLength(joined, 34); } - private static String renderPartHeader(String symbol, String label, @Nullable RodPartDefinition part) { - if (part == null) { - return "§9" + symbol + " " + label + " §8§lNONE"; + private static String partLine(String prefix, @Nullable String itemId) { + if (itemId == null) { + return prefix + "NONE"; } - return ItemType.valueOf(part.itemId()).rarity.getColor() + symbol + " " + part.displayName(); + ItemType type = ItemType.get(itemId); + return prefix + (type == null ? "NONE" : type.getDisplayName().replace("§", "")); } - private static List renderAppliedPartLore(RodPartDefinition part, @Nullable SkyBlockPlayer player) { - List lines = new ArrayList<>(); - for (String line : part.lore()) { - lines.add("§7" + line); - } - if (part.requiredFishingLevel() > 0 && player != null && - player.getSkills().getCurrentLevel(net.swofty.type.skyblockgeneric.skill.SkillCategories.FISHING) < part.requiredFishingLevel()) { - lines.add("§4❣ §cRequires §aFishing Skill " + part.requiredFishingLevel() + "§c."); - } - return lines; + private static String formatStatistic(ItemStatistic statistic, double amount) { + return statistic.getDisplayName() + ": " + statistic.getPrefix() + format(amount) + statistic.getSuffix(); } - private static String formatNumber(double value) { + private static String format(double value) { if (Math.abs(value - Math.rint(value)) < 0.0001D) { return String.valueOf((long) Math.rint(value)); } 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 index 87ac626a1..3c5ebb102 100644 --- 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 @@ -2,22 +2,23 @@ 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 RodPartDefinition getHook(SkyBlockItem rod) { - return getPart(FishingItemCatalog.getRodPart(rod.getAttributeHandler().getFishingHook())); + public static @Nullable FishingRodPartComponent getHook(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingHook()); } - public static @Nullable RodPartDefinition getLine(SkyBlockItem rod) { - return getPart(FishingItemCatalog.getRodPart(rod.getAttributeHandler().getFishingLine())); + public static @Nullable FishingRodPartComponent getLine(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingLine()); } - public static @Nullable RodPartDefinition getSinker(SkyBlockItem rod) { - return getPart(FishingItemCatalog.getRodPart(rod.getAttributeHandler().getFishingSinker())); + public static @Nullable FishingRodPartComponent getSinker(SkyBlockItem rod) { + return FishingItemSupport.getRodPart(rod.getAttributeHandler().getFishingSinker()); } public static ItemStatistics getStatistics(SkyBlockItem rod) { @@ -28,15 +29,15 @@ public static ItemStatistics getStatistics(SkyBlockItem rod) { return builder.build(); } - public static void applyPart(SkyBlockItem rod, RodPartDefinition part) { - switch (part.category()) { - case HOOK -> rod.getAttributeHandler().setFishingHook(part.itemId()); - case LINE -> rod.getAttributeHandler().setFishingLine(part.itemId()); - case SINKER -> rod.getAttributeHandler().setFishingSinker(part.itemId()); + 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, RodPartDefinition.PartCategory category) { + public static void removePart(SkyBlockItem rod, FishingPartCategory category) { switch (category) { case HOOK -> rod.getAttributeHandler().setFishingHook(null); case LINE -> rod.getAttributeHandler().setFishingLine(null); @@ -44,16 +45,16 @@ public static void removePart(SkyBlockItem rod, RodPartDefinition.PartCategory c } } - private static @Nullable RodPartDefinition getPart(@Nullable RodPartDefinition definition) { - return definition; - } - - private static void append(ItemStatistics.Builder builder, @Nullable RodPartDefinition definition) { + 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 = definition.statistics().getOverall(statistic); + 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 index 235e2a63a..fd0ba7fef 100644 --- 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 @@ -6,6 +6,8 @@ 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; @@ -21,12 +23,12 @@ private FishingService() { } public static FishingSession beginCast(SkyBlockPlayer player, SkyBlockItem rod, FishingMedium medium) { - BaitDefinition bait = FishingBaitService.getFirstAvailableBait(player, medium); + FishingBaitComponent bait = FishingBaitService.getFirstAvailableBait(player, medium); FishingSession session = new FishingSession( player.getUuid(), rod.getAttributeHandler().getPotentialType().name(), medium, - bait == null ? null : bait.itemId(), + bait == null ? null : bait.getItemId(), System.currentTimeMillis(), 0L, 0L, @@ -49,13 +51,16 @@ public static void clearSession(UUID playerUuid) { SESSIONS.remove(playerUuid); } - public static long computeWaitTicks(SkyBlockPlayer player, SkyBlockItem rod, @Nullable BaitDefinition bait) { + 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) { - fishingSpeed += bait.statistics().getOverall(net.swofty.commons.skyblock.statistics.ItemStatistic.FISHING_SPEED); - if ("CORRUPTED_BAIT".equals(bait.itemId())) { + 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; } } @@ -69,7 +74,7 @@ public static long computeWaitTicks(SkyBlockPlayer player, SkyBlockItem rod, @Nu return null; } - BaitDefinition bait = FishingItemCatalog.getBait(session.baitItemId()); + FishingBaitComponent bait = FishingItemSupport.getBait(session.baitItemId()); SkyBlockRegion region = player.getRegion(); var hotspotBuffs = FishingHotspotService.getActiveHotspotBuffs(player, session.medium(), hook.getSpawnPosition()); boolean hotspotActive = hasAnyBuffValue(hotspotBuffs); @@ -98,9 +103,9 @@ public static long computeWaitTicks(SkyBlockPlayer player, SkyBlockItem rod, @Nu if (caster != null) { preserve |= Math.random() * 100 < caster.level(); } - RodPartDefinition sinker = FishingRodPartService.getSinker(rod); - if (!preserve && sinker != null && sinker.baitPreservationChance() > 0) { - preserve = Math.random() * 100 < sinker.baitPreservationChance(); + 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()); @@ -123,9 +128,9 @@ private static void awardCatch(SkyBlockPlayer player, SkyBlockItem rod, FishingH player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COLLECTION, DatapointCollection.class).setValue(player.getCollection()); } - RodPartDefinition sinker = FishingRodPartService.getSinker(rod); - if (sinker != null && sinker.materializedItemId() != null && Math.random() <= sinker.materializedChance()) { - player.addAndUpdateItem(net.swofty.commons.skyblock.item.ItemType.valueOf(sinker.materializedItemId())); + 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) { 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 index aa9167c0b..a2ae344c8 100644 --- 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 @@ -2,6 +2,7 @@ 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 { @@ -12,12 +13,12 @@ public static DatapointShipState.ShipState getState(SkyBlockPlayer player) { return player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.SHIP_STATE, DatapointShipState.class).getValue(); } - public static void installPart(SkyBlockPlayer player, ShipPartDefinition definition) { + public static void installPart(SkyBlockPlayer player, String itemId, FishingShipPartComponent definition) { DatapointShipState.ShipState state = getState(player); - switch (definition.slot()) { - case HELM -> state.setHelm(definition.itemId()); - case ENGINE -> state.setEngine(definition.itemId()); - case HULL -> state.setHull(definition.itemId()); + 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); } 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 index de0af4eb1..a3c48b9c0 100644 --- 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 @@ -15,6 +15,11 @@ public record HotspotDefinition( List seaCreatureIds, List spawnPoints ) { - public record SpawnPoint(double x, double y, double z, String serverType) { + public record SpawnPoint( + String serverType, + double x, + double y, + double z + ) { } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java deleted file mode 100644 index fbd19e56a..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/RodPartDefinition.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.swofty.type.skyblockgeneric.fishing; - -import net.swofty.commons.skyblock.statistics.ItemStatistics; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; - -public record RodPartDefinition( - String itemId, - String displayName, - PartCategory category, - int requiredFishingLevel, - ItemStatistics statistics, - List lore, - Map tagBonuses, - boolean treasureOnly, - boolean bayouTreasureToJunk, - @Nullable String materializedItemId, - double materializedChance, - double baitPreservationChance, - double hotspotBuffMultiplier, - @Nullable String texture -) { - public enum PartCategory { - HOOK, - LINE, - SINKER - } -} 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 index e9ceb5727..d2ebd4041 100644 --- 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 @@ -4,11 +4,8 @@ public record SeaCreatureDefinition( String id, - String displayName, int requiredFishingLevel, double skillXp, - List tags, - String corruptedVariantId + List tags ) { } - diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java deleted file mode 100644 index 60667cf38..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/fishing/ShipPartDefinition.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.swofty.type.skyblockgeneric.fishing; - -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public record ShipPartDefinition( - String itemId, - String displayName, - ShipPartSlot slot, - List lore, - @Nullable String texture -) { - public enum ShipPartSlot { - HELM, - ENGINE, - HULL - } -} 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 index d8d9b39e6..2857b9bd1 100644 --- 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 @@ -5,9 +5,10 @@ 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.BaitDefinition; import net.swofty.type.skyblockgeneric.fishing.FishingMedium; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +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; @@ -29,75 +30,77 @@ public final class FishingGuideStackFactory { private FishingGuideStackFactory() { } - public static net.minestom.server.item.ItemStack.Builder buildBaitStack(BaitDefinition bait) { + 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, bait.statistics()); - appendTagBonuses(lore, bait.tagBonuses()); + appendStatistics(lore, baitItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, bait.getTagBonuses()); - if (bait.treasureChanceBonus() > 0) { - lore.add("§7Grants §6+" + format(bait.treasureChanceBonus()) + " Treasure Chance§7."); + if (bait.getTreasureChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTreasureChanceBonus()) + " Treasure Chance§7."); } - if (bait.treasureQualityBonus() > 0) { - lore.add("§7Increases treasure quality by §a" + format(bait.treasureQualityBonus()) + "%§7."); + if (bait.getTreasureQualityBonus() > 0) { + lore.add("§7Increases treasure quality by §a" + format(bait.getTreasureQualityBonus()) + "%§7."); } - if (bait.trophyFishChanceBonus() > 0) { - lore.add("§7Grants §6+" + format(bait.trophyFishChanceBonus()) + " Trophy Fish Chance§7."); + if (bait.getTrophyFishChanceBonus() > 0) { + lore.add("§7Grants §6+" + format(bait.getTrophyFishChanceBonus()) + " Trophy Fish Chance§7."); } - if (bait.doubleHookChanceBonus() > 0) { - lore.add("§7Grants §9+" + format(bait.doubleHookChanceBonus()) + " Double Hook Chance§7."); + if (bait.getDoubleHookChanceBonus() > 0) { + lore.add("§7Grants §9+" + format(bait.getDoubleHookChanceBonus()) + " Double Hook Chance§7."); } - if (bait.mediums().size() == 1) { - lore.add("§7Usable in §" + (bait.mediums().getFirst() == FishingMedium.WATER ? "bWater" : "cLava") + "§7."); + if (bait.getMediums().size() == 1) { + lore.add("§7Usable in " + (bait.getMediums().getFirst() == FishingMedium.WATER ? "§bWater" : "§cLava") + "§7."); } - finishFooter(lore, bait.itemId(), "BAIT"); + finishFooter(lore, bait.getItemId(), "BAIT"); return ItemStackCreator.getStackHead( - coloredName(bait.itemId(), bait.displayName()), - bait.texture(), + coloredName(bait.getItemId(), bait.getDisplayName()), + bait.getTexture(), 1, lore.toArray(String[]::new) ); } - public static net.minestom.server.item.ItemStack.Builder buildRodPartStack(RodPartDefinition part) { + 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.category().name()) + " Rod Part"); + lore.add("§8" + StringUtility.toNormalCase(part.getCategory().name()) + " Rod Part"); lore.add(""); - appendStatistics(lore, part.statistics()); - appendTagBonuses(lore, part.tagBonuses()); + appendStatistics(lore, partItem.getAttributeHandler().getStatistics()); + appendTagBonuses(lore, part.getTagBonuses()); - if (part.treasureOnly()) { + if (part.isTreasureOnly()) { lore.add("§7Only allows you to catch items and §6Treasure§7."); } - if (part.bayouTreasureToJunk()) { + if (part.isBayouTreasureToJunk()) { lore.add("§7Replaces §6Treasure §7catches with §2Junk §7in the §2Backwater Bayou§7."); } - if (part.materializedItemId() != null) { - String itemName = ItemType.valueOf(part.materializedItemId()).getDisplayName(); - if (part.materializedChance() >= 1.0D) { + 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.materializedChance() * 100.0D) + "% §7chance to materialize §f" + itemName + "§7."); + lore.add("§7Has a §a" + format(part.getMaterializedChance() * 100.0D) + "% §7chance to materialize §f" + itemName + "§7."); } } - if (part.baitPreservationChance() > 0) { - lore.add("§7Grants a §a" + format(part.baitPreservationChance()) + "% §7chance to not consume Bait."); + if (part.getBaitPreservationChance() > 0) { + lore.add("§7Grants a §a" + format(part.getBaitPreservationChance()) + "% §7chance to not consume Bait."); } - if (part.hotspotBuffMultiplier() > 1.0D) { - lore.add("§7Increases the bonuses of §dFishing Hotspots §7by §a" + format((part.hotspotBuffMultiplier() - 1.0D) * 100.0D) + "%§7."); + 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.requiredFishingLevel() > 0) { + if (part.getRequiredFishingLevel() > 0) { lore.add(""); - lore.add("§4❣ §cRequires §aFishing Skill " + part.requiredFishingLevel() + "§c."); + lore.add("§4❣ §cRequires §aFishing Skill " + part.getRequiredFishingLevel() + "§c."); } - finishFooter(lore, part.itemId(), "ROD PART"); + finishFooter(lore, part.getItemId(), "ROD PART"); return ItemStackCreator.getStackHead( - coloredName(part.itemId(), part.displayName()), - part.texture(), + coloredName(part.getItemId(), part.getDisplayName()), + part.getTexture(), 1, lore.toArray(String[]::new) ); @@ -148,4 +151,4 @@ private static String format(double value) { } return StringUtility.decimalify(value, 1); } -} \ No newline at end of file +} 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 index 5dd5df60a..7b14e8009 100644 --- 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 @@ -9,7 +9,7 @@ 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.FishingItemCatalog; +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}; @@ -32,7 +32,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont )); int index = 0; - for (var bait : FishingItemCatalog.getBaits()) { + for (var bait : FishingItemSupport.getBaits()) { if (index >= BAIT_SLOTS.length) { break; } 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/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/ItemConfigParser.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/ItemConfigParser.java index cc4015e79..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,10 +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.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.fishing.FishingMedium; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; -import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; +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.*; @@ -168,36 +167,33 @@ yield new EnchantableComponent( } case "FISHING_ROD" -> new FishingRodComponent(); case "FISHING_ROD_METADATA" -> { - String displayName = safeConfig.getString("display_name"); - String subtitle = safeConfig.getString("subtitle", null); FishingMedium medium = safeConfig.containsKey("medium") ? safeConfig.getEnum("medium", FishingMedium.class) : FishingMedium.WATER; int requiredFishingLevel = safeConfig.getInt("required_fishing_level", 0); - Map enchantments = new java.util.EnumMap<>(EnchantmentType.class); - for (Map.Entry entry : safeConfig.getMap("enchantments").entrySet()) { - enchantments.put(EnchantmentType.valueOf(entry.getKey().toUpperCase()), ((Number) entry.getValue()).intValue()); - } + 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( - displayName, - subtitle, medium, requiredFishingLevel, - enchantments, - safeConfig.getString("legacy_conversion_target", null), - safeConfig.getString("legacy_conversion_part", null), - safeConfig.getBoolean("rod_parts_enabled", true) + rodPartsEnabled, + legacyConversionTarget, + subtitle, + extraRequirements ); } case "FISHING_ROD_PART" -> { String displayName = safeConfig.getString("display_name"); - RodPartDefinition.PartCategory category = safeConfig.getEnum("category", RodPartDefinition.PartCategory.class); + 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, @@ -221,6 +217,7 @@ yield new FishingRodPartComponent( ? 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), @@ -233,8 +230,8 @@ yield new FishingBaitComponent( } case "FISHING_SHIP_PART" -> { String displayName = safeConfig.getString("display_name"); - ShipPartDefinition.ShipPartSlot slot = safeConfig.getEnum("slot", ShipPartDefinition.ShipPartSlot.class); - yield new FishingShipPartComponent(displayName, slot, safeConfig.getString("texture", null)); + FishingShipPartSlot slot = safeConfig.getEnum("slot", FishingShipPartSlot.class); + yield new FishingShipPartComponent(itemId, displayName, slot, safeConfig.getString("texture", null)); } case "ENCHANTED" -> { if (safeConfig.containsKey("recipes")) { @@ -737,4 +734,4 @@ private static List parseGemstoneEntries(List tagBonuses; private final double treasureChanceBonus; @@ -18,6 +21,7 @@ public class FishingBaitComponent extends net.swofty.type.skyblockgeneric.item.S private final String texture; public FishingBaitComponent( + String itemId, String displayName, Map tagBonuses, double treasureChanceBonus, @@ -27,7 +31,11 @@ public FishingBaitComponent( List mediums, String texture ) { - this.displayName = displayName; + 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; @@ -36,11 +44,11 @@ public FishingBaitComponent( this.mediums = List.copyOf(mediums); this.texture = texture; - addInheritedComponent(new CustomDisplayNameComponent(ignored -> displayName)); + 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")); } -} \ No newline at end of file +} 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 index 7fdad90bb..c7dba0d77 100644 --- 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 @@ -3,7 +3,7 @@ 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.FishingItemCatalog; +import net.swofty.type.skyblockgeneric.fishing.FishingItemSupport; import net.swofty.type.skyblockgeneric.fishing.FishingService; import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; @@ -29,8 +29,8 @@ public FishingRodComponent() { ); } else { String itemId = item.getAttributeHandler().getPotentialType() == null ? null : item.getAttributeHandler().getPotentialType().name(); - var definition = FishingItemCatalog.getRod(itemId); - if (definition != null && definition.legacyConversionTarget() != null) { + var metadata = FishingItemSupport.getRodMetadata(itemId); + if (metadata != null && metadata.getLegacyConversionTarget() != null) { return; } new FishingHook(player, item).spawn(player.getInstance()); 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 index 81a9b6faf..ccb7f8c8c 100644 --- 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 @@ -2,51 +2,41 @@ import lombok.Getter; import net.swofty.commons.skyblock.item.reforge.ReforgeType; -import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; 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; -import java.util.Map; @Getter -public class FishingRodMetadataComponent extends net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent { - private final String displayName; - private final String subtitle; +public class FishingRodMetadataComponent extends SkyBlockItemComponent { private final FishingMedium medium; private final int requiredFishingLevel; - private final Map enchantments; - private final String legacyConversionTarget; - private final String legacyConversionPart; private final boolean rodPartsEnabled; + private final @Nullable String legacyConversionTarget; + private final @Nullable String subtitle; + private final List extraRequirements; public FishingRodMetadataComponent( - String displayName, - String subtitle, FishingMedium medium, int requiredFishingLevel, - Map enchantments, - String legacyConversionTarget, - String legacyConversionPart, - boolean rodPartsEnabled + boolean rodPartsEnabled, + @Nullable String legacyConversionTarget, + @Nullable String subtitle, + List extraRequirements ) { - this.displayName = displayName; - this.subtitle = subtitle; this.medium = medium; this.requiredFishingLevel = requiredFishingLevel; - this.enchantments = Map.copyOf(enchantments); - this.legacyConversionTarget = legacyConversionTarget; - this.legacyConversionPart = legacyConversionPart; this.rodPartsEnabled = rodPartsEnabled; - - addInheritedComponent(new CustomDisplayNameComponent(ignored -> displayName)); - if (subtitle != null && !subtitle.isBlank()) { - addInheritedComponent(new ExtraUnderNameComponent(subtitle)); - } + 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)); } -} \ No newline at end of file +} 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 index 16f6f2403..1cc4f105e 100644 --- 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 @@ -1,14 +1,16 @@ package net.swofty.type.skyblockgeneric.item.components; import lombok.Getter; -import net.swofty.type.skyblockgeneric.fishing.RodPartDefinition; +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 RodPartDefinition.PartCategory category; + private final FishingPartCategory category; private final int requiredFishingLevel; private final Map tagBonuses; private final boolean treasureOnly; @@ -20,8 +22,9 @@ public class FishingRodPartComponent extends net.swofty.type.skyblockgeneric.ite private final String texture; public FishingRodPartComponent( + String itemId, String displayName, - RodPartDefinition.PartCategory category, + FishingPartCategory category, int requiredFishingLevel, Map tagBonuses, boolean treasureOnly, @@ -32,7 +35,11 @@ public FishingRodPartComponent( double hotspotBuffMultiplier, String texture ) { - this.displayName = displayName; + 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); @@ -44,10 +51,10 @@ public FishingRodPartComponent( this.hotspotBuffMultiplier = hotspotBuffMultiplier; this.texture = texture; - addInheritedComponent(new CustomDisplayNameComponent(ignored -> displayName)); + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); if (texture != null && !texture.isBlank()) { addInheritedComponent(new SkullHeadComponent(ignored -> texture)); } addInheritedComponent(new ExtraRarityComponent("ROD PART")); } -} \ No newline at end of file +} 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 index 3a2aef7dd..3ef56d3d2 100644 --- 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 @@ -1,22 +1,28 @@ package net.swofty.type.skyblockgeneric.item.components; import lombok.Getter; -import net.swofty.type.skyblockgeneric.fishing.ShipPartDefinition; +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 ShipPartDefinition.ShipPartSlot slot; + private final FishingShipPartSlot slot; private final String texture; - public FishingShipPartComponent(String displayName, ShipPartDefinition.ShipPartSlot slot, String texture) { - this.displayName = displayName; + 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 -> displayName)); + addInheritedComponent(new CustomDisplayNameComponent(ignored -> this.displayName)); if (texture != null && !texture.isBlank()) { addInheritedComponent(new SkullHeadComponent(ignored -> texture)); } } -} \ No newline at end of file +} 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 +}