From ffd84d2bfa62f8aa4c450201dfb46b2650a06886 Mon Sep 17 00:00:00 2001 From: Big Pappa Date: Wed, 2 Sep 2026 15:21:03 -0500 Subject: [PATCH] 1.2.0 Fixed: - Plugin incorrectly reporting update available if installed version was newer than github version. Added: - Arm pose position menu. Each Arm can now be individually posed using the menu. - Radius View Button. This button initiates a red sprite outline of the scan and slaughter radius that stays for 30 seconds. - Show/Hide Name button. This button hides/shows the RS MobStand name above the MobStand. --- docs/images/ArmPoses.jpg | Bin 0 -> 39160 bytes pom.xml | 2 +- .../rsscripting/mobstand/gui/ArmPoseMenu.java | 372 ++++++++++++++++++ .../rsscripting/mobstand/gui/RSAdminMenu.java | 5 +- .../rsscripting/mobstand/gui/StandMenu.java | 116 +++++- .../mobstand/listeners/MenuListener.java | 238 +++++++++-- .../mobstand/utils/ArmPoseUtils.java | 174 ++++++++ .../mobstand/utils/RadiusVisualizer.java | 362 +++++++++++++++++ .../mobstand/utils/VersionChecker.java | 123 ++++-- 9 files changed, 1312 insertions(+), 80 deletions(-) create mode 100644 docs/images/ArmPoses.jpg create mode 100644 src/main/java/com/rsscripting/mobstand/gui/ArmPoseMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/utils/ArmPoseUtils.java create mode 100644 src/main/java/com/rsscripting/mobstand/utils/RadiusVisualizer.java diff --git a/docs/images/ArmPoses.jpg b/docs/images/ArmPoses.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5fdbe413aa1798cd31a824442afc823942542954 GIT binary patch literal 39160 zcmbTd1za54@-Es~fCvNv1a~L6Ltt=s*Wm7&1OfvgKyY`L!6gKT5F~hTP0-*D!EG2` zXYaGmIq(18eZPBO)3SPITB=s9ufD2U-2b@$1w2)dk(U9GkdOdV@DI3O0c@q;*jWRB zvNFI7000JnibM>cfh{C(6GbBVcUuOD5kUFtb7b&KP5|5kIN+uNZhsb2aQk!3Uq>}F zJ7-Te6=^L>UN%lPPA>3C^MEAq^wDFi#}A)kJ;B1odHRfyiG+}VfRKxpo}5XTM^r?J zM^Hdq{*{`zw7!ghpoWX4zL}++y&Xi=!`I!~=ar3})t{Rn;o#yD;uCU^kZ@Q@3QAi2 zA20VE01gIn5Hd3g5-xy@gM@;Ebl(k7fNzfm>gA7W{qoATaK*zv*_z3(#{ZjxL z2?Yfi6$K3q6&3uoANW0hii3tr#VP*anYtM|wHqE+U|b#sjYLf+zQ*`(T5faq_m~d} zo)Z!g)6p|9GBNY;^6?7@3Q0;y%gD;fD`;wI>*(s~8(3IcS=-p!*?V|;dB1-1)+gvg za7gIKu<-bV#H8eu)U@>cf}=i0jZhQ_AmmacEzJ-vPX1A`NjQ`0lEKYq@w ztgfwZY;JAu>>i(-o}FJ@UR~e(kqZex`CF`iOZGqH!U5$%Mny$IMgJog67p+sL%~5s zqvCvkE3S@i=Jt%5D-Z)uA}+6{6O)Ep<2Sy!`}jiwTAmfU<3FPPCE5R;VDJBbN%n8S z{v+2M@E8RN>^u}400N9nG&eXx-`xXLO5<GgQ^cEa|j zo=moJ?$FRiZMOvu(~pYDE_*hfr9(}WH{@ zQ~yWsj~ND`b|gjG@BZGhHM~3stMfr2->Jt5w5@eAP?U6PS>jo6mEV ziWOeQHYH_=+XD{NlZ%zwte<5g#ot}b?i}L8S)$TWIqX|7e*B22L zm$vsn!vj)b6)+jx*S0&w5tS-0Ykb~)=+SO%kDk8Zs^v6_^sHDUX7RMGX-c_hM?*+g z=qNh8(Ap1pu&-#T`5uP;CT+UfpllY0!7hgiOzn);gz%%IL=SxokLfX^Lfmkdq(Y=?`g%n$j+h6uNVB# z!)nFMkd`l=hs|Es-UNn`xn$2e&3$6vYu2w~;H0^e3- zcpauHonQMtq2bxpgkiQ0U?tO6(tSs_q+_*>SLpB6aCcVqreo#Akg>C8z!)}=Nh}*l z*bJ&=F^M_jheJ|f?e{>8AOw4pnUn^D7Z;}EWewx^HgE1IOvoiaA5nL?wS|si!=d*; zr9OU6ZP@hr;5{&WMN?dtalp63x7b?S>#>Yao^TIPZnslxI^^RqH7yn}S=3;{P2RJb zXX&2%_ywQCW&hYVD53*lNjXhAOkOL6r;%sn9?-}+4A+BB72oDJ7!qN@awRmzkpF8% zbGV+H8YXX;^uKBb+hgLLK9C z>Q{JMTOBVF#*nVxJ5cx*k2GLkZdgi>Tv{>VP?$>ApzKn`a^B@>ss&xp@mc=RYt|WP zPRTtmig6D>5N)FBM*DRP50><<2OCsZAve=u#mXgLq8pS4fKNz1*q2}H=M~dvbBd9AjgdK#R@PNCAF={SmT}o@`s01mhDxZ<=Wk?Rtc>Nl-VY(I zHO{mcyc$t`i_WzjEx}5DAx$gQVe=IaQ9nCzfkRPeBltX&Y_M)W0B1y=)@>4=zVJ0J z?^9DUcc@%i;?2`1{0f-Hp)b=0_U7#E5Hh{!{`)I#lN4(PO;e^$X-Ja|58<@tNt zczfU2%+;zzBFG-PyDe<=6CUWg9I!d_KAL&Iq_3s2#`qy}{YJ-`?SfSV!?Er*OA`9i z9QW;;#Z#onv%Ry*N)!Zb7>m8>d_+Le%gBVtt-wq#GW!)&1S@7@j>M|HcLVqQjw+IG z(#fhd;52}ed49BGba#HDSPiw6ic~iyWpPy*6FAz@+BMKIe3ZO< zzern%k{SPYV8}naORWY^6UBq56*u!QdVKmiz<{yei?( zRfB&n`b(YHn%gL8$GDVVm6&4|v4R#Rzkm;;I0pSR6@1uT_bO^<-_ptCFlI2hhUc06 zJ>coDRfpuyW5Oh=KIUCaITwy?77o0#&G6qvXl)~o*2D;MTR2^h3nLB%;k#`HnaM*b zc*AcP>N8NxS-`6U_3`a%4dZtTpnt1c@3*lcI>t|v!)$5Wa@jJvN$bA9U$9)Vq=%|I zpx4)OT_@blPtMJ@_FqC2v#?ZcPz4@7(Rokuk7n?0O#h|E6Q;9(e`#i26V%2(D*rF# zN{a?C?$-3Syep&*>T_|EuN*Y%e& z577MEXv5Y)&&01d; zB@u6AukV5L9rx%h*%dGPUF-d)*s~zaYrL^Qb_mQ?2nyc^g*@jIB4(-RX3Rwn|L27U zkI6QAqCU9K%hwF$$#=Xoy}4tyqQm#*sj}F+f$bYa4d*L=#CTL|yRBuDY18(q@jXi$ zvY*5%ZSt;OW?f`~piyA-w*Vm>4HfwTkw-cPq>&Y!e8>_B@!Xv>#ix)g&+Mlu&vl<3 z+-_3{?gYi$Wt>&4U^%fF!7NO^eYLqDtIlZko{U;_ONjYK*jH~itEJ0a6ZHBu=S%5g zqunR=tYc4ML7b+@TNEpE4Lb@C4Wr}>Mh+{6t8$&#EVVn;4s$;N0Uk%4RS9ap_fu{X zFIin{Xb$F(4_^XUJ{B-DW|s^p`=ZKH4MohCoJ3zjtg_`XBCt{c(uC#eL5M+dg@a3J zSIt`%Jp0a;^{u$s$s7ebM%W=HJ%XlitRB;gg(2Na+A6jL1B0+bWVFp~X0HDHgEfmj zypF+*1n=}J#@@BusziZ!+lNfNxc}7dVxs@GaCb!?nLG;bSl0AVdW{Gx2X1n}zgNmH ze_S-!)frG`!x}^=6O>~qrY1ApjEul^fC1NC>;G}@*OJ( zEGECP{{fb>`U#K|0RO$>sUb-N|6}LziUxezAH#}8Sf_O7fTNt^&Yfatmeu9sTz0QC zeps%$7%@!biD&?E=DWhvS$v(}t5!5s%ygnU8d2l!C9t8e$gFQ;V`Y>ZR=Xj>g)VI; zIX*Dj9&2SWst|EhpK$YsjL33D@dQK8T2r2r4rT_Mi9*>b^h(gW_7(m5{Bl~w_d*yO z(dwxS{9|Vo_|`HDg{5Sj<=VIT#@u-oO=;B#%(}zFdjQk(Qn2SX>MT#Te_3IJpE5r{ zI0}LgpIJU1fX2cm?}2qPCooJ&xqf&Q+7)f*Jg{T`;lDNZ-))Pl421X}5LAapNw0=s zge*}$m@)60jkyPm-B)v3;_C4$N4&#-3CRa^;MD=C;Fci^V+CyAyj#;mnZ|&P$?!V* zu;?1IN0FZX*x7Mt>iE})X9V&C1fD4Bv`*<-?&ouKzGwc066psus9ou=w45Sb!WeQO zq8aL4SjU2sa~p-9csnl3?MKdoLu^iNb~q_l1}*OtLx*U9a3|=_{_GxGkm6s(rey?$tS2T|CZexDREmc`7+n>)f?-BM%tKWHO z9IH{(#3kkHb(Sopve8X-9tCD&gl0a8OCM<-G};)$Vy=?(L3N|v17p(W27_IT z#C%r5Zn16#FANNL6!ZL?J?kaq)Ae+G>T%F|BID$Gz_v%_1DlDUp2YL06nHr=qc}a!&ScGnmB25 zTRgP~J$Oher+2pZfOo{`dBNRWZ_#G#k7{XaHFdFvWC?V7F)*Gp9wW?xuV&p5tqZR9 zFpUhUlL7<5wS)rG8{*M2ZNg@pQhoJNS|b*>Z69ssk48n6I*L6AUYZ4Mk8Y!iT4i}$ z@kCSqB;BXGjL1ViiNAm0(wbbfAiPvmrtRI0<=vFp%ljLJw78r)?9kC0ALM>XAXct; zb2~JglLuMT6@2w@y~jXlzzg6&p9IhneL0Y1M88qcIoIGb+7VXsgxas}sSrDuzU~WIHmSmDD(`qNt*eB{bQ&(b(6# zTgGiaryU3+pZw?_g;|Fwe>uixMR_+k7zAV@bKYofJW7`-QFh}R9Q^9AuO=$j`S{0( zYVoVYW{Hg-Klqv5xn$Sfw1#@jOv75A34K~@oNl?u?{r@qsEKpS8jdLj?Necxk(f}A z+EL%Fj_-H4&pM)R|2dCTzvang)zRTrdQl}s*2XWt;-L|@5q_KM+d4fqgYaFVLeAcm zRCibAd~wR!28}`<_xIlrsL>y&4H?d)6XlBDmQcIo9lj*x|j26%%= ztv2!LS-U+&z1;94$kl~v-}N}ifXT~25Elw@V*oVVm{YvvC;hR@{gXnyMbund zD1!L)WVF&U6<%Jlw>GNxKu!$Yt-Y&7Fva6h{<*biyLGg-R2BL$b0o#k_$c|xP?S(_ zO1E0%TQy;yLn>%*%1g;K65jU+8ut&fj%AAxqOu!-vUMMu$J>m?kMWn`r$LBo$eQAu zl;HTpEZtpw33Rj%A<({}IG4L6YiQ)ylC@viTxE$)c&##iqkf>)JpNM`hjr+b?Wc9T zG`fH_t;WSy@e%KRiBfAyMk3m5G*^pC^4WgDk=cWWoYQmkJ2-x?#zjSr?MQvSFPeGL zFH2I_!k7)CB=YG{VWGFYd$f-1X_S51CdWMc8|Oe-9x_@*AQ30YM|Tuah*mh6l#ePsAlEax-zl z!~B02p}iMJe~>Togc8r)?xV`es1HyhE`WNYhANpLSAj`7hFYALd&UEF3%JS}JUe;_ zd}do0;|?J|M>#9owAGRM;QsdbP)$aFI<5E~C~>)L&#lazH%J@MPhrQ;Q2pF7x{UA= z>8I|Uq>TCU_Gaeum3sPO>S?K7KMmgPCxsfCfCmtv{`@F5?7Up8o8&f>%>SaM|FFV; z`0BA-Dp@u(k~%QGt@C;th!diF@zRS*Tge`oAMw4H>igynBErY7+R@%8H_`*1R83fNa!-hv&T7L z8iv@q0MQ0rL=+`93c2Q>oKv2nx5;XF;S!;nsgFH4$3v3%+d{RBp?%-{DF#2~blZ`I z*MdeWr^UZSRG8Ge7`}HIEUK-S;)=Sy8cOgXl{}>26y>q|6S*GMukD~wR?nmoP#p44 zgo5;|kgLV-{AMi2&%dr)&*KBbTn771t(+z32|0#&Mb9~LTdRN(W+Gp;2UR(U+hI>RR@=ERwkL6?)X0UgV3<*o=$;%h6xXiAz{ zxP4`J6<*|VdVkHB?3OC2e(%Mj9HsOa)wq!YM@$eE%i%o&yJHz+2c^?DQZU88O`6%<`0C14wDsI|Ww7PBNS9#2~pO<`*5Syuj{DRzIR6RUst}V*xQX{iN z@z5j2E?g9Q^oJy%jys3n@XJsoO$DiH5ARc+S(|JbE_5H-R-J-W1mwXDFffXnufAEm z2l^+gE$kefX~a|B{M7P^XJ)9-TWb*z7&VYOdS&)QF*97uM-8P14+x1(2Rl9&(v0^Y}fDEaF9ess>-fTis zt0LKZ?;e-GV~~{gL1$DK!#~HqMqdEEIXyxqN)jApkn@4|xYFbyjh~q^cJ(73*y_#i zqYGD)vCl!q`vsDPCT(1(dO-yJl9N_`PCB%E!NGVJ_8xZxi7a5)7<%q>#$y}=Lru$A zht}U{P1~@3geRTz(oxo6MEMO1r6D_-fC!>oz71-buR0fAYWtTu0Ffu?c}1w6+PHXX zC=`|0GqB{4aXAZ6IYv2052^n?ps}XTZ_@7s?gMx!?Z+4QK334n?Dd!VlydK9xIMxv#L_Ne;m%H`X&I*1q)Pp+WMT~M4tZyLOZu9#03q2&|? zZ0*xAm4c46IwoHjO};Qcq$QI^DJeuP%qq^F3e79z47;4&ld@oA`j~EVZXE`lPM4%o zsi$kd`F2*OuR&iR?%igG-@NlmeeR_f9+sONCekovE^uB*yBUC|#)!07imd=B*yW-+ zpOGgb5#>%IPZ!@5oEL%^spDUdOUwrs0kuE+H=TIni-6=HnkhC}3LYJ|OENEGj;p^4 z9KusW^ZU2?6{y_`C8+W0HFycVAU7j6^`Mu43+v;oB(oAQAY-G}%;a9Ce;uMOoCSY@~S~ z(0Xm#r9k%3CtxTvZ%IqgJ|i6|J12H%K{yIyj>3Vg2YL_n+Gie$2?jotFCIpemOc(= zKYyP_v5eQPmvX0HBuv&cY9L9ld}nr}Z&WNg_`-w zlg`4a!SEjPCv>?7s*PD87FeAJw65H7v33dBczzD)y~S@GKuv%}zNYrU__56qWZ~ZS z!B(2z1?bJZ_!57GG%tU7Rn;PJeA%z}-0lHC_A6cVPid0})b4rF(q1%O7a0SmhkUZRwTCTjy z_kfKam_|-&zq>K{U9daaCGUA?h;>pbC^xT4+jjmUIMg z8do``gNMQr4%sIP^^6$N-lELJ@};g*s9 z;2?a_63=;ZKCH+jjH5vSOnJ~)skj(E6qk ztkSfQu5^wKh(rdwGQ{aixl?F_-}K#5SJ>yAJWctHkfoAzHL>((|=`C{uAT>KUyfG z#oP6?+k7aa1}j2XlgfTKPPIPW?SmPGAlG4=M>L1;6&>MOuzvT{j{kpmY5yZR`Il$7 z{F|8klq}UjN{oCei>l$1$Ls0JqsuuYL@iY!-uaj@=Fa?18rhdP!b>O;6ML0gZL%im zCx0rU9mbW0GW20hph%5?lyEcF3-6FV_J)O_c~9f&d2XUsvO3r?ua-kk^0)4ML5^D= z-G^@y6{oIcDgXSYSu{}=QDy?8XJ}!p3*aO@FUdJ-oN1J+E zWPc4QA2($;SO_p=cH6hFqv(;(m7aCo*Rw&NNzL)pm4^ z_59^Gq(;qI{x&W3x1gtF2YE_L^L!|Rm?}T6hOQm{P8M;6@C42BKg8yNXZxPX-I~;2 zd!vcP^vduQ3eZ_Z{B2x(Y-gX|dxR6Bw!c1xB|a^PKBFYTzL|yvSc@M>BHMvH2DD5a zyT`$z=a@68p%4WM7$q6{u{!#(CgJx#w@}Wxv&+NGxUpHPyD2^^P`aJT(Ly9mV})?- z>Q96DE%p_7u+~@a_#5{=S~=NYSm@hK!%Ir)21JeMhvD*ws~a5)-j|?!R78-yFob!` zBWS;j>dh)NwXy^*rD{=@-=fqN4*XSI`2W~p5qR8IKi(@cWRMz!MK&y z3J)HdZPhDXWm#%$>u6Dnb%oQIUd0sYpIlt?`LM2leFVEFC5827t)3)7^ z_SL^6W4Vqe=;fZvP_^Kje{BY0)nB$LL~*Wh540k9QnR;5Z1rjcNz=2NHd;l(p~x&G zuW5)3Y85t;L;941|oUHU_!Io=#x~2$bqZ5NiKYLp1H2EfE zFMt2sX{Z{8^R^N3`(`$!(mB{_YBP5xK9#LkH8fh=;6B9U=5(%WgzU|O$qROmhVVKZ ze7q=m)Gy#^DpqEj&e;+&)z3m&Aji4123W|T*s?hvZ z`$N|Dh~Ihd$=nbXezr}ZX^PfSeJ1>Rxgura`#bMr+>P2D6EL+W;Z=mhZZGev7LdGr z`0Pl!{igOjFA7H)QD2gA=b-k%WhcjHayMt9=(EOUY%q~A z0OgkV>sjo(^K{v?Q(QG|;I0zAy3sI#47DHL1Da|Ns)O6tX&CO@AVXRRT%`1!@Td+( z^siXZ4xK5T$~f+V|4p++HfdI*x|{a}^XINv=;|vu*QnLE2WnUDn}l`4pXEwkXJc0G z@FW*$E-aMY1I{2(&OSzXRrC19>iu)Rb3Hyx{!6dQ#$@{N;IM#?pP7nj1i5iIA-iA_ zAGaLO$aLe=6>p`AuWobr(t{B05L0Z55Rau#jz`YF8snFUB)-urvWFbpztWQx4t{*y|0)xgC28{9A;XS!g`b7&Q|yDs&j}eAGX3le41|r+G~%ZY zSO~Uygp7cLq%G4QEVvY-3@8*)4x{9o-qzD@m#=tZ*9{D);R`$!hBVupL09QHb~q>8 zpQ`y=j>$_sVrNx}4;N5P=tVvY_DxOQYKhADNWZ1&KM@wLv9^fsUQgIloPUcQd){)& zio9;%;GMuRcr^F6m;XsKoIBmV%tc*5pFBgmy^a;K)iQnB*Nm24d6x%fH$`Tm-&{T- zu&=&|Du!R0{C!sTzj4<8Cm(74ttskJqZqdq+acIxg)a&!E3Z+-as>Y%<|==g^Sxt&omM%iS~k@;P@z+qde2b z70lNNR!^n*+E)AA17Y8dfJWTFF+r5m%1Kn(c=O1FsU$o-m_D6Fc2&^+7<7~nq#$t$ z-!ArQMrVRM!oc}^Vg-Q#f`zulULKSmK`^SO;iX5ku-dh6dJDTp(hF`S5oI?;ZyzlL>Prru&Y8lR>%v^jgL@!6 z!etfCtT%4YkD0lZ9vzD-w{jeLEKi6oSXpu|Si^ilqVdb;;nEg6Q<5ii0!(^py)s=C z<%|~cV;-UGXO8A+aN&U62znN&&$7Mj7Oh zDjvlC)KY6?$nt#8P{Z!kriYME^~Ija^DmA1rQe1)B1M?2x6iv9 zgm73h{MX1s;)ncyW#7h};Abfh#98nx%;?gVLwz4(j0*}cz5#r;(hI5?u^+8%Qoi>K zfppKr$|uHYEnmz8;8AI0rbOOq2pa>SAgK|p(Bro=#uo%Bc@I?*mdod=N%(TWL@-I22H0& zgWIp2q*=#qb&ILXsPh@M)dPSI$M8#FcBOI3BbV94*P69~4)f;QVr&A7c-&&FcUtuja>P~N>r^RF_<^(&qj_X>8Ah&;JH6o;)b2u|pu)!+EY0f~C3_rI z_ePJE&a02^2h-@7b<<4-jg^L?l(*~E$aL-2+)#D~h9lxl6;}jxlHH|{pJMmeE3PtG zuHG*JVgsV^Sx#kJ3*F0hoUysZKCjmAkNMVwgVo08ZBy?cl?FC+2KIb4d0zDWpM)Cm zRdl)J^bmM_j9qh|`N($ch$CTEmNc$3;8K!n^>%TVC9pnNp4ml0_#B@!!k4(WqQP;b z*C;^7XSHkzj9DoZ`jQW_3(4}^9+?q(1YPS`kq_e!*_(nD@pk4Bl|)}2(%vsbB%dos z>#a0AC$TIXpZcu(Kd4E8L9B2*Y(9C|1?Rkbp<8<&nR4;{_@W^>k6>$xJq!iqDQ?x;V)5zNNrhF2pN9^j;Xlj-7e~Gi6xhYs!xy$C_ zYi#hpYDC?l7_2jDn3~~Phd`VI%JX)WpBpmYbP8{YA)Jn z)l11s(+1A|-Y4{_twy9l&6sPA0*J(|n#cxTZsiJRYhj)_Hk4ZBTy*OUF|1*}h=Bb` zk3Wq7YFEBSl)RFS!~h92npk-OMAGMYg<0MW%jC7ESP(D+N2NvXkcXXIO$a2McnPAk zuV~U2GCZ)02WT^q2I!mnk_rXg^=@j0*~HzS*S}p&MvZkGzS;+#$Ejzy9M(1bF+;>Y57@!gJEmf5#DGRuRxoVRwav{OkJlhXyxn4k6mVvyuO;HR@t!d^(Wgj;t3DG>oa86(Go*1#4 z7j<*(ax#)3TQ2RU2^5CP~X>G+Nt9gNx z^~Cc>fjW3-Y6ZE3_&+h+v#nW(m=U|4E zmWE(?N?SzK%srM-ZI{lBIAOpd+-U(~7ZyuuahT(iqM0|T_=t(kTK!n+Q-8yIBAl)e z3Kkm*@6RqsXyT|inL%nJsopH=ay1gQe$x!w%sn~B2)v9Mw-`>NQq2%lKL?qJq@ynl({Kis`QM-kTFAPCcU&0>aF-0 z&xJ}RVf_BaQ4v`ROY5a>lq`#C&?w89cN2$R3Yl~*>~}?zGcLF5&?q$?55;EDuAGx3 zUffDgg)O^vn<_5b7NDPd$3W7oF8O1*h7);`IgXIlvyrhTZQwokFrZ%saZI=^zgBzj z{;Ul7Mjg&{O$>~cQ8=gEmV&KzEd-dIQ))jxLev8$WK1;;SJO3-0k%j}YH0sJ#y`h@ zLx=iA;6y`ox5!|l$)DiA8jRdESv#MG6BOp_wT?gcQ9_5<%VTkhJNI?R0Lg*HIn>T0<*}48F%`Xmem9v zqi=2yk$D?vTl9ryap6xMs$P!HBuyQ;R08_ogb*$0QvU465kH5A8Sw+#qxIHu)(N6h zNa{%Ox2X33PGMk2`&KQ*o{9LQQ6oDN3YLH z*{ox}6N=n1x-|@`xi^P;H#N`aD6lOmuRZmR*)WhbU!0%%ImH@tfoIA;vsfSZzg}G_0eQ7fd{Cw4tT7ghCF`t zCsDvkZ;L|y+(xN}HYhUPs%9h9rgtHINa#CAecmPV$Vfcd9Ii zQ=@Jot@alldqB#k`z%xT8LrUr9rJDfP^ibVJ`XYM`kL%JA%bl~5#OM}0ugy5e$B!RI!R9G$jnOQa7|UyC-fxZ*wwzRFN4BYm z-$ZKG$6TG8T=t#t;*|-?7rjuXBP^w%j&H%Dp8hl74_=~d+RWcf)%tL@4eT06?8wc> zCAvU@j?1~bq94faDRVO?E`>N5-ZJ~t3#a+=*$mBlAE(#6c8;h;Yn@W|aCA~o$h!Vm zE5pKWLzAZ)>bfUQ8jtOw+HA0OXL_Tt5ZN!9RH&(_ep+h(k;ywfm+{pfzHm6P{8$O{ zCqNR@DTn-=T|V6cD*^r)a3*7{p-Kbj?-=`>Q?M2t_Z)8L(bweuwb$xZhRl@d{MQM| z)}qe#Ya6`lgk1tF;`+M`Fme#pg9B+{b=>GZ{uj-CQ*SRzSM`D7*l zUwEQe0Z3*$lU_;yQtELp@_-t@$@6^n)~m4&ib|TemH--;FLnrZXL&*%VBX~FCKRki z?JCkzIK;gCwOJ(`w(q1oWP=wRM)Lyb-&>xmPwvIlwXM>M&JE9oHi_184edZ?_@~CH z7HKFnl&J_P2|wa26*dHCqtOOyWjKJQOB!BI`10tx&y;#+s0}t6x$V3!xNp4T5CZS=C2qI9S_M!jCsx zzmSXL+YV$e!${-yMeSZQH{@|g;;Z&gCs2~tHB(&{IL$iS-yM1}2f8BrHroblqn`cMc&P&G6`6Cq28J z9tM^A)Sz&od*G%7*x6Cc^d!nf9j!-?%T5Hma&h*+d}UuHKvWQ80Bo6?Q&bz6|L(Y* z*iwl~msUdl@dUld*8bD`(!S`!plJ1^?k zJbWqcM%j&1AxWk>1pRha;S=$>!g>2`f?Bw@squG$H6j7tEVDN=?k~c*v}XnNcWt}r)SrWlMR3=tGz)+fRGan93GZ<+cj!Tp2;&aC*NJ~9n)jF1T6 zE?(T?!&{rhe=*!3fdy*|f zNM$+Y~VA<4G3!}b-Jb74i+eUv&%NU%L*uW7grjz979um}J<&*LDn7rwr?2Hhmg<$q$c&}rmSg@t{*zGH#uS6xcVsTn z_BCy=_N6hEs5WoWUSHLwdtSzCRFZ9N_r&_0`xgYoihiBDlwewkmtp2_Eo?U}`?u=4 z*3K$$;e1O{_Y;C9Axreml&g>UEFy~_df3dZU`2}Sz1%Wymt z!N@cD9ssjPoXV47&l(`DchZ1^7H;iZXK~73V~epwiMmWR#-Strb(NPfGbIw0tpZPC zk;=i!b(w)Ka&6xRS@Wn*{2B<1Y60fB+~LwYVko%EPi9iFBMuQf(w9(Tr3dnt!?=E@ z63E)O1v?UV<7b5&pTWl#!l6k7CdX$vF(;K&&A2~)h=mG|@d=W~1?@?=##2Zm@*B2I z5xm>?fcUMXtBgGbZ_3yN4@;tk|8~i{%`-e;2Wvd~TW-mwx!5S`sTje!8qc=A`1fRn z(;h{<-E<=bcljsqVL+DttUg+wnk3@cspTOd3IosH^}Bgn4lua{<{}h;Y8w9o(lYqZ zUs#C)fww%6m{T60lndolqC&I~YVhHy&=^{MJi4jq5SNPRb=f%oQ3Ayh9+F6xOuLuF zueH*WDiQ|rGa%plBcmEdpX7N->Mur75Qbm))f`8a#wclXxZ5JzxmZ34C_WFQ894ek{dn<%qDrOl7*5zBen0(|CRQYrJ5~_ z54NI3yx&9?3=6yvEX!2?bE@oyb6e6?nmMsy9Be+D{Wa=FTPaC%|g-Mx{T`$O32-fJDM`??`xfs%-g2yOJHJz z0y~;URBt{42|pfEpFfj+SWgyNdD$<1o&MF5g>!)VIxw(rCa*~yZzx>lfzTauVs%M6 z|4N#PV&sd!ELBRHKg45?O z@Yaa7(q|jmeg&uKcd5s+KY` zF3Uw0C<*HrcI8_?95v@uGphNK`P4_7+TBB;$H*C+5l0>dR_SEQc3E#>CKt8FgkDFa zsf~y1nxf(RFIP7~nOPy&d-A4Yr`!j3_LiP%-p$?#?%C%I%H#N>zY#nswC}z|pUZW% zOAs?oV}}hX{ReYm zPGL3R5S99S7NZq7KZgPr`URTxoZ|SH{dVhmR?Az4-Cc1;i2)Z6_8#E+2MzCA7KDadZ}N9Z&wJr~QLGLLlMP3Ku2 zW?Z$xa~SYsCS*?uy$8e%J;blV4w>8DklWq>Qvax#r zK?`M`AW2}25}UV3xLe+3BDqsMp2e@_YHV{S-3aE4#>-qS%!d(?*I_7zP=dJ&ON|8? zqdZinAvr&t5Ao=xhBx<$_G_8ce<%|Rh&eH;t-F0Sw zpQ!KO-lV4^2z(XobZxZ)<+tVn7=zM3@Yy0yiJ?m#GPjU^%6;^#QN=esM0WrLCz2N; z0RA(6NI)*8JGw%s7r+L6huu_kISd%YeMZw+6vKt$%YIQqy(*Es9Yg)uBi*_bK+hgG zk-K~(_RP7Y@pcTEn}+n-UbPf&4w(PFE%VHp@sbM7(6)cX7lCgg=4C7vBEa?m+oKZ^ z5+I}?(c#5|gc2!OQE8*+z|^fSL6nB#Y|*iP0T;1FUV>4i6^}IcK7YM2dRC=jtZ-ue zgzj6WX@CGJX*4=sdJEu<(PKyz*h$u-Se~n_;##JKi-lbZTh04$ zB26F2)y02=SFEw!K#DSa}8$q ze6XHwS5t49q#+Y2b9$2m9Q{3_W_r1n=JEquZCn)zrIWY|c6q-jg!^v4jmQ(7!+mt{ z+wOYm#BqLyUMWON^W28_{;E~{7-pD2n$<~z0>5(*?L9uUX50-x8$Og7@MhZz^D(ewkztV+W{FBHm~=L44W%+d zM@@2p`b;(^oAB|TQaJzOY>m_^3u}G2n!0goJ*^%TbuG}*XVCJBoi~-^yB9#;Phfu5udr5U(TgsUKFz#gFu~mK;r|Eiw6|^Oskd!g_;Ni_<{U zCC|WUzi9oq?5ZHA3Gz8*eoHj+@SjLU9~@UJ^68Vi`uT-Z;n0VDS`M?2)T*y* zIQcpN$!Hb+>iT0RIw#8V?eI1;9l;H8vH76iik9WnV_d*uvDarcuQPgkvZAx%ab$bibT*+fhcj zMKU7V?1Y?ZP74&)5Tf8z18^#;P^1lMd|xvI?aYq8-oS2Gxat2Xu55tZM7jjT6k1x0 z5M>Zpg3?6aXK)UE82dndR@{q3BwEKoxM*j2yU2)ieAg)jbye%I;2*O4Luyi=@h?IY zNDgygasxa^=Ld+Rb3D7{y?GE%SoEBw8hB_Qt2v=Yo+`DPCtD>ZiJB6j|Cp(^Ks#=i zzKI>~%E>G1vU`oa1i3r2BgUET-+0Rv{hCb(NA5w7(~HlPBh#iF9tWzjoO~OU7VR(& z`svVkvj{;JLZUt+E#iV?+tkeXEL&uzA9#`EGUx_QV{@@s+2b1Q0_iaZEJGR8p z$MpXq>Mekx`oq5Ovn;T5E=adDNK3PH*V3WVvLHwa0s;#NNH@|f-AJb>N-Q8fN!t2_H zYzc~4``Tkq>O{}5XBaXA&?Z#J);K2-?2=34!$F`cOy{u{Av2`zxDx{q6g-StV*-XI57635BOi zG@t7Elk(?iq?kW>eN}-=jb+habPXzgd+$Z4AbVx1-IHipTg^+BxE!H0xrKay+qqQp zL#*)KypjJha;_Y=f<8W zXKW%1$EB7g{ae`Z|Q-YO4F?bN%@b82pR0 zDYP^q$Y=5^Nks(ijl+RFbs?Na@C{<$gPQv|+*K|6X=C46dcw;W^wT4odV?m~8rsFq zsLX$AUMbDZxE1|Aet$^5>FPZFSEuKux;63DR(OTiC<1WIEs!DEUJ{O=;ej-4zkgUHbR%$s-O(*DB#+p8ol%ku>60i1adK~K?&4c7$fdDgZ;z* zfWv=^r2n}hzeFsLmvkk@othC8;8PgA_Y2|IQ0Ms}0hSmN99p+4B}$#VcADTXwpe8_ zFwJv3{*Y-c0-Gb&`hV$16|p$?V)j<WYlGp>H> zOgxf6vnJ0_I2+4&vjl8;PTYmI^MQIf!BO#RrMW5G^ZM+A_j}p5D(U8SkCEi8w>5yx zFE#%aFi8`=j&kq*`gM}dj&2AptYHX*MFGz4bPVkQCT3}^P&4Q|2la`Ex)qMAJc zhS_BE#;8=TS%IPbQDvS6l$y8--3a{EySg$H*NhQPX>X&8PW$ACt#xv*wXxQ9+B{sF z75$ytPjrD9DflV0x;BM*s#-C-I-_7HP5cdqWyR8azl87|^Lq|rTIB>2B7r*=gs5sU z^+aN1jN!@kM(W$~PH-Mt6c$v>#bO&AN##2^6P*z*l~f_5^Zk#l+Isu)0b2y@LXsuX zK}fJ)wn)l|{^aYFxtOsvr+Pq_^HVXv#D9bZGc8%S( z&|Qd_6M4R0tzK5b_U-vk1G6Q~YWn(}TDknr*M~_Z?b5Lxw-=YjPtU=+NIi~^M8#X{ zTXk&ok(&oj4{N6hFLClRUk2WYn1Y)u%%}dQu0`t&9f@edM>`@oDA(94Cbs0@(Is&tZ(%m{ST)?J?_t^ zrgUqU1uEZ`GYQMkC2nV%tnZ@iP_`hKcvyQZD36VZ1G*~1bI4>?L9exSDC+`RNY9&i zYiiaL-`?KjzLWIf<2eju%0i~v%)x*AZBTBP^>M0Co|eT1G<68o999=rUFD99KN7$AR(&V-m%P9SE zjfRBPNA-4GGzIJI;g{gTs)Puj48N`!ZyXayelhjZ#dc}nPxG>#UI$Va5U&R-on6Bj3LvMoROFwEw}NB`~Zb< zq@z3q^1r)Rw?7c2ewxa%?=v$*hVmT{PO_1l9&xVJ=5yfu#QKw@^cqjmd0E)E3sk1n z(sGhiCm-s`T%V{Ub)V%LSNIuQ_+>7zyQ?0a_hytA8uJ^@E%eZ&k$)K4AoqLZ`a^v(e2FVS>Lf{* z-IirhX7X0y(g-H$nZ#uQg(~P*Ma$-9Jpye> z#UF>=f?m@evPzmtX)8pz*c6?D@%uYXLE=4MHx06=V1|T7AbkqS9Q}kMai^faxPlQK zYKEIWDAW$0^>(_mGLGV?^1$Y^Hn=%%vec@iOV2hVx+hX^gkD6 zC%Yxd5N4V|9G8-@$l3Zg`TCqc9`KVG`iy| zU$kLbs4_!)UCkwzT=p%q2I8CR!A>Z?ubNa@uFmd4ns4W~V?q9E!en6>R2A-7?5Khg z%tz(VgeHQ1K<~iK@>PHSoSb??Hnrj3G>)d5>Dz;9Ikym9@1 zSDZ00L(Gl+515zKyQReXl+#SO37H3H$+Ka5J;oCD)p;(lm$`|tg4(Hj9owO27$@js|?Tw_C zrsqKTZJ6vr4i)W5H2grzPW6<#E=}O++54!wMVCh((f_DZX7{h&ujv~IZGzT&wBVAh zGHLUnGUv$$dT6?_)e0hp>11*Z5zEQ%Xy0Y_AfCbrRC5*bn?vb2lY;=Y4*ueok8vLh zfFGc-#h2C<$1xK7I=M__Ctom$-nc@7Sf1A;`f^e+ z+OtF)F(xB1Xh{nAT6!YiH6?UR-Ocj52e z;YT`OCWXnTaskVA*AK@PPLmJ1=*xw$qoSA7UQEJU8l+p|HwIw^;({8CO6W>|v8M-w z??*v`mdDoBjIsY6nM>cqhJLya4dvBORh}m~!iUL6HG2We2=j>N8%D$$AJ7V7WT*_t zcH7H$9PJSwf$~G1<2jLa-|+nOzo1?A+Jxmm_C8@+8cDk>4*5=gXy$9~Ht*m7hE8Ha z@2j@UU)o0rw;2!>M!rpY(~pG*gHKHw;p(O8WLDuzazt%Pm#;5Ppi+k5i7gB3{Go$f zboU`JJX!;7R$;OZOtPtqpJlqGxIl&Q4^`8#25gpeRaf~-+e13$T{Xr6i@DWuH@<7Z zlmubR>OY&YG$l_wNnm#TUDnc1H0Ui)`~H+=esK`A*kJZfg4NS9SU89>zI&KSw5*1O zVAlra#QoA1ThsMy9W20SY$C-!e#WG_N)PWUH9iyypBboODwt30TJ z)`3;R;9?UfpfeWAm3+8lAI|t}-_@0vZDm>umQR_Ggd)T7MTd-Y(obA+NZFFmU^^?; z(?9#ls+`&0<^dJn!{?J7B~1J6NQYTS=#vf48KeNf!o6F zePh+Jbqrrhp(2Y2pF+|Tvu59*7{L_VDE9SXayg$geKkG9%}*89d=rZ1n;%25p+{>f zIEMwd#qYo0MkLDJsD^>wT@TWPjn3}$m}B&ADK642Y_AlYqB>sA6GVTGC7;QmhC8SO zsM@gNk=@`q%JDpNqzunBFH~ikpabDOt5iTSaxath2p=bj9s-AOhJVeCbMH-natTec zE3+=dzw&Z^Xt`pB;S#Zmqbu)w<1eS7$^GlwS)tJqa$ zbRF3i#%a~nF7OJb;Cm*4iZs?T#AbO01Hl71iw zHi2kQNL7%3mS_&Ftb{J1Ne2=X4?}h!TpmwA2XE^$^Xn7D$3h4kt+IUc;bQJ>P|;|7 zxcQo1bRdKNSY3a+i1cYaP*~BUPttknP^sjKr?s_ybaCTu=_QI_D!W>+NE{w*GD*re zyV2+q`XoDY+nDu%nN$~bhruVUTV2|~WZP}9AR$fW!6*#rs;>~mt0Pw&H%KRzPvJxA zrdXKTr)Kvy-v`x8$oTY`Uox4(ovFA+BgOwy zM*~ITAwya4k@piz1X@Uw@A<7Kx!&dcM$!^*CL?b6++*(AFF7O2b+1f4`#87ttthlb zZU%fZ_qF?~{eJieDpS*Q6ZFTm2&LPoIg4|jZP$*Q+Rb)yS#&1`005I&aE!;wp@M?D zO{9*_So;2(4lm~+@o`qrrDpYwE>2AK!b0&x&YmDk#wYmKRX8Hpcc@#t39~;%6}*rxp&{+dIE~cBo3#rgXha8srnf2A9cKmK%N6pK z@ivhBYBR6v{Z{R*3;N!Sg*^sLVUyhba{6WD$s!84s_8y8!gC+!CX}_l(u8}53_`z` zCT-kJcZi&okr41B^i{A@5FH`Vs`&OY^IMEdE#KV_JiUgZrRC1SS^r=Nsoe~v)F9-i znC?#nz8zqqYt9|r#wJhHx5GVt7e|UHyf5U34$4c`!fF67#Mfv* zoz2uolYCY1qh|xI%xv?-)b{i(fD`QqwT$q&b9l7Szmo#>D|_0F!Z-#n=r}OH4WG#l zVgU5lW^!~kEYrQJwma*jQwv*X&-J-S6Fg_w%K0_jBB!b1fS$_8SaMIk1=d}|s~=!% zwF5@!I5%Va9{{@ljLBL}DyXctz$tWxt;NZaAAucs_#)Oi0o3Ff=k0d&)N^Klu zEks{cf_W+E)vQ!0FM`fgDc^H@HhMrjX*=x_aV}^RRs~u{r`^FZ;6H1h>=Gk=?_jTg zuE$_bqv(m0R>g#`0McN0ec8r1@kf*_S#*_iwbI(O_wr1~bkCusy~qF zroW%rv(H~OjtrSqnNNHqb>kTRQ@=0sa44P{hV>i%>^U~3g?_d&+P8K95 z4c{?9UJT*$p%aV}nk2R!9<;!L0p4W~hmh)R$4A}ZL5R{h#U&3)&F+AaD7FG@*x!6g z)(IFTzbM5`Gz(Ti>eh5#Q^68EXt*Tr2fRX}_>3w^l-Lo($NvGKr-fPKND@3jp{Bsd zQ#w&IBN6X(vvtkDW&ZRNhHa1K!vuS$FF{KhX+mQ@zWQw%NrKWJCfwG7-5imhr;?4f zixLffmt}t!kK<~fc+F?<=_c%_1%gNf13A#v=+C&wjIz(GkFeoGWRS<$x=_f_U5eD zuz|5;kZmr9Ip?EYI2F1>E8`}tz)wmOI-^NC{!+6bk)S$!{$^Y5==h4wHQ`OkhJkvRN4{qxp?r zT{QC}XoMEgDhjmug;CSo*bdVPbdV*o(_oeN9F%`Hf|EkRU)rWa0FocYP;douvb9jL^b9Uxu>(& z=_rj6wy4a`TbzRO4O%|K2h&kBoXM{Y1B2Nw&$?28gqGCEIA=g9tWB)o<8bJTI>*h= zvy#=umy~mq=6qxuZq24F7^6D^YjGws5yijRGfY{~#t7O2d=BZ`Ga(QNaeD>`OP~vp`gxND?n|(z()6#vsd>CpcrLu(i+ea$B# zP9+rz;HU7*YfqL z#G}VMp*}2fhZV2=56es-^u9lmeKooK1_4p8N;zMHrCDB_8D@_7H9JMtyBakABAUt-AzCkfO44Z#*jKTMOsuPg={$%p30-r#GJCKTCQIbHJ}2BTWr7Ww4`^A&@)TR-&)lTnC~T+{7DG7&(RUpcg&5On$Oaf zaGyG&FF4(Bsj;hdVU{fWX>r}8loo|Y7k?>c+55t%CTeImZq$*iJm~D2zjwUf7VrDl zSCi89#dkRidlu1NKC;u+OzXqC!mcrgto2YW>k!DOSV8y>!YAbu=uOM>fH<`C+NrYE z<1p$*A_xskh4R6hDqAsAcy`C&V;99Pzlwruqpi5QF~^}qMzm(GPP*j_EggQcUtn@* z9af`sWQ_VBuLgqH_n&X}f4^TaCuYn5`!eQWU&gAAlmKRINZF`@O&~cja}kKsf^x0a zQdzF&nnPSGpxX+3!2DJJ9%7d-T=1m_M|Kbr5>t+!P2$=5D}Vjg6cVDe_9bljHsdc` zY^cl&fos0!c)ts0c!fNBX0+J(nK7C!Tr2HcYvRU9QX6xRgJQu>!gNm_?QcN#jZ&t% z6ceKN)z)d*nK?BZ73VWE)+GLsW^*RT<3Z>Bwx!WK>|(? zQ5Kq$cu$*adO+-uHarO+Ditm(eU(z=tDA$D6DAoWG&ggzC4I_7WV`*MEM4W;cG%R* z^2Fq8(K63W^HUSk*1K^EO;tS7aFC@Z5~!Hr%8*&XGj3lP9nHSjE;}bS&C6DDwu889 z`l7c==I(EitGVF=uL(#UMM zWgto=-kt(mg6ZebQ0g)HRXX8JXuzYs=KrY}Nw~*V6tt9VLi7!PGw%UD-YZKFCF>`T z{BB%{7mFmBAwD`T`q0ix&owP!l^-GRS`&VVhoI6vrgNaVBmY)`FNV8)CE>BH$SGO| zNBAzDlPbpnedYK$Y@uLaMu4W0B|4p-m5Q?jbBY5_7ykGDH}2bTWDA0tbt#+I$0sMXJ`luhbdzjs-ZdQ?gUgWF2xHgv2w zJ^&KO3skR02HZ_P@F`-&1oL?GTF30nvvSb1hb*50+`3 zqy?R5;gC7P{}!imLNc~aFvRkK3!~qLVW-sq_pua|U3nZpH4oIL&n{Ikd()V$x+9*KvluZvD6AikVt^mCRscIxF!nQFovOfg49jlrfs0e$&Y( z4#vD=TWcE^b~diRY?J1rugk|iT8Wbxgrw(v!OId+(l?=9f)$)E`$X85B*QZcS7nD1 zS-^9k@pvmZykVl3EZ~E+(5}krK~Qz2-Q5%I9X(SA8NdkIjH)9#!@y!VXNs3YcpIr@ z0#+PyanVlDiz(=|?K4TrKv|KJJ{`keQRc8$41fve>9;{8C&Q_=-x&OA=8NK00`a$@ z58c%gI2OU>0&og@K^<*z3Az!pKZ+qml|XA~Do@%P%4Uj<9Xp;ly7 zu`+jf8d)pIP+XgdoJk>NMoky{uNLG{V5q!g=Q9wIN$=X+io9h=li1#NJla5-$MI2p zb^Kgz+1_!lweccE0rg7Pi5u}PCTRNjGaZ|8RWvVbYHAuIPkk{1p|_aL4V`*E2uK>* z@w>#O&=|(fR0cMSf({=6T$#QFOkz{ z@f$X%yP6(KMKbM8aiExS;Y|;f;YQQlnFZ@FYk+lwX_hW6umZwZV$_a@Qg&Q+kx#Q@liH?j33W1K%`$%Z{`gh7e?8`0+cl17wtm|dw7JMWmeO2gB%<`O z@=Nm*GpkqIKMEA3Gg#p1N63{cyjNdxE^`Z}(N{U;F5LtT@?$@J|C&yZ89BO^;XV>k z61m=eoc*4z4};I8jOs|EJui|3H^Oh3FrK*8DjL?~M&ONQA0SN2e2&+#a4J|GBgs#4bI>uUUjaqqw= zDfjdXnoDOTa|O}Dh7zUqqGUt(c+6nVRa$QdXQl@mo^7-v9t5d(=;eu;%rPnX+5Ay- zP@D{se4<`T4%3|{6Jm5k6J`#vU5bTSVd4+ci+hb=4e=^_ZBG@f5!bF~rYX}sGh!NDXs8SB! zxZ(i)%zQK0jRpf(h_N#LpopHrpaPImHK;M!={=JOsMHsh9+#EjGnL5zESXei4gSyA zcL50u(`E|RSWj6SL2NGMcU9ZSz?<|j^vX-=@;@L-B99tH)AE3{J(9#dFZ#qX3B5wp zpur>IpiI*88~$WVTAEq0ZT>|HuNng5MUiEU~N>Nx|Rz~n|x+UKa-ej)_R+IVP=`vj4jyftJxG=X8OH{ppuv_ly*GQqi}rZ z3cz5}@E)xLJv^b*1f#bsU}JRfrEeI{o6gmG46J$(K&Gp&iR%9qsi)d4&BBlcZGK!8 z9b>UOdl+_k*6lK>9IopnLz|2nK~$u(>uh;R^T$i(Gnj z?PZY4`hQiSP@Y=`@HJYgvTFVsbg-Pzr;zwfau;)tK8b?2*pbW+s4GX&l*IVRL}Td; zf^tKwzlWfR8mZ1DgbcGyd*OMM0<#uxxQw8=K9z@? zNv&v~Wlk^CNaGB)b@I`8Hb#M#`@~V@f|}N@c;OGe@*N*+1r%3BO3RQa|B)DaWOY%;5~DczzE)#P$6sQRm=HCQ7nFSYIy!{!-A+UOMq^A}xrVa9t_!{hX$q9*&^hD%9X z8uD+!6@Pw!xkB51arA{U6k{h-en4>%-w`O(ich4VX>B@3rs#(o6uFdJOVQ20FKPGa ziza!xR~3BzDP1cKhYae36)8jTLE$Wwq0!G)RBq}1}9(;r0DXZGfP z6+%0PsZ^VzQr+t1%^OoXiyLM1tms<3mxW!I^HvwZa&ujo!e?XwD;i&vVb zrTg`Z2}Zb{aX+-;?BWo#~2D+bNs@F>hAxOpE3?JDVhEa(==k z5eHf6Yn~-EixDIOUxAN#UbZlV4`S^hyJY9fG80@0-^$FZ#L1@j-A1r3PyQ9TZNoT! zJ<=jGxTNjqd7f9Zc46Ax?>V>W_=9!WtUihVJtLp7-dL`{<4ocTY3UD=PeBZl(T}4r zW#pG$SvQ^iQZA(C`CM}7{2NVCgNW@h=RIp*Wk!-r;4+DCIo8;9qL$SCX5pGtF6US) zA|tUZ@@pIc*o)UAvIflLl!tsmc6cdyGv-YD@^0+b+AMG*Q@nN7I(&Q*wRhcajPRN5Mp!G57&@l(@ohj9ZP=T$QpxlBOw%!x>kWV)3mmo|iW-}ja#L7PY7V)1Z%qjPqX z&Dpfb$bvOl=L2$JwW!tJw^-Mb3$OUK*G`Hu4Vp4DQot@UCCH(umCP}0U;pO!g*i`A z07zA(0-?4pMXk!dWhaK^oP(+Tj(gS__+~7d7%!9dkZl}Q@y7`evsfOG6>wz)JzT#s zv%?R>z*?KNyo>rwrl9ApkZHllBNhdIb);-AP$*?Qv}_b3?+Ay8d?+(x>B2bt;?sd5 zD0}YzIxTB-SCmKhr}_zK-uhMc#Y_88W8s*0n|!8WrYm%ueo!Z0gmcfD%LyD}_vU0;Pr4JI zA;{#sbv9(F#N1AHZv2&|L~dITWBn?+;cix#=UU`RK@>q#s_{0d#;W{zI@(QqZU%$W z?@EwUVy?F<)k17(Ys3ucyTRo3z>>{N@3+nT8s#~ifQ70vil&-T!#06dVViS_dp{a= z>9cfutS8_5YP)o)L7OenC+H7Lt0$kn&=`Y&8hWFP1m#2b$=vgtU6a2Q zJ>y(%kP)RQZKs+94evNFUoCvGpn7@mh)LqSLwMp@D%z0bn{-k{FMB7slF=m1ucG0R z%O(r@Sb%8;67J*0mo!sL9q~Q}-dAAyMkh%oCy4;|Ju{oCwJvfYFaHeO?Uf@R$F&4A zK%qAlzj^p`URx-4+9#Dm*O1BV=`HnF z?jWcfCAe1W%c)13!>ee@(iiFZvoB-z^l%d`+Zn_4 zy{uYtfsDazH;M;_-`R}q?jBEi=NhwL&OoAI#WbAS$N$=s?^epEMMAPU^2e;vjLLSrIM2UJ zGD}_MmU92O3?c&NkaW&koJ%eB^&7rj+R8V(z`NhDEiRLf%oti8=5Z*0x7f{eccq<0 zr369Ar}PuDkllXgci<`uV}>mr>C>uv&j^H?t4~I@$)S6QJ1>T(#RmA3t+&eFinlvC zDD)5kwY8nEjkDAz7KX%6p_eAl=)T=eXii}f`Bb>ZlUwG!V4jMMbKz=CfhPw&3E5^I z*~!4e-q&#y#X&#egAxhq53gTsrrus)9Gqs1@M^7a4kurj8i5@T+RnLr|9jEq+v;ZJ z4mYJj^LG2P)F2-3)l|*u%DGW!M%_fRJJp~@3;R)WJ*|+zy=n_2*d7W?J}ot7do?V> z1nzh77I`yOs%|_1V(Btm>q&w$n0R;j96+@UxX!Y)pgpfCOjlh!)zr@W#!b$O#Qx8j z^k%w7O0|2JxN-$$J4|TD^z-YH@==yAKUB;eu!26Qgby0}Vm7;@5+8l_CI+o+ww?sd zbTTGs2K_7=m^3fyd-Y*lM$4qHN>D^yUi#9AJ*RR-5|EHCKmM?TfGmaZ)l-8>@%EK0 zZda*?NFS<_cH;6QefvXrfgu=t-s--`dI$==IidKlO?XmOXT@xJ@3T^(!J6wx$qEHXHx(ztTS8hi$Z^$}|;r%jcZ71Eojp``~E*e7L8MQys;Z_)AKz}6I<=05(^^eR2 z8V=IqR62M0qanRJzpz~=i$;C6jeF)qbIWRs)h+;8ey$xc+rGEaYCOad6pXr>y)d?u z)3^wflmh2hHRFZzaw>JwD_2Iiigpj*mrLme7=-@%Q-LEf@arv6!-Q{w;~s*V-OHzJ z&iif7$CI;iFX6y99k>aXacbD#zg!_WS&~v_8a@C9*AyF+xH(CP?F9t$D4g0AYN`_p zI`76}Ae%fs=1Tjj(Jc>1OsF#2s%x*OY+***aIFhRDt+VT`l z4Y?h+H2}wXln>)va2ty~77q+tZ% z_kkNsX@R1zIAwaLsSiGTCFIL8a0z2X28L8jPGl_6M<(b^Fld;HHignyxK1nEH(P(N_5L2d;l#WQGMv;z+V<>gXVp*y0?zBgX*= z9pj`vILl(SPyMzlpj%=g|s-Z%`12nLoQ<&>*lv34PofB7l6rOMXV0{72uPfof?F zk|8vT`}F7@=P?)@7oIE}_j&WvoFC|s#mOL@e=tU~lysH5XpkhBCar)6cUHn}ZPUn| zmf2(NiJtuYB$t;uo0NP?De<7Hd)3l%csrubKuYPK=>M+~?jCEsUX?x|?y!bSVp>mO zpO6dGOjkS~*O_YE8OA`QAW^G1U=bA6w=+@|3#|uqT1587RhR5&dl>ftUldl2iJRCY=;Ew20+ z7@-_`OC$_^()uabjxJmfee;J|F|rMmHX)aBQbP|pL^S=&@C*LDA#D;JjJ*rP^?y|F zYbi5CX6Obq$saFkZ|ZI2(T(eRxSB@42ICUGs^^K1^dl2%NF#uS&Y<}X%WVws4}Qk{ zhED!9Yhl}#ozjg9E+tx1FJ#Xyvw{_07+zevyXF_7zNKsr<}a&#ZL&(8%6~@JkeKR( zY$(n+!*w$0;!kXM;csrd(2@-G;Qwx5;-^0{S}1-BHubDwf~f^O->%)PTK76ZA%62% z*G@j`=WA36SNUSS{$pPM(L_c^X?wllIKy|YKE!EcsFZU?b%6h@vLAF6Wm~VB4#NMG ztZuMZlZ3{cRC@a~R*H$8(cHBv2J!xBf689BLFxYoSnzj(!|+_4D{S}kHh%)kMvv0k zHQxe(Z70iI4E+1RM0rZMIkSoyqF6yUQz-!1&88fFF?G;J97N<~#gTab%}hFqh6q_W z6rRt;Tl>j_HHJo|`EfPPCwM$$F<^3`7&$OyY^ROYaRzYLPptj@@qjGj6MvJh;4Ouq z^;k1`O7{%+fF9RxH6ubc&Q4Rf=qZmnZ;0u9@YjBZ?9!*%XNnn+f?xt|60ecBWR-N+ zd>Iha(tAekk9C@^YzNC=BL-ywiW!zfxuLlolsPV3?6|zJ^rHv%(HzD8ynvmZBaM8O zpihhI13l^x8tfVC&j&PPgbcLiY=2<6wy88pQZ{_`>jE4}3S_?4Emq5(f(V~LE(U`% znuHg*J!1Q?Fy+7tJzvNykWmK0pp z11#ryV$J(;z==g0N%0-LpgG1weRS7WWv}VC19kL4gvSArmb-_PU^E(61eawfe}H#H z8Vo_bEc72ln__#rSTi4pMgM$`A#+>P>F)3}1(7R(2JU5-Q!v4ln&Uvp_ud{PUq9c?XENSfi5;s@)K^gVXY$VJ3P6o@IspV=-)gP)z+-<~ya|u5R~P zH`M|AFR1f7ldnvOWP7|oNWeV8j0gkZ1I*QUaptnNw5TDc^qvl5>{Dg)bsxx=h>&f% zFQRlK_HmW>vTej3OAPo-R%^>g9r}##Dt)Y)foi*Gf~3Qx7FVclFf>Jrvw}ZvZ0`q{ zL(C@~t6lw&KHsz2@rgMieP0i_*RLwU_|EFi*l%}WI|v5!x|3gxXja08CFsv)K+*61 z$TUwniy`aj#p0udJx(jIV$v%smn^M7v0+dMz>P196o-JNkuC{Rm`mOMGl{sy{uxHd zw{T8~;d{XGsy)F6SelYjy`O4f#-TkwUr%Y;xZeqCp=Ij@LUeNMEmI+gqDxeCysv!v zSPu3>NoTrqnoGrc!8RdeL0So9ozxUeD~{?GBXjtdzvdfKLZv69uP;sRR&=l$$EKVO zW7J0xAEHeoPpj_Z)Ox$3R5W-AG(3t0Z8^aLa_#?Viu_x}ctRAB~Qtd)CP4kSw{iji>u#V{6_x zO|c^NeZI|ms@lU#bgoz{Hw%7s9n&|)NWWA-8{C+kVefWWfZ9yuioa@_RTu{hD=hB_ z$afLRDDNFv+Yg^(@I(uTFmK=4SQ2|IZymm=#t?Ov|7uBgI1wj^#JduNdtn2l{2$zXk%zFt4HDaxTRPdbm90uzZq2tulldX+h zOqhk7Nm^!%{YN~EuP?r@aKRUu4Xesw>tV571Sc(b`ppTsJc*HE912z8V?XZXla28 zCh}ZiC2Kt}Z!Oc-VVo)P!`CPXX@dT9-((_~7O|9Md-ly!p#crFON>zT71JQW4Et6*F{;b`KQMDG&L`ia5LpjDS~2tM3r za9ZwgLUj;zwC!&JiQ`FU-yZ4P*_ml&4e-o>j6QU|BjV|r^Vs;ybI-z}o1mR4Xmr~B z*io&71ld{=$_Jk;2mLxbV;^`SmSyNqPcdXf-Ffec)xNlE=ZcRkT_@WYmV#Ucd#j8M zZP?;`&$#e0mixKE*v;8`*x7pqAW07U=p8gP(;6*_=??!7h<6Wb8+4k2DO-Avb0J>( zKn|ABQtzflK8oIE<}n{#pFSFNg_?Q(;~%`L;c)UkmeL2@N=t7RU`x%eP*-oO)CYPo zkdCn4alj2<(n@&hX2s$RLwvVI-<(9OjB?)iY*=pC7Krb$B0MujlK$ z=KpJ+HIv@7>zwB{v-vn7=I1z3)L`gN zi+R%}+dLb-r~$O{*Iq)%1@~IS^p^W1_79e940llj_WO6rE}`-@Q&*)3ey&V?C2kZ( z3OlBEEAh%kG@K6!`e#FfnU(#02>v;DZvne*k`dE2EqH`WazUgngp-y5=1>NjBYw(c~ z2bN5l)Q(qF#j)8Fy#82+SL=lFW zzFYcKKF4%Sm{}5F0*S@4R345ZA)@v!)W=7XT+IFRQh=9@2kWKjy}gemkX2&*p{0Z& zm~BpnELJPaN|76!caRy20c}IE<6Z@>&?r6-8l3Qzvf{NR2$M<;&t0^#EV_89`QVi< z0{GnStTA~ROE-zg`95KbG?6j_`~5pSw0R3;W4k;k``F7VGn#&=9U=d4%RFGyMgD8p znG46XBVUN6O_6OUZqWo;-;QLtk*Yo%bJzFFiYoLQ&6V;F3L?_Y*0JToAD{O4xFp4t zxqb|q_G(tDF^WCl??&fK4k9BY%oMDK6!>=ZRk=^q(*V{K+B921NkZB*SH z-YLin%d=CX%HPSNlV561OTI~yJDE$1^z2A1P$DMqT5SfEk3$sa;5Q#4XJnr5cFx&+ z9leF#77KrHdpiI1^x|~vOB!xX;|3Iy7pV=yr&@5{q zQXmLLw;ZGY-al<3EpcC-0=YX$2`RCj0qR;wd_8Yt2)`d%Ab)F!O}PLT63_SOlEhTZ zcnuj?xhanSlaHm4u2$=y{|Zv>9YfgnqH7yM4jsna|6;M32Oo>7r5_31FpBGY{?2e! zX%5Hge#B-xS1kSY$0NnfU9dR7{nw?@nVN%hA24pKJ{&{V%PF_w}~5FgR>m8&vN%# z`RV)7ISE=yM|=mqpRjVAedvUc(snWL3d)%CH%M_oYqb`+L{DM0xFj&;%xg5hLn{M4 zYp-zfY0{_it&tX`6;HuvQ|RU|4*ldCXzOo7Vw%QjQ2E4W>R4Y?RG_W@g}f3$*{h`;$b9~* z={-tGNii^?AnbE|m7hzn#`ic$)B#WlHny*lt3Gy~0b7-bZ1V~{&yuGi{C9wc2UO{rr4dS_ek zhs_TSppBoq8hS&h8rKPW%k%X-d(^Mf(T}SjkNhR)Mm=qYsha|33$U654>A!hXUoPn z$cHodQeUJWcYn*O9bsyPOr}m&>-9vSO39O^_sS^Z-Xr`quGdE#G!giS2&eIYQ$y?b z+Y7?>n|+NomQcL}1!_WdTL;5G6M0i3AFm;VF;y+$sC4_Q8-3$U2?PmSwLHR9Q*4ubwW9h2H-SWYhkEZ-aakxm-R7M-FxQDf& z-gLTvCi>Pkk2Cexe?T}M{NNxb{F6(QF>P_1N6nG1_Jz;n*^-$siAUJ2KfeiIu{a?A(mxqZ0# zQJK3+qcBQO6qIn$*joqS{-KE5rnOv|O=Erwy%>3bwmQ~8-b{U`0ekc^FO-ab>>A%p z>u*w&Aaa697puKIVg1Ih{sRJ<-+P0kWy_ujIRgVfL0`!7Y9p`d#O6QANe_wSJ8Hyl z^RXqyVb8iNHM`^+qRU%z#|H&T(E`ZOcXY7li0u7C%p%DpU^lrOG8K;7w}^Iy7AQ&! zIOwONZf%|Lz;dOMbBXAL%Sos?ja{WIub`TSIEIzTj-&8;J3VGA5hMPxckYBjkVGrb z*eqO6OP_FX>KkkO$y3&?K>ljRx4qf6t=vF*e>`My)l*zUIHIym&RX!)^v{~D_(zt6 zLNM~1TbGU$t*I+*oY#$yAFsW6oQ^i(!tZo^UaLEJRxPM+CQ*7}Xs2L^Y10dw-~46N z^G@5b#S4^aB5~bhxs#zD+i%NWice9*fD5lCd}3op&fAk%qL(Lfz9*$08IDKJIJWc@1x&BQ$0odMPxA6{!BJTQrEkrs+BQLFmG87# zC@4u6vNp3KU59jQ+UN;G@cp=qhHoQISQv8I74qAGsIb9)Y8?g6;fMuJLwboZP}WLi zee;}jJV2d*AK+O@DoX+O$5ko{aVCE-0LHiPv;`MP3kf<@L@ybvH$<(9qn^CiE{kKp zHJ=^q^~s~TJ`c0LTP2Pvw)3c5DpG*}MyV3Kp4&3$1s-r5p^Tq9mhmbH57guQKDo<@ zd%)$W%3N^PVg-@D<(4gknj`x<9}c^7{Eo2ZN{rcu6PK>`*{g;C72`{ZAF#Z8?K^vl zDZza7V`zYH+nAQDR}8SM01RIk?|_X8SSR!YWh)orb>2H)|Hj$vnI_u*OcfuG-jGT+ z@Fh_zMbP&c1q4NXJ$lYCHvEYWnWSu*%)EOmxN<;Ony6Px*0Cc0;tpsFc zi@ZV327#GTs5YQ`<1?j^o)m+^aZ!^ToZ0VHYoYCTul-CDz1`?B*25yqe zLS7u!#`N>Tc=pK`0LXH+lgSXyO0U(3N$AcXOkW*kA}}D5*?ge*E)|J);cV2N$JS!h zYY70mmw|$wUuxsN%ys;=tr1v|{e?5E>m13t^uad#!yypILYQ2}mx~UVK>gRl7YogQ zImrQ{3L(wS{>4yKl~|itfvtXuZ$xoARoX|BWj;r}@x?Ddaow0b>NW%Q6=9ycu4g?j z)7ebLc4Pwz80Pz77@BgOapw8GzA3@k6-d@$bhS48{O zx*y|^p_0#BI;%h7b*~USeDkNQyk|{iD=)K|3DRle;{a z-C43{YJ{n@Izoye1&9cffR?Mx-8G~j&*=DeSNdoW%<5mxhV#zhYAOPu zK6`tFsS*f8_PU>*X28y^E|9ojpDj?zIb+)lEwl2@odZjv>(_;?ZRN|o?iE6>U^nym z&sv67P#Z}F-=EHYOg%7insWWwyG#%S#KYASCpp%(8@X`XRp3hY_ z&_OW?QJD8P4Pz*308v$FDc~p@U|*aRC_AY8Wnoz|$5Zs6^nlEgU(ZVQIKeP}lQkS9 z-XC1j0CVy>n_-1P$aye_^2?PiHtVz%v`Ym%c1y=!Ejh#h^9&chD!FQa)n+S>90_D= zw?uVD{+?Wr10M*tg`hG_T#Ck@H~epySENJXkO7Mv2@=5xuEBxGGPWELGKQpC0@gW5y85W37pVSbn*=S-2Ap6b?D)j#YH4O=i^-{4MrADs$G2BVzd zm4EbIf=h^&EXjBuG-1r4ZB8en66cTTYeoCIOGhV9LvqkQyEqS5*h zmb+1U&lVHiv24nj^4~#|2uoevjnvZ*@w9#pJ>J=dWd#x0dJvD24d44%iUo7`vw@FK zukAYyAOQ5(&x8tnABeS+`7HBG~CNtj&?t6{kgx#yT8&c(C7a29oY`LFo=O7Zs z1r{;n{4;!>L?Tu&Wd(%)-wvBiE=MBS+5)com.rsscripting rs-mobstand - 1.1.3 + 1.2.0 RS-MobStand diff --git a/src/main/java/com/rsscripting/mobstand/gui/ArmPoseMenu.java b/src/main/java/com/rsscripting/mobstand/gui/ArmPoseMenu.java new file mode 100644 index 0000000..30238dd --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/ArmPoseMenu.java @@ -0,0 +1,372 @@ +package com.rsscripting.mobstand.gui; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.utils.ArmPoseUtils; +import com.rsscripting.mobstand.utils.RSMenuUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.List; + +public final class ArmPoseMenu { + + public static final String MENU_ID = + "ARMPOSE"; + + private ArmPoseMenu() { + // Utility-style menu class + } + + public static void open( + RSMobStandPlugin plugin, + Player player, + ArmorStand armorStand + ) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder(MENU_ID), + 36, + ChatColor.BLUE + "Arm Poses" + ); + + ItemStack filler = + RSMenuUtils.createFillerPane(); + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem( + i, + filler + ); + } + + /* + |-------------------------------------------------------------------------- + | BACK + |-------------------------------------------------------------------------- + */ + + ItemStack backItem = + new ItemStack( + Material.ARROW + ); + + ItemMeta backMeta = + backItem.getItemMeta(); + + if (backMeta != null) { + + backMeta.setDisplayName( + ChatColor.YELLOW + + "Back" + ); + + backMeta.setLore( + List.of( + ChatColor.GRAY + + "Return to MobStand settings." + ) + ); + + backItem.setItemMeta( + backMeta + ); + } + + inventory.setItem( + 4, + backItem + ); + + /* + |-------------------------------------------------------------------------- + | ARMS DISABLED + |-------------------------------------------------------------------------- + */ + + if (!armorStand.hasArms()) { + + ItemStack disabled = + new ItemStack( + Material.BARRIER + ); + + ItemMeta disabledMeta = + disabled.getItemMeta(); + + if (disabledMeta != null) { + + disabledMeta.setDisplayName( + ChatColor.RED + + "Arms Disabled" + ); + + disabledMeta.setLore( + List.of( + ChatColor.GRAY + + "Enable Arms from the", + ChatColor.GRAY + + "main MobStand menu first." + ) + ); + + disabled.setItemMeta( + disabledMeta + ); + } + + inventory.setItem( + 13, + disabled + ); + + inventory.setItem( + 22, + disabled.clone() + ); + + player.openInventory( + inventory + ); + + return; + } + + /* + |-------------------------------------------------------------------------- + | MAIN HAND + |-------------------------------------------------------------------------- + */ + + inventory.setItem( + 9, + createLabel( + Material.IRON_SWORD, + "Main Hand" + ) + ); + + ArmPoseUtils.Pose mainHandPose = + ArmPoseUtils.getMainHandPose( + armorStand + ); + + inventory.setItem( + 10, + createPoseItem( + "Down", + ArmPoseUtils.Pose.DOWN, + mainHandPose + ) + ); + + inventory.setItem( + 11, + createPoseItem( + "1/4 Down", + ArmPoseUtils.Pose.QUARTER_DOWN, + mainHandPose + ) + ); + + inventory.setItem( + 12, + createPoseItem( + "Straight Out", + ArmPoseUtils.Pose.STRAIGHT_OUT, + mainHandPose + ) + ); + + inventory.setItem( + 13, + createPoseItem( + "1/4 Up", + ArmPoseUtils.Pose.QUARTER_UP, + mainHandPose + ) + ); + + inventory.setItem( + 14, + createPoseItem( + "Straight Up", + ArmPoseUtils.Pose.STRAIGHT_UP, + mainHandPose + ) + ); + + /* + |-------------------------------------------------------------------------- + | OFF HAND + |-------------------------------------------------------------------------- + */ + + inventory.setItem( + 18, + createLabel( + Material.SHIELD, + "Off Hand" + ) + ); + + ArmPoseUtils.Pose offHandPose = + ArmPoseUtils.getOffHandPose( + armorStand + ); + + inventory.setItem( + 19, + createPoseItem( + "Down", + ArmPoseUtils.Pose.DOWN, + offHandPose + ) + ); + + inventory.setItem( + 20, + createPoseItem( + "1/4 Down", + ArmPoseUtils.Pose.QUARTER_DOWN, + offHandPose + ) + ); + + inventory.setItem( + 21, + createPoseItem( + "Straight Out", + ArmPoseUtils.Pose.STRAIGHT_OUT, + offHandPose + ) + ); + + inventory.setItem( + 22, + createPoseItem( + "1/4 Up", + ArmPoseUtils.Pose.QUARTER_UP, + offHandPose + ) + ); + + inventory.setItem( + 23, + createPoseItem( + "Straight Up", + ArmPoseUtils.Pose.STRAIGHT_UP, + offHandPose + ) + ); + + player.openInventory( + inventory + ); + } + + private static ItemStack createLabel( + Material material, + String name + ) { + + ItemStack item = + new ItemStack( + material + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta != null) { + + meta.setDisplayName( + ChatColor.AQUA + + name + ); + + meta.setLore( + List.of( + ChatColor.GRAY + + "Select an arm pose below." + ) + ); + + meta.addItemFlags( + ItemFlag.HIDE_ATTRIBUTES + ); + + item.setItemMeta( + meta + ); + } + + return item; + } + + private static ItemStack createPoseItem( + String name, + ArmPoseUtils.Pose pose, + ArmPoseUtils.Pose current + ) { + + ItemStack item = + new ItemStack( + Material.ARMOR_STAND + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta != null) { + + boolean selected = + pose == current; + + meta.setDisplayName( + selected + ? ChatColor.GREEN + name + : ChatColor.YELLOW + name + ); + + meta.setLore( + List.of( + selected + ? ChatColor.GREEN + + "Currently selected." + : ChatColor.GRAY + + "Click to select." + ) + ); + + if (selected) { + + meta.addEnchant( + Enchantment.UNBREAKING, + 1, + true + ); + + meta.addItemFlags( + ItemFlag.HIDE_ENCHANTS, + ItemFlag.HIDE_ATTRIBUTES + ); + } + + item.setItemMeta( + meta + ); + } + + return item; + } +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java b/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java index d029a50..787c940 100644 --- a/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java +++ b/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java @@ -182,9 +182,10 @@ public class RSAdminMenu { ); } - else if (!currentVersion.equalsIgnoreCase( + else if (VersionChecker.compareVersions( + currentVersion, latestVersion - )) { + ) < 0) { lore.add( ChatColor.GRAY diff --git a/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java b/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java index 5781712..86796de 100644 --- a/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java +++ b/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java @@ -34,7 +34,7 @@ public class StandMenu { new RSMenuHolder( "MAIN" ), - 27, + 36, MENU_TITLE ); @@ -185,6 +185,44 @@ public class StandMenu { inventory.setItem(6, pauseItem); +// View Radius item + ItemStack viewRadiusItem = + new ItemStack( + Material.ENDER_EYE + ); + + ItemMeta viewRadiusMeta = + viewRadiusItem.getItemMeta(); + + if (viewRadiusMeta != null) { + + viewRadiusMeta.setDisplayName( + ChatColor.GREEN + + "View Radius" + ); + + viewRadiusMeta.setLore(List.of( + ChatColor.GRAY + + "Display the current scan area.", + ChatColor.GRAY + + "Shows horizontal radius", + ChatColor.GRAY + + "and vertical scan height.", + "", + ChatColor.YELLOW + + "Click to view." + )); + + viewRadiusItem.setItemMeta( + viewRadiusMeta + ); + } + + inventory.setItem( + 31, + viewRadiusItem + ); + @@ -238,6 +276,47 @@ public class StandMenu { inventory.setItem(17, babyFilters); + // Display Name item + ItemStack displayNameItem = + new ItemStack(Material.NAME_TAG); + + ItemMeta displayNameMeta = + displayNameItem.getItemMeta(); + + if (displayNameMeta != null) { + + boolean visible = + armorStand.isCustomNameVisible(); + + displayNameMeta.setDisplayName( + (visible + ? ChatColor.GREEN + : ChatColor.RED) + + "Display Name" + ); + + displayNameMeta.setLore(List.of( + ChatColor.GRAY + "Show or hide the", + ChatColor.GRAY + "RS MobStand name.", + "", + ChatColor.GRAY + "Current: " + + (visible + ? ChatColor.GREEN + "Visible" + : ChatColor.RED + "Hidden"), + "", + ChatColor.YELLOW + "Click to toggle." + )); + + displayNameItem.setItemMeta( + displayNameMeta + ); + } + + inventory.setItem( + 20, + displayNameItem + ); + // Leave Alive item int leaveAlive = @@ -355,7 +434,7 @@ public class StandMenu { inventory.setItem(11, gravityItem); -// Arms toggle +// Arm Poses ItemStack armsItem = new ItemStack( Material.IRON_SWORD @@ -367,21 +446,28 @@ public class StandMenu { if (armsMeta != null) { armsMeta.setDisplayName( - (arms - ? ChatColor.GREEN - : ChatColor.RED) - + "Arms" + arms + ? ChatColor.GREEN + "Arm Poses" + : ChatColor.RED + "Arm Poses" ); armsMeta.setLore(List.of( - ChatColor.GRAY + "Current: " + ChatColor.GRAY + "Configure the Main Hand", + ChatColor.GRAY + "and Off Hand arm poses.", + "", + ChatColor.GRAY + "Arms: " + (arms ? ChatColor.GREEN + "Enabled" : ChatColor.RED + "Disabled"), "", - ChatColor.YELLOW + "Click to toggle." + ChatColor.YELLOW + + "Click to configure." )); + armsMeta.addItemFlags( + ItemFlag.HIDE_ATTRIBUTES + ); + if (arms) { armsMeta.addEnchant( @@ -391,17 +477,19 @@ public class StandMenu { ); armsMeta.addItemFlags( - ItemFlag.HIDE_ENCHANTS, - ItemFlag.HIDE_ATTRIBUTES + ItemFlag.HIDE_ENCHANTS ); - } - armsItem.setItemMeta(armsMeta); - + armsItem.setItemMeta( + armsMeta + ); } - inventory.setItem(22, armsItem); + inventory.setItem( + 22, + armsItem + ); player.openInventory(inventory); diff --git a/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java b/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java index 0911145..ae12e14 100644 --- a/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java +++ b/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java @@ -5,7 +5,9 @@ import com.rsscripting.mobstand.data.MobFilterData; import com.rsscripting.mobstand.gui.*; import com.rsscripting.mobstand.managers.StandManager; import com.rsscripting.mobstand.gui.RSAdminMenu; +import com.rsscripting.mobstand.utils.ArmPoseUtils; +import com.rsscripting.mobstand.utils.RadiusVisualizer; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.ArmorStand; @@ -691,7 +693,157 @@ public class MenuListener implements Listener { } -// Stand Menu +/* ========================================================= + ARM POSE MENU + ========================================================= */ + + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "ARMPOSE" + )) { + + event.setCancelled(true); + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + player.closeInventory(); + return; + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + player.closeInventory(); + return; + } + + int slot = event.getRawSlot(); + + // Back button + if (slot == 4) { + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + } + + // Arms must be enabled + if (!armorStand.hasArms()) { + + player.sendMessage( + ChatColor.RED + + "Enable arms before configuring arm poses." + ); + + return; + } + + // Main Hand + if (slot == 10) { + + ArmPoseUtils.setMainHandPose( + armorStand, + ArmPoseUtils.Pose.DOWN + ); + + } else if (slot == 11) { + + ArmPoseUtils.setMainHandPose( + armorStand, + ArmPoseUtils.Pose.QUARTER_DOWN + ); + + } else if (slot == 12) { + + ArmPoseUtils.setMainHandPose( + armorStand, + ArmPoseUtils.Pose.STRAIGHT_OUT + ); + + } else if (slot == 13) { + + ArmPoseUtils.setMainHandPose( + armorStand, + ArmPoseUtils.Pose.QUARTER_UP + ); + + } else if (slot == 14) { + + ArmPoseUtils.setMainHandPose( + armorStand, + ArmPoseUtils.Pose.STRAIGHT_UP + ); + + // Off Hand + } else if (slot == 19) { + + ArmPoseUtils.setOffHandPose( + armorStand, + ArmPoseUtils.Pose.DOWN + ); + + } else if (slot == 20) { + + ArmPoseUtils.setOffHandPose( + armorStand, + ArmPoseUtils.Pose.QUARTER_DOWN + ); + + } else if (slot == 21) { + + ArmPoseUtils.setOffHandPose( + armorStand, + ArmPoseUtils.Pose.STRAIGHT_OUT + ); + + } else if (slot == 22) { + + ArmPoseUtils.setOffHandPose( + armorStand, + ArmPoseUtils.Pose.QUARTER_UP + ); + + } else if (slot == 23) { + + ArmPoseUtils.setOffHandPose( + armorStand, + ArmPoseUtils.Pose.STRAIGHT_UP + ); + + } else { + + return; + } + + // Refresh the Arm Poses menu + ArmPoseMenu.open( + plugin, + player, + armorStand + ); + + return; + } + + +/* ========================================================= + STAND MENU + ========================================================= */ + if (event.getInventory() .getHolder() instanceof RSMenuHolder holder @@ -829,44 +981,16 @@ public class MenuListener implements Listener { } -// Arms toggle - if (event.getSlot() == 22) { + // Display Name toggle + if (event.getSlot() == 20) { - boolean mainHandOccupied = - !armorStand.getEquipment() - .getItemInMainHand() - .getType() - .isAir(); + boolean visible = + armorStand.isCustomNameVisible(); - boolean offHandOccupied = - !armorStand.getEquipment() - .getItemInOffHand() - .getType() - .isAir(); + visible = !visible; - if (mainHandOccupied || offHandOccupied) { - - player.sendMessage( - ChatColor.RED - + "You must remove all items from the MobStand's hands before disabling its arms." - ); - - return; - } - - boolean arms = - armorStand.hasArms(); - - arms = !arms; - - armorStand.setArms(arms); - - player.sendMessage( - arms - ? ChatColor.GREEN - + "MobStand arms added." - : ChatColor.GREEN - + "MobStand arms removed." + armorStand.setCustomNameVisible( + visible ); StandMenu.open( @@ -878,6 +1002,28 @@ public class MenuListener implements Listener { return; } +// Arm Poses + if (event.getSlot() == 22) { + + if (!armorStand.hasArms()) { + + armorStand.setArms(true); + + player.sendMessage( + ChatColor.GREEN + + "MobStand arms enabled." + ); + } + + ArmPoseMenu.open( + plugin, + player, + armorStand + ); + + return; + } + // Open leave Alive Menu if (event.getSlot() == 13) { @@ -906,6 +1052,26 @@ public class MenuListener implements Listener { return; } + // View Radius + if (event.getSlot() == 31) { + + double radius = + standManager.getRadius( + armorStand + ); + + player.closeInventory(); + + RadiusVisualizer.show( + plugin, + player, + armorStand, + radius + ); + + return; + } + // Gravity toggle if (event.getSlot() == 11) { diff --git a/src/main/java/com/rsscripting/mobstand/utils/ArmPoseUtils.java b/src/main/java/com/rsscripting/mobstand/utils/ArmPoseUtils.java new file mode 100644 index 0000000..016d83a --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/utils/ArmPoseUtils.java @@ -0,0 +1,174 @@ +package com.rsscripting.mobstand.utils; + +import org.bukkit.entity.ArmorStand; +import org.bukkit.util.EulerAngle; + +public final class ArmPoseUtils { + + private ArmPoseUtils() { + // Utility class + } + + public enum Pose { + DOWN, + QUARTER_DOWN, + STRAIGHT_OUT, + QUARTER_UP, + STRAIGHT_UP + } + + public static void setMainHandPose( + ArmorStand armorStand, + Pose pose + ) { + + armorStand.setRightArmPose( + getRightArmPose(pose) + ); + } + + public static void setOffHandPose( + ArmorStand armorStand, + Pose pose + ) { + + armorStand.setLeftArmPose( + getLeftArmPose(pose) + ); + } + + public static Pose getMainHandPose( + ArmorStand armorStand + ) { + + return findClosestPose( + armorStand.getRightArmPose() + ); + } + + public static Pose getOffHandPose( + ArmorStand armorStand + ) { + + return findClosestPose( + armorStand.getLeftArmPose() + ); + } + + private static EulerAngle getRightArmPose( + Pose pose + ) { + + return switch (pose) { + + case DOWN -> + new EulerAngle( + 0, + 0, + 0 + ); + + case QUARTER_DOWN -> + new EulerAngle( + Math.toRadians(-45), + 0, + 0 + ); + + case STRAIGHT_OUT -> + new EulerAngle( + Math.toRadians(-90), + 0, + 0 + ); + + case QUARTER_UP -> + new EulerAngle( + Math.toRadians(-135), + 0, + 0 + ); + + case STRAIGHT_UP -> + new EulerAngle( + Math.toRadians(-180), + 0, + 0 + ); + }; + } + + private static EulerAngle getLeftArmPose( + Pose pose + ) { + + return switch (pose) { + + case DOWN -> + new EulerAngle( + 0, + 0, + 0 + ); + + case QUARTER_DOWN -> + new EulerAngle( + Math.toRadians(-45), + 0, + 0 + ); + + case STRAIGHT_OUT -> + new EulerAngle( + Math.toRadians(-90), + 0, + 0 + ); + + case QUARTER_UP -> + new EulerAngle( + Math.toRadians(-135), + 0, + 0 + ); + + case STRAIGHT_UP -> + new EulerAngle( + Math.toRadians(-180), + 0, + 0 + ); + }; + } + + private static Pose findClosestPose( + EulerAngle actual + ) { + + Pose closest = + Pose.DOWN; + + double closestDistance = + Double.MAX_VALUE; + + for (Pose pose : Pose.values()) { + + EulerAngle target = + getRightArmPose(pose); + + double distance = + Math.abs( + actual.getX() + - target.getX() + ); + + if (distance < closestDistance) { + + closestDistance = distance; + closest = pose; + } + } + + return closest; + } +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/utils/RadiusVisualizer.java b/src/main/java/com/rsscripting/mobstand/utils/RadiusVisualizer.java new file mode 100644 index 0000000..138aeff --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/utils/RadiusVisualizer.java @@ -0,0 +1,362 @@ +package com.rsscripting.mobstand.utils; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +public final class RadiusVisualizer { + + private RadiusVisualizer() { + // Utility class + } + + public static void show( + RSMobStandPlugin plugin, + Player player, + ArmorStand armorStand, + double radius + ) { + + Location center = + armorStand.getLocation().clone(); + + new BukkitRunnable() { + + int ticks = 0; + + @Override + public void run() { + + if (!player.isOnline() + || armorStand.isDead()) { + + cancel(); + return; + } + + drawOutline( + player, + center, + radius + ); + + ticks += 10; + + if (ticks >= 300) { + cancel(); + } + } + + }.runTaskTimer( + plugin, + 0L, + 10L + ); + } + + private static void drawOutline( + Player player, + Location center, + double radius + ) { + + double minX = + center.getX() - radius; + + double maxX = + center.getX() + radius; + + double minZ = + center.getZ() - radius; + + double maxZ = + center.getZ() + radius; + + double bottomY = + center.getY() - 2; + + double topY = + center.getY() + 2; + + Particle.DustOptions red = + new Particle.DustOptions( + Color.RED, + 1.0F + ); + + // Bottom square + drawLine( + player, + new Location( + center.getWorld(), + minX, + bottomY, + minZ + ), + new Location( + center.getWorld(), + maxX, + bottomY, + minZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + bottomY, + minZ + ), + new Location( + center.getWorld(), + maxX, + bottomY, + maxZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + bottomY, + maxZ + ), + new Location( + center.getWorld(), + minX, + bottomY, + maxZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + minX, + bottomY, + maxZ + ), + new Location( + center.getWorld(), + minX, + bottomY, + minZ + ), + red + ); + + // Top square + drawLine( + player, + new Location( + center.getWorld(), + minX, + topY, + minZ + ), + new Location( + center.getWorld(), + maxX, + topY, + minZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + topY, + minZ + ), + new Location( + center.getWorld(), + maxX, + topY, + maxZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + topY, + maxZ + ), + new Location( + center.getWorld(), + minX, + topY, + maxZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + minX, + topY, + maxZ + ), + new Location( + center.getWorld(), + minX, + topY, + minZ + ), + red + ); + + // Four vertical corners + drawLine( + player, + new Location( + center.getWorld(), + minX, + bottomY, + minZ + ), + new Location( + center.getWorld(), + minX, + topY, + minZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + bottomY, + minZ + ), + new Location( + center.getWorld(), + maxX, + topY, + minZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + maxX, + bottomY, + maxZ + ), + new Location( + center.getWorld(), + maxX, + topY, + maxZ + ), + red + ); + + drawLine( + player, + new Location( + center.getWorld(), + minX, + bottomY, + maxZ + ), + new Location( + center.getWorld(), + minX, + topY, + maxZ + ), + red + ); + } + + private static void drawLine( + Player player, + Location start, + Location end, + Particle.DustOptions dust + ) { + + double distance = + start.distance(end); + + double step = + 0.25; + + int points = + Math.max( + 1, + (int) Math.ceil( + distance / step + ) + ); + + for (int i = 0; i <= points; i++) { + + double progress = + (double) i / points; + + double x = + start.getX() + + ( + end.getX() + - start.getX() + ) * progress; + + double y = + start.getY() + + ( + end.getY() + - start.getY() + ) * progress; + + double z = + start.getZ() + + ( + end.getZ() + - start.getZ() + ) * progress; + + Location particleLocation = + new Location( + start.getWorld(), + x, + y, + z + ); + + player.spawnParticle( + Particle.DUST, + particleLocation, + 1, + dust + ); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java b/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java index 1668e7e..0cb351b 100644 --- a/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java +++ b/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java @@ -88,39 +88,59 @@ public class VersionChecker { plugin.getDescription() .getVersion(); - /* - |-------------------------------------------------------------------------- - | UPDATE AVAILABLE - |-------------------------------------------------------------------------- - */ +/* +|-------------------------------------------------------------------------- +| VERSION COMPARISON +|-------------------------------------------------------------------------- +*/ - if (!latestVersion.equalsIgnoreCase( - "Unknown" - ) && !currentVersion.equalsIgnoreCase( - latestVersion - )) { + if (!latestVersion.equalsIgnoreCase("Unknown")) { - plugin.getLogger().warning( - "=================================================" - ); + int comparison = + compareVersions( + currentVersion, + latestVersion + ); - plugin.getLogger().warning( - "A new version of RS-MobStand is available!" - ); + /* + * Current version is older than GitHub version. + */ + if (comparison < 0) { - plugin.getLogger().warning( - "Current Version: " - + currentVersion - ); + plugin.getLogger().warning( + "=================================================" + ); - plugin.getLogger().warning( - "Latest Version: " - + latestVersion - ); + plugin.getLogger().warning( + "A new version of RS-MobStand is available!" + ); - plugin.getLogger().warning( - "=================================================" - ); + plugin.getLogger().warning( + "Current Version: " + + currentVersion + ); + + plugin.getLogger().warning( + "Latest Version: " + + latestVersion + ); + + plugin.getLogger().warning( + "=================================================" + ); + + } + + /* + * Current version is equal to or newer than GitHub version. + */ + else { + + plugin.getLogger().info( + "RS-MobStand is up to date." + ); + + } } @@ -160,6 +180,55 @@ public class VersionChecker { } + public static int compareVersions( + String currentVersion, + String latestVersion + ) { + + String[] currentParts = + currentVersion + .replaceAll("[^0-9.]", "") + .split("\\."); + + String[] latestParts = + latestVersion + .replaceAll("[^0-9.]", "") + .split("\\."); + + int length = + Math.max( + currentParts.length, + latestParts.length + ); + + for (int i = 0; i < length; i++) { + + int current = + i < currentParts.length + ? Integer.parseInt( + currentParts[i] + ) + : 0; + + int latest = + i < latestParts.length + ? Integer.parseInt( + latestParts[i] + ) + : 0; + + if (current < latest) { + return -1; + } + + if (current > latest) { + return 1; + } + } + + return 0; + } + public static String getLatestVersion() { return latestVersion;