From 14a6bc1f85c2bec1a8aaff6afb7a6dcc01838dbf Mon Sep 17 00:00:00 2001 From: aMannus Date: Sat, 10 Jan 2026 13:59:32 +0100 Subject: [PATCH] Add Roc's Feather (custom item) to Rando Item Pool (#6035) This adds Roc's as a fully implemented item into the randomizer pool. When both Roc's and Nayru's is found, you can swap between them on the pause menu Many people have contributed to this over time, so huge shoutout to: - kentonm, this item is directly inspired by their Roc's Feather from their romhack Indigo. Also provided me with their GI model, icon texture and animation to use. - PurpleHato, for providing the images for the item name shown on the kaleidoscope. - Dana The Elf, providing another custom animation for the item. - Reppan, for helping to tweak the animation and exporting the GI model for me. --- .../gPlayerAnim_link_rocs_feather_jump | Bin 0 -> 142 bytes .../gPlayerAnim_link_rocs_feather_jump_Data | Bin 0 -> 1810 bytes .../object_rocs_feather/eff_unknown_12.i8 | Bin 0 -> 1116 bytes .../object_rocs_feather/eff_unknown_12_i8 | Bin 0 -> 1116 bytes .../object_rocs_feather/gGiRocsFeatherDL | 16 +++ .../gGiRocsFeatherDL_tri_0 | 21 ++++ .../gGiRocsFeatherDL_tri_1 | 30 ++++++ .../gGiRocsFeatherDL_vtx_0 | 64 +++++++++++ .../gGiRocsFeatherDL_vtx_1 | 81 ++++++++++++++ .../gGiRocsFeatherDL_vtx_cull | 10 ++ .../mat_gGiRocsFeatherDL_feather_feather | 22 ++++ .../mat_gGiRocsFeatherDL_feather_stem | 22 ++++ .../objects/object_rocs_feather/model.xml | 10 ++ .../gRocsFeatherTex.rgba32.png | Bin 0 -> 2111 bytes .../gRocsFeatherItemNameENGTex.ia4.png | Bin 0 -> 3934 bytes .../gRocsFeatherItemNameFRATex.ia4.png | Bin 0 -> 3808 bytes .../gRocsFeatherItemNameGERTex.ia4.png | Bin 0 -> 3608 bytes soh/assets/soh_assets.h | 19 ++++ soh/include/functions.h | 4 +- soh/include/variables.h | 2 +- soh/include/z64item.h | 2 + soh/soh/Enhancements/debugconsole.cpp | 2 +- .../Enhancements/debugger/debugSaveEditor.cpp | 14 ++- .../vanilla-behavior/GIVanillaBehavior.h | 8 ++ .../3drando/hint_list/hint_list_item.cpp | 6 ++ .../randomizer/3drando/item_pool.cpp | 4 + .../Enhancements/randomizer/3drando/shops.cpp | 7 +- .../Enhancements/randomizer/3drando/shops.hpp | 2 +- .../Enhancements/randomizer/RocsFeather.cpp | 101 ++++++++++++++++++ .../randomizer/RocsFeatherCycle.c | 25 +++++ .../randomizer/RocsFeatherCycle.h | 9 ++ soh/soh/Enhancements/randomizer/draw.cpp | 15 +++ soh/soh/Enhancements/randomizer/draw.h | 1 + soh/soh/Enhancements/randomizer/item_list.cpp | 2 + .../randomizer/option_descriptions.cpp | 3 + .../Enhancements/randomizer/randomizer.cpp | 32 +++++- soh/soh/Enhancements/randomizer/randomizer.h | 2 + .../Enhancements/randomizer/randomizerTypes.h | 7 ++ .../Enhancements/randomizer/randomizer_inf.h | 2 + .../randomizer/randomizer_item_tracker.cpp | 22 ++++ soh/soh/Enhancements/randomizer/settings.cpp | 3 + soh/soh/OTRGlobals.cpp | 2 + soh/soh/SaveManager.cpp | 3 + soh/soh/SohGui/ImGuiUtils.cpp | 17 +-- soh/soh/SohGui/ImGuiUtils.h | 2 - soh/src/code/z_inventory.c | 30 ++++++ soh/src/code/z_parameter.c | 6 ++ soh/src/code/z_play.c | 4 + .../misc/ovl_kaleido_scope/z_kaleido_item.c | 9 ++ .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 6 +- 50 files changed, 626 insertions(+), 23 deletions(-) create mode 100644 soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump create mode 100644 soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump_Data create mode 100644 soh/assets/custom/objects/object_rocs_feather/eff_unknown_12.i8 create mode 100644 soh/assets/custom/objects/object_rocs_feather/eff_unknown_12_i8 create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_0 create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_1 create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_0 create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_1 create mode 100644 soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_cull create mode 100644 soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_feather create mode 100644 soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_stem create mode 100644 soh/assets/custom/objects/object_rocs_feather/model.xml create mode 100644 soh/assets/custom/textures/icon_item_static/gRocsFeatherTex.rgba32.png create mode 100644 soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameENGTex.ia4.png create mode 100644 soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameFRATex.ia4.png create mode 100644 soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameGERTex.ia4.png create mode 100644 soh/soh/Enhancements/randomizer/RocsFeather.cpp create mode 100644 soh/soh/Enhancements/randomizer/RocsFeatherCycle.c create mode 100644 soh/soh/Enhancements/randomizer/RocsFeatherCycle.h diff --git a/soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump b/soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump new file mode 100644 index 0000000000000000000000000000000000000000..331911d025b662b2650d6f702662097a14cb3ca5 GIT binary patch literal 142 zcmZQzU|{g|bMyyN4Da`?y$8Y|HnD&asF0Vz1xUun`-cR@$LA+yr6!jY>!&B?rWWKR xR>o(irWWX@2LPF=MUHuyx$!xfdD-zr`N_rcX{m`N8L36_S*5uJ@h*uai2!neBB=lX literal 0 HcmV?d00001 diff --git a/soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump_Data b/soh/assets/custom/objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump_Data new file mode 100644 index 0000000000000000000000000000000000000000..616c28c8156c2a570b485cc410d2b1b6d389dfe6 GIT binary patch literal 1810 zcma)+dr;I>6vxlLL3s$70)mNxq;3`pC}=Y);TD*y5`-CwDM%?Y;Y^bwWuY^QCW%ds z?+gJ2b{RoJQ-oC*@QFgf2I3d)%o=}nXMT6j-gCa^etzfN`vU-2 zIB)SH{s*2_72lE`%sTac7f?FhkezRw(Be)UMg3cN9G@L zcwl~B?SopB$Jd)W<;8iR;^p+fWlx$XtrE0peb>4QwR}E2Um7W&^H)~+9Jf9fOC@=O z%O^OAT@BYqUHEjZniJwlTRjq>^VR=S0DNV;CO^|u&c(9?wTHyf=A}I@S#5P_jlpbe zk33=FBus0km_CUzy%tAV0IcG9J%KSqakTc!5sBSXi<-rzu@{$SM*+loQG~rC6zw31eyYJ6EO!!! zvRGiH9@j|#Qs#7hmWZ*PrY0=Gdfy!^ zP}I{3s?=WLTucci%{%icC*m~MqYo5G)REZ28LpqS)ti_*6nmZmOq?A z?GEtqY*N2mi;RAQZJCZvr(b-CTw%*>@t04RP0)Fx4wuB|nA2r|G~NWEzA!0s>a;AwhI8HVj58|)U*|v|whxwc8%L%opOCo(*l<;21-CZ6YNh68?JyY0jIF(j( zZGB~T3VAivN1uE)HKTYqMFW32Bd!S)2_k_4aWWe%seC?$+r!R&kc<^<#qraUEbhr| zf6Pa=G}r1Y$t?iYb|z4~8$tTONSXmcjNN}O+C&s_g@O0m>c?JAbJlrl(}`l>R z|A9t3g+MOmDP)gHjr!NcLliN1M^w^%l3ULHP#3X(Fs;lW-N{<(rs6T285e2YFG(*4 z)k+j7)~QK9W;yK)khx$&PM4Hyw_>-Zu3JlgIpVe6|K57>=dNr?}sZu zj+HFbKV(B4nFy!A$MiSb!{U^6ECEJeP|4OX{UtU2i1Re=)^^F^Do{1Npped|6S02d zU>3{^eZNTQMik*S2b#ZSow+AE$IpleC5n2S@}%NU(`A7|h^M)R|7y*Z4gS}+4GdAt zff1l(**FSAy*aiLj@3rXnz+p0Qg9dQ!kI-Z?WhBl`31$oL5i?#lm+1QL}MAgK@{We zVf%g0t`e0&5%!&uC}J$@`)717t+m&JRsphk3X_7~<>i|i1W~ZbG8s>@p8~Y(3+S&} zAp3^%XwBd$O6Lw(T%>oe4t7IDIfD3(Am)5eHezkxmecYCqPRUUxu?@-?b-KkRlYrI SCheDE3bWiazFB9dAkDwf^EE{P literal 0 HcmV?d00001 diff --git a/soh/assets/custom/objects/object_rocs_feather/eff_unknown_12.i8 b/soh/assets/custom/objects/object_rocs_feather/eff_unknown_12.i8 new file mode 100644 index 0000000000000000000000000000000000000000..e305f366839ae2322f8b19595a2cdeb0c01ae75e GIT binary patch literal 1116 zcma)z`8ykS0LH_tbYeAKk+qIEo~l-zp%~&Cb(GCHR}&LQHO>kRl@OA+#oTcO&EgIs zN)n;f3B_1Z*BGkLthUzKnzg>uXZr*8KF{ZQKR>)L1OkEh+IzZ*o%CyA+sX${^nd5n z$x`({{yh<`AdnLzAP|JBUn|r5f|%S_RPG&L1ATpq*k`r=2uWFFR@6At&f2yk2^D`u)x`9K0OIu{W6j^D&^mM&wtPpFdGuE`t zr3b7?MPxCLf%DK&L-CF`(>*+IqLLa*<2@zSLmwUUDO8HOGeuNmD5vL0eGcAD*QUnh z)wdH_$uMN$7HA62Dzl8PoFM7QIuqKr-tWzKg~hQ%ZHb*6Cv?Xlm@O_XkE|Jf8t87B z$r*gO_Nt$b&L7xlN+7T0kXt6-?g~h$5!}}s82?b-n5ekpkSwfVNyt07b+!UvvZB8qFGX#S_*w#iDgldZ$;B(7-k^>wSR5*-6 zHbn)4s-6ck$_gnzszo&350)|ezQ+x!2sb@Txm$7v$y_UR6lJVVM1*G;kKR~ zO=R|wf~>qeyo_GU<++snG=I1~qxtdY$k2>Vf?r%v-bA2Dge*+)8o8nF@h~Ri=N)h~ zAor=9RU(xgp4LYw=TqncbthG?6gqQ?pFkR3Jq8>#BP~;0Nk>%gI=!N{|MwT^X)Xcj zb%TEhlWLxI?Sr|3cmpJb@hG}wwUgPm3yxM=3vXp{mcbagcOv0eurpVn?^DHINv4eO zy0^A>!A2MTZqCp?c*>|tF=zst{YkEPn&_Z~F65IJIs|{skOEv{<^hA#1Y(5s3TyzA$h-g5;KPHD)X(oTprW+hI zVNFj%-RA}5EPUMv0Q+^hRB3nG{jy*ksB+Q_SRnW!l+`1kRl@OA+#oTcO&EgIs zN)n;f3B_1Z*BGkLthUzKnzg>uXZr*8KF{ZQKR>)L1OkEh+IzZ*o%CyA+sX${^nd5n z$x`({{yh<`AdnLzAP|JBUn|r5f|%S_RPG&L1ATpq*k`r=2uWFFR@6At&f2yk2^D`u)x`9K0OIu{W6j^D&^mM&wtPpFdGuE`t zr3b7?MPxCLf%DK&L-CF`(>*+IqLLa*<2@zSLmwUUDO8HOGeuNmD5vL0eGcAD*QUnh z)wdH_$uMN$7HA62Dzl8PoFM7QIuqKr-tWzKg~hQ%ZHb*6Cv?Xlm@O_XkE|Jf8t87B z$r*gO_Nt$b&L7xlN+7T0kXt6-?g~h$5!}}s82?b-n5ekpkSwfVNyt07b+!UvvZB8qFGX#S_*w#iDgldZ$;B(7-k^>wSR5*-6 zHbn)4s-6ck$_gnzszo&350)|ezQ+x!2sb@Txm$7v$y_UR6lJVVM1*G;kKR~ zO=R|wf~>qeyo_GU<++snG=I1~qxtdY$k2>Vf?r%v-bA2Dge*+)8o8nF@h~Ri=N)h~ zAor=9RU(xgp4LYw=TqncbthG?6gqQ?pFkR3Jq8>#BP~;0Nk>%gI=!N{|MwT^X)Xcj zb%TEhlWLxI?Sr|3cmpJb@hG}wwUgPm3yxM=3vXp{mcbagcOv0eurpVn?^DHINv4eO zy0^A>!A2MTZqCp?c*>|tF=zst{YkEPn&_Z~F65IJIs|{skOEv{<^hA#1Y(5s3TyzA$h-g5;KPHD)X(oTprW+hI zVNFj%-RA}5EPUMv0Q+^hRB3nG{jy*ksB+Q_SRnW!l+`1 + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_0 b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_0 new file mode 100644 index 000000000..94927832f --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_0 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_1 b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_1 new file mode 100644 index 000000000..9ab8f972b --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_tri_1 @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_0 b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_0 new file mode 100644 index 000000000..6b1681449 --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_0 @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_1 b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_1 new file mode 100644 index 000000000..44ab97157 --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_1 @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_cull b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_cull new file mode 100644 index 000000000..e43cf3bda --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/gGiRocsFeatherDL_vtx_cull @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_feather b/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_feather new file mode 100644 index 000000000..e21e92ff8 --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_feather @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_stem b/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_stem new file mode 100644 index 000000000..b523babf2 --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/mat_gGiRocsFeatherDL_feather_stem @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/assets/custom/objects/object_rocs_feather/model.xml b/soh/assets/custom/objects/object_rocs_feather/model.xml new file mode 100644 index 000000000..5d798a1ab --- /dev/null +++ b/soh/assets/custom/objects/object_rocs_feather/model.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/soh/assets/custom/textures/icon_item_static/gRocsFeatherTex.rgba32.png b/soh/assets/custom/textures/icon_item_static/gRocsFeatherTex.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e4f99da1dba7c95122e0e36bbe080789a026ac GIT binary patch literal 2111 zcmV-F2*CG=P)OVv zMgO3-LEC~LD1wMq{eW(pkkdCBD4}zh^F6#X@5jtLU=L)ptl8p)Y%XsE{XX|{WX0Y7 zMjKB08Kx(ynfgL#K1|c`{eVr?`w7*n`M!q38BdrR*gAx#HQmSy&k6@N^Sa_);XW-L zjSC+Oj~jA8;TxsLs{E=rRpn2`MmRVJcGc6Js^eH4YiT1ZJSObPW(wNhdDKl@iQH01 z>Y&UaOoI6F;U-3bbu#3ckeZXs8vDEz-y$30(d4gF#1Kb{w0OrwElAgd)THPM`7#t$ z?*H>NlT(w`?k*p+zF5}B2(<4(xnx;CCze${1;;a7!?MBqT->4KFAvMupNq5JaE_ zB1G`Tqa=zyCXD2;Apu?nj?Rs-CVL78^Bs zNNKDr*p}#IXAT`Y-MsRh4mx~-nW98$V2>yS7=k58q)N5-i89r-{@J5dOG)q*2@N5VG zg-phSl+y`>`#G-hU!ZiYXlc@{W>zk7davMhdw;5pO?hH(q;|%8Dat2jq-^lgHz5cN zWLiO&a|0-0Kv*uvHK62d&f*Wuk3^7oef>N^YeXW<{Z#69N&G5a1zTI4H9KWdAZNIsg<6%-wUaCNz57MhKUOm7PT@O(GhYrkkj3ffvq# zmKvn1Kslm&WbDG-GL#n=fc1D?E?BGjp=utDmJ+0uTlgx`*i#BDI|?Equ=*T0MG4}- zH?h(<27nka040Ra;o?*69}_2&7M|-dj^d&e^`wDc=irtIz{emQ1;UjeJrAV7;kqDh zTraq8V_Xy`LV4;Tcxk^=pPJob@vi5asbp=2%Qv?NE1yJz}H2xt`=^CdICcqV0 zqe6C14DfMN{p^?g*|iI7&MaD1uN4VuDS!$JOj;l#5}2~E<*e>}P!`g5gwqjEx~*+D z&#&8XC-^P8?3V#??r%SP&sMXsrGay35DYUE5`u{UI28`w3zP!pVFn>S8;Jw^`IVhJ z%361QdmAwQoY%~T9$~1WG_Y{{KdUVr848{5vT@|(%aSL-{TOCV^Hf?ehS z$&j9%&S=BjnGfrT$0giykoW@gYVPV8hL z%n>7vhD*5L4JZqAy>!-b6IsVey2;=6R-gRp?Ywogls23AWOwiDzS{R60A^1kp_x?k z(K-zfz`CRPK`NktrKsT_%Pny=1)V4Mhc55i9=g)_&7FP|ifq-wdy{lK55o;j_Tx#n zJggiB<)dncF0TJ>H`n1Af#F!ZDh1a)*BmCymg5_b)ZI&HG{GBo%eAHzldEq5{}LVZ zH9m1huk1+gF>F99W_Wn)JpN-m>%@NzmcwPGS{ji7QeR?o2&C|(3=Z@-opMCx()qTd>*}ZF z(XQm{w`5KW)xPLc@%oLTGfr9g#k7EA;_8ib;!;PltNms=b)oId_wPP;Tg|s=A(rt+ zd%#WR&5f#GpD9>^nrDbScStW^y%nNWlAOMF`K(S~8Nd6(IhFW#Wx-6s(QUXhEz6^Q z0Pvz1*tE+Qv9QG&78Pz71SZD$*!bE$k0XA+=Y4<-iUD&y`}|w5{MAnm|C>%UtLx4b zeAJE`%1L0>PUCFabN(XSN@=^Rd+Tn_b2wS-S@W(8Y~FST%0`Ss3xXhK{{hxFsH&vbZbsY#0XB`P4Rm}R>RWRE)uOs>aNa$NA>*19sG4i0Jxt)-I6yT<7H#1j`p?qXgY$w1P|yc pSb`&GkHarZ%dhmb+yetQ*MDl0{#xQHl*j-8002ovPDHLkV1fv+>k|L~ literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameENGTex.ia4.png b/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameENGTex.ia4.png new file mode 100644 index 0000000000000000000000000000000000000000..bc72f3ced5b7a5b8cb4d9bc7edda23a9e1435bba GIT binary patch literal 3934 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 Lz~0#FdE$Qnsab7b literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameFRATex.ia4.png b/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameFRATex.ia4.png new file mode 100644 index 0000000000000000000000000000000000000000..dc42bdc072d91aa01878ed832cfeedea8491a310 GIT binary patch literal 3808 zcmai03p|s1AAeRTM-E6}aI?@I2n_G^P>g06d z9GxPON=cC?Vrd;ZV&`}_WX|KDv-`ucU=Mg}kg z004}9eJFJBHyON47V3fD-K_XD0MK10V6YS{S^$9~5uw;zNhA-Y6iGoG0ElaqQZ{ER zPXUkQ@daXc#7OmJ1YE#%M=+ge7@CyKix&87lktMLtz&SuZRNOf5oa7Q3O9R6OM%lV)!jg<*!mAM==PskJT#0ohYi^8Hm<@1z+kKTyo@52QK z4n2c_bj)XTg&^v0=rhQl=+bD3LL!frNIy9B*%lw*KN*7I{%aE@Tl!aI8ts46MWWA+ zAy-i2z`(sv!e>7Hv4NbSlJd}Wo?H?uF!g_&{CuC6sU{K{?Hrx?d zoXdZqp`W7ok04nhl*od?D&&DyvyW#&NAMM~`8=k8tBC$6_7Mo+iTSh0oX{*Vplq{0RAy$?Ij3D1i{fsfW+XC7*__?f#B#&aB{ZCU>e&#!Tx{znI3=>xg3H*pb+wAS93i<5-R3ab4#IMrV$82wwUjZP$Id!D0Zw+f$&i9 zlnNqxrfGzN_tvwkKg@~f&$Nl4Z!{XgM<7>7WU5cL3+BaqzTIr^!QrzNMPPGg(&3Jf z$|T%a4v#x~OwjQ;R4$29#It2Q5+5ukcLXUaN&qHK1qa(&z!&pma2yJQnhW{|oA_uR zsQ34AM1OjiKb#|?|K$GM**_T|pxxXva4>-r4*g-ofr}4Ak|zcyqYNB@9b<0?0RXZ? z0G7a?QV#&Da$+PF>}pqwfIm&T}_0@BF^r(3%$XQ?r*485Be6r@*DSf z=08;4oVY&noYH~-u^WBNJs6`=E{$YFp;5#|H~s+|AMVk(R_r@*y@c+`$K6Iz7-) z7v>wRHfEMAy#Fpgh_T2+&_KZ?pSrkiI=`n`Yx(nq;iFsooX2^??)}YUKPHTfAD*o4 z$T2oFu3c&p!Lt3yXvO@g+SkTbxiD?5MKb#3-W=>DqxN!F&eBHyv6svU6ZMtwpC)TZ zcGSeZl6cVfYHJNctjT(1<|yBdK>tBc59>JXK- zbLY<3if!}e&ErmMry?f_j&zq5?sYb3T)igzrw4&UZnt0Fwkou%ef3mLrEs5I%dmmgHZ}PkEi9xK-_yVId~on< zufm{*4PY^~}u7Y#kjLH$(WM zFBj=0tbJ0T!^t}u2a&n436Sf4sDL^Db zj*pM8*;tkB7C)T5f4?`K4mCG7w{ijB)zE144Yk@gFmNRt4&*jbC={LAk>nK(ZTmd~ zWHMY^TbqlEOZL8fDW_kLwQa9U(QR#SKYDNQeg)6)>C>khrtBj6SR4mfM)M)(tS60G z;nZ8_&!4vs1SAGyTbXn148p! zA>KbICS);w4M&-n++f8Z4g<FIy$_=!eA={3$8wTbhy2JgZ<6n%*;%hr-yW~@z%Yrmn1Xb6iRD!1g6%G#h=+8 z9la1(upo8p?Wks4o|u^Ek~HCHyxhZzRQ68uh4N8L%VRu|7@$ItgKVzdoFox4Tnl=ircAlQ1?h-_hB5zR8j$*V;}nlc>Au>PX`5i@pg7 zZa{f?`QpWkfuebrfwS{ado|tfnnqhLK~61t8J_UC&^t>x+NUdj)?C-tmRD6(wLBp4 z-AneK)YPV?rn>t2owc=|U>qP;5Ol-PA^z=xpx|IKShyY@9=lRg&7jc8Cr!6+^V>^8 zOF~cUd3$?9q0qF-$h_&>nFY$)4g#9H!YZ|iTt zm6et2gMvtrk%-aJQ5RQNT|SrF+u!e;ZY<6DmrM5-$-bU9K-%EYP*GKtM<+H$Km z+JR@!ygWSt(3f9ION~x<25j7DMIw{B^5{;ZCp&e;=QPXU?3-53qy5 zV8_bJ`2DvI@7lF%eMks3CI$;0&N9R6*{#Fsi8s$x6aW4ipi-$|x^fE&GFzgHE?hX+ zbxtyWXo1%czXqBFC*!@WTb3OE_jud|dE8XIDj;sk=A!D2#_B%XqKldMU24SiL#B0t zs%BZEwcAuk@ACHTU~?#y%Dv`e9ecOut*ITHb~~}wwEMflDRzF!Qy+&f)z-qF+Wu*t zv`nh!!c3^?CW>%AO%d^ha_I(?@gbE9Kcp> onV+3@1^mbUg2(cWqS1iW;Qd1In)%!f&Yk)3rLLo#{3ashKZdF%L;wH) literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameGERTex.ia4.png b/soh/assets/custom/textures/item_name_static/gRocsFeatherItemNameGERTex.ia4.png new file mode 100644 index 0000000000000000000000000000000000000000..5842acfeb59b25cf2c5db8868234ac030df38214 GIT binary patch literal 3608 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 AYXATM literal 0 HcmV?d00001 diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h index e1c7b810e..c0ec61420 100644 --- a/soh/assets/soh_assets.h +++ b/soh/assets/soh_assets.h @@ -354,6 +354,9 @@ static const ALIGN_ASSET(2) char gKeyringKeysGanonsCastleMQDL[] = dgKeyringKeysG #define dgHouseKeyDL "__OTR__objects/object_housekey/gHouseKeyDL" static const ALIGN_ASSET(2) char gHouseKeyDL[] = dgHouseKeyDL; +#define dgGiRocsFeatherDL "__OTR__objects/object_rocs_feather/gGiRocsFeatherDL" +static const ALIGN_ASSET(2) char gGiRocsFeatherDL[] = dgGiRocsFeatherDL; + // overlays #define dgOptionsDividerChangeLangVtx "__OTR__overlays/ovl_file_choose/gOptionsDividerChangeLangVtx" static const ALIGN_ASSET(2) char gOptionsDividerChangeLangVtx[] = dgOptionsDividerChangeLangVtx; @@ -437,6 +440,18 @@ static const ALIGN_ASSET(2) char gFileSelLanguageFRATex[] = dgFileSelLanguageFRA #define dgFileSelLanguageGERTex "__OTR__textures/title_static/gFileSelLanguageGERTex" static const ALIGN_ASSET(2) char gFileSelLanguageGERTex[] = dgFileSelLanguageGERTex; +#define dgRocsFeatherTex "__OTR__textures/icon_item_static/gRocsFeatherTex" +static const ALIGN_ASSET(2) char gRocsFeatherTex[] = dgRocsFeatherTex; + +#define dgRocsFeatherItemNameENGTex "__OTR__textures/item_name_static/gRocsFeatherItemNameENGTex" +static const ALIGN_ASSET(2) char gRocsFeatherItemNameENGTex[] = dgRocsFeatherItemNameENGTex; + +#define dgRocsFeatherItemNameGERTex "__OTR__textures/item_name_static/gRocsFeatherItemNameGERTex" +static const ALIGN_ASSET(2) char gRocsFeatherItemNameGERTex[] = dgRocsFeatherItemNameGERTex; + +#define dgRocsFeatherItemNameFRATex "__OTR__textures/item_name_static/gRocsFeatherItemNameFRATex" +static const ALIGN_ASSET(2) char gRocsFeatherItemNameFRATex[] = dgRocsFeatherItemNameFRATex; + #define dgEmptyTexture "__OTR__textures/virtual/gEmptyTexture" static const ALIGN_ASSET(2) char gEmptyTexture[] = dgEmptyTexture; @@ -459,6 +474,10 @@ static const ALIGN_ASSET(2) char gLinkAdultGoronTunicSkel[] = dgLinkAdultGoronTu #define dgLinkAdultZoraTunicSkel "__OTR__objects/object_link_boy_zora/gLinkAdultZoraTunicSkel" static const ALIGN_ASSET(2) char gLinkAdultZoraTunicSkel[] = dgLinkAdultZoraTunicSkel; +// Animations +#define dgPlayerAnim_link_rocs_feather_jump "__OTR__objects/gameplay_keep/gPlayerAnim_link_rocs_feather_jump" +static const ALIGN_ASSET(2) char gPlayerAnim_link_rocs_feather_jump[] = dgPlayerAnim_link_rocs_feather_jump; + // LUS Logo #define dgShipLogoDL "__OTR__textures/nintendo_rogo_static/gShipLogoDL" static const ALIGN_ASSET(2) char gShipLogoDL[] = dgShipLogoDL; diff --git a/soh/include/functions.h b/soh/include/functions.h index 8d4990290..13ebb0507 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -2452,11 +2452,13 @@ void Font_LoadOrderedFontNTSC(Font* font); // #endregion // #region SOH [General] - void Interface_RandoRestoreSwordless(void); s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw, bool* shouldUpdate); +// #region SOH [Rocs Feather] +void func_80838940(Player* this, LinkAnimationHeader* anim, f32 arg2, PlayState* play, u16 sfxId); + // #endregion #ifdef __cplusplus diff --git a/soh/include/variables.h b/soh/include/variables.h index 27ad4584d..e296017aa 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -103,7 +103,7 @@ extern "C" extern u16 gUpgradeCapacities[8][4]; extern u32 gGsFlagsMasks[4]; extern u32 gGsFlagsShifts[4]; - extern void* gItemIcons[0x82]; + extern void* gItemIcons[157]; extern u8 gItemAgeReqs[]; extern u8 gSlotAgeReqs[]; extern u8 gItemSlots[56]; diff --git a/soh/include/z64item.h b/soh/include/z64item.h index b1fa897fe..9bbb8bb30 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -309,6 +309,7 @@ typedef enum { /* 0x99 */ ITEM_STICK_UPGRADE_30, /* 0x9A */ ITEM_NUT_UPGRADE_30, /* 0x9B */ ITEM_NUT_UPGRADE_40, + /* */ ITEM_ROCS_FEATHER, /* 0xFC */ ITEM_LAST_USED = 0xFC, /* 0xFE */ ITEM_NONE_FE = 0xFE, /* 0xFF */ ITEM_NONE = 0xFF @@ -592,6 +593,7 @@ typedef enum { /* 0x7A */ GID_SONG_TIME, /* 0x7B */ GID_SONG_STORM, /* 0x7C */ GID_TRIFORCE_PIECE, + /* 0x7C */ GID_ROCS_FEATHER, /* */ GID_FISHING_POLE, /* 0x7C */ GID_MAXIMUM diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index ff40f149a..6a1e619d4 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -394,7 +394,7 @@ static bool GiveItemHandler(std::shared_ptr Console, const std::v if (args[1].compare("vanilla") == 0) { getItemEntry = ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, std::stoi(args[2])); } else if (args[1].compare("randomizer") == 0) { - getItemEntry = ItemTableManager::Instance->RetrieveItemEntry(MOD_RANDOMIZER, std::stoi(args[2])); + getItemEntry = Rando::StaticData::RetrieveItem((RandomizerGet)std::stoi(args[2])).GetGIEntry_Copy(); } else { ERROR_MESSAGE("[SOH] Invalid argument passed, must be 'vanilla' or 'randomizer'"); return 1; diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 4cd3b4f45..342dc34fa 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -13,6 +13,7 @@ #include #include #include +#include extern "C" { #include @@ -540,7 +541,16 @@ void DrawInventoryTab() { uint8_t item = gSaveContext.inventory.items[index]; PushStyleButton(Colors::DarkGray); - if (item != ITEM_NONE) { + if (item == ITEM_ROCS_FEATHER) { + auto ret = ImGui::ImageButton( + "ROCS_FEATHER", + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("ROCS_FEATHER"), + ImVec2(48.0f, 48.0f), ImVec2(0, 0), ImVec2(1, 1)); + if (ret) { + selectedIndex = index; + ImGui::OpenPopup(itemPopupPicker); + } + } else if (item != ITEM_NONE) { const ItemMapEntry& slotEntry = itemMapping.find(item)->second; auto ret = ImGui::ImageButton( slotEntry.name.c_str(), @@ -1843,4 +1853,6 @@ void SaveEditorWindow::DrawElement() { } void SaveEditorWindow::InitElement() { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("ROCS_FEATHER", gRocsFeatherTex, + ImVec4(1, 1, 1, 1)); } diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index b561985ed..ec0382661 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2477,6 +2477,14 @@ typedef enum { // - `*Color_RGB8` VB_APPLY_TUNIC_COLOR, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - `*int16_t` // pauseCtx->namedItem + VB_DRAW_CUSTOM_ITEM_NAME, + // #### `result` // ```c // true diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index 4962aeac2..6a0c8babe 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -1964,6 +1964,12 @@ void StaticData::HintTable_Init_Item() { CustomMessage("a gold fragment", /*german*/"ein Goldfragment", /*french*/"un fragment d'or")}); // /*spanish*/un fragmento dorado + hintTextTable[RHT_ROCS_FEATHER] = HintText(CustomMessage("Roc's Feather", /*german*/"Roc's Feather", /*french*/"Roc's Feather"), + {}, { + CustomMessage("a feather", /*german*/"a feather", /*french*/"a feather"), + CustomMessage("a chicken wing", /*german*/"a chicken wing", /*french*/"a chicken wing"), + CustomMessage("a blue wing", /*german*/"a blue wing", /*french*/"a blue wing")}); + hintTextTable[RHT_BEAN_SOUL] = HintText(CustomMessage("a bean soul", /*german*/"eine bohnenseele", /*french*/"une âme de haricot")); hintTextTable[RHT_GOHMA_SOUL] = HintText(CustomMessage("the soul of Gohma", /*german*/"Gohmas Seele", /*french*/"l'Âme de Gohma"), diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 710869d81..26c7119fa 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -384,6 +384,10 @@ void GenerateItemPool() { AddFixedItemToPool(RG_SKELETON_KEY, 1); } + if (ctx->GetOption(RSK_ROCS_FEATHER)) { + AddItemToPool(RG_ROCS_FEATHER, 2, 1, 1, 1); + } + int bronzeScale = ctx->GetOption(RSK_SHUFFLE_SWIM) ? 1 : 0; AddItemToPool(RG_PROGRESSIVE_SCALE, 3 + bronzeScale, 2 + bronzeScale, 2 + bronzeScale, 2 + bronzeScale); diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index 970b05389..01683eec4 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -887,6 +887,11 @@ void InitTrickNames() { Text{ "Triforce Shard", "Éclat de Triforce", "Triforce-Fragment" }, // "Triforce Shard" Text{ "Shiny Rock", "Caillou Brillant", "glänzender Stein" }, // "Shiny Rock" }; + trickNameTable[RG_ROCS_FEATHER] = { + Text{ "Chicken Wing", "Chicken Wing", "Chicken Wing" }, // "Chicken Wing" + Text{ "Roc's Leg", "Roc's Leg", "Roc's Leg" }, // "Roc's Leg" + Text{ "Roc's Fapper", "Roc's Fapper", "Roc's Fapper" }, // "Roc's Fapper" + }; trickNameTable[RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL] = { // TODO_TRANSLATE Text{ "Volcano Seed Spirit" }, @@ -1539,7 +1544,7 @@ void InitTrickNames() { } // Generate a fake name for the ice trap based on the item it's displayed as -Text GetIceTrapName(int id) { +Text GetIceTrapName(uint16_t id) { // If the trick names table has not been initialized, do so if (!initTrickNames) { InitTrickNames(); diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.hpp b/soh/soh/Enhancements/randomizer/3drando/shops.hpp index 109ea6143..a5b42cf68 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.hpp @@ -27,4 +27,4 @@ extern std::vector GetMinVanillaShopItems(int total_replaced); extern uint16_t GetRandomPrice(Rando::Location* loc, PriceSettingsStruct priceSettings); extern uint16_t GetCheapBalancedPrice(); extern int GetShopsanityReplaceAmount(); -extern Text GetIceTrapName(int id); +extern Text GetIceTrapName(uint16_t id); diff --git a/soh/soh/Enhancements/randomizer/RocsFeather.cpp b/soh/soh/Enhancements/randomizer/RocsFeather.cpp new file mode 100644 index 000000000..e90b4d3c1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/RocsFeather.cpp @@ -0,0 +1,101 @@ +#include +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include + +extern "C" { +#include +#include "functions.h" +#include "variables.h" +#include "macros.h" +#include "objects/gameplay_keep/gameplay_keep.h" +extern PlayState* gPlayState; +} + +#define MAX_ROCS_USES 1 + +static uint8_t rocsUseCount = 0; +static uint8_t groundTimer = 0; +static f32 effectsScale = 1.0f; + +void RegisterRocsFeather() { + bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_ROCS_FEATHER); + + COND_HOOK(OnPlayerUpdate, shouldRegister, []() { + Player* player = GET_PLAYER(gPlayState); + + // Reset Rocs count when touching the ground for 3+ frames + if (player->actor.bgCheckFlags & 1) { + if (groundTimer <= 3) { + groundTimer++; + } + } else { + groundTimer = 0; + } + + if (groundTimer >= 3) { + rocsUseCount = 0; + } + }); + + COND_VB_SHOULD(VB_CHANGE_HELD_ITEM_AND_USE_ITEM, shouldRegister, { + int32_t usedItem = va_arg(args, int32_t); + + // Roc's Feather behaviour + if (usedItem == ITEM_ROCS_FEATHER) { + *should = false; + + if (rocsUseCount < MAX_ROCS_USES) { + rocsUseCount++; + + Player* player = GET_PLAYER(gPlayState); + + func_80838940(player, (LinkAnimationHeader*)&gPlayerAnim_link_rocs_feather_jump, 5.8f, gPlayState, 0); + + // Actionvar needed to prevent weird animation morph + player->av2.actionVar2 = 1; + + // Move player forward on Roc's use + player->linearVelocity = 5.0f; + player->actor.world.rot.y = player->yaw = player->actor.shape.rot.y; + + if (gSaveContext.linkAge == LINK_AGE_CHILD) { + player->actor.velocity.y = 7.0f; + effectsScale = 1.0f; + } else { + player->actor.velocity.y = 7.5f; + effectsScale = 1.5f; + } + + Vec3f effectsPos = player->actor.home.pos; + effectsPos.y += 3; + + EffectSsGRipple_Spawn(gPlayState, &effectsPos, 200 * effectsScale, 300 * effectsScale, 1); + EffectSsGSplash_Spawn(gPlayState, &effectsPos, NULL, NULL, 0, 150 * effectsScale); + + // Remove hopping state when using Roc's after sidehop/backflip to allow grabbing ledges again + player->stateFlags2 &= ~(PLAYER_STATE2_HOPPING); + + Player_PlaySfx(&player->actor, NA_SE_PL_SKIP); + } + } + }); + + COND_VB_SHOULD(VB_DRAW_CUSTOM_ITEM_NAME, shouldRegister, { + u32 namedItem = va_arg(args, u32); + if (namedItem == ITEM_ROCS_FEATHER) { + *should = true; + const char* textureName = gRocsFeatherItemNameENGTex; + + if (gSaveContext.language == LANGUAGE_GER) { + textureName = gRocsFeatherItemNameGERTex; + } else if (gSaveContext.language == LANGUAGE_FRA) { + textureName = gRocsFeatherItemNameFRATex; + } + + memcpy(gPlayState->pauseCtx.nameSegment, textureName, strlen(textureName) + 1); + } + }); +} + +static RegisterShipInitFunc registerRocsFeather(RegisterRocsFeather, { "IS_RANDO" }); diff --git a/soh/soh/Enhancements/randomizer/RocsFeatherCycle.c b/soh/soh/Enhancements/randomizer/RocsFeatherCycle.c new file mode 100644 index 000000000..31dfb9030 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/RocsFeatherCycle.c @@ -0,0 +1,25 @@ +#include "soh/Enhancements/randomizer/RocsFeatherCycle.h" +#include "functions.h" +#include "variables.h" +#include "macros.h" + +uint8_t Enhancement_GetNextNayrusItem() { + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NAYRUS_LOVE && Flags_GetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER)) { + return ITEM_ROCS_FEATHER; + } + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_ROCS_FEATHER && Flags_GetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE)) { + return ITEM_NAYRUS_LOVE; + } + return ITEM_NONE; +} + +uint8_t Enhancement_GetPrevNayrusItem() { + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NAYRUS_LOVE && Flags_GetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER)) { + return ITEM_ROCS_FEATHER; + } + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_ROCS_FEATHER && Flags_GetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE)) { + return ITEM_NAYRUS_LOVE; + } + + return ITEM_NONE; +} diff --git a/soh/soh/Enhancements/randomizer/RocsFeatherCycle.h b/soh/soh/Enhancements/randomizer/RocsFeatherCycle.h new file mode 100644 index 000000000..859cb5ab6 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/RocsFeatherCycle.h @@ -0,0 +1,9 @@ +#ifndef ROCS_FEATHER_H +#define ROCS_FEATHER_H + +#include + +uint8_t Enhancement_GetNextNayrusItem(); +uint8_t Enhancement_GetPrevNayrusItem(); + +#endif diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index 0334b9e1d..78295f45c 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -490,6 +490,21 @@ extern "C" void Randomizer_DrawMysteryItem(PlayState* play, GetItemEntry* getIte CLOSE_DISPS(play->state.gfxCtx); } +extern "C" void Randomizer_DrawRocsFeather(PlayState* play, GetItemEntry* getItemEntry) { + Color_RGB8 color = { 0, 60, 100 }; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_25Xlu(play->state.gfxCtx); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), + G_MTX_MODELVIEW | G_MTX_LOAD); + + gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiRocsFeatherDL); + + CLOSE_DISPS(play->state.gfxCtx); +} + Gfx* GetEmptyDlist(GraphicsContext* gfxCtx) { Gfx* dListHead; Gfx* dList; diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h index 3830fdceb..474835c53 100644 --- a/soh/soh/Enhancements/randomizer/draw.h +++ b/soh/soh/Enhancements/randomizer/draw.h @@ -28,6 +28,7 @@ void Randomizer_DrawMysteryItem(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawBombchuBagInLogic(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawBombchuBag(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawOverworldKey(PlayState* play, GetItemEntry* getItemEntry); +void Randomizer_DrawRocsFeather(PlayState* play, GetItemEntry* getItemEntry); #define GET_ITEM_MYSTERY \ { \ diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index bfd487ed6..4ff3e1e04 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -424,6 +424,8 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_MAGIC_SINGLE] = Item(RG_MAGIC_SINGLE, Text{ "Magic Meter", "Jauge de Magie", "Magische Kraft" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_MAGIC_SINGLE, RG_MAGIC_SINGLE, OBJECT_GI_MAGICPOT, GID_MAGIC_SMALL, 0xE4, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_MAGIC_DOUBLE] = Item(RG_MAGIC_DOUBLE, Text{ "Enhanced Magic Meter", "Jauge de Magie améliorée", "Verb. Magische Kraft" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_MAGIC_DOUBLE, RG_MAGIC_DOUBLE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); itemTable[RG_TRIFORCE_PIECE] = Item(RG_TRIFORCE_PIECE, Text{ "Triforce Piece", "Triforce Piece", "Triforce-Splitter" }, ITEMTYPE_ITEM, 0xDF, true, LOGIC_TRIFORCE_PIECES, RHT_TRIFORCE_PIECE, RG_TRIFORCE_PIECE, OBJECT_GI_BOMB_2, GID_TRIFORCE_PIECE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ROCS_FEATHER] = Item(RG_ROCS_FEATHER, Text{ "Roc's Feather", "Roc's Feather", "Roc's Feather" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_ROCS_FEATHER, RHT_ROCS_FEATHER, RG_ROCS_FEATHER, OBJECT_GI_BOMB_2, GID_ROCS_FEATHER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ROCS_FEATHER].SetCustomDrawFunc(Randomizer_DrawRocsFeather); // clang-format on diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index ea559f7a8..be68728a5 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -770,6 +770,9 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_SUNLIGHT_ARROWS] = "Light Arrows can be used to light up the sun switches instead of using the Mirror Shield. " "Item placement logic will respect this option, so it might be required to use this to progress."; + mOptionDescriptions[RSK_ROCS_FEATHER] = + "Adds Roc's Feather to the item pool. Roc's Feather is a custom item granting the player a jump on demand. " + "The jump can also be used when already in mid-air. Roc's Feather is not considered by logic."; mOptionDescriptions[RSK_SLINGBOW_BREAK_BEEHIVES] = "Allows Slingshot and Bow to break beehives when Beehive Shuffle is turned on."; mOptionDescriptions[RSK_LOGIC_RULES] = diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index bca464444..c2e60dd5b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -67,6 +67,7 @@ const std::string Randomizer::triforcePieceMessageTableID = "RandomizerTriforceP const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; const std::string Randomizer::IceTrapRandoMessageTableID = "RandomizerIceTrap"; const std::string Randomizer::randoMiscHintsTableID = "RandomizerMiscHints"; +const std::string Randomizer::RocsFeatherMessageTableID = "RandomizerRocsFeather"; static const char* englishRupeeNames[188] = { "[P]", @@ -982,7 +983,13 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe case RG_FARORES_WIND: return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; case RG_NAYRUS_LOVE: - return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + if (!GetRandoSettingValue(RSK_ROCS_FEATHER)) { + return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + } else { + return Flags_GetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE) ? CANT_OBTAIN_ALREADY_HAVE : CAN_OBTAIN; + } + case RG_ROCS_FEATHER: + return Flags_GetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER) ? CANT_OBTAIN_ALREADY_HAVE : CAN_OBTAIN; // Bottles case RG_EMPTY_BOTTLE: @@ -4311,6 +4318,22 @@ CustomMessage Randomizer::GetTriforcePieceMessage() { return messageEntry; } +void CreateRocsFeatherMessage() { + CustomMessage RocsFeatherMessage = { + { "You found %cRoc's Feather%w!", "You found %cRoc's Feather%w!", "You found %cRoc's Feather%w!" }, + }; + CustomMessageManager* customMessageManager = CustomMessageManager::Instance; + customMessageManager->AddCustomMessageTable(Randomizer::RocsFeatherMessageTableID); + customMessageManager->CreateMessage(Randomizer::RocsFeatherMessageTableID, 0, RocsFeatherMessage); +} + +CustomMessage Randomizer::GetRocsFeatherMessage() { + CustomMessage messageEntry = + CustomMessageManager::Instance->RetrieveMessage(Randomizer::RocsFeatherMessageTableID, 0); + messageEntry.Format(); + return messageEntry; +} + void CreateNaviRandoMessages() { CustomMessage NaviMessages[NUM_NAVI_MESSAGES] = { @@ -5310,6 +5333,7 @@ void Randomizer::CreateCustomMessages() { } }; CreateGetItemMessages(getItemMessages); CreateRupeeMessages(); + CreateRocsFeatherMessage(); CreateTriforcePieceMessages(); CreateNaviRandoMessages(); CreateFireTempleGoronMessages(); @@ -5765,6 +5789,12 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { INV_CONTENT(ITEM_NUT) = ITEM_NUT; AMMO(ITEM_NUT) = static_cast(CUR_CAPACITY(UPG_NUTS)); break; + case RG_ROCS_FEATHER: + Flags_SetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER); + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE) { + INV_CONTENT(ITEM_NAYRUS_LOVE) = ITEM_ROCS_FEATHER; + } + break; default: LUSLOG_WARN("Randomizer_Item_Give didn't have behaviour specified for getItemId=%d", item); assert(false); diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 7cdc2935a..b745edd38 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -38,6 +38,7 @@ class Randomizer { static const std::string NaviRandoMessageTableID; static const std::string IceTrapRandoMessageTableID; static const std::string randoMiscHintsTableID; + static const std::string RocsFeatherMessageTableID; static Sprite* GetSeedTexture(uint8_t index); bool SpoilerFileExists(const char* spoilerFileName); @@ -75,6 +76,7 @@ class Randomizer { static CustomMessage GetRupeeMessage(u16 rupeeTextId); static CustomMessage GetIceTrapMessage(); static CustomMessage GetTriforcePieceMessage(); + static CustomMessage GetRocsFeatherMessage(); }; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 9275dc44d..5427b5e01 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -212,6 +212,7 @@ typedef enum { LOGIC_OCARINA_C_LEFT_BUTTON, LOGIC_OCARINA_C_RIGHT_BUTTON, LOGIC_TRIFORCE_PIECES, + LOGIC_ROCS_FEATHER, LOGIC_CAN_BORROW_MASKS, LOGIC_BORROW_SKULL_MASK, LOGIC_BORROW_SPOOKY_MASK, @@ -4659,6 +4660,10 @@ typedef enum { RG_BACK_TOWER_KEY, RG_HYLIA_LAB_KEY, RG_FISHING_HOLE_KEY, + + // Custom Items + RG_ROCS_FEATHER, + // Logic Only RG_STICKS, RG_NUTS, @@ -5784,6 +5789,7 @@ typedef enum { RHT_DEKU_STICK_CAPACITY_20, RHT_DEKU_STICK_CAPACITY_30, RHT_TRIFORCE_PIECE, + RHT_ROCS_FEATHER, RHT_BEAN_SOUL, RHT_GOHMA_SOUL, RHT_KING_DODONGO_SOUL, @@ -6595,6 +6601,7 @@ typedef enum { RSK_SHUFFLE_SONG_FAIRIES, RSK_LOCK_OVERWORLD_DOORS, RSK_SHUFFLE_GRASS, + RSK_ROCS_FEATHER, RSK_MAX } RandomizerSettingKey; diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index 7017ec738..f15f7c1d1 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -2100,3 +2100,5 @@ DEFINE_RAND_INF(RAND_INF_DEKU_TREE_QUEEN_GOHMA_GRASS_7) DEFINE_RAND_INF(RAND_INF_DEKU_TREE_QUEEN_GOHMA_GRASS_8) // End Grass DEFINE_RAND_INF(RAND_INF_OBTAINED_RUTOS_LETTER) +DEFINE_RAND_INF(RAND_INF_OBTAINED_NAYRUS_LOVE) +DEFINE_RAND_INF(RAND_INF_OBTAINED_ROCS_FEATHER) diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 02b1860cf..7c846ec32 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -137,6 +137,10 @@ std::vector triforcePieces = { ITEM_TRACKER_ITEM(RG_TRIFORCE_PIECE, 0, DrawItem), }; +std::vector rocsFeather = { + ITEM_TRACKER_ITEM(RG_ROCS_FEATHER, 0, DrawItem), +}; + std::vector beanSoulItems = { ITEM_TRACKER_ITEM_CUSTOM(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem), ITEM_TRACKER_ITEM_CUSTOM(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem), @@ -838,6 +842,16 @@ void DrawItem(ItemTrackerItem item) { RO_TRIFORCE_HUNT_OFF); itemName = "Triforce Piece"; break; + case ITEM_NAYRUS_LOVE: + if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_ROCS_FEATHER)) { + hasItem = Flags_GetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE); + } + break; + case RG_ROCS_FEATHER: + actualItemId = item.id; + hasItem = Flags_GetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER); + itemName = "Roc's Feather"; + break; case RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL: actualItemId = item.id; hasItem = Flags_GetRandomizerInf(RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL); @@ -1493,6 +1507,9 @@ void UpdateVectors() { SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), dungeonItems.begin(), dungeonItems.end()); } + if (IS_RANDO && RAND_GET_OPTION(RSK_ROCS_FEATHER)) { + mainWindowItems.insert(mainWindowItems.end(), rocsFeather.begin(), rocsFeather.end()); + } // if we're adding greg to the misc window, // and misc isn't on the main window, @@ -2241,4 +2258,9 @@ void RegisterItemTrackerWidgets() { SohGui::mSohMenu->AddSearchWidget({ hookshotIdentWidget, "Randomizer", "Item Tracker", "General Settings" }); } +void RegisterItemTracker() { + COND_HOOK(OnLoadFile, true, [](int32_t fileNum) { shouldUpdateVectors = true; }); +} + +static RegisterShipInitFunc registerItemTracker(RegisterItemTracker); static RegisterMenuInitFunc menuInitFunc(RegisterItemTrackerWidgets); diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 6bc89940e..11fd5cf38 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -1230,6 +1230,7 @@ void Settings::CreateOptions() { // TODO: Compasses show rewards/woth, maps show dungeon mode OPT_BOOL(RSK_BLUE_FIRE_ARROWS, "Blue Fire Arrows", CVAR_RANDOMIZER_SETTING("BlueFireArrows"), mOptionDescriptions[RSK_BLUE_FIRE_ARROWS]); OPT_BOOL(RSK_SUNLIGHT_ARROWS, "Sunlight Arrows", CVAR_RANDOMIZER_SETTING("SunlightArrows"), mOptionDescriptions[RSK_SUNLIGHT_ARROWS]); + OPT_BOOL(RSK_ROCS_FEATHER, "Roc's Feather", CVAR_RANDOMIZER_SETTING("RocsFeather"), mOptionDescriptions[RSK_ROCS_FEATHER]); OPT_U8(RSK_INFINITE_UPGRADES, "Infinite Upgrades", {"Off", "Progressive", "Condensed Progressive"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("InfiniteUpgrades"), mOptionDescriptions[RSK_INFINITE_UPGRADES]); OPT_BOOL(RSK_SKELETON_KEY, "Skeleton Key", CVAR_RANDOMIZER_SETTING("SkeletonKey"), mOptionDescriptions[RSK_SKELETON_KEY]); OPT_BOOL(RSK_SLINGBOW_BREAK_BEEHIVES, "Slingshot/Bow Can Break Beehives", CVAR_RANDOMIZER_SETTING("SlingBowBeehives"), mOptionDescriptions[RSK_SLINGBOW_BREAK_BEEHIVES]); @@ -2379,6 +2380,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], &mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_BEAN_SOULS], + &mOptions[RSK_ROCS_FEATHER], &mOptions[RSK_BOMBCHU_BAG], &mOptions[RSK_ENABLE_BOMBCHU_DROPS], &mOptions[RSK_INFINITE_UPGRADES], @@ -2612,6 +2614,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_CHEST_MINIGAME], &mOptions[RSK_SHUFFLE_100_GS_REWARD], &mOptions[RSK_SHUFFLE_BEAN_SOULS], + &mOptions[RSK_ROCS_FEATHER], &mOptions[RSK_SHUFFLE_BOSS_SOULS], &mOptions[RSK_SHUFFLE_DEKU_STICK_BAG], &mOptions[RSK_SHUFFLE_DEKU_NUT_BAG], diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 114435e9c..0f2364ca8 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2419,6 +2419,8 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = Randomizer::GetIceTrapMessage(); } else if (player->getItemEntry.getItemId == RG_TRIFORCE_PIECE) { messageEntry = Randomizer::GetTriforcePieceMessage(); + } else if (player->getItemEntry.getItemId == RG_ROCS_FEATHER) { + messageEntry = Randomizer::GetRocsFeatherMessage(); } else { messageEntry = Randomizer_GetCustomGetItemMessage(player); } diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index b6070d00c..2de2ab025 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1094,6 +1094,9 @@ void SaveManager::InitFileMaxed() { gSaveContext.entranceIndex = ENTR_HYRULE_FIELD_PAST_BRIDGE_SPAWN; gSaveContext.sceneFlags[5].swch = 0x40000000; + + Flags_SetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE); + Flags_SetRandomizerInf(RAND_INF_OBTAINED_ROCS_FEATHER); } #if defined(__WIIU__) || defined(__SWITCH__) diff --git a/soh/soh/SohGui/ImGuiUtils.cpp b/soh/soh/SohGui/ImGuiUtils.cpp index c80293a53..69690ff53 100644 --- a/soh/soh/SohGui/ImGuiUtils.cpp +++ b/soh/soh/SohGui/ImGuiUtils.cpp @@ -133,11 +133,9 @@ std::map gregMapping = { { ITEM_RUPEE_GREEN, { ITEM_RUPEE_GREEN, "ITEM_RUPEE_GREEN", "ITEM_RUPEE_GREEN_Faded", gRupeeCounterIconTex } } }; -std::map triforcePieceMapping = { - { RG_TRIFORCE_PIECE, { RG_TRIFORCE_PIECE, "RG_TRIFORCE_PIECE", "RG_TRIFORCE_PIECE_Faded", gTriforcePieceTex } } -}; - -std::map bossSoulMapping = { +std::map customItemsMapping = { + { RG_TRIFORCE_PIECE, { RG_TRIFORCE_PIECE, "RG_TRIFORCE_PIECE", "RG_TRIFORCE_PIECE_Faded", gTriforcePieceTex } }, + { RG_ROCS_FEATHER, { RG_ROCS_FEATHER, "RG_ROCS_FEATHER", "RG_ROCS_FEATHER_Faded", gRocsFeatherTex } }, { RG_GOHMA_SOUL, { RG_GOHMA_SOUL, "RG_GOHMA_SOUL", "RG_GOHMA_SOUL_Faded", gBossSoulTex } }, { RG_KING_DODONGO_SOUL, { RG_KING_DODONGO_SOUL, "RG_KING_DODONGO_SOUL", "RG_KING_DODONGO_SOUL_Faded", gBossSoulTex } }, @@ -216,14 +214,7 @@ void RegisterImGuiItemIcons() { entry.second.texturePath, gregFadedGreen); } - for (const auto& entry : triforcePieceMapping) { - Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(entry.second.name, entry.second.texturePath, - ImVec4(1, 1, 1, 1)); - Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture( - entry.second.nameFaded, entry.second.texturePath, ImVec4(1, 1, 1, 0.3f)); - } - - for (const auto& entry : bossSoulMapping) { + for (const auto& entry : customItemsMapping) { Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(entry.second.name, entry.second.texturePath, ImVec4(1, 1, 1, 1)); Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture( diff --git a/soh/soh/SohGui/ImGuiUtils.h b/soh/soh/SohGui/ImGuiUtils.h index 2206b4e48..a92a1d737 100644 --- a/soh/soh/SohGui/ImGuiUtils.h +++ b/soh/soh/SohGui/ImGuiUtils.h @@ -36,8 +36,6 @@ typedef struct { // Maps items ids to info for use in ImGui extern std::map itemMapping; -extern std::map gregMapping; - typedef struct { uint32_t id; std::string name; diff --git a/soh/src/code/z_inventory.c b/soh/src/code/z_inventory.c index 4141ffe1f..5f317672d 100644 --- a/soh/src/code/z_inventory.c +++ b/soh/src/code/z_inventory.c @@ -3,6 +3,7 @@ #include "textures/icon_item_static/icon_item_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/parameter_static/parameter_static.h" +#include // Bit Flag array in which gBitFlags[n] is literally (1 << n) u32 gBitFlags[] = { @@ -168,6 +169,35 @@ void* gItemIcons[] = { gOcarinaBtnIconCLeftTex, gOcarinaBtnIconCRightTex, gOcarinaBtnIconATex, + // Push down array to reach newly added item IDs + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + // Start custom items + gRocsFeatherTex, }; // Used to map item IDs to inventory slots diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index a9dfdd01f..86a72456f 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2463,6 +2463,12 @@ u8 Item_Give(PlayState* play, u8 item) { } } + return Return_Item(item, MOD_NONE, ITEM_NONE); + } else if (item == ITEM_NAYRUS_LOVE && Randomizer_GetSettingValue(RSK_ROCS_FEATHER)) { + Flags_SetRandomizerInf(RAND_INF_OBTAINED_NAYRUS_LOVE); + if (INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE) { + INV_CONTENT(ITEM_NAYRUS_LOVE) = ITEM_NAYRUS_LOVE; + } return Return_Item(item, MOD_NONE, ITEM_NONE); } returnItem = gSaveContext.inventory.items[slot]; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 4890fa2a4..aa51915c1 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -594,6 +594,10 @@ void Play_Init(GameState* thisx) { gSlotAgeReqs[SLOT_TRADE_CHILD] = AGE_REQ_CHILD; } + // Handle Rocs Feather requiement + gItemAgeReqs[ITEM_ROCS_FEATHER] = AGE_REQ_NONE; + gSlotAgeReqs[SLOT_NAYRUS_LOVE] = AGE_REQ_NONE; + func_800304DC(play, &play->actorCtx, play->linkActorEntry); while (!func_800973FC(play, &play->roomCtx)) { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 28e5e3ed8..1bf210630 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -2,6 +2,7 @@ #include "textures/parameter_static/parameter_static.h" #include "textures/icon_item_static/icon_item_static.h" #include "soh/Enhancements/randomizer/ShuffleTradeItems.h" +#include "soh/Enhancements/randomizer/RocsFeatherCycle.h" #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" @@ -374,6 +375,10 @@ void KaleidoScope_HandleItemCycles(PlayState* play) { KaleidoScope_HandleItemCycleExtras(play, SLOT_TRADE_ADULT, IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), Randomizer_GetPrevAdultTradeItem(), Randomizer_GetNextAdultTradeItem(), true); + + // Handle Nayru's Love/Roc's Feather + KaleidoScope_HandleItemCycleExtras(play, SLOT_NAYRUS_LOVE, Randomizer_GetSettingValue(RSK_ROCS_FEATHER), + Enhancement_GetPrevNayrusItem(), Enhancement_GetNextNayrusItem(), true); } void KaleidoScope_DrawItemCycles(PlayState* play) { @@ -393,6 +398,10 @@ void KaleidoScope_DrawItemCycles(PlayState* play) { KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_ADULT, IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), Randomizer_GetPrevAdultTradeItem(), Randomizer_GetNextAdultTradeItem()); + + // Draw Nayru's Love/Roc's Feather + KaleidoScope_DrawItemCycleExtras(play, SLOT_NAYRUS_LOVE, Randomizer_GetSettingValue(RSK_ROCS_FEATHER), + Enhancement_GetPrevNayrusItem(), Enhancement_GetNextNayrusItem()); } bool IsItemCycling() { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 1e53d8180..b4cb2d793 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -22,6 +22,7 @@ #include "soh/ResourceManagerHelpers.h" #include "soh/SaveManager.h" #include "soh/Enhancements/kaleido.h" +#include static void* sEquipmentFRATexs[] = { gPauseEquipment00FRATex, gPauseEquipment01Tex, gPauseEquipment02Tex, gPauseEquipment03Tex, gPauseEquipment04Tex, @@ -2493,7 +2494,10 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { osSyncPrintf("J_N=%d point=%d\n", gSaveContext.language, sp2A); const char* textureName = iconNameTextures[sp2A]; - memcpy(pauseCtx->nameSegment, textureName, strlen(textureName) + 1); + + if (!GameInteractor_Should(VB_DRAW_CUSTOM_ITEM_NAME, false, pauseCtx->namedItem)) { + memcpy(pauseCtx->nameSegment, textureName, strlen(textureName) + 1); + } } pauseCtx->nameDisplayTimer = 0;