From f0b28416c0af10895391fb0abda09e63bcb9de64 Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 17:38:06 -0700 Subject: [PATCH] Add fishing stuff from TU 31 --- .../Common/Media/MediaWindows64.arc | Bin 28555724 -> 28556979 bytes Minecraft.Client/Common/Media/languages.loc | Bin 1345659 -> 1352096 bytes Minecraft.Client/Windows64Media/strings.h | 20 +-- Minecraft.World/Enchantment.cpp | 11 ++ Minecraft.World/Enchantment.h | 4 + Minecraft.World/EnchantmentCategory.cpp | 5 + Minecraft.World/EnchantmentCategory.h | 1 + Minecraft.World/FishingHelper.cpp | 118 ++++++++++++++++++ Minecraft.World/FishingHelper.h | 82 ++++++++++++ Minecraft.World/FishingHook.cpp | 81 ++++++++++-- Minecraft.World/FishingHook.h | 2 + Minecraft.World/FishingRodItem.cpp | 6 + Minecraft.World/FishingRodItem.h | 2 +- Minecraft.World/Item.cpp | 4 +- Minecraft.World/LuckOfTheSeaEnchantment.cpp | 25 ++++ Minecraft.World/LuckOfTheSeaEnchantment.h | 13 ++ Minecraft.World/LureEnchantment.cpp | 25 ++++ Minecraft.World/LureEnchantment.h | 13 ++ Minecraft.World/cmake/sources/Common.cmake | 6 + .../net.minecraft.world.item.enchantment.h | 8 +- 20 files changed, 401 insertions(+), 25 deletions(-) create mode 100644 Minecraft.World/LuckOfTheSeaEnchantment.cpp create mode 100644 Minecraft.World/LuckOfTheSeaEnchantment.h diff --git a/Minecraft.Client/Common/Media/MediaWindows64.arc b/Minecraft.Client/Common/Media/MediaWindows64.arc index 70c6ec67ee74241d25fa4a4362ad1cd306eaa5ae..0ccfd55c802d0d9cc314e4a74aaa4d83cd2aac90 100644 GIT binary patch delta 4401 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 diff --git a/Minecraft.Client/Common/Media/languages.loc b/Minecraft.Client/Common/Media/languages.loc index 3fb5b1a0671cbbd08835e2fd5b458058d99a0d3f..f65559b2b574222fbf878b0be91d35c5d0c737e6 100644 GIT binary patch delta 4484 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 Z#R5p3|9YYA{_BNbor9=ZSTB;Q2mlaIr~3c^ diff --git a/Minecraft.Client/Windows64Media/strings.h b/Minecraft.Client/Windows64Media/strings.h index 5e4fe229..8853998e 100644 --- a/Minecraft.Client/Windows64Media/strings.h +++ b/Minecraft.Client/Windows64Media/strings.h @@ -1,7 +1,7 @@ #pragma once // Auto-generated by StringTable builder — do not edit manually. // Source language: en-US -// Total strings: 2339 +// Total strings: 2416 #define IDS_NULL 0 #define IDS_OK 1 @@ -2345,19 +2345,19 @@ #define IDS_TILE_PRISMARINE 2339 #define IDS_TILE_PRISMARINE_DARK 2340 #define IDS_TILE_PRISMARINE_BRICKS 2341 -#define IDS_ITEM_PRISMARINE_SHARD 2342 -#define IDS_ITEM_PRISMARINE_DESC 2343 -#define IDS_ITEM_PRISMARINE_DARK_DESC 2344 -#define IDS_ITEM_PRISMARINE_BRICK_DESC 2345 -#define IDS_ITEM_PRISMARINE_CRYSTAL_DESC 2346 -#define IDS_ITEM_PRISMARINE_SHARD_DESC 2347 +#define IDS_ITEM_PRISMARINE_SHARD 2342 +#define IDS_ITEM_PRISMARINE_DESC 2343 +#define IDS_ITEM_PRISMARINE_DARK_DESC 2344 +#define IDS_ITEM_PRISMARINE_BRICK_DESC 2345 +#define IDS_ITEM_PRISMARINE_CRYSTAL_DESC 2346 +#define IDS_ITEM_PRISMARINE_SHARD_DESC 2347 #define IDS_ITEM_RABBIT_STEW 2348 #define IDS_TILE_DOUBLE_TALL_GRASS 2349 #define IDS_TILE_LARGE_FERN 2350 #define IDS_TILE_LILAC 2351 #define IDS_TILE_ROSE_BUSH 2352 #define IDS_TILE_PEONY 2353 -#define IDS_TILE_PACKED_ICE 2354 +#define IDS_TILE_PACKED_ICE 2354 #define IDS_TILE_SUNFLOWER 2355 #define IDS_DESC_PACKED_ICE 2356 #define IDS_DESC_RED_SANDSTONE 2357 @@ -2416,4 +2416,6 @@ #define IDS_DESC_LARGE_FERN 2410 #define IDS_DESC_ROSE_BUSH 2411 #define IDS_DESC_PEONY 2412 -#define IDS_ENDERMITE 2413 \ No newline at end of file +#define IDS_ENDERMITE 2413 +#define IDS_ENCHANTMENT_LUCK_OF_THE_SEA 2414 +#define IDS_ENCHANTMENT_LURE 2415 diff --git a/Minecraft.World/Enchantment.cpp b/Minecraft.World/Enchantment.cpp index c2f981a6..5d0743cc 100644 --- a/Minecraft.World/Enchantment.cpp +++ b/Minecraft.World/Enchantment.cpp @@ -3,6 +3,9 @@ #include "net.minecraft.world.item.h" #include "Enchantment.h" +#include "LuckOfTheSeaEnchantment.h" +#include "LureEnchantment.h" + //Enchantment *Enchantment::enchantments[256]; EnchantmentArray Enchantment::enchantments = EnchantmentArray( 256 ); vector Enchantment::validEnchantments; @@ -36,6 +39,10 @@ Enchantment *Enchantment::arrowKnockback = nullptr; Enchantment *Enchantment::arrowFire = nullptr; Enchantment *Enchantment::arrowInfinite = nullptr; +// fishing rod +Enchantment *Enchantment::lure = nullptr; +Enchantment *Enchantment::luckOfTheSea = nullptr; + void Enchantment::staticCtor() { allDamageProtection = new ProtectionEnchantment(0, FREQ_COMMON, ProtectionEnchantment::ALL); @@ -67,6 +74,10 @@ void Enchantment::staticCtor() arrowFire = new ArrowFireEnchantment(50, FREQ_RARE); arrowInfinite = new ArrowInfiniteEnchantment(51, FREQ_VERY_RARE); + // fishing rod + lure = new LureEnchantment(64, FREQ_RARE); + luckOfTheSea = new LuckOfTheSeaEnchantment(65, FREQ_RARE); + for(unsigned int i = 0; i < 256; ++i) { Enchantment *enchantment = enchantments[i]; diff --git a/Minecraft.World/Enchantment.h b/Minecraft.World/Enchantment.h index 7daa1a37..d7bbca58 100644 --- a/Minecraft.World/Enchantment.h +++ b/Minecraft.World/Enchantment.h @@ -47,6 +47,10 @@ public : static Enchantment *arrowFire; static Enchantment *arrowInfinite; + // fishing rod + static Enchantment *lure; + static Enchantment *luckOfTheSea; + const int id; static void staticCtor(); diff --git a/Minecraft.World/EnchantmentCategory.cpp b/Minecraft.World/EnchantmentCategory.cpp index b1c951ee..437c8e5d 100644 --- a/Minecraft.World/EnchantmentCategory.cpp +++ b/Minecraft.World/EnchantmentCategory.cpp @@ -11,6 +11,7 @@ const EnchantmentCategory *EnchantmentCategory::armor_head = new EnchantmentCate const EnchantmentCategory *EnchantmentCategory::weapon = new EnchantmentCategory(); const EnchantmentCategory *EnchantmentCategory::digger = new EnchantmentCategory(); const EnchantmentCategory *EnchantmentCategory::bow = new EnchantmentCategory(); +const EnchantmentCategory *EnchantmentCategory::fishing_rod = new EnchantmentCategory(); bool EnchantmentCategory::canEnchant(Item *item) const { @@ -38,5 +39,9 @@ bool EnchantmentCategory::canEnchant(Item *item) const { return this == bow; } + else if (dynamic_cast(item) != nullptr) + { + return this == fishing_rod; + } return false; } \ No newline at end of file diff --git a/Minecraft.World/EnchantmentCategory.h b/Minecraft.World/EnchantmentCategory.h index b5976307..aebf97bd 100644 --- a/Minecraft.World/EnchantmentCategory.h +++ b/Minecraft.World/EnchantmentCategory.h @@ -14,6 +14,7 @@ public: static const EnchantmentCategory *weapon; static const EnchantmentCategory *digger; static const EnchantmentCategory *bow; + static const EnchantmentCategory *fishing_rod; bool canEnchant(Item *item) const; }; \ No newline at end of file diff --git a/Minecraft.World/FishingHelper.cpp b/Minecraft.World/FishingHelper.cpp index e69de29b..1d2015c5 100644 --- a/Minecraft.World/FishingHelper.cpp +++ b/Minecraft.World/FishingHelper.cpp @@ -0,0 +1,118 @@ + +#include "../Minecraft.World/WeighedTreasure.h" +#include "../Minecraft.World/Biome.h" +#include "../Minecraft.World/FishingHelper.h" +#include "../Minecraft.World/ItemInstance.h" +#include "../Minecraft.World/EnchantmentHelper.h" +#include +#include "net.minecraft.world.item.h" + +FishingHelper* FishingHelper::getInstance() +{ + static FishingHelper instance; + return &instance; +} + +FishingHelper::FishingHelper() : + random(new Random()), level0Array(3), level1Array(3), level2Array(3), level3Array(3), + fishingFishArray(4), fishingJunkArray(12), fishingTreasuresArray(5) +{ + + // Source: https://minecraft.wiki/w/Fishing + level0Array[0] = new CatchTypeWeighedItem(CatchType::JUNK, 10 ); + level0Array[1] = new CatchTypeWeighedItem(CatchType::TREASURE, 5 ); + level0Array[2] = new CatchTypeWeighedItem(CatchType::FISH, 85 ); + + level1Array[0] = new CatchTypeWeighedItem(CatchType::JUNK, 81 ); + level1Array[1] = new CatchTypeWeighedItem(CatchType::TREASURE, 71 ); + level1Array[2] = new CatchTypeWeighedItem(CatchType::FISH, 848 ); + + level2Array[0] = new CatchTypeWeighedItem(CatchType::JUNK, 61 ); + level2Array[1] = new CatchTypeWeighedItem(CatchType::TREASURE, 92 ); + level2Array[2] = new CatchTypeWeighedItem(CatchType::FISH, 847 ); + + level3Array[0] = new CatchTypeWeighedItem(CatchType::JUNK, 41 ); + level3Array[1] = new CatchTypeWeighedItem(CatchType::TREASURE, 113 ); + level3Array[2] = new CatchTypeWeighedItem(CatchType::FISH, 845 ); + + fishingTreasuresArray[0] = new CatchWeighedItem(Item::bow_Id, 1, 0, 1); + fishingTreasuresArray[1] = new CatchWeighedItem(Item::book_Id, 1, 0, 1); + fishingTreasuresArray[2] = new CatchWeighedItem(Item::fishingRod_Id, 1, 0, 1); + fishingTreasuresArray[3] = new CatchWeighedItem(Item::nameTag_Id, 1, 0, 2); // Doubled the chance of name tags to account for lack of nautilus shells. + fishingTreasuresArray[4] = new CatchWeighedItem(Item::saddle_Id, 1, 0, 1); + + fishingFishArray[0] = new CatchWeighedItem(Item::fish_raw_Id, 1, 0, 60); // Fish + fishingFishArray[1] = new CatchWeighedItem(Item::fish_raw_Id, 1, 1, 25); // Salmon + fishingFishArray[2] = new CatchWeighedItem(Item::fish_raw_Id, 1, 2, 2); // Clownfish + fishingFishArray[3] = new CatchWeighedItem(Item::fish_raw_Id, 1, 3, 13); // Pufferfish + + fishingJunkArray[0] = new CatchWeighedItem(Tile::waterLily_Id, 1, 0, 17); + fishingJunkArray[1] = new CatchWeighedItem(Item::bone_Id, 1, 0, 10); + fishingJunkArray[2] = new CatchWeighedItem(Item::bowl_Id, 1, 0, 10); + fishingJunkArray[3] = new CatchWeighedItem(Item::leather_Id, 1, 0, 10); + fishingJunkArray[4] = new CatchWeighedItem(Item::boots_leather_Id, 1, 0, 10); + fishingJunkArray[5] = new CatchWeighedItem(Item::rotten_flesh_Id, 1, 0, 10); + fishingJunkArray[6] = new CatchWeighedItem(Item::potion_Id, 1, 0, 10); // Water bottle + fishingJunkArray[7] = new CatchWeighedItem(Tile::tripWireSource_Id, 1, 0, 10); + fishingJunkArray[8] = new CatchWeighedItem(Item::stick_Id, 1, 0, 5); + fishingJunkArray[9] = new CatchWeighedItem(Item::string_Id, 1, 0, 5); + fishingJunkArray[10] = new CatchWeighedItem(Item::fishingRod_Id, 1, 0, 2); + fishingJunkArray[11] = new CatchWeighedItem(Item::dye_powder_Id, 10, 0, 1); // 10 ink sacs +} + +CatchType FishingHelper::getRandCatchType(int level) +{ + CatchTypeWeighedItem* catchTypeWeighedItem = nullptr; + switch (level) { + case 0: + catchTypeWeighedItem = static_cast(WeighedRandom::getRandomItem(random, level0Array)); + return catchTypeWeighedItem->getType(); + case 1: + catchTypeWeighedItem = static_cast(WeighedRandom::getRandomItem(random, level1Array)); + return catchTypeWeighedItem->getType(); + case 2: + catchTypeWeighedItem = static_cast(WeighedRandom::getRandomItem(random, level2Array)); + return catchTypeWeighedItem->getType(); + case 3: + catchTypeWeighedItem = static_cast(WeighedRandom::getRandomItem(random, level3Array)); + return catchTypeWeighedItem->getType(); + } +} + +CatchWeighedItem* FishingHelper::getRandCatch(CatchType catchType) +{ + CatchWeighedItem* catchWeighedItem = nullptr; + switch (catchType) { + case CatchType::FISH: + return static_cast(WeighedRandom::getRandomItem(random, fishingFishArray)); + case CatchType::TREASURE: + return static_cast(WeighedRandom::getRandomItem(random, fishingTreasuresArray));; + case CatchType::JUNK: + return static_cast(WeighedRandom::getRandomItem(random, fishingJunkArray)); + } +} + +std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType) +{ + + std::shared_ptr itemInstance = std::make_shared( + weighedCatch->getItemId(), weighedCatch->getCount(), weighedCatch->getAuxValue() + ); + + if ((itemInstance->id== Item::fishingRod_Id && catchType == CatchType::JUNK) || (itemInstance->id == Item::boots_leather_Id)) { + itemInstance->setAuxValue((int) (itemInstance->getMaxDamage() * ((double) random->nextInt(901) + 100.0) / 1000.0)); // 10% to 100% damage + } + else if (itemInstance->id == Item::fishingRod_Id && catchType == CatchType::TREASURE) { + itemInstance->setAuxValue((int) (itemInstance->getMaxDamage() * ((double) random->nextInt(251) + 750.0) / 1000.0)); // 75% to 100% damage + itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, random->nextInt(9) + 22); // 22 to 30 enchantment level + } + else if (itemInstance->id == Item::bow_Id) { + itemInstance->setAuxValue((int) (itemInstance->getMaxDamage() * ((double) random->nextInt(250) + 750.0) / 1000.0)); // 75% to 100% damage + itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, random->nextInt(9) + 22); // 22 to 30 enchantment level + } + else if (itemInstance->id == Item::book_Id) { + itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, 30); + } + + return itemInstance; +} \ No newline at end of file diff --git a/Minecraft.World/FishingHelper.h b/Minecraft.World/FishingHelper.h index e69de29b..78431785 100644 --- a/Minecraft.World/FishingHelper.h +++ b/Minecraft.World/FishingHelper.h @@ -0,0 +1,82 @@ +#pragma once + +#include "../Minecraft.World/WeighedTreasure.h" +#include "../Minecraft.World/ItemInstance.h" +#include "net.minecraft.world.item.h" +#include +#include + +enum CatchType { + FISH, + TREASURE, + JUNK +}; + +class CatchTypeWeighedItem : public WeighedRandomItem { + protected: + CatchType type; + + public: + CatchTypeWeighedItem(CatchType type, int weight) : WeighedRandomItem(weight) + { + this->type = type; + } + + CatchType getType() + { + return type; + } +}; + +class CatchWeighedItem : public WeighedRandomItem { + protected: + int itemId; + int count; + int auxValue; + + public: + CatchWeighedItem(int itemId, int count, int auxValue, int weight) : WeighedRandomItem(weight) + { + this->itemId = itemId; + this->count = count; + this->auxValue = auxValue; + } + int getItemId() + { + return this->itemId; + } + int getCount() + { + return this->count; + } + int getAuxValue() + { + return this->auxValue; + } +}; + +class FishingHelper +{ + private: + FishingHelper(); + Random* random; + + WeighedRandomItemArray level0Array; + WeighedRandomItemArray level1Array; + WeighedRandomItemArray level2Array; + WeighedRandomItemArray level3Array; + + WeighedRandomItemArray fishingFishArray; + WeighedRandomItemArray fishingJunkArray; + WeighedRandomItemArray fishingTreasuresArray; + public: + + FishingHelper(const FishingHelper&) = delete; + FishingHelper& operator=(const FishingHelper&) = delete; + + static FishingHelper* getInstance(); + + CatchType getRandCatchType(int level); + CatchWeighedItem* getRandCatch(CatchType catchType); + std::shared_ptr handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType); +}; \ No newline at end of file diff --git a/Minecraft.World/FishingHook.cpp b/Minecraft.World/FishingHook.cpp index ba0876d9..23ceb241 100644 --- a/Minecraft.World/FishingHook.cpp +++ b/Minecraft.World/FishingHook.cpp @@ -11,8 +11,13 @@ #include "com.mojang.nbt.h" #include "FishingHook.h" #include "SoundTypes.h" +#include "../Minecraft.World/FishingHelper.h" +#include "../Minecraft.World/EnchantmentHelper.h" +#include "../Minecraft.World/Enchantment.h" +#include "../Minecraft.World/ItemInstance.h" +#include // 4J - added common ctor code. void FishingHook::_init() @@ -29,6 +34,10 @@ void FishingHook::_init() shakeTime = 0; flightTime = 0; nibble = 0; + + // TU 31: Fishing rod now has a random nibble timer between 5 and 30 seconds, instead of a 1/500 chance every tick (plus modifiers). Source: https://minecraft.wiki/w/Fishing + nibbleTimer = random->nextInt(501) + 100; + lureTime = 0; hookedIn = nullptr; lSteps = 0; @@ -52,7 +61,7 @@ FishingHook::FishingHook(Level *level) : Entity( level ) _init(); } -FishingHook::FishingHook(Level *level, double x, double y, double z, shared_ptr owner) : Entity( level ) +FishingHook::FishingHook(Level *level, double x, double y, double z, std::shared_ptr owner) : Entity( level ) { _init(); @@ -63,7 +72,7 @@ FishingHook::FishingHook(Level *level, double x, double y, double z, shared_ptr< setPos(x, y, z); } -FishingHook::FishingHook(Level *level, shared_ptr mob) : Entity( level ) +FishingHook::FishingHook(Level *level, std::shared_ptr mob) : Entity( level ) { _init(); @@ -172,7 +181,7 @@ void FishingHook::tick() if (!level->isClientSide) { - shared_ptr selectedItem = owner->getSelectedItem(); + std::shared_ptr selectedItem = owner->getSelectedItem(); if (owner->removed || !owner->isAlive() || selectedItem == nullptr || selectedItem->getItem() != Item::fishingRod || distanceToSqr(owner) > 32 * 32) { remove(); @@ -230,12 +239,12 @@ void FishingHook::tick() { to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z); } - shared_ptr hitEntity = nullptr; - vector > *objects = level->getEntities(shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1)); + std::shared_ptr hitEntity = nullptr; + vector< std::shared_ptr > *objects = level->getEntities(shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1)); double nearest = 0; for (auto it = objects->begin(); it != objects->end(); it++) { - shared_ptr e = *it; // objects->at(i); + std::shared_ptr e = *it; // objects->at(i); if (!e->isPickable() || (e == owner && flightTime < 5)) continue; float rr = 0.3f; @@ -325,16 +334,48 @@ void FishingHook::tick() { if (nibble > 0) { + nibble--; } else - { - int nibbleOdds = 500; - if (level->isRainingAt( Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z))) nibbleOdds = 300; + { + // TU 31: Raining affects the nibble timer by random chance rather than being a fixed rate. Source: https://minecraft.wiki/w/Fishing + if (!(level->isRainingAt( Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z)))) { + nibbleTimer--; + } - if (random->nextInt(nibbleOdds) == 0) + else { + if (random->nextInt(4) == 0) { + nibbleTimer -= 2; + } + else { + nibbleTimer--; + } + } + + // Only calculate the effect of lure if it hasn't been calculated already. + if (lureTime == 0 && owner != nullptr) { - nibble = random->nextInt(30) + 10; + std::shared_ptr selectedItemLureCheck = owner->getSelectedItem(); + int level = EnchantmentHelper::getEnchantmentLevel(64, selectedItemLureCheck); // Lure + lureTime = level * 100; + nibbleTimer -= lureTime; + // if the lure effect causes the nibble timer to go below 0, reset the timer and lure time to recalculate next tick. Source: https://minecraft.wiki/w/Fishing + if (nibbleTimer < 0) + { + nibbleTimer = random->nextInt(501) + 100; + lureTime = 0; + } + } + + // Checks if the nibble timer has ran out. Edge case for if it's raining and the nibble timer goes + // below 0 due to the random chance of the rain decreasing the timer by 2 instead of 1. + if (nibbleTimer == 0 || nibbleTimer == -1) + { + // TU 31: Increase the nibble time to between 1 and 2 seconds. https://minecraft.wiki/w/Fishing + nibble = random->nextInt(21) + 20; + nibbleTimer = random->nextInt(501) + 100; + lureTime = 0; yd -= 0.2f; playSound(eSoundType_RANDOM_SPLASH, 0.25f, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); float yt = static_cast(Mth::floor(bb->y0)); @@ -420,7 +461,23 @@ int FishingHook::retrieve() } else if (nibble > 0) { - shared_ptr ie = std::make_shared(this->Entity::level, x, y, z, shared_ptr(new ItemInstance(Item::fish_raw))); + FishingHelper* helper = FishingHelper::getInstance(); + + std::shared_ptr selectedItemSeaLuck = owner->getSelectedItem(); + int luckLevel = EnchantmentHelper::getEnchantmentLevel(65, selectedItemSeaLuck); // Luck of the sea + CatchType type = helper->getRandCatchType(luckLevel); + CatchWeighedItem* caughtItem = helper->getRandCatch(type); + + std::shared_ptr fishingItemInstance; + + if (!caughtItem) { + // Fall back to default if caught item is a nullptr + fishingItemInstance = shared_ptr(new ItemInstance(Item::fish_raw)); + } else { + fishingItemInstance = helper->handleCatch(caughtItem, type); + } + + std::shared_ptr ie = std::make_shared(this->Entity::level, x, y, z, fishingItemInstance); double xa = owner->x - x; double ya = owner->y - y; double za = owner->z - z; diff --git a/Minecraft.World/FishingHook.h b/Minecraft.World/FishingHook.h index ec91e630..275f6cf6 100644 --- a/Minecraft.World/FishingHook.h +++ b/Minecraft.World/FishingHook.h @@ -25,6 +25,8 @@ private: int life; int flightTime; int nibble; + int nibbleTimer; + int lureTime; public: shared_ptr hookedIn; diff --git a/Minecraft.World/FishingRodItem.cpp b/Minecraft.World/FishingRodItem.cpp index b9eafd18..95408fa5 100644 --- a/Minecraft.World/FishingRodItem.cpp +++ b/Minecraft.World/FishingRodItem.cpp @@ -30,6 +30,12 @@ bool FishingRodItem::isMirroredArt() return true; } +// This makes it so that fishing rods can be enchanted at an enchanting table. +int FishingRodItem::getEnchantmentValue() +{ + return 1; // Enchantibility of a fishing rod. // Source: https://minecraft.wiki/w/Fishing_Rod +} + shared_ptr FishingRodItem::use(shared_ptr instance, Level *level, shared_ptr player) { if (player->fishing != nullptr) diff --git a/Minecraft.World/FishingRodItem.h b/Minecraft.World/FishingRodItem.h index 5d95177a..4a6153d5 100644 --- a/Minecraft.World/FishingRodItem.h +++ b/Minecraft.World/FishingRodItem.h @@ -17,7 +17,7 @@ public: virtual bool isHandEquipped(); virtual bool isMirroredArt(); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); - + virtual int getEnchantmentValue(); void registerIcons(IconRegister *iconRegister); Icon *getEmptyIcon(); }; diff --git a/Minecraft.World/Item.cpp b/Minecraft.World/Item.cpp index 7e115adc..c4e9de69 100644 --- a/Minecraft.World/Item.cpp +++ b/Minecraft.World/Item.cpp @@ -398,8 +398,8 @@ void Item::staticCtor() Item::egg = ( new EggItem(88) ) ->setIconName(L"egg")->setDescriptionId(IDS_ITEM_EGG)->setUseDescriptionId(IDS_DESC_EGG); Item::fishingRod = static_cast((new FishingRodItem(90))->setBaseItemTypeAndMaterial(eBaseItemType_rod, eMaterial_wood)->setIconName(L"fishingRod")->setDescriptionId(IDS_ITEM_FISHING_ROD)->setUseDescriptionId(IDS_DESC_FISHINGROD)); Item::yellowDust = ( new Item(92) ) ->setIconName(L"yellowDust")->setDescriptionId(IDS_ITEM_YELLOW_DUST)->setUseDescriptionId(IDS_DESC_YELLOW_DUST)->setPotionBrewingFormula(PotionBrewing::MOD_GLOWSTONE); - Item::fish_raw = ( new FishFoodItem(93, false) ) ->setIconName(L"fishRaw")->setDescriptionId(IDS_ITEM_FISH_RAW)->setUseDescriptionId(IDS_DESC_FISH_RAW); - Item::fish_cooked = (new FishFoodItem(94, true)) ->setIconName(L"fishCooked")->setDescriptionId(IDS_ITEM_FISH_COOKED)->setUseDescriptionId(IDS_DESC_FISH_COOKED); + Item::fish_raw = ( new FishFoodItem(93, false) ) ->setIconName(L"fishRaw")->setDescriptionId(IDS_ITEM_FISH_RAW)->setUseDescriptionId(IDS_DESC_FISH_RAW)->setStackedByData(true); + Item::fish_cooked = (new FishFoodItem(94, true)) ->setIconName(L"fishCooked")->setDescriptionId(IDS_ITEM_FISH_COOKED)->setUseDescriptionId(IDS_DESC_FISH_COOKED)->setStackedByData(true); Item::dye_powder = ( new DyePowderItem(95) ) ->setBaseItemTypeAndMaterial(eBaseItemType_dyepowder, eMaterial_dye)->setIconName(L"dyePowder")->setDescriptionId(IDS_ITEM_DYE_POWDER)->setUseDescriptionId(-1); diff --git a/Minecraft.World/LuckOfTheSeaEnchantment.cpp b/Minecraft.World/LuckOfTheSeaEnchantment.cpp new file mode 100644 index 00000000..6dd8edaa --- /dev/null +++ b/Minecraft.World/LuckOfTheSeaEnchantment.cpp @@ -0,0 +1,25 @@ +#include "stdafx.h" +#include "LuckOfTheSeaEnchantment.h" + + +LuckOfTheSeaEnchantment::LuckOfTheSeaEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::fishing_rod) +{ + setDescriptionId(IDS_ENCHANTMENT_LUCK_OF_THE_SEA); +} + +// Source: https://github.com/GRAnimated/MinecraftLCE + +int LuckOfTheSeaEnchantment::getMinCost(int level) +{ + return 9 * level + 6; +} + +int LuckOfTheSeaEnchantment::getMaxCost(int level) +{ + return Enchantment::getMinCost(level) + 50;; +} + +int LuckOfTheSeaEnchantment::getMaxLevel() +{ + return 3; +} \ No newline at end of file diff --git a/Minecraft.World/LuckOfTheSeaEnchantment.h b/Minecraft.World/LuckOfTheSeaEnchantment.h new file mode 100644 index 00000000..0428dc3c --- /dev/null +++ b/Minecraft.World/LuckOfTheSeaEnchantment.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Enchantment.h" + +class LuckOfTheSeaEnchantment : public Enchantment +{ +public: + LuckOfTheSeaEnchantment(int id, int frequency); + + virtual int getMinCost(int level); + virtual int getMaxCost(int level); + virtual int getMaxLevel(); +}; \ No newline at end of file diff --git a/Minecraft.World/LureEnchantment.cpp b/Minecraft.World/LureEnchantment.cpp index e69de29b..d44e76a4 100644 --- a/Minecraft.World/LureEnchantment.cpp +++ b/Minecraft.World/LureEnchantment.cpp @@ -0,0 +1,25 @@ +#include "stdafx.h" +#include "LureEnchantment.h" + + +LureEnchantment::LureEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::fishing_rod) +{ + setDescriptionId(IDS_ENCHANTMENT_LURE); +} + +// Source: https://github.com/GRAnimated/MinecraftLCE + +int LureEnchantment::getMinCost(int level) +{ + return 9 * level + 6; +} + +int LureEnchantment::getMaxCost(int level) +{ + return Enchantment::getMinCost(level) + 50;; +} + +int LureEnchantment::getMaxLevel() +{ + return 3; +} \ No newline at end of file diff --git a/Minecraft.World/LureEnchantment.h b/Minecraft.World/LureEnchantment.h index e69de29b..e549f64b 100644 --- a/Minecraft.World/LureEnchantment.h +++ b/Minecraft.World/LureEnchantment.h @@ -0,0 +1,13 @@ + #pragma once + +#include "Enchantment.h" + +class LureEnchantment : public Enchantment +{ +public: + LureEnchantment(int id, int frequency); + + virtual int getMinCost(int level); + virtual int getMaxCost(int level); + virtual int getMaxLevel(); +}; \ No newline at end of file diff --git a/Minecraft.World/cmake/sources/Common.cmake b/Minecraft.World/cmake/sources/Common.cmake index ece0ab26..12e362ac 100644 --- a/Minecraft.World/cmake/sources/Common.cmake +++ b/Minecraft.World/cmake/sources/Common.cmake @@ -469,6 +469,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_UTIL "${CMAKE_CURRENT_SOURCE_DIR}/WeighedRandom.h" "${CMAKE_CURRENT_SOURCE_DIR}/WeighedTreasure.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/WeighedTreasure.h" + "${CMAKE_CURRENT_SOURCE_DIR}/FishingHelper.h" + "${CMAKE_CURRENT_SOURCE_DIR}/FishingHelper.cpp" ) source_group("net/minecraft/util" FILES ${_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_UTIL}) @@ -1206,6 +1208,10 @@ source_group("net/minecraft/world/item/crafting" FILES ${_MINECRAFT_WORLD_COMMON set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_WORLD_ITEM_ENCHANTMENT "${CMAKE_CURRENT_SOURCE_DIR}/ArrowDamageEnchantment.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ArrowDamageEnchantment.h" + "${CMAKE_CURRENT_SOURCE_DIR}/LureEnchantment.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/LureEnchantment.h" + "${CMAKE_CURRENT_SOURCE_DIR}/LuckOfTheSeaEnchantment.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/LuckOfTheSeaEnchantment.h" "${CMAKE_CURRENT_SOURCE_DIR}/ArrowFireEnchantment.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ArrowFireEnchantment.h" "${CMAKE_CURRENT_SOURCE_DIR}/ArrowInfiniteEnchantment.cpp" diff --git a/Minecraft.World/net.minecraft.world.item.enchantment.h b/Minecraft.World/net.minecraft.world.item.enchantment.h index c0df5226..57ec4753 100644 --- a/Minecraft.World/net.minecraft.world.item.enchantment.h +++ b/Minecraft.World/net.minecraft.world.item.enchantment.h @@ -21,4 +21,10 @@ #include "ArrowInfiniteEnchantment.h" #include "ArrowKnockbackEnchantment.h" -#include "ThornsEnchantment.h" \ No newline at end of file +#include "ThornsEnchantment.h" + +// Fishing + +#include "LuckOfTheSeaEnchantment.h" + +#include "LureEnchantment.h" \ No newline at end of file