From d75e167f12a06e461157e020f0d1a250474d4b36 Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sat, 4 Apr 2026 06:58:01 -0700 Subject: [PATCH 1/9] Add fishinghelper and lureenchantment --- Minecraft.World/FishingHelper.cpp | 0 Minecraft.World/FishingHelper.h | 0 Minecraft.World/LureEnchantment.cpp | 0 Minecraft.World/LureEnchantment.h | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Minecraft.World/FishingHelper.cpp create mode 100644 Minecraft.World/FishingHelper.h create mode 100644 Minecraft.World/LureEnchantment.cpp create mode 100644 Minecraft.World/LureEnchantment.h diff --git a/Minecraft.World/FishingHelper.cpp b/Minecraft.World/FishingHelper.cpp new file mode 100644 index 00000000..e69de29b diff --git a/Minecraft.World/FishingHelper.h b/Minecraft.World/FishingHelper.h new file mode 100644 index 00000000..e69de29b diff --git a/Minecraft.World/LureEnchantment.cpp b/Minecraft.World/LureEnchantment.cpp new file mode 100644 index 00000000..e69de29b diff --git a/Minecraft.World/LureEnchantment.h b/Minecraft.World/LureEnchantment.h new file mode 100644 index 00000000..e69de29b From f0b28416c0af10895391fb0abda09e63bcb9de64 Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 17:38:06 -0700 Subject: [PATCH 2/9] 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 zcmZA3c|cTE8^`f82O&TaP&S!`+1MFEbHP2_7cdZT$t6b_We{eFnNi#`Q&Zd@%Ux1S zEejX4c~dHT-#5!Qx6HC~$yResEz{Q}`#pm*Vt;(TH}5&;&bfE4lZSpk5>k8rNXU-N z*r6L<6A{^F+c=kboW+r2vAJ4jW~4hNjuqe4RtS;V^B<$_T0I=S+Q{WxTxGkCrMmGDkx@ap-=AK3B%gShim%rj&~4Y>T%-Rv3he%ARWMM4ZwJR0!c%=sb<1_p>Q?+V|2oUg0JNbaMNK~}P>0%fEh zO;V|4Sq!bjVb>ILt2FXD(Mgp?nR!5np3jNU9JAHd@PS^K9#3KF=(e>7g=n)$gn7q( zA9mqFDMmIv8u8uI#ki(4LammA8q-u91{cv9wMGsJpnZJUM5oj()I+m`Xx~qS=U5yL ze3#wqmEPOCxU7o8HL>!ut7Ot>q<<0RXyRno&1A#L$_q3ff7)fBZ8+2lI;7Fc+9Pxo zhus?~EH1juo{2(a3>2ZcW}CgjTxRxO_tMX}lZ^f%%sb$_lgm*NG(1ivdzoo+oVx9V z8qCXnG|zWmmp9)LV$n}L;&NCTKCCNk&eGwym`)|t#xr`PI-Ez+})XMdaXR)o|fpf@v3?FxIED!-{N#yZQ~qSt|F_Q zcjQ}lBkx=KQXenp?52DA1X(A^XwU^*JBfAc$!>_GQHCIy;G*#cy&U!(EjAbem*OpJ z{i}$h=MBy2u%W3ukW6O`Nr8747-3kN36Mw+ZiMR9pkMw z{&`arAL~YWNii~b4~YFTaVttr(a4id>YJjMalcSmiebjsaYFR|15X#1%(s+U#yA`Pl~UBy48wS(XyPa@ zH9Lwej&x_GQ&DsC3n8MP6-^4PWtNJEzy6BtAtoXGK6!Zd;rFN59`=XlY=~#B_iIyZ zkJu+fBL#(~Mzx5+_8Uo2Kg0VbDYmOVpf0J=O6?*cIv*CH1$KLBfwkP>yYR?iRGu0m z*Cx{ZRF(YZ7Hv&ctD@h->@P%^ced|xI|>)j_o=aRc_7`#;Z!oUNK;CEe`=c+C#_>> zaGF-`SVEI<^46#HYMMrNxkK-!X+~tt6hclG5d|)%y~1iP&9#@i%DwlztNUI2ANSZl zM!j3yHT5%$9uSd_t@S;FU3->NOOsAsTTcZhy-Y5lN|QRWXtL*uLA@)?<;B)9j^T>h zb^YiqOu*rYNh5cr(^ZpE?%O>pB7JT|x&kElK_l>o0C)ldAqaw@F*Jb?XbPba2I0^Q znnMIcLKH+p477k)P=X57pn*8hf)4ax03*ah0wh8bBtr_MLK>KW_x&VfKuc%^PeE&F z18t!lWI}uB03D$dbcQa_6`qDH=my=P2lRwq&>Q+dU+4$@AscdF06YV^kOu=H9}1ul z2Ekw$0z=_h7zV>(1dN2|U=)~PG>m~Fu)tUt2gP885*QDqPzE-zLpeMT72p6TxL^WI zgi4qMlVJ)>g=sJyX21(D6JCT_@Dj|1IWQMqhIud_s$c;ughj9zmcUY21_aCD6?hd^ zz)DyJt6>eSg>|qVs^K-*02^Twybf=`X4nE-;Z1l8w!z!*4%EPQ*a16X7u3RT*aPo^ z8~z3F!Cu%0b?`oX03X7B_z34zL1$ah5y(JQ?G$S7VZ}QR;Q_Nfsk!h3I7tasb8*;GfIX3c)O`TCJehP{L7uD zZurmSFcC1h*wnpGfl%BSErd`ga7mk~FkgtE^0@<=eFlfz1DYM~_DVu%wrk9It$nPv zpxC0#x0pqvY*z*TJ?vRjza?H&z2z_*aaV6SIv{t&{$)p2ugG0~s!>q=PI<`S~r+cf4e**W$#yT z(w(yR>yM{5m{I=}c*ecVZ{S<^z06Yu!+bNED9Y!KSbhplyGJZPV@>jmG{uwgJ}O>& zqVA0QMBQ2Ubn|~{0zUqdH5ABz(u$Om*EOrh2P*BT!$O*JNyAR z;ZL{)x8eVA2kyc>xDS89gQ}_;#bV${jvuEH$Db3xd4dzj3E~8E8grU(LO4x1p`0*I zIHwt>IVXY>$%*1bb7D9xII$chN5xTdG@Lk&mZRh7IR=iA6VFNDByy5C$($5UDkqI& z;-qt)#nE#T+ZAgfpH~$|>X6ICf4s=Xp*A$H8%OT$~Ap!8prW7hmb@fgY2^}kwh|@SVMwFZ6P!pYByxa5HpdP*h)}s)7p7TQcbnB z)Sg&+jh1^$?`^rQplZFXDs`)h)>1?-b$?G{2L0pned|5vJ@0wn8B@C+9tl2t`$+Ki zl;|OqAB)gTt7CkLb-c~h-{vT3my*=lHFcagU$sDpl%9VX?bzn==ugKm+E0W%b8T|c z9URw!OB6cL#=Yrd^`jMG}2&-)%^cU$W= z{!>6tA^uDeA(>8V-H7*ImmAL#;w8nC0q?_H9#x8g0Yd4$!uK4PJ%=%p^<-p_ot$ca zsZ`T+wMG^sQw0v&-Xf1$E3a*((`v1%?Rg=3juIjLt#-%LFZ9avuB6mNbf~&0MEkWu z=^gjo?8>FrFtX;!i0_epiH@Za8jZ|0(@Y$4X3;wut<2TYUOw!jZ#7YxyrDvL>MNS{ zx4B&SEW10Wc^~hWMeC@UHd-EROct$HidocOtCO8SB?nHrCC$g5wx!V)9IB$|uvRat zF4M0#RPQCFE~5SRr9vd-h>$F+!&z*dWc99l^#?pjQa_>e4)~trS~Cj`*QsUt44R?S zbeMb)^D>{z^F7zKH7$f#e2GU&T(+lQ*7c-&RHKVbv)vb>-9ypLH^Fz0>#Oc!=#dEX z4doUU+TGsGT|at<40^3>c!JXPQL@uc8m`yLqJ}gJhnZ(+wO%jxgwuY#-f;V-5J9I! zSayjuzu4+<=i0|R><;fjzllSnFlc4wVlo)ivSI>t!=dIPjWB3r0|U)87-Y&`de2}? zb)?|)nnvJ4HRikiX6aSRHmYRxAaWS>@?s7xHR@v`*5G#8A}ZJBcH14}UFjwH zb|>%1cipYb+jPvCn zmsb4b#2EA|_#5-R2z`1v-xu!gm#67?j8Q7$=`IfGxfI>fBnk~ z!3r7~tCefjR2r+6=hjgr4$b`NlUQ|w@eg%$Hr61Mtn>g^j4da9oF=r~505iQ_`4?B z9sKjADEMj^WyeKIzaum;P9;ZF(i?GFx#B!+jMIjj8VM27RRr?vK0WH@FKW|+zKe^N zWk#xv)5w0Q6cMkNuf9*6;`MF+_#N|8MR5K6J|+2emuwAuP6$(pP}ZN$aP+oLvel1R z*3rWF$li;)2obqnG^v~5z3M~!9GGs4rhM}0YrZ@w#OMR{=QFKiY=y46wYDX!q^t27 z*<&IFw$jM?{V2YbRvuqO8Lf;m`VmcPWtwfBBSi1t@piFfuC35E*8TKfDMi&LH^!%l zAXibL)m30~wRTT)E2?f>6Cz@$2+FfhvK2r6^;cB;_Y$JP!N+GGe}0PUpy0Z*!F6-J zADf~&*X9@PTdZzx6m4DUBdQ5|ubx+X-ZR2zioQX@k0oX)~Ldy&hx@DMi@ zB}B^d=V^X|TAozW#srPJ`EkttMku|reamgnT2B`eqU90;J;dQucZy0>NliX=NYu&v znKU?2FSl%>={R}o0t%X_6qLL!-Gw!KncyD zIkbRK2!n8lfJlgfXi$L~G@u0?=)nL+Fo79jpe4jY9K=H_NPtAJ0Pp)bNP=W&18t!l zw1*DR5mKNNbcR$&gD%h&y21014&C7e=m9;U7xacckO6(6A7ny*7yvIq7Gy&XlMF6lTL5mj@DKPD_QL`A4E_oKg3sX#I0%Q}-=5IcUmp8$LbmYBw^@4h6f$d= z@UyurJ#&Rji4cC{iY>izgd7+x{OoQ^MxK!PM~~kGtEF$2kfq0k-$bXSA0`a53cn(^ zr91vJZi;9$qrmb)pFE+sc}NJMP+&=iWniul0gkc(&A)=fo&n8kx~~YSAFaQ)2r!lH z-cSQaJi9j>9gtPNy7p+0!c?}U_9z_lY^nV^Fs1y(YK^EmKx}=TTOiv&S{X9lVdlgN6g=Jca|`dv2B$?>Y}Zzy-JnKf)#WFZ=|T;b*u4 zzra%bC7*0!0EGLc=&uPU;;3RS^oYtJ@I7ysjP8&{JPCHI}P6tj$P70?Jr!yy&lg8=7 z>B{NGd7hKb>CSn9(}UBK(~Hxa(}$D6>C5TI$>j9s4B))T$>L;layYr1JkCJQAkJXU zOPnE`p`2ly;hYhik(^PS(Htvh3}-ASpJU^Ua1!kNOE%9+NQ&Y8h^nKP3!i&M&(&6&fQ%Xx(}kMk<$HO}jtGR_;EH#ze;3pfio zi#UrpOE^n8%Q(w9#CeOeg0qrS&Z*$M%~{2Hhf~RUm$RDl9_M||2b?vWwVZXF^_&km k8#o&|n>d>}TR2-e+c;I6YR-1f4$e-+r^UN=Dbkz#A4hoTt^fc4 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 From 6bc57b2b97b51ba75a129e8b3e8c135e9b004256 Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 18:16:49 -0700 Subject: [PATCH 3/9] Fix minor typo in magic number --- Minecraft.World/FishingHelper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Minecraft.World/FishingHelper.cpp b/Minecraft.World/FishingHelper.cpp index 1d2015c5..cd6b7227 100644 --- a/Minecraft.World/FishingHelper.cpp +++ b/Minecraft.World/FishingHelper.cpp @@ -94,7 +94,6 @@ CatchWeighedItem* FishingHelper::getRandCatch(CatchType catchType) std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType) { - std::shared_ptr itemInstance = std::make_shared( weighedCatch->getItemId(), weighedCatch->getCount(), weighedCatch->getAuxValue() ); @@ -107,7 +106,7 @@ std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weigh 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->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::book_Id) { From 406e7e2f060579e254d94bbe134d0e1ed5bffb4a Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 18:38:34 -0700 Subject: [PATCH 4/9] Fix formatting error --- Minecraft.World/FishingHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Minecraft.World/FishingHelper.cpp b/Minecraft.World/FishingHelper.cpp index cd6b7227..47307237 100644 --- a/Minecraft.World/FishingHelper.cpp +++ b/Minecraft.World/FishingHelper.cpp @@ -98,7 +98,7 @@ std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weigh weighedCatch->getItemId(), weighedCatch->getCount(), weighedCatch->getAuxValue() ); - if ((itemInstance->id== Item::fishingRod_Id && catchType == CatchType::JUNK) || (itemInstance->id == Item::boots_leather_Id)) { + 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) { From 7d67bbc24c9be70c662d1a5b125a9d6386efa9eb Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 19:25:10 -0700 Subject: [PATCH 5/9] Add comment for clarification --- Minecraft.World/FishingHelper.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Minecraft.World/FishingHelper.h b/Minecraft.World/FishingHelper.h index 78431785..a1f686e4 100644 --- a/Minecraft.World/FishingHelper.h +++ b/Minecraft.World/FishingHelper.h @@ -70,10 +70,9 @@ class FishingHelper WeighedRandomItemArray fishingJunkArray; WeighedRandomItemArray fishingTreasuresArray; public: - + // Setup singleton FishingHelper(const FishingHelper&) = delete; FishingHelper& operator=(const FishingHelper&) = delete; - static FishingHelper* getInstance(); CatchType getRandCatchType(int level); From 02ddba76ada926e9fe85f08179083ca4633f561c Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 20:18:15 -0700 Subject: [PATCH 6/9] Remove unused include --- Minecraft.World/FishingHook.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Minecraft.World/FishingHook.cpp b/Minecraft.World/FishingHook.cpp index 23ceb241..5a682625 100644 --- a/Minecraft.World/FishingHook.cpp +++ b/Minecraft.World/FishingHook.cpp @@ -14,11 +14,8 @@ #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() { From ab1475b325a3bd4483f7fcfc03150d07037010fb Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 21:07:28 -0700 Subject: [PATCH 7/9] Fix conflicts with new book & quil item --- .../Common/Media/MediaWindows64.arc | Bin 28556979 -> 28557355 bytes Minecraft.Client/Windows64Media/strings.h | 16 +++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Minecraft.Client/Common/Media/MediaWindows64.arc b/Minecraft.Client/Common/Media/MediaWindows64.arc index 0ccfd55c802d0d9cc314e4a74aaa4d83cd2aac90..34328525a0cb05eecbbaacb0952d22c2640af3f0 100644 GIT binary patch delta 4580 zcmZA4d0>p!8prW7ClU!+2H7Vwd1of8WKtm_mLiB)f~rg(^Lc7h=sop;iR7b-v1v9$SP`5#fAbzGOWi~}RVY6;QRq}E?r}~GQ-$+Xl`!FCwO-7{-x^nm?KteK z6kn($zJH*&fy04NArBAgdf+$4I%PAzOufl$(NESpulwsI+)1aQOzs?T-O06}d7>aZ zjHjOw)#1wI$|%gscrwp*U)Q!+7+Y|WM(kF@(+}%0F_fRJ?5$kt&7ozU@ST6wap6#c{8$Te*2*zIdn(?HO?f z=0-#o$bHad54D^HHG9<0MtW3KhLUKt{?Gzz|dzc6VeetEB0q>&<3GQ3u%>{i*GcMd``T0sEOk5SBnU(+T->JtXm_@+5j;@>&2t5i!!Z- zj~yizYPFtA@F`2W%)-Ts+79BF)|Ve$C(dhQJRh~j`72D}I4?!C;fXgze1w*l&+hKH!dk%(BHlP_*XMD&_>i?N>bac3?2eEMT>_mdiIM)vHW^O@Xz zR4cL~!+7Uu!W=2_5`5)Es-=4R#C*^EpT3;y19$IaviK@e!&}c0_i#vW5TQ|8UUy#f ziHhb&2Z_?C816n-EWyeCsiG-LnL4`^y9;Ci&dcQuru{j$aQ_hY*Hg&?pB;8R;rkC( ziGXMg@A8xA9ot;COUp?uj)@d$@= z>qJPrf@?n($?@TQ(pfPoUg8a&q6#M;^cBnFRlKi79Eewq?e~B&Ud{Y-?KZQ;s4ven zSJ*3@_uP}X91`SPKB2lO2w*y74PQyF?Br0{v0K;v^ z6}{3e`ifFxk+ne9xaK3V4HIxUu2b=bx5W)z1b;t%wtqsMe}W7+xIrs$2M=fsp5O&- zpe=ZV5BP!~$e|syhYsKm0T2j55DXy@3JM4VC8!`ABv69}v=9N25Czc?1F_H%;vgP$ zK>L0UIzb|IhAxleSg|}cGtcMM-5jMfwuo_-Vx?*wCM)tGTwDNbDyNw4asD@wuZTv znRP=kp}>c^SJ-s@@W)sU^QbP>^&gbWWVdaMF_{dPH0kp2b?;SGH@yAl@I}+`_Q(1y ztMwjbG1_bflhn^_E@NF%r9vDfD}Dwt6ibCwlC9Jr>Fu^svqg$2(wj_Xn^b6!rnW3H znqm`}FD;eyreZ0}ZY(cns#M3tuvBl8u;$qX3CwG_q0%O0;-^&Rv%YneEY24ANx$GSG*$%CK7u z_yONuR3@1xI_BjV^es=I`T5clII#H`9B(?X`NZYS6@BB6w_ma5{t0hcRo(XcC*aGb z?e|Y^Olck&k@yvj6eNBHr>Byzu0r&F`b*qASnV$yc6hlCM1P7VDVc zi&u5NyEH?6_y}2@LZEPp8>JP+o#H`hP4T37QQA=2QoJcX z6km!TMNVl)X;0}u@uvh(0x3b1U`hxjl%k-7QIr%FC7dEr)D#UxONpRFQlco)lo(1Z zr6VPd5>L@l5-876I#CiSohe-?NtCXXWJ)(m3Z*-x2c;*a7v*_MZ%Q9ZUrH*aAEiHK z040qwkdjUrL>WvOLK#ZQpbVo7r;MOvQnD!7lpIPfC66+aGK!K<8BG~Od4W;qAaE?p$N)S z$}-Aw$_mO#${Un7DXS>;l+~0ql(m$%DC;QeDH|voDVr#7Q#Mn!P_|OGQMOZdP8)d0&{}04{Ls0+# delta 4327 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 E58B;bM*si- diff --git a/Minecraft.Client/Windows64Media/strings.h b/Minecraft.Client/Windows64Media/strings.h index 4c4c51ec..1ed1b4be 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: 2416 +// Total strings: 2425 #define IDS_NULL 0 #define IDS_OK 1 @@ -2416,13 +2416,15 @@ #define IDS_DESC_LARGE_FERN 2410 #define IDS_DESC_ROSE_BUSH 2411 #define IDS_DESC_PEONY 2412 -#define IDS_ENDERMITE 2413 -#define IDS_ITEM_WRITTENBOOK 2414 -#define IDS_DESC_WRITTENBOOK 2415 -#define IDS_ITEM_WRITINGBOOK 2416 -#define IDS_DESC_WRITINGBOOK 2417 +#define IDS_ENDERMITE 2413 +#define IDS_ITEM_WRITTENBOOK 2414 +#define IDS_DESC_WRITTENBOOK 2415 +#define IDS_ITEM_WRITINGBOOK 2416 +#define IDS_DESC_WRITINGBOOK 2417 #define IDS_TOOLTIPS_NEXTPAGE 2418 #define IDS_TOOLTIPS_BACKPAGE 2419 #define IDS_TOOLTIPS_ADDPAGE 2420 #define IDS_TITLE_EXITBOOK 2421 -#define IDS_DESC_EXITBOOK 2422 \ No newline at end of file +#define IDS_DESC_EXITBOOK 2422 +#define IDS_ENCHANTMENT_LURE 2423 +#define IDS_ENCHANTMENT_LUCK_OF_THE_SEA 2424 From c5a8e8b786597d324e6fde0ee9f02ae569c1b6bd Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Sun, 5 Apr 2026 22:46:44 -0700 Subject: [PATCH 8/9] Fix MediaWindows64.arc (forgot to update it before) --- .../Common/Media/MediaWindows64.arc | Bin 28557355 -> 28586982 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Minecraft.Client/Common/Media/MediaWindows64.arc b/Minecraft.Client/Common/Media/MediaWindows64.arc index 34328525a0cb05eecbbaacb0952d22c2640af3f0..e3e0f77866cacd3daf22f76387183ef3fef16f82 100644 GIT binary patch delta 36202 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 Z+kSQS`IB2eKfIT~H>lA60CAcEz~6L##~%Oy delta 6341 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 From 97a82c20ef5ad54ff049077e25e4d3da59bdb232 Mon Sep 17 00:00:00 2001 From: BrainFart17 Date: Mon, 6 Apr 2026 01:21:36 -0700 Subject: [PATCH 9/9] Use Java 1.12 source code for loot table, clean up code. --- Minecraft.World/FishingHelper.cpp | 72 +++++++++++-------------------- Minecraft.World/FishingHelper.h | 39 +++++++++++++---- Minecraft.World/FishingHook.cpp | 15 ++----- 3 files changed, 59 insertions(+), 67 deletions(-) diff --git a/Minecraft.World/FishingHelper.cpp b/Minecraft.World/FishingHelper.cpp index 47307237..b9903c9b 100644 --- a/Minecraft.World/FishingHelper.cpp +++ b/Minecraft.World/FishingHelper.cpp @@ -13,46 +13,31 @@ FishingHelper* FishingHelper::getInstance() return &instance; } -FishingHelper::FishingHelper() : - random(new Random()), level0Array(3), level1Array(3), level2Array(3), level3Array(3), - fishingFishArray(4), fishingJunkArray(12), fishingTreasuresArray(5) +FishingHelper::FishingHelper() : catchTypeArray(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 ); + // Source: https://github.com/WangTingZheng/mcp940/tree/master/src/minecraft/assets/minecraft/loot_tables/gameplay + catchTypeArray[0] = new CatchTypeWeighedItem(CatchType::JUNK, -2, 10 ); + catchTypeArray[1] = new CatchTypeWeighedItem(CatchType::TREASURE, 2, 5 ); + catchTypeArray[2] = new CatchTypeWeighedItem(CatchType::FISH, -1, 85); 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[3] = new CatchWeighedItem(Item::nameTag_Id, 1, 0, 1); fishingTreasuresArray[4] = new CatchWeighedItem(Item::saddle_Id, 1, 0, 1); + fishingTreasuresArray[4] = new CatchWeighedItem(Tile::waterLily_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[1] = new CatchWeighedItem(Item::bone_Id, 1, 0, 10); + fishingJunkArray[6] = new CatchWeighedItem(Item::potion_Id, 1, 0, 10); // Water bottle + fishingJunkArray[2] = new CatchWeighedItem(Item::bowl_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); @@ -60,26 +45,14 @@ FishingHelper::FishingHelper() : fishingJunkArray[11] = new CatchWeighedItem(Item::dye_powder_Id, 10, 0, 1); // 10 ink sacs } -CatchType FishingHelper::getRandCatchType(int level) +CatchType FishingHelper::getRandCatchType(int luck, Random* random) { 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(); - } + catchTypeArray.calcWeights(luck); // Recalculate the weights based on the luck level of the player + catchTypeWeighedItem = static_cast(WeighedRandom::getRandomItem(random, catchTypeArray)); } -CatchWeighedItem* FishingHelper::getRandCatch(CatchType catchType) +CatchWeighedItem* FishingHelper::getRandCatch(CatchType catchType, Random* random) { CatchWeighedItem* catchWeighedItem = nullptr; switch (catchType) { @@ -92,7 +65,7 @@ CatchWeighedItem* FishingHelper::getRandCatch(CatchType catchType) } } -std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType) +std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType, Random* random) { std::shared_ptr itemInstance = std::make_shared( weighedCatch->getItemId(), weighedCatch->getCount(), weighedCatch->getAuxValue() @@ -102,16 +75,23 @@ std::shared_ptr FishingHelper::handleCatch(CatchWeighedItem* weigh 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 + itemInstance->setAuxValue((int)(itemInstance->getMaxDamage() * ((double)random->nextInt(251) / 1000.0)); // 0% to 25% damage + itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, 30); } else if (itemInstance->id == Item::bow_Id) { - 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 + itemInstance->setAuxValue((int)(itemInstance->getMaxDamage() * ((double)random->nextInt(251) / 1000.0)); // 0% to 25% damage + itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, 30); } else if (itemInstance->id == Item::book_Id) { itemInstance = EnchantmentHelper::enchantItem(random, itemInstance, 30); } return itemInstance; +} + +std::shared_ptr FishingHelper::getCatch(int luck, Random* random) +{ + CatchType catchType = getRandCatchType(luck, random); + CatchWeighedItem* catchWeighedItem = getRandCatch(catchType, random); + return handleCatch(catchWeighedItem, catchType, random); } \ No newline at end of file diff --git a/Minecraft.World/FishingHelper.h b/Minecraft.World/FishingHelper.h index a1f686e4..9a32b044 100644 --- a/Minecraft.World/FishingHelper.h +++ b/Minecraft.World/FishingHelper.h @@ -15,17 +15,40 @@ enum CatchType { class CatchTypeWeighedItem : public WeighedRandomItem { protected: CatchType type; + int quality; + int weight; public: - CatchTypeWeighedItem(CatchType type, int weight) : WeighedRandomItem(weight) + CatchTypeWeighedItem(CatchType type, int quality, int weight) : WeighedRandomItem(weight) { this->type = type; + this->quality = quality; + this->weight = weight; } CatchType getType() { return type; } + + void calcWeight(int luck) { + int newWeight = this->weight + this->quality * luck; + if (newWeight < 0) { + newWeight = 0; + } + this->randomWeight = newWeight; + } +}; + +class CatchTypeWeighedItems : public WeighedRandomItemArray { + public: + using WeighedRandomItemArray::WeighedRandomItemArray; + void calcWeights(int luck) { + for (unsigned int i = 0; i < this->length; i++) { + CatchTypeWeighedItem* catchTypeWeighedItem = static_cast(this->data[i]); + catchTypeWeighedItem->calcWeight(luck); + } + } }; class CatchWeighedItem : public WeighedRandomItem { @@ -59,12 +82,8 @@ class FishingHelper { private: FishingHelper(); - Random* random; - WeighedRandomItemArray level0Array; - WeighedRandomItemArray level1Array; - WeighedRandomItemArray level2Array; - WeighedRandomItemArray level3Array; + CatchTypeWeighedItems catchTypeArray; WeighedRandomItemArray fishingFishArray; WeighedRandomItemArray fishingJunkArray; @@ -74,8 +93,10 @@ class FishingHelper FishingHelper(const FishingHelper&) = delete; FishingHelper& operator=(const FishingHelper&) = delete; static FishingHelper* getInstance(); + std::shared_ptr getCatch(int luck, Random* random); + private: + CatchType getRandCatchType(int level, Random* random); + CatchWeighedItem* getRandCatch(CatchType catchType, Random* random); + std::shared_ptr handleCatch(CatchWeighedItem* weighedCatch, CatchType catchType, Random* random); - 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 5a682625..9ff420ef 100644 --- a/Minecraft.World/FishingHook.cpp +++ b/Minecraft.World/FishingHook.cpp @@ -461,19 +461,10 @@ int FishingHook::retrieve() FishingHelper* helper = FishingHelper::getInstance(); std::shared_ptr selectedItemSeaLuck = owner->getSelectedItem(); + // TODO: Take into account luck potion effect when calculating luck level once it's implemented 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 fishingItemInstance = helper->getCatch(luckLevel, random); + std::shared_ptr ie = std::make_shared(this->Entity::level, x, y, z, fishingItemInstance); double xa = owner->x - x; double ya = owner->y - y;