From 8410aee3a1315dac368bb3d6b59ae0caf27d5e84 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Thu, 22 May 2025 15:25:48 -0400 Subject: [PATCH 01/12] [Sprite] Fix Cacturne and Kyurem variants --- public/images/pokemon/332.png | Bin 6892 -> 6886 bytes public/images/pokemon/646.png | Bin 17027 -> 50251 bytes public/images/pokemon/back/332.png | Bin 19460 -> 19467 bytes public/images/pokemon/back/female/332.png | Bin 19460 -> 19467 bytes public/images/pokemon/female/332.png | Bin 6911 -> 6904 bytes public/images/pokemon/variant/332.json | 38 +++++++++--------- public/images/pokemon/variant/back/332.json | 36 ++++++++--------- .../pokemon/variant/back/female/332.json | 36 ++++++++--------- public/images/pokemon/variant/female/332.json | 38 +++++++++--------- 9 files changed, 76 insertions(+), 72 deletions(-) diff --git a/public/images/pokemon/332.png b/public/images/pokemon/332.png index a9979480673646722fc78640e946c91e4e45b676..44e374426b4dd37171447e1c4d155753e44a3cee 100644 GIT binary patch delta 6534 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 diff --git a/public/images/pokemon/646.png b/public/images/pokemon/646.png index 64b0af2d1518727150cbcd49eaa5747ed8f11b80..e54083bfc7318d9a27185f7b948294ba32950d8b 100644 GIT binary patch literal 50251 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 literal 17027 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 P-RnCl*`L%vjAZ>At>jlK literal 19460 zcmZU*cQ{+|`}mF6Ga_~nnrNt5qoF9V5=yPA*;-YzwW`z%v3DqnB5GFcP3=wXJzAS; zt0*;Fe))Vq-{<#S&-MI~>s(i^ocB3N&bf2nulsc;N>5jlftHJwgoK0vgH|&jAtBZJ z&x4wh_>7+r8wGJg>S>^fA}Jq*?2?c`Nib?EMm~@C0&e;649>VRWvV1Cu*P&Le8z^~ z{H#)CO3n(ll(m=iG70}j8=c$rGdKMo6(gi3-BKk2qatW=l=TD zYZ->Bzg=zEVO5dmC+*)t_`2nkj8@qWiv?4Fq#dNcH+){cl&9ND{u1;{|9h_lQq;fE zqP@LTR!NkcPE4f!=luvz{{aOSrqL+4uigl74GxV*27bCy_;<1Cv-srdrTpT*=T|`x zMU8YNi|41;>F&F|*!jx&JSiTPZd-RR3jF~E^YQQxC`=NpQ!OOw`f>Zht0emcfjeTr z<)rZ@ML8f#jHvt+v$TS4ouvwR)J28+0}Wio7QeZYqojM!@{89kypqM$*wizf#C&hF z=PdX#Im0y1WwUz)%kFCvT8Wj7diCp)`2e%;3Wku^y#;qP7tMnLPNr_NJq*Ls)+zky zyME6$x6~6RM^LTf&}#JqYq8%mL$`*9iiCBfT`q=%8P{4%68`#M`d;`SQRItqt47*b zK#^i)iLmJ_i}us-ZfZ!IM1O=jUGm$9VZVRo>>Ppkd1c&h{LmM%Bba#dZ5Y&Pl9h3<;1mJx`?I1@ws1s)Hw);*r!5xoB-geg^q4SF@L$( zRU|_xeP^4R3sq0z=Q5*_-wdQ>OPvgJAb6=W$f;vPZEj!?t=jzcCuZ^ehsloeO7frD z#S~%dm0(PMK<<%~mC7Zcc3n-Iiov;>f}5=zy||e=&FHkj3{R=cqa;g;4bgNu3lf=p zF7#oQ3`?fa+Ahq@C8UC6D@50RM>?DsM{ClvrM0(4u2oHZ65 zSN!XZzgx&4&jfyE=&EvwHsMf9&oY(ADWw$BO+u(9-A|$l*_d)Da^avo%3wdi8% za}48rrE&{wF*wjMY%+{OeOay&&8EexlH?OkZb(L6;GFfbcCex;0)CYZppUZd$@2W| z(cH4YH;CZO^Bk9OHPzUhlIobvzSy!1~w8* z$=Gq;Te`dSjLO~jX!~;a;-A-wasES}>nZRq2Xm=A!@=3V(wcL9_MLs+r~);F%w{l0 z10ogfzM2_*AXyd_TDl1YQLUU!HCBx9x|n=4<;LSC;kUU$C3=%qrr;@F@uIz@{Qis2 z+!S1F1{uN*pf{DrCONc9nd>R3;;VYFUA|)P92?ID095A2Yap#-?hW0D9$vFZL0@~v zdd>F?(=S-4{#u5FiAGK>ioJVcfe7fb0w~`|sd`r)@JNo=%AhQ1^qjs=9nN_CVZ~20^-lukm*40%O zt&;c4c*T7AVR&URaox~Wb*D^a(%7S&w9LhX1Zpw`H-+~3FE1X8bOPqmSOc>DDXW7;WDXYL;_f@c%@fQI`K40CE8v%!I!=d_9r zoz*WN;g$BTq!fv!Ef7kD(JSdg^=Bes=z%n*FiN4VR|?Kz+zKY;(qDM?9*-8_cAiZg zuU(ppms^Oal3`q3NA#qTjXj=pNQXwd=z<=7r#;d!X zX10z}%_bJolpp2T_cVeYWiEUA%9(zPj_%e$E5&hq4!G z*NT}u=QBm!R3#l4`Rr_nPSLZV^wFH_vbQce-$iW6D5@V?B}J>c0X@_hEfz2wS69D& zW0hA|IM5hrjR^=!jIX$5$E_-4-1X_N zF-_M>>;iL(0qt8x5UU#r`-NjSTWH9v3*{powLE{u569-8u&@DjAd>Nbxvkhr-=2Pk zMcF{OTcVYf(w&sR@GSTHwdnY1k#@9N_ZFf9upZtghz45mc_k_r>XD(&RXEhLU+2H$Fpl<|>&ht5jvQkBpVW4QM&+k6zn|C$=`5-`O zGC7w)qE!SXLx=_yyX2D(_jhddO5Q<*IB&Kts+W+g+1oH{(>|tL1@LBi6Ix$gOSOwk=FN&7oDg)LFpL-o=t!0+C;*oIe9 z7ZrIsJ9RL&js_>axJstN%X=MWo6CNiN!ky0(Tgv zWgSzKE<^RHa(N~O>AX_1&4ml-H6GV-c4>--J6;nrMJ!;@d zSPQ648j4V-6|$M4uT9&?<-D=v(z^FpbhTr}>u~RH_hm)d!Tb*;BIW$!cx zvXRtpGhfSM2&~j(^BQ8p^AWMys?SGOTVkhU%U$bAvXHqv%kGUA=G;`Zw~XQk-#*np zP=<3Dy3}@tjtHJnHch5+Hmd%if$OOC&6dh+WCQ3XsRmy^egN8H??9RH4Uagqg9fg4)`_asTk(x$5;tj65uK&U!{5-9rAwEtwK5dGN-8JVp9f1 z9_@Cr{|SSHO$!!Rm@Vc0aItx7P_Zqabjv5vMrF7r-y~f(G^E57;i<_4Ydd=pi%g_~ zzGs}#DP}r*G2q}L^C`X9Kp3A@TVB6)8@P)MpQOiR?q;#ML2oE$=9`B1SocJR!hGD+ zkxINh^Ei8msy^IW<&=JbbM&ZHItip8f(^8=QzKMz(E`OE$Lr6in)&oxO9JxXZ+mImqai`*&cu;l`EM!y7>1}9 z>uB3pPeoA44C!HwojI!3mBVAN`&@1bGRGvEEDrF)gM~gS8Q`dyL&J;^D2{{A!56To zU#|a{tXElp%{jBaT5fJ{Y+;b~e<^Lr@45wT_5@(M%h=!UvsQ$ONQg<#w@@%u{86i3 zc*i&iFq&6-T`v=y^>@2@(j*DZuNJEpey|g;Y2$mbciQ>L%u;~k;?jV_AvVNQ)Q;&> zyV;W47eB`qHwrQXk@}F(5o-lAx91vfs`QP-y3x!-iAlLHs@B;-lvkH{6C7GBN?0af zMk5*7UaOpM1;yO0BRecA?Pk2Ut?n0{!h)=6?l9okxq@X3_P% z_iu&obnw5q*#vnu`cVqkD}WM;gZgZE=CATgcwFg*v$lYH1c6Oi>SY5N*&F6d#ak$0 zCjU`^ha{-KLTgA*cY*1X<@O4O7y;B>D(bWfJb>VP_&qRwdY79Hv@A zgD4@<8ZG5#?7+I@6^M&29+%1P07K3UzJNXaB5+bP8`ukHYNTy`|} zGO$=T^Sgo$1eSC0=0r48Zyj5w7V@gRfa^_yD$^9{4PI^ z{9$p@PUDRg80h%Ui-stC%?oLIMeM$0(4*sjB8@QBQgS<4lMRjG}_ zO`}Q36?zYU)pDY6Y{r?Cn~NzodQC-miW(GydEQCb?u6Pz-J^a8FIj&l&em?>`m<5hQ zgS0q~OG~F5gM9fZ`C*{RVtjC}8Ju>m&TuUKN?Z2z3@yAMM_X-1lB3aSdbzQdV>23J z^Db;pK91!J-ZFioc!qlLGy?W_poDn>6&2p*d+OAD;U(2HtFbVUY=}VYg`g+(f4u3# z|4YmNDylZEZ5u4P)0YU6+ytXNPMRoC0*pQRGei{qN|w^w?0|rcWsPB& zl`a9t-dF1HHT~F!eqC%KNQqFRruK!5%B-Vf(?^I(fOV)~uM0d3cZIRDVNf*6un8tA zU4fL0OAxS59luyy(uy|Fb=)Pq8Bj@ntmUNV6>kJKi^_JfF+~v*@WFh}hM0nzcN=n< z2T?-s+CH>2D$28@@)qlwg`;svoA!R@uzBGsziX-Y--1(DQUH6PC^flG?sPqa)Q1$Y zBs?WcolM>bJtsH;#WD z3lIJXL(i`7Ycsd2i}++xiX~`9{@ncCz&`V`^a3yuAV&Yd`?^VU)BZZ(oLmC5ZRkm zB~5qxy@0I1=H^|&E!kZwE;N(R@i!<6wOh?($7SxF1+uvBl1g3qfwrKm`^-FH0><0} z9?CxWHi5z6tgQsJJDsV(I@DWxSA0`{E?d64(j?U%?;F(??Q|Hff1^mqeus-O2P8)f zG`i$_yFGlEW%2HpQ1rU=s*iu$KZSs{^WV;{0x90K+yDGtfn+~X2`1>fFQE6VY$OTN zVT3zX$8rpL!>PTuH(}cY7bo??_nhz2T>(&C4{bT*@pO_#@{%5Q70x($vu4D(oM}B$|Y8$zt90qYd+9aqQ zlAi#rGNI$O4+_YGz6254LK8&Y^TPu^!V@K)NKh|??!79BOX-4XA)KiJ>{OXa^N}1< zBqejx0xH8k`H>+#Bxb)_;_k`(3_Z~_F^7_ViqE+}bvR)iM77JmM$->#m@=Y!s$&fW z(vV!-NdlNBzxfTFB<=BCme5MdeJJ7-8B)71YR4xtDJ*}VxJN*d(Q|EqMq37xoiBW{8;XT0<`nV-W1b?}-+kx6 zp_O*|%!7halgmoQw3w%i{YfGzO5y}os^`ER_KLz6IXojApL~!0dHoA)esSx&_&nz_ zcsCs@9KgU#I#!j`d8)x!=Sp0jR@H%^C}E;{t;7507qY;c)tT?_m8|A>?H$`~86rQU z2roP;ME>?`#^Hm%m;gWVu;^>eE;KW{_h|3-1ptGUf0Qqu=(Ni&hua zOp@2FE3XKP7*5yZm6v_2UW9v%h9(D5Q!g^tRhd{*p z`P=L^E`T`~P8MN(%${n9=7$Xg5r6?EyaP+sR$ppK?Rl%GIQMnkOfgV3@w|@MNa;-t zYL?G@^1^jS=>zpsmz}YkC(rF4pp;suQ2)cornUdD<>-}j(mk@&-9XGP2N?=`tYZB# zlCy4OoQ^&kT_WN%B?+7Q@EKO=^H(U0}+x_a=VV0s2p4 zU7=miN8GJqC&nU54H=zbaBqk+@vcwndta=VVI#y$B@j<;Aplk02B-xE{g-@gy&5VE zn*&X3;tq7a>T!i!Z+D<3>+w73Hl`tTK7Hrs3tsN-=N(oP6=oJ4HTnLLtWt=KE##k#^+# zzqm^WF0CYC`IrTlh{rD8AM3O+HzzM)MYFTjy$dJ5XJ!TQ00$|x8XX>qU;7n%S_a7b z`+xJkzG{;z`>k?=(Tuxf3rU1vy;DUG>^1+K?7fAb)#ya7H;J!OrC1KzH*+Sj38}xKAY6|#yo^5-~9-d zAIO6Gq);Y{`KI?$JZ&S{N>^vkFZ`=B!$7vUsx=|s0oi;N+_}pWFVU#m>L^UfUZ~1L zAKDTmFmn5OZ?X8=0!jL(BuDDME6`g!k-yyzY+ih{UR9FSm%=g<^Hr*XFj(8B&j9yM zmjDa|!l&mAgvHQ>PrIjXhc4V?=L1%)M+!|e<`sk1S3R@Lme5;(3x=E5+h0oMdQS@a z#hzoAmLET8|992qEmRe!ryRDUmFMiyhQFwLgs^;k^n~vPpLL=t1YuNEmL5q?E=+ko z^=B_@y${m(*oi~vG0T|5pz>Jw>84|tHp0_7X~{8ti%R&8gMr9vaf|OF`TmuM_*tvP zvk{HCf)ThtKdLn9{aKWO$v!sDp=G@ZE#P%dj z;10Q*u7_AvJ&_119jfhHWPXaHu^Oy)J--sB|SEBddq$D2sM1UDzxXau#UlM(=*p?693uI zFx&^4BG+mkjl_{8{Ch_)Z3kJFI1q`O^Gd=ly0ECzi;(B{ks6?2`HZ0rQJS5LUbkT0 z_^4o@Qik8EMVr>zdPH|muJdGMYTf2`XxW2|K%4~4Kd~(U`_Q=J;oU!-vf4T_PRXif zOVsYdUGNoxcu! z$pMGle8YGD#)Lc_Hzia?XF6=wVX>M$Q!jNBzz!Z=f|xk`L=92JhmDOoF#9;j={lIE z%!;Av$AV60%3YrdmFj7=7CP%B?@HQGg#3EIB#FLrzk}pj9A#&GL;%`5cLYDwpY!7SNOA*!~`|dCaHpM2+P} zKM{{%r53X{AZ!A-zCS?2P%=nSq0|n39Cp~+VM-@%%4?15c63VFEDU*eCWw)1_)Ilb zGLhIPg;El#S9=XBlwj|+fZ&)BUU85&tbUXH&_pyp3X;Rw6+Jz3$=Z-4GJ zR98n%87s|PYudIdLbzJ}4Z#^DV10|m!40u1Vc?=WG?D@p)PDlVo`^(K@PJPA{8i86G%m%1ox((c`hSh( z>iwL_&kL*)e=IJ0SII`GSo|Ida|nqr>gN>3Fpse@Yl#A#S%-l_uRHl4foDRd(5#rtm#dP**xp8 zRTn>L9w%P|p$6r&t`p?wuW0T61HypI$i(NX0rTU}ZrD&s&Ao)9tBfJzzvg?l%MVvu zMr%hS47`(^ZEmvf1f0^m;c?r;qjsJByb1Xk#-m*1FN5d49av_KU6$JSR)d8;-|pdZ zQ_l1(G8cn5`M;DhHhS%yb*$y`?d2o~;iG=Wuvkg~MMxVaWK5kXRP5~Tm7cU+TZV$2 zJFw&h`O4|YPgiljhU2R8idxHSE%j*f)cd2_ro?^`*v$;Ws*UR3K168Kk^3_GU-z93 zYKumBW>@g5yL_mkg!p_ZG6GkzL9~`AS|x%5jLjLKR_tvbLzb*!O;Sf?YiOS8U`dLB z+JigyJ)?7vA1fK8`!Vz-h7@s$Za`Th!4cLrYfHh8PPF7nO}z_kdKnZptGRHHq>bZqg+*b;wv=0G*mRTehI@EGZW$4*J<;njwPP6qa(?C_zjCF;c_r(JrHXQfr-Hvl z>;>$OZ&Fzg{{3fam;!Wty4I@FBd#qkqE#ko4_)&ov zy*_H3HcUEq{L!?TL@b9*hu@+=N1ct82JK|v_{$PqfPe13-PGu`+>f|LzutLuVM+(v zTb%%iQd_3zKey~*-h8a;po>(do>tMd@8Yf&OF>6RXvznSLmb(TbJW^Wz_T)r12pJb zJTBZ{S2e>?PmNS}H3L2j>~2Jm8;nBERG)B2oZW5gj?;fvRVpr+K zzo&3tb)A#f&6yhijm`T254+u<^KrsG{KQ{6G-c3yOg2Z z$zhn+VvY&J6G%-2xJ86af_Gl#@2g?2Qzle+H$$qc;l7#@N zRb_1meMoHGwsRaHG~#(Bm^ULT2`;Dq;o6|eWYRtLXG`HR$wvnp@wqg5JPuE}pE-4N zs;1%v@$NT^d$8Ty<8qUF@-C&l+JY3X_K~%tX4U5Wk^Iw97Xe~VhP`Y=KFuy9vd4oa zDgQ)EG22dn`1$wL`jz^mtcK=;0SamKyf)vHod+aps0+MEv^gn~0C~csUu2t7E*h|% z8(<3q{}thzsoMZ1-eC7~u(aLHf(y~s7eY7nEfF#(L5c{b?CmRp%G}>_$I`;Mj7ukV z&8d5PO&Q)Vm=oA89+Z+xpE>m}D73!`wDpY5;SV5aJb)Tq z;<>l}CcFvk#;mgLS|oX~5%MuSIo2Jejt%O`Azx8yauPm}7+l|rA6eh(uFZeGk|n?h zZehQwhIq-|Wf#R68yeEj{i%)ZJ@FIgNKbk?mi6rollhNV#smwL|Cy9+Sg}!y=hr#S zPmd)MY2AnjXDFiJqP18rZ_1qQPMqFJy!!sXIk%@-=6u**-0#h;N3U9H?&c0_;bcvs$WqcS0q9ip~{uw0c3D}QRMdbXv@*HFRJ4=i7wHpsi z`&#v_^;+yXLy^03p$y~$EnI=Thq*stE@wx)Z%_PMo@X!c&h@?c#{!@K=am+Sh^aGy z_%ccZ;<`{bz*-2++UF+aT080VA7B6H&{3M*j*vtL&WP_QN5KEp!IC_dzUwOt{bHb- zLcaddt|Q{d2sL||twRluoG_Q(jTU^}-31={dNIbc~DonB>5Y`Sq#shRZ>GW2+Ja+X_t4%bQVA@*c3HAKnl zKl|>pU@``FM+EODxiCZsqa3B^*@0?_qR~(38O=)#8R&VnR*5SpnDrBgU&;|lXDn<) zKGs!$oNm0K`pkdTO#){kw%ROuh&|)okk%k^SFVs{#Go)Qzy}LXx2bdVSMPWV^utqq zJd6G;9B?5mu1*9TKf0WyUS+1xnQy34&w-1o;1N}Vki0l1!!sXE?g~B|N2d6kgrMD6 zUY*~K-;@6;ye?z5k@HKUOkS_GEi@t&sB`Jy^x6lv^PKdG^D9o{Lc*0VIpjNEcyOUt9zd}sqyV-LQ4BGfbW{&15?YL9gsW2ko&E$3(BGreK= z`kxZ@9B4Ql5h0B!PZ;khb*9|kY@{Cs)A2qPgQtG;6oq`gYWOAL;Qx99Fte{MubXL7 zKN?X-X)uV2>b!ktQPEfK%bH;l(uKbf_8J=E-kHx3IP&k-;c0;y{?ju@h_XcB$6o8t zrWz6c#al>A&POju)f^#2cEkFoQzG#CyUP`44os$Zl8Ai19Q|FNIo_)Yop1ZUY)H_( zlBF5br}z5N<*5adq`U5JZ1$P5=?pbAe)}Plc?Y3UZ?OkY2Ty?T$NzPsfxp`juya*O zA?D%8j}z7@9oBLF9Hc$XWF^9=!MM=5oBa4fq!X^1RV9V?sSsp#TS9BCQdTM5Mvg49 zo4P(ym6@RS%y)5+Ayj$38I7OV?&>rSaj@j@x%61GO0}Mi?R4XKqLGlLQHnKUC2VF- z9kZ23-cIqZ=vB6ONo>KTC48PRxyagKJC`7fRJ~}WghbQ86NDXaub=n+3Vi?ggU$u+ z_uum^!M69RHk>iti|;W~&GEg~bp9OiM;+mHYkEcqovM6Or@vnwWx|+h3ikaxtESgU z6zW6NX&KFXNNihrNyuIvjr$Z(0uB13b`Bm&NiH}LC8Xd=br1+UO{>ZXwdv@V5nTf= zMJ&#_19smq$v`w1S~{dUaw3LL3tQfQ89rA}`LFx5Wctjd-hhj0`TFl)m*&Ps|8b4l zo!(cPukKk4g(T+c6_R!K;;(XMr`-VsULu=e_ur3FsG&v7`muSZMq`{^oqt;Tto6+O zc2qGD`cq=)NCyReyk})i(7o1x%P*f8xx{lDXBBsPuy?7tR=-cJbz3+v@jQ4CUpQ5B z@BYr%wcyaK8tN@A`5iG1a9(74drMZM)%uEqf-hg1N-CKE44CCpg&Tuy_z>rMLh&s`3(^=@@wm%gb`kNwKg$qRVt zE6201Tl8h{&eYXKk*^Tmj>W1%Z<}nrQom#G=R-7%6v8z&cu0gQkN>zP>0_Y&s0A)Y z`{VQ}&sjH)P$sIBhT!gHrWnyog^RO|mffSl=OKEi4ycI&{J{iO{SBxkJ_sTt& zHi`&BFE)rRUzX2h!f)TZ^M;kwT`xKF`34~qBs;S`J)honkIE?y8raN9HC>rn)u=bt37+s++HT@{=h7X>Ul}OK1EL>#$?5zm0wLE|$;H@@Ko!*U_g)sipiW-&xFsGATQ|+Onp{xTot5%7Llt zveElo8PTM?N!bO4n0sji^V9e1vrv;UYN&)go3?y@C5l}Mh{sTiGDbS2d2qnV|6|nr zaTI0LJ|rFE@jiS?g-{DLO88vH>~&8pa$AA&YNS_JI8l~v>lBL?cp21sIb+cxea~gU zd(#&Ij4bpZvzDD^FBd1p=^%C-MvLF~4G6Mpi!!2FQr$QTh`v!>k{^RVf*)w6G=5%3 zE)Zck9?eFsY@m}=cqDn^@ECBZFu(BQl7@F)G3RC#ZGkZqr93Ym_nIOvhAV=cx;8Xb zX!Tk(pt|m^mkvFnQqminqQk860r|9ze4}CMbhdNltXz8A`Cj%G>aw6M*`AwP4rIe@ zLLN%a=gJF+_6Xzjoz-Ab*VnKVS?mA>Zdl4eQNt062wDFZeoz-4Y6P(?(HQV7hldn* zMp&~`$&UXGN%1o>J1pB}5T&Bs4Q?u}L?K5jX$BtO24bL;zZihEaWgEdKVX2F5 zx-Dw+H&ehJ4%u+l``H0-nu2j8qS8W^bvWnUv#u?7s^)o>%FI^=}E=rcBYY-(nS=|tA>!S6?AsJTA8I+ z-9XB4eAI#F6AJ+=AqZ-$cmFYgo>Nm7iqh!h=C09qE*398Fk6?K3sEI@Pxw=Tk*Vjv zE_YEP0;c9w{GCx&NWT-UY&-e9`H_p75NqJkRRUX9rhY*_uOmPJ{+gPziq40K$jPKx zGtQgEEN%*srn?S@sk%l?d{8D?!JEwgdS?jrIJBmLAQD$02~|;v4$hEgB8&vt^rzXH z6%rXSv3{gof^GFYp)di_KV~x2%pirFXJ7Hk4h-Fp9cy;3?T9hUMQb=A{QKFXbeQx8%%OBSjDRVY8rqIk&T}@#*8G&&sqtZTwrVdTPpQ;fIx%Zc2{sRscUR+N4+q#{v#;#A!AXMy%J6h)P8EkUbYTg z_j*Z~PUKHJrN`>6pIUS!8bXMdGk^EDFeX5RxN+)|tUyWQ4W-0Qh{sD>arMc_KcdFxgWLZi*U+rc8A3k5w;`0eydgU%eSRp zn)VHc9RC{{Bua6v)2ph+1bQ8-TvbT{>q1T<^WHtW`hcnWi0$OcqIj#}*sYBFa+?o< zr)|B}{<6j7F5?0YFZ)RpLw$i}R$@Io{*hDEP~j!Mx)Y!N`EsTscyeU6mk@4UJ4zJ| zv*gapx90>a(?b|5cv5?a&18Y-ycdsgU)dkT2_L%B%{>#>rX%cM$w(k{!n4jW@A{0- zmE-eXwan8JyV>{-H`dY-9i-tDeI)$4^0hADK@)pVH6>-4JY83L_|)oFy79Th&-ECY znQ8`wDssMR+5+*taFg}ig#(T%>3j6ki}Y^AN^e<0L3U_&&~_bHcVwKf`A%s5-^64V zY09#NUN*M@ffRnMgtO#XL({oSaXsc#;+}Kxm|TDc6^kplaS1>UBA1=j7;IGDVenRx) zr>R*K?1K=pDr2QYq=TS)y#u>>H*w5>lv3e(D*47CJ8J;JajgoG%XtvNHh@wWf?|(=G`u>)fahX+Q5JG-_G%vub5U{E39&r|TCh z8ta1r6;H&i*)7J~!q%$rs#pN4diO~KTvcJ#9@sP=0HkA5l>qJvsQkE zW=qh&fnrcdspl2APP9|o)2MBC;#!u8OCoV$l7NEQ)fKHPON{r852eTwNu!K}J?TmJ9 zyp51R&+*D9dq*Wb7s5B0&9A(f{mssZDSC$_=?Z z5gK(JsMg7ildr9(D{N(2m7lFS@H-+eM_1JYHrd&==r3lYM0sYhVc-(?$4u0o0Y25LYzz!~6cFna9p(sxB$s)1z$sg!i+XrdC&RyMP=k~q?tgv$`F0gOJ539E z7w_GkdCjLO&TL;{az;m016*&V^|v3`DFI8?8{tw7`EKWld2gxr*j7 zAN?t@SI^%9K$4Ar_j(1qO*1d~t6VVLY}~+PiR-Il_lw={_MUlA{wE10jSw}a1+@XW z=OdC@F2Oldd5Y3EQp^)z{&td46Lf5%T)5d{+p+zoeg4m8wGrw#eDpjyhruto-sNlC z#f!}_3_iQ6l2c6_l3SPf>G4WT=rPUH(i7sKR^WgA4ze$)KMZ9<+-#0uOn9by8_fyezZ52uyauoc1(ASY4{X@o8uT@n5I-BV`q6G{y zu?J^=H-GiUuqPZ4YFk*9og&Gzt-HI!dkuOJQK3C5E~X-{_uJ#l4g5@^*@?EtEj;-q zn|c=WUC1enY|Y0+<{LV5CWKTj7>KB-lS$ zU&v=#P=kgLD;Zhm4#h1I9S%NMx$U73ZWU#JR=@)$0mX6Jc)dw;N(%^@-k*e6nXh+g zNW6A_#vrwp-kU!sp}ne~$-y5w_cwbTiWWIIndS0X?S}X1e{8xopCm>T7?Jx#m`q|f zh+|pu?=_Q^mBfc`X#KqxYp2`I6|lcxv26fKsH4_+9??X}+o(3VgUBZht+;%#VoWg?8!fp{$MQz13Q}g#)xCRG<{|(~{d>9yaih?za}mgAlFQPp z)H+Kuf3-(UOy3@Qq+bpCU%CpklQZ9|RmF^mq*W&O+BXXrxOqqb_q+XLSHf0s2&}oap-v@@|tQHEsPb6n(yR!X!I8?-0 ziBtR7w~y1N$sBhh+rWQU_>a9Ii~D_AF}j^|=xbmo67XVUTyaeNvCfLp-N?PnJ1Y<7 z_KPm-^90E~4!%qnViD?DU=igjIn>`5rZ+aFQ)3atx3kFoL)te7Zee1Euz6o(WWK83 zD(WEA`y=JDa2}_@=i!m}KYSp$Tbf#lM2wK{nf-5UxMh~z#?!!|Dmb~bij7do=@hGP zb${X+1G~k9cC?Cf`3R3nIIkWG^IPef~o6j#9E)M(~u!kMTA04=y!VlH-;FF z_Y&%$^sp@ZlEdV$bH?6;NV5#f0&<2)?|Qe#qL~8=a{?$w5H1Fwo?IgEmIXI?>Jb$N zj*+1bqw9ufOf;h}&TP5;vJ$G3q#cO*N5Q9D(7S0tCtCw`gzvk_`z@{$-5Ft>8uX7Y z7Um+(u&QMxKW&meM=$$c`|{^IUISJ( zRV3Nl`Nj;W9Ul!w%_@7bber@2_Z81fWa2$s|Gj!6fXp#)MMcwOci#-PMOywBIw1aj zfhSJWP!E|YRm1qzY1tx+^YbJ5RpOitVr_IR679f9O%`dr-4E)19gTSbOpglgzasux z9y!JRUz%Vsyrb9M%aJxtRlEQHM+$8oTtw5uU4p1%CN|o~wCXy6 z!2#NC1v`uMkDS492vuFogP&-eN(@$;14{e9qferxu7^9!&w+yr;s2el%9P^&Sn4f0 zH!-h9&BUu{uvD(Z(K@%_$>{kuO!-Dgl+s030b6LI1ThWU@wzvMmsd#m{}Km# zG&IHQ>*1fkYIS#$uuoQ4}-)nkZs9GMh ze`Uo|33&f6_q+EJU)1FdsXfAG`SB5G{y*6UBCA-LB(VCga_Jk>?I|lV3lw$9**hK? z3Qv>WI>8tYk$97Cbf>CEnHonv$Eq*L`fT{>dPM&reS=Fto{}=T`;#S;$(MXV{&xbD z7Ic7G)Es?bMVk-28$4Uk+%Bho-8?<{Sbuj=Pu$K9z1+xsHePcmqL6%@nH3IZs?ZDX zQTZ;(Skcf6=)56G-T7n1VswwuS5L=*N8lAPn%mFrC>EFmn{X8|cai-|p0)Mw!mZ^0 zL1g`4@ynUQO*GMWZvq53#lXkcLgCEoq33r+kxVn2E^|#}R3JJQ&zkE?rhQ%-tPaOX z8oOstMCjb7f|x%|jT^kMSo`sfF2*d`CG}5gX1b;%3uB-81Uq2$wNWyaegDfoTKC_V z@up|l@@*J9G0a|7W zT{XpmPqpi$N6GXaB!GAIH%DZw&oOaB zPClbI0B!7FUAxP7Fg?CVF7^goVv_!KYD+rbk@6zVEGK$I!lfj&#}s{L6$5RY=-~=~ zfUqnemO5{0u9YS{{_y3In7{rH6Dg&0MTAt{+|m3quxvAU!^qrCBk9(DvJupEV{o74 ze-0fDcoDlRd5}p?O;0)L1(8i4t-L>$em8{J88#7dh@w!N+$J8j@7GU%HjJa9AXo<@ zMW4;Kc0FiItePX4@Q9Gn36Ai+Hjt)D_>W;>w-=79i8a>{Dz$|dD{XB#<0N_(0` z;?P|`3YQNZz8ltKA~-<(NV?390yUrz3hS);(#cc7!juA%1#?5p1TC}MqN$#Y+OlYy zl>{H1Yl!k+Ef~A%Enw*i;~sSUTBzWA9=qpniHPmk~Fk?K1i|A$FDctM;8^N%hBHa-69W}<5w4OeeBb5Ug${xa5A2IT!T zR`d7^FI!zEm5vc+R^+m>F-LKm&iYVdFb>Y!J+lS`+DFvwWWpH2W^3-8?@tzRpwhMN z?vK5tqjFsOd{nC&dY~*SS}$0z>p4m-P^*-57idQB$`UmW;@vYjtEP3mK6HuByPq^3 z35bIK2@`B<9B}-JYB`yD`68!v>dYw{-iuqJdBt^F!G^&lb--ST9CAo!7O*O1_UDdH zwn~3B1gWGz$vMqM7-g3oPR}?Xusv`&R$XWZTDMY{Qy) zpKWSp+Q@roD=%wCGm(}`k|vRtl%XP&F=JS5vl~fuk4;AO!d^DQGVtqdN^KfXM4;YlYp#*D5RX+F@&#`cOj`-cAzdI&fjPxq#Kv_E7hvgF zDp=Zz{R6=q6^>xp$WUSzk(!k~pMFGNPJ-oQ@#(elFlo~pn8h*bUqQu<8eq&5VM}y8 zPGz@0$7vz7q&Fq7@{ljKfkMxDXcUrUUq0VhuWT7hM3xb8K_z0E?qD9?)JGd$e%Em$ zF{f~_UCXXm`g6P18PAKW!g#f2R?lz{@U7f4Z@6t!H;48tvqp20XW~;7vbV{ruX{wB zT~7U18ijh`@suMq{3x&`{LJ%T_tGa10r$w&yIouq&{psoW|5=IghZowQPTM^@d%ZO4P?p7~B`s8`W9W{0pwG1_&Yw7<0y(>G2Ne6&zWY!%> zyLyj0!d#Rm*y3CYWSRIUy*~ZZtLnddC;w9d8MbdMd%5qKLo6D6;Z@mS* za?xe~pLzyU&CLmyr$|?I@g$f%HdS-P3C}aQbvz&R z2g>D)b%Z7}D;u00^vLQ{8h`$B!$e4UWh-anbKr0ah-zeB4mTw8Md;knjyi7JtoOmi z>pMoV9?IYTxUf9EWU$~?ZU%nu7xtwDsVq3k=y4CF+S>*K*X>?&vv=5P zm+z<$`QSr2up@qa)#-{q=N>n(XJjz&?Rp;~c{Ss`a0l_lus&t1R7rH4yq^Zgz$Yb% zD3?MD!a)W}=d@ZD^w6d6si%wvO+61jaQ?2Xnu)kkfFd0*dW@n-z9P$j1kc8V6wJ1z zcS{TbF2sb7dNyLe{4tfVcnL^B+{;kCyL4g7meBR^rxKmzx?HI_@_OY}4Z!}Y2O}g= zjWc9GX-w!qjMC&61G%}=Joco$C_E5vw1layI&b+*6B51oI3HR?3Yck}Ua~pN7^;Ux zuEa9Z3Jnoc1Dv)9LqBaxEpMyQ&Q>jJPf5NkWk3sq-*@<_%Dy|J1@sDky16|xKd{2z z^0!At!3#t0<3tSKroBrczlOg`N;fo47*Qt<+R36-u#HU@2=hAwT zO92~fB9@4|l$KEUl<#FMt=6RZo)Iy?eEJ6*?IUTHNsF22+P?LNrzynaAZE$##A!#} zw{0bfBLkSzMG=|N`uq5boA=o^0?sGzTtrk;h6dFoY&$V&RA?jdQ)?CMk9lrdpti(1 z>@%EZf6ky&)@0e^q}qQHr||XU&QNshQ1t{Y~}e|gL~-t3i18%)2Hm+K>>Q- z3J6;j4QeKb{@J<;PjmpRWhdFxqq%q^|| zyfQiBQApbPhMzy~Tagg@~1 zMFWs8tse)*=*DwDC0Ak`YkE3)U|(3?0~hYG zr)V!;N3N*#TD2XW(-36{w2rEFHyD#kaaVS)BRIl+m%0QIzMSFE zFn!45+r$d+|UeCJR&KYQbVp|_|Q)n_;w`EbfUFBhDTZva!qfK=xYa45?Bnq z))=!>2dtOv)fpE%?O@Ad85juWp=9`VP`9b~7=khA#oX{32WQ&(O&5hoH7=x_7s1mp zc9AB>8v~2Auf2*w$PrQtV8n5k@vz zrN{86c<$Pxg0L&tEDm4Rbl3=lK4v>yVe~#2zF31MVU*HHch~CuA9>8W zKA&qfbAX z(^?^MA(ONA>dbj`n-A0G+V!|1ZsOYTqtn7e=8g3B7R%zA<&G2o2qP*c#u?3t!%mAL zP#p|G&Sn_19t zRwqz7AfQ+WZerj8ph7}nQVa&TYk<{bpoMu(D<81G0q-c))V+uskz+5~0WfwY$6OM# zD7Xeu2XWvCB(=X4d&Um_9|%mkrR_+lJ3y42*@Acs2d5^p0baTn3mS8SLxi2%tsC z1Bjh}bf|vAA%Nf+mTY0uQ?xAf0xJI z*W){o*ayeo(^?1ng(92!GIe+dn14SY2s--Ioo!w^9?e^EWW2|fP$oGR@z2_@+y@2tkf$iTrB2w-?a3zV1Z^nTmyH>DU+B|Z@kb3efb3D>O zCdGbv;kEMIwW6Di9}?IY9wP5=Wy7Lldcb+Eocu3JW~<<=R~uh)Op;Px${OsS^>KD{ zW-7nFU?3!QzA^Jl6o*%nY+~sj%Pk*Jk*dtc|7_lMLE*9p;E}P3%tyoL`l^=gG~xP6AFkh#%S&n!i0B#eSc>=!9kvta4|A*o;Q@ zllD)3KW=V&MC01u3o3x}0uqfbBUu_Wr+3`D$;?2`PkY4CE+^+}Wc5FNo6Wk>S53Zr zm=e#B3Ij>GcRD3tnql;JxE&iCQlsR8tm~6+UE}_kEL>p%9a#t;?{3YMzOBLf!Tgi5 zrV;Oe;xfFJIsTNNf)DGNaJZ=_UL09d@@*_K=JME!Y-9`GeeS_jboi8D#+LX-n4S;$ zK3|v_&#nN3-1J64ON6IB>$9Q?qq_GM`P74F$aSdaL)ccusA{Cj9QMP#b&{S1`5-1t z<+&sMvlsKv2jVf#+q*c?7fQ?AvZQb`_?|5wtp&r$&3v%k7oM-l?~qw&4F)Qi{!+bi z{`I==Qv2{ABna^wERnp@5e`s%AZ#G+X%TM4gQdW=cBQrW#)tLugOzv(zy>4t03-_k86G{*hp-+x}3>?C?Ay*pRMDVu&jBJ*h*n0D~1(CT09on@i z$n^PQkZqt;--`WHDDb!caJ7*p*e5F%Ii@kIw?Hr$%%Dl z3Jn3r^};t~E=Z<-E928%Qj3wneFsUwZxxJVomkXI?zQ2v+I}s8!=sX5mQa9Db-DLT zfLf*x4go*7uyRYy+xw1fz2w()SPe1M-=LoMY>c&-jV-p>&pt&WT|Er3$Iep105F`! z+;mO5?Z;^pluyqdL!`j`j@_DDXMQG>&W@R}2=e!hhK<)WG%*1!o%vDp%n4WOcNLOi z7**1em2hE^=o%cvP(F-5G@6GA*s=L%bobA%{P^F$*9UKOPqr?#RpMUn{w+n1$s(?= zz!vxB3e)zkZo5V9vK8rcAyRwxr;jdRgVCIG6@#f({K@aOsHw98j zV<(5^?Od9KaJ zALyBFuP=cO4+K_Bg<`JMgG}~6jd>*L3zRL00*~#&A|#{7XQeLQCWr@j+0$!@q}S$E z1;0RpVB9aXz{2P18`l3*>q}25I~p1FL;*+wo(I(>*Tj z5M~YOA?2eSUZdR(m37K>10U%J+ltGJuLfOVYxpfzU_hDP?GCkTq#5bHd`PH)MA$k#GJVs!qeDUNmH(fAtbs!2G zp1!a4Q!#@>Q1S-<&)-Vbz4)%UG-AN{hOKlJK|+Vlz|(WkTmjQe@ngZbG&{u>Q!L!J zX^${huJ8>FOAGq&YzO`6d*A9MH9MntOF+S;7JeqXt;iJTLQdBQmRP?f2{SRg^*3?w zMx>@_A@^Fowh0UkwKbb11w&It7S(MWUFF|e6BL*#R3O{>Pm}VulX|~()5LA*xZm1{ z4QG;nB5}y;c+Ymm-tMS9QQAuBWbHgRKJoAV%FhU^MP%@ci$6K~#M*^SZ~tw0?qTv> z!jX>g%{BX!SRHSWuP%@GsoQAdKPnYO}O-n;=lBuX}yBju?2@eH?Aye{0;briPJ27L$cwNlXMH!E7n!cuEHU z6>nm|(>lvXK=$CM6%U4u(Jw=4|L*aWfQw{$BH2hY_vBfRcem%3PQ2x{;GeAS9=S|! zix(l2C!TcC6~vguuXH?85%Cb*^9gTExXl7XLbHxIit~lZ6nEhu=7m1)_y&vK_CG^pk5 zZex0!w^m*Xte9f(S*D=DYf>we*#g%J${qEOPrn-$#jJ^ci1Q5M(L7JQy1zh+MWWscGh9h()OE2Q_CT z&}f9$pRLn(iKeSC&`lS2Y72>1u5-N_wVeJo-{TJKN*avE!Uz`q3u=vzXoZY59-z z!?cG=QTA+tA-AP+UOriVOk$CqCXvP(4Ym1kJs6W5?n@CpGc)d`@|KZZjal4UHzI_H4lT7{BfPjEo{WZOt6^rfx%s&KqE z@71?(KG5Qr3wr5c6f^#7nq5 z%HUxecQuz$WWDqATPTJ1yf>Qu5sln;^RJ|nkf%EOj<1(`bf4iFQiT04qhhQ{IHLXxwRX~!hOkMZk!PI6d=o#-^R9I>#*D6mSzQkn{h+fF12@8! z0+!FKPVCS*BMdr9t!d7X2{RT5S;-_O!bC`LQe218rjkgBrRS6TmoRhP7y%KktxwT0 zq_MOPE&^~NnApnANivJiX%7v+U*}GQx;n(*_pem`N?%;O)Q7`RPSL@lYEdSXSv_2C zGyU31MJKk9OQj}ylo<_#Z3L3pL&>yoo+~aCvJx8eXYfIBEg}UQ4JETL4WEAK*+2eO z9hOx8R#)cW%nIrfALb|N#QCn>X3qOopj)dqBOP8MBP@K7sD9J?p8m613oEH^9M{L> zl$Tz$%e-Kwf2Zlx?;sU(Nild*KMm7XuT^9ZH&AP!+bbRT3e;RLRRD^L4W6C~ZgMQW z?6Eh@safi9uTmNe1Z&rW^(^kzZ)PNfH1bqr;0!6MR{OXM^5y1~5?Qct-mFZ}(b1AX zS5>1{krOo4XH4~NIbHb|%r1*|PIne^GF6|8AmO@w(~tp5ClZ0P2^-x@6-O|mkyr~u zaUF+oRVI}mljT5>CKDHo873LC{KYyjR{&VY^>KoSpc75#TSw?ft$6EA-9NJ)JKZg~ zgQ_(u{NyfjV&s!uRj*vn;~De(I{R>_&LuNnm7(05cL8w*Bs{#knq`)01 zc2BD|W*X>HM9zjx{QD0(7(Jd&@dF!j8T-o8F`qg`F+jhGs4eVGLu9i#{IIL;CCdL* z2DE)OYea$=Yd+K?gGED5sCl^`Ws>TXA!vz(tvhqO><|uxTg~a>!3d(hRZiOY(&NCH zTI$5#qvIw1W7V&Z#!^GFZz>ZLlf?{RK+1=-b8cw_)@fHj*4DUsltK$NG zZzgrmSg7rs>o1_HR}&J7)|Vv!Q6sGpzKb$ZTLt%b?Pn=JZg0+i5$8H3^nJP}^oI4$ zrg#{M?i3Jd7oP2I-!M(fRU{x!(S4?%7Pq}@b00$D_1>LyQK>>>7F8>qd0}xQqF`C* z$YEzphG$sP0|T-|Ip+)s&#ku_jr`VwtDHm!(-D8x^18z+1tN!`zCsH3-bGg*q>7=HNc8hvF1EB5tWkuMH*dcDZ585ln#j7MjUS{%W@K0Vknb2=@C|GjLyz-$K@e}cajvFR*wa7611oBH znxj!v#qa@#D)+0$ddq)6-pc*8qil`>#|gRvsmc`Rq9jS#sZ8~ zO#0@wu-z=58Fk4G{X;Meu9`R=HSvt5AIryWaP0qcG`XPoxyB~^gq^P4pxRM{9$$&> z!O#BAg)Z7imS(%;BV)UKq*_NRiWU#ub?qfFKu`E&fd-Nd#bkZyo-q9=YY(oA_jb~b z!Sig;So+PdP#!bC-vZOWx6#(Bleu*C6Ad;WB?6E!Wu|X3th!jrx!o#ZT->-njaB2z z$woq{5qSAEX%wjlLY(@BcL&uXz~kp5c3GAw#42cg`b}^4hT`aCtxx?@#<1OoE(_Pn zHQ-pzN{H-5CQ(1U0>VI?I6|c+-M^O!>{uMK$O1*H-C)R53-zIjT2 z=0lpLxcGJ$Zme`lBms3QZSdYUx~#O9#&IY?80GK*oxHl`$41hHdGDaNyLkGGU3BZs z!F(EO^FlA4K3@5vKY+A1C6jo23xf{I-|s>xd2h~xuy6UX5 z=nTtQoRmZ=2^@ke5CY~>CEhd&?iPn^u&@kFDasui)47}yF8V%w;^jAJxp+PJ$_(WV zNo!Ff)j<9pucev4l(q=)Xdh)pK-A zQh#kgfNZUDPXT8u^eqI6L)6V(_ZoSEJ!8V$p&{@Z!_bwa4)!>K_8$;I_m{+rPtQN>(onc=BzT@&cHhGvFnBRa0&Aev zjN=yABy|*@x)x4?S{m95^W3-9cn2CB7vsuQl{j|>YKfz7^_{p4E1PjiM=_vweTk7V ze`B97*{4!mi^WM#qy6%PI7i(8m;b&f;2LBrW(YyS=*LRgSHUvhg1-SspsbIkqTGi2 zk+)zqki-9v$r;#5>%M_J&5u2nbm*L$@Oh+)brR!k*Ql~ z4H2FWnu}NS_c~YZfj%lO)jBgTaeq%7pjVYrE5B%ejoZ*Rs)_e0-*2UMzT3cv;cUbu zU3SpbptkpK1!b-21;1*4M!i{a=<9J7vt;0zB#liG!GOPNJtEPTrMF?+Qdvg5j+HrC zj_7!GDZLT6(yFMRrVFwZpC8;zRG3Hvn}&aT<5bJ85+nPj?S19P;n|_C4fUyYjAEiA>uH(3 zZj4NYo&={U=Z;-l(4T05bpIUE%>rw~=8z}V1`@?t6+Mq|o<$kKR$PXzrKP((4TS&! zh)cMUc;>pgD(?$9({KYxVworJ-zPQ#<)H>XBYk8#>bVe_=D9U!fuTo zQtTYlaPR7dAJ}g-49Ra)o1~&@`e}V-kDwkC6$1@=qJI1*cyagNS>RoeaBa$1mM+^J z4kC>fXh8PNBjAsDG=p$A3kzdR4`Em4^anR%c^csGVvt9Sh~k!`R4D0Bi1r6Tk9H%^ zA|6o->`fhLGv;$VMW2#Ii@Q<^VX^5I(c?ifjrcBj{w*g8)oXTrp<`KmP@~Dt9N2nx zu}Fx;3?tf-S7IaX&Pv5?G$RYTKo67aAH#9Xpgx~&alNqXwPnJrV{J{zk0$Cl@9~z{ zH-d2^pM748#71`44W30}gagw6#m^tD@fbCjuY;HfIHNMB5|GND7Z*f@b2$T3@nyk;m)lJxtDQWJ#Qm2I@UXDUf8DF-ds>J0m@H;} zM^+!l2Y;r>DV`cbKH`_PEclocl^PU}YA8pR0?d!D@^X!E3h*I;jzDWl$#t;K$U*xv z#+h2KbcUqs7fY4)d-p&e7XotN}{8V5Gyg=P=sEPtrp1RK7X|4gz`#VIDPSbwIZvi0QFCIhHx_XNhs zkg5Test22#1QgeDWI{iU`rzuZ4niQUAguNU6X&&$8gXoQ%6>^79p$}a<-5v3HhLe0 zPKR;6a3(Ic$YdSmU4}Hk^uA*zRofwgQhnE6=VzZb%hb*=zmfYWht$4SwN)2u-W%Ob zi0IS@@p6f0+q}Zj#laFC`U%ms9JzH)#$~#w22K{i^2EYu^I3M?xj)6=&}sBw{oDnM zAwD)LBjX?ro$VxALTvwS?mGp&Yq)k=hM=N5&EUO5hu_H6xqA%dSk_{62G|F_jO#$r z(K%^o9h?nl{`?y3XYr)e!zMtI%fuA0u*y*^e5}k2No{*r$wbP$^n! zCy!Akh5|s|no|JM{M+*O!f5M^Vb3zvAftuFOF!6qX3dCG6y1=z5%3y5jb38W}N9!b7z49G&l&s4z zE~6w?`akfcGxZR0`c5<+Zx|Vv)Y|lrxmIgI1?}q)8u$#vqM^ZG>Z;0`sjbBmz=K%o zUVC`^ODB|AuOOJodz+IvXQkv1l>?V+8G48?3w;uQHfz?*o!RLaboBUFozJn0$L@Lf z>+QvX-yP^2Ph4%y9t!mq$XYBJ`}p5Nwf=CPCCvN%k+SlUMTq3Hb!>zDzlE>i!yJyV z=)pbl)MGmvF%~@?rD}t4X;k-5i}tx%6J3ThdzD&o6d3jz+K2Xmkk}HR?Gxk0sVJ{S zTL^5#E98)o*jykkDP$bQ{R30nm=exO_}o$`f3a=wg+|b+f3wDycx;Sp*XP}Ibti!_ zc-Olo>9-lW&k^LJiQl6yFR4dZ!2r5`O%4;8-d;4u^B)u#{waSj6w-ZkyzAgqL0nW- zvXBo2rqGr%7e^r5Rs%i=Y;+-zU~pvtF?3n=BmBb-;%>QT(S9fi z>{;^IDc*W4z&@zHk&6}al8fidA2~Can4}S71fE}S4a^*HnY3{1tzFL-n(&wAMdF%% zSf`fmB}I0qU+na%XQBVgThz_xlPXZRyTWq4qifAv!8E*zNZrasd{j&^nhABdo(?4- zQX(2zp2+dnbMs2x?Nm-@zQ~{bD%y!@xkeS9MZ2M9>Z9`0qF#=4&^I>|JVzKVT_EHah z)IMcdq1n7db!emgi;0~<9wQ0E%anVY=ca}34)@2gpv9G8#?kw^Dzzi~p>N>!-yYAa zB2(`R(h1KiS9;QjnQiK@-wsxFe3a>0ih6cL6D~Y2n+Z=HR zdttbu1{|e}{Vo%b6Tnkp(u8#odkz3B6}B)XuD#|NYM(J-e=C~ca?|LZ#^;lw&8vX4 zksZ8-H<|qwce|yKN8N-~p^{2bLjtH2+nH9xuI-*RBbd~R@HE~gXJC@WmT0o((F)PJ z><5$1uyi|@E2Sim6#WRl{v{wj%A(5$|EE&{Tv=B`q`{Bt-f~GOkqoS5xnrQ=t-bVa zFf^i9swimD`gkiI5*n4ULdwu{-9|W_{(X3Rd-i(98`k0p_qS6D&jm%U!@r$OXisxr zQb`c$^(zQ&JArV8xmm1-L;@`6m}9!dmoP?tp*54tLDa2s*3_4}wX! zPGO#Fe;5!Yf8jB&$~E~@`|LXy-mUOW>~&A^39=f_j%QZA*Z zT6NwD67C*5&|Fo~p`(J2GHInKF4aC{ut{l5U?0X5E#xr`TuMpfbh#VNjmnFZ4teRL ze53F9jbWzNSU@x4D~L(fU-(Yq(Bc2{0&p4EA@$;x@+CN5T`+JB5x)ath;=U+SGuem zxw55qR|7%P#XIm+m6`e8?mzP+v9Zv%H(f^(re9=plFL3ou0;;9#E>eHFFVOa-MCs6 zw6bMb8I(LROW(KHzYo8CMJ&@|0t^7gZ?+(j!<#C%n%&q%BHn4>-@^1`(#MVGT;ko9 zIz;&Hjigp?O${+qsZ7!UDqYrpX<4}8Yy51!`t!7LzY@BXWkrwh9=7-3?qp!Vx902K zHN}D&QCzVS?rK9{f&dA&N}&C@L19i*7-HuA+(=S z_a2_|TkQ9{iEp6`%2ejO-SquNJ1m>$}A&E(_>Li4%#P@_CZfpguK6ZM@n&bTp{*CK~Q>`B9O_A0oRI0d1 zY|EmS{xeH>^GYr^5Vei)XHvg@;4sW)0x}g&&n-N7`iZ!ERi=*Z4mxzPH}pRJaCfAg z0GC=;%g|-**p}rG|2`?DhY8FJ4@w?rq`!$HaI3Xoc3Mr#wnF?$c?@sQ)v=)_>wTx- zW%Td#qmGsdUeY-i2Jl5P10cT+TF;@pdoA8&dsBnf7B}lwimp27B&GEN?j(#6{K*oM zpaWCzJE`TFQcd99tK09-Tba=7A@nSU2B9)O0cV%L<_I|InFZRpw!Q@G#wBtGm)`oK z!&zU%dZ*k&{W~V$$=K8ht(D00bmsn;O-E}koRK>He4R&ovmvNR=7>LDn9)qprdRtC2o3C}bT!dd z-~a0?cw=13h7(Qz%4eE%WEiT%d0<(5CwTw}zqqQCh5MAnTWAW=QWz}tDxhjar#__iUzBjd)gk!1Da#M z2059j-;WwNEX6T$lWs9n3!{eqmvc(yh z1dFUpugW8dQ0!`}f|kF&Nb zu8i}AhdPbh8XzZGnS$aScLDDoUVS4vem|F53i{wnmBbuQgx;_a{D6t_B|E}m!jtrN zg`e_>C>E5~qyJGZ7{RkgZ;pVVwXdlUV-JgOSa(dg7~XfUhDR_vCIzix@#-93n>FT> zvDI2~KvUu3AU&PKo=Qq(+NoPPTl!O~oCZKu_KNxCIW%%J+*D(7)@^ZCFIn%NNObsE zyYb*-?u_mm^K~hkoCi|<3|uj5JP3pBXOGqUb%zMD(XL1MJ@HOv12j{BDW5uJLTn?M z=*(rfNs}SRieT2gM)%g!7k${8*g4Kazz5yFBv!Ic&nXzR6OIXq*jJ>Nw|&JqB;P|kYOl>rg*E=ZsKr{n`l?d>LuB4YCYg1YN^vd=m3%)c!p4|N-~6J0ZSj|wnt#f1 z7Hnw6lGtaf-~8X*S815~mzua|k?4!a~B) z+uA1YmE*28UF-PgrBPL&UIaLg8Q_d`og#X03tNY@rT1)HjLH+H_|k4j#&A-Oprxbq z(H9>#_)uxVuK7@@pSFaxmBcUDQRkz!;#Y+OUu(6299^Sn+_i0r6dwKg$b6q zy{WL?T<>Tl4dbO1K2P;0(ZyGe{|4;(-92zg?Yox0+BfQ$02&yLQ)mt4! zN$viyB%y$HjYa(vrLJWiphS`X=p`YXz_(gLxnR8@PLGYM;l-;GmwwNz+ieEJ4Oo`I zM*nm<6Q9dTZaCZoN2#c?&!R3l$rvr^NcPRV>9%%&Ka=Epxi?w)^GYO#z{@C%4CZW+`tTXnaykHiQ_mXS9s|Tzb6(td6DhLBfm* zm=RE3{FREtVH9`h-Iv&8y0je~NS z!xD;zA4#QfUJ3bJyx`YC&NAOGOBEHd%k}!H{JnU#$V}YqcF_Ciqi@O9y~{F3E@Sak zjy~3OLT^{T)DrJucrF-PO1Nh5FPyritr9a1o_I-R*uX;i@HMzjVhq&YBNM9i@}3}n z^#l#}JH|(-%}rEPAOT{?0&2uz5y>{h545`M0hm%0%;D7hRQ(>@eNBfW%A#A!n{#(# zZ~y($J+EJGL7=ssewlaYzqZTdm2A-o^i@wEKbFhQzpd^jGW%;kDe&O};X_#ROY;)C z&YskNX71mcL-DGReQb%v1|0$ksa(+-4Sco1zO;C9YelB4(tSh6Aj)D~3K#97E}ZIE zQx~k9n-?rw72ZoPUiDyD#bo#f&W01JbdorJLOvdqIMpQNRaf3$$mfFcHvtH2d!*Q0 zRDg#%2Yjn!B=a3xL^m>np`<0wj{|<(;k(1sS<>zY!p4Pr-u;EbuuB5}HozPH*vHLJ z-{V!MQ>xR+tcwWF35#&#BKGdm9-0Mx%LY;YgEXvuoWi?`IWG=~MS5_0tAh=tKq{dj z8;j^BBXL^Hg;4UY6G$;+v7?~UYhEy+oHBulA6oUl!G1eT>m{e(icV8p6d-G>>$>Rf ztF%3l%DA(i-R*sHxz9bvmehYBgI|Wku_3BN{)_~B_F-KfcAeJy|G|m3Xst4J@xW~F z>xT%l_mzr*7+~>XtixrkUxK7V7lPvr0FuCHmr`FSis3)jnnPDfpyeLz(YF6y4LuJ+ z^VQY$DZpDnUR^&y`lo)iX{<$q*gp^8skpDVsjy{AYLHjp&BaH8YzzhExmsBqhY>$4 zX^7k(WwYhKm&v~A@4?5>kCD(YeROEY1JBhL^g@OJQU>S!Aj!}VMBe%WM%rX6%c9Mo z_$%2P9U2e)f1f-FWA-23FsQ(mUx)^Q8chrBLcbOCUZrE0)gIv4JvYzy*aqfthliUv z6@PYBFTMO`Xbpp&l;bGT(*TKycYpKWv*#rrR)2{+)@3oVpF!vi-IWv)7g(DfVf_V# z)fAhUk;X(pEg{~Im@50kIT-ZJ-z|XJro5A53olOs9u2kVf)tNOwjKJIvTrB*CK+CC zQ+!We(-ID*uJs3lHsh3dN+SAYn4|i+b5niviFdn$ov$#RAw9zdS4A|_k^X%UhCuRc)yEMwg7EyA5e(}R;Ei%Yj+rNR?hxleuo8)+NC3kl8s7Tr6e+ekE?{N3a(v2`QvlacCGvgm0?fN-1UvPZnX- zORsG;FzB5S%}8=f7Y?;)rmtl#BJ$6YW2ry%i~inIjZ6nNV0bHYM5~7;;sQYMTCXn1 z2JUdWsU|JP)S!O%HC-)(28m*`j8Ow}vYVK+53;BKYaE>A<@#vOBZ6W`34@^f^qX|e zg+MJ4a#Ui*?&2uH)Od}y_RceCg)b&S<(Dur^*ES=nwf#ZrZ;#EIrw}Z4TAuvC&MUq zl^!B%6qj6l!!CJc*Zxk6rwD2;b@qurSwRf@Dbj_*G11|I;OV8z416vO;6lCAkivRJVD#=y;6gh>_#R}w90Pi)jfAA2v|wJ zCf@IN0;%c)ppIUY-B=F&GjdtPAzpP_rE$jL$u^Wd$X(N~LG9>)p-Mu_9(k^ZzRvKo zK8J?Wg^wc)OsYI0VCU>w6_txsO_?UKcR1MB7bQL@7z$9&4l@2|rC5Et`KNfU=Znt= z(e(NyPXp|TQS9!k=)3v%08cd9ZFlAQyHhj(e0AQ$z$+VN!MUdPCVor zW=l{_B1Q*7*5%RLc?Y;6{eu76@>fXJv|R=SyKv}kZ=TJrvX`csP`n=s>zUnlKx3S^ z4C%VBRVXPh8Joz%Gye8`SK&}!vjGk8L+igw09yG?!!sRisQ5pQ+5OcWfo4Y*>WdiO zp5>^eL^*dmQpSR0&E4fY$R|#w?1st0JqB4DRP>|t$|H|6bzjHSbOc)O%xlykOx1-9 zT@^ixUVgu3%stbph;36e)ur*lHmD{U+^Losg<>zm>@&h2>DlCq&Zyki4(sIKqQ-}0 zE8ZS$PNtb@EMXl?%*L`*KcXg7kA)q?Bs!DLB!c$DWJm5^=gr*-+e`P6sq4QQ{MPAX zy0e&G3@orUD6~==3klQRg8Pv^a zS-3QPRv~Zn71bG1Jn_pYB-t+RJ6;C(&f5KZz2)rBFVK2XAivK*LJzb@sf*e37O?M> z0sFCfY7232{HjuS`qF>GW28G2&o6Uj(cauh$EqkYNydaj*kZJB^D?fc--7&P%jOwe z-z{wc4BPXrysU1S=OmH@1+rb)Ew1;nMM(aRd+Nm|j zm@_<^lPOB!>!WLMpQx1WSMFiB&0>lZIn3Bvrk(>V?XL`adp8W?Ggch%Du0VqNiKH$n5NbXy!FG0M^PL3 z^H#hc!9merL&R=sNVGwNJ+wtOne`4^mwoJ=d(^@@=HP+XukURJH@q6tiWX29awi#O zhpQ7YcyGgPf#=Up;~d4JO_-Zy4e(y&=Joc_SsSY|(NfuH$cdL~CODG3#7C5Sh64*y zE6=oBE_x>#PbJ#FtkzS zUs;SVb;!=-zHT?bqWAdyXb~A8vbOEx^9F|&h`Oq@U>2bMJs)5=v=4b z^^BM-a*W)6wsQWM+9JO-r=y{{PwmKx=6=B$`QQF4fhV>)>FCbo?_X~n%DzHFO0>O= zGlpn0p%vHEQNLxLDOo9FlWG3je?@P1rS<*sKuy!1!Q-bvQ($7%1-5)`c(=72vkfFX z8#v})ow5C&S>QkbuQ6a_A}N1T)Cj;lwfOkwvQpV`2uQo*(% zsz2g?{Z=9O`VY|p+8Eg>Qp7O4BzuNkPgUjV?ZER}){SnQlM!QjAmA69|FlX)ou5{n zK-YLkP-;j{YuqHo15F-<5#7W`U#w=$2Lb=j?7<*p*lJ5#6p33DR8se_Hr9(z#o%C+ z)E?7mz0?pw0j^nhY)!iqp^qj{Kq+GIu{&=_PlGF=>_}E}SmQB&!T0d8<)na++ix;pT;^hWdXwbbPNl z8+;6?>ilC!9DPhEC(U1HQ^IF}zS;ICqA08`>j3J^qVC2m;X#5}+CK;~15)^_!rPh&@6lNbvJX|^9b`Wu>nKJlvi zLye=}Jli3rpD73qY3x+!oPb7|NZ1BuM{yS-A)<}Q45Vqp#jAtgLNQJb9WCZ_kET9~ zVjcRQRu9tN@U|Kd#hxU0KcbrcNGZb~#tLt0bf!<-AuP6%9KN5R^wJe;c3Jd*cw8Nw z>Ja3LeFGL6{ln(nlz4wPTg+8_J)|a(xU+EXoxWMDrg& zpnkq{<6)&VWxZ&`fmSShm_X`sE|b*{mDS5vBzWsdqnRpIlph`(_&&Wo`P9U=R70sp zv}9TL0(q6L(~=`c+n7-oy`NQNEdY_#CsOxqHkCpAirD+A$}KDxHI*B(@E2`+EH&FG zrPNjHk;ae!UglU)OFcO;KymdNm<ByONIBT+Q~He&yd&Z|BD3+&=#e%` zwcKQ)wg*5nJ-J1pfVM>G8rNB%ryck^E?@@m$i3e>BFGx*AL^3E28OX+}_-LnE zEJ962w2EItwrN*le_yeCCii9A(=Oq)qFpX~_o?PWqUwr`MijqPZ!<~bWpHV!Sofbl zJ%vgISESFIsm_duEy+@90=>X&2}jb!_^snu4RTuSNi|u8C!>Z?Ydb=yU-F-3d}R$^d3g-)Zr7UrfRl=*c&~3>$WA*MADJ@iT(acW+H_&&u6X#|ize=pCwh zRl?Gdi&m%&RN<1bA_V+F=-kHtk2)|f{*O7pdv%cMJa2m+vzx+o3*dcJ%ApQ6{+lpl zk@XXihh}KO{s8ss6eT}4Lqm2uvT?D9hc~jhzTf`1lf4x-YjEVJV)EjRL9=};4|RuHoC+J6`vG7GedV!Zy9Z-oZiN1n+x&VLMuVnl_%iymaAXG6r|0_vcIEYlgB^DKvSm~= ziCIBf$nJ=+fB6njVU4Wz@vvX!CPV%&E_=gkWn`64+k?-4$ACVQs7EFm`a#FL*-iIr zHFzHq!bzj-j|rbc$DLcFGjRiGHux#upKgXMN`_J`)70^ZqHwfO^}U_bZ*I&8!U=8< zz>1Q}q89Zu+WO9q*+azkUS^NXGAKsy2=Aaf5!aC}6W>c z`0s{_cYgVLg-1KfkcC4KQb1=B{aTP=6&gaD{h?qK)ONWLJsjWUNWXGdAAdy?Ohn7$ewTh*3crG z{qo)O;DWX9n!2=&2akWn)n4bFHD_=%8%p|~($bT9wXAV59&uw{tXylhH|@3<=|59n zV4jDLJ1#1-fS~L}o5!EknL6aIIQ|46l+g~gFHsPXLC$z`2_LoNzyeu(m}Rbj8k7mJ zA)Tl7O<{&WLP!gSi-of6a}Q97VeHeH*A{2TI)v|@s{o_l3=i2Yn7M=qw6R#+<8C%B z6YbwCG%)zwU_~h2eCPc4R$myeu=?jj^*dK0XK+Fww4jJ$7*3evHPUQtSo88eWkUgr zTzX*nGeF@GJy)c|9^;rBVX}xvMDvh4TF9ymDuPuNbU;%uCjGl+Rh(=Q=j|a!ZX=uW zkd;3P6}QZ3XxJ+M^S=Q4lEVLHu6vr#gtC<+n05U8BQ4|=zuYP`!=|Z!`BNdiqfrh9 za-IBXTh^C`i=St1XBL2n00pTed4<$l7hyPZ$fFP29}Jj=mgv>GyJPBNUX^SMl7-uYE_ zqp4MIdp%0@71BK;*!s(`;ID|9=I5(j;H0JR-T**d_w0&EY9#i@XwKien|OBNPbj&P zjZYEb^`7fKHl^ADFEb#vX=4W}cNw^B@;_VzNJcis=(?~Z`AY=djA%S>R@Sp9!MRXE zDXAw|?%RY_1%L9b)6KVy!}G2|ibtsqUE3tJgwv~W$gcm>&egv&y*BXUr5R?;Led<} z+a||jwXu0S%*M7NjXH?DrMyJu^(Z=RY&OhhR!WL#Q)(0{oDzl52_p^_waj}+*D1%- z!#U5l>v{f%=a=WV`*U5N>$*Spb>BaHzn}Z_xhat%=Zil>Dh5V$ss>^LPA-O;d_?oi zX)spt5C8Fuav)IA8A!twI!g(~mUk&gu$-(fuseQTp6__$k4^|a$_`~5@GHq5%G!AQ9KCzRxRuZQB>RcLNEAbA?`U zjuh+sQM?rRRs`*&?JX24mH2mMBs4S+3D!0{Rrk})6{jxlRmGkQv3^Xo-n~|ip;svP zi-IMPsqtAXP^>x%2mb)0OH$asPwLL+$nCL?Z3vD{A$Uw?HLT%`q;g7G8n&ljKxr11 zSqxTDY~0^LPgNZyS=+rQJkWzkEl?{*@Fu_O(|kn8zamxa^yQ?VyQNdtk;9X}>w@AMnwImHt?DEY@{VYWu zmScGTFk6srJ%xhl%)sGixHWV~bHs}Uy4`2Enh3E^=5Z++_)Vd5rz$+VMM%=;QAIeB zBV_yz1DkzQMC-s!E7YNGO=4po?vH61Moy)jS+DhirJGr%<#u916GYGGTlPaOUX3fH zbov!v`}kg5XW6;!1PkhSUP&6i zEM_x)u*GfdL5ka$6n*R)tAq7e%bn1=;nVUibBXdGqg#X-iyC!;L>M4`t0F{K>+e`> z1gy73{4HJCv!gH=!40H+VgPIDY(Y=qW*EbM3ueqLHk{sT#o5uCS*UTr1ShbI*+ysO zf%1ZS(JNgeVc1=3Ps)WWJbC)Kg z`#+5LIaytCPkeoJdLm%T*#|{1qrC?luVE$J6X;{1Fbj_pGZC2!;#3n{v8C-v8eX?V zjRih+Bdfg~vRYi#98r7D#E zyI!U8UmNn+V&Gj9J{}(WEG|3#{@emkb=w+NXDovbs~4OihG>9k&7td+rUkuNhZXFC z-Y?e0mNPJ1M|qzkN~F^cJ@Rr8-pkUscl{wrGZ10B9-7f^JM!oRs;NN+v!xkv-x z##5WUlsc&h#X|Y8){+Y+j0sC=qZ}h!cW>y9Xx{b#PVX9XC^lgIaub~?h(99voIOzK zDPA)s6cgd@a&0ZC=g=wP9E$O&%P3;Ev>+D~TFF7e$1J`7D zmaerU1^zrBArgr)?wLJFexRS&Co(*(Ow1bz3pw z6}c&Z263Ii+&@G~^pWrp^sD5=(mb@N0+$9?38ht&_*w(-;4GR^El<>uMyJV1YW9VaQ)zMWgDk*#do#WpIij*b+0oXoH1BNax* zfDePj)r9SX8n^t{@;ct{bpMHgO+QfKkGXo$1AWk*tR2g{8+zr${YV%FpZ}<~7Wz^h zPM*Bpk6l?{P&Rppq+^5eAN>>L%g?>X%1Z~r6Ls1*DfSkk4d9&_le^aJ zu}07#WV=vw+b~8s;kV+J>Z^}_ggSh^Ok5lK)NACJ5|Mh*W=J|Nv(3Sdx9}gj)JTi$ z(ee@;*sl=%rGhRw)nj~MnTFr~Yr*kpp|5_R|57?4v-z*berMvt-ham7V(a)R$^JIt z*UxCX?F^NbQ5o`pOvrK{wKrhN?cU(!A8qYt!|kapm9MmA9J$G- ze#0ZZCcN7E{XLzWaNX88GXA2*<3C)WuIX_h0=?T4ze7HksCc{MPwWq%MZTVwp4I?-k7pW|?8z1B+TcR(H z{oY0;wu$e$WKb>&L#5G5`2O*XnD(4L%uY5v6AG*`x~a7Vy>Ef@sWf`c{ovJBd68U#b2k{=`nYTRv&0G%v z@f%;7U4bbL%@yp_ZF!RqCjgq%Lc!jv*KsZr(0f-M5Y`YWJiGH74GVzU_v1sWfZikL zJ$F7ggrt6q253SK0I-{1UjZsRb%0g1vAkBpmjT)c0RF$2|K-kf{;f6c2FrC(yL1|O P-RnCl*`L%vjAZ>At>jlK literal 19460 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 diff --git a/public/images/pokemon/variant/332.json b/public/images/pokemon/variant/332.json index e9b487bca25..336ef4a22f3 100644 --- a/public/images/pokemon/variant/332.json +++ b/public/images/pokemon/variant/332.json @@ -1,34 +1,36 @@ { "1": { - "319452": "831a1f", - "4a7310": "982443", - "7ba563": "b44040", - "bdef84": "ec8c8c", "8cbd63": "c54b4b", - "215200": "710f2e", + "a5d670": "df5252", + "4aa552": "9f2f2c", "a5d674": "e16363", - "196b21": "891222", + "7aa953": "c54b4b", + "7ba563": "b44040", + "215200": "710f2e", "f7ce00": "7aa1df", "525252": "123a5a", - "63b56b": "b2332f", - "a5d673": "df5252", "8c6b3a": "448bc3", - "4aa552": "9f2f2c" + "bdef84": "ec8c8c", + "63b56b": "b2332f", + "319452": "831a1f", + "196b21": "891222", + "4a7310": "982443" }, "2": { - "319452": "b08d72", - "4a7310": "4f3956", - "7ba563": "704e7e", - "bdef84": "a779ba", "8cbd63": "e3d7a6", - "215200": "583823", + "a5d670": "d7cda7", + "4aa552": "c5a77f", "a5d674": "8c669b", - "196b21": "78582c", + "7aa953": "704e7e", + "7ba563": "704e7e", + "215200": "583823", "f7ce00": "f2aacd", "525252": "a53b6f", - "63b56b": "cfc191", - "a5d673": "d7cda7", "8c6b3a": "df87bb", - "4aa552": "c5a77f" + "bdef84": "a779ba", + "63b56b": "cfc191", + "319452": "b08d72", + "196b21": "78582c", + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/332.json b/public/images/pokemon/variant/back/332.json index c13c07c34b4..fbfb3705202 100644 --- a/public/images/pokemon/variant/back/332.json +++ b/public/images/pokemon/variant/back/332.json @@ -1,28 +1,28 @@ { "1": { + "196b21": "831a1f", + "7ba563": "b44040", + "215201": "630d28", + "215200": "710f2f", + "a5d674": "df5252", + "8cbd63": "c54b4b", + "63b56b": "b2332f", + "a5d670": "e16363", "319452": "831a1f", "4aa552": "9f2f2c", - "7ba563": "b44040", - "8cbd63": "c54b4b", - "215200": "710f2f", - "196b21": "831a1f", - "a5d674": "df5252", - "4a7310": "982443", - "a5d673": "e16363", - "63b56b": "b2332f", - "215201": "630d28" + "4a7310": "982443" }, "2": { + "196b21": "b08d72", + "7ba563": "704e7e", + "215201": "583823", + "215200": "3f3249", + "a5d674": "d7cda7", + "8cbd63": "e3d7a6", + "63b56b": "cfc191", + "a5d670": "8c669b", "319452": "b08d72", "4aa552": "c5a77f", - "7ba563": "704e7e", - "8cbd63": "e3d7a6", - "215200": "3f3249", - "196b21": "b08d72", - "a5d674": "d7cda7", - "4a7310": "4f3956", - "a5d673": "8c669b", - "63b56b": "cfc191", - "215201": "583823" + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/332.json b/public/images/pokemon/variant/back/female/332.json index 9ec50cb7e92..17f8d3c5f74 100644 --- a/public/images/pokemon/variant/back/female/332.json +++ b/public/images/pokemon/variant/back/female/332.json @@ -1,28 +1,28 @@ { "1": { + "196b21": "780d4a", + "7ba563": "b44040", + "215201": "710f2e", + "215200": "710f2f", + "a5d674": "de5b6f", + "8cbd63": "bf3d64", + "63b56b": "9e2056", + "a5d670": "e16363", "319452": "780d4a", "4aa552": "8a1652", - "7ba563": "b44040", - "8cbd63": "bf3d64", - "215200": "710f2f", - "196b21": "780d4a", - "a5d674": "de5b6f", - "4a7310": "982443", - "a5d673": "e16363", - "63b56b": "9e2056", - "215201": "710f2e" + "4a7310": "982443" }, "2": { + "196b21": "b59c72", + "7ba563": "805a9c", + "215201": "694d37", + "215200": "41334d", + "a5d674": "f6f7df", + "8cbd63": "ebe9ca", + "63b56b": "e3ddb8", + "a5d670": "a473ba", "319452": "b59c72", "4aa552": "c9b991", - "7ba563": "805a9c", - "8cbd63": "ebe9ca", - "215200": "41334d", - "196b21": "b59c72", - "a5d674": "f6f7df", - "4a7310": "4f3956", - "a5d673": "a473ba", - "63b56b": "e3ddb8", - "215201": "694d37" + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/female/332.json b/public/images/pokemon/variant/female/332.json index c86429d13c4..7a1dc0f1457 100644 --- a/public/images/pokemon/variant/female/332.json +++ b/public/images/pokemon/variant/female/332.json @@ -1,34 +1,36 @@ { "1": { - "319452": "780d4a", - "4a7310": "982443", - "7ba563": "b44040", - "bdef84": "ec8c8c", "8cbd63": "bf3d64", - "215200": "710f2e", + "a5d670": "de5b6f", + "4aa552": "8a1652", "a5d674": "e16363", - "196b21": "7d1157", + "7aa953": "bf3d64", + "7ba563": "b44040", + "215200": "710f2e", "f7ce00": "5bcfc3", "525252": "20668c", - "63b56b": "9e2056", - "a5d673": "de5b6f", "8c6b3a": "33a3b0", - "4aa552": "8a1652" + "bdef84": "ec8c8c", + "63b56b": "9e2056", + "319452": "780d4a", + "196b21": "7d1157", + "4a7310": "982443" }, "2": { - "319452": "b59c72", - "4a7310": "4f3956", - "7ba563": "805a9c", - "bdef84": "c193cf", "8cbd63": "f6f7df", - "215200": "694d37", + "a5d670": "ebe9ca", + "4aa552": "c9b991", "a5d674": "a473ba", - "196b21": "9c805f", + "7aa953": "805a9c", + "7ba563": "805a9c", + "215200": "694d37", "f7ce00": "f2aab6", "525252": "983364", - "63b56b": "e3ddb8", - "a5d673": "ebe9ca", "8c6b3a": "df879f", - "4aa552": "c9b991" + "bdef84": "c193cf", + "63b56b": "e3ddb8", + "319452": "b59c72", + "196b21": "9c805f", + "4a7310": "4f3956" } } \ No newline at end of file From e053ead67cbe4c19aeadb9d61ae5bb791c7a0411 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sun, 25 May 2025 13:37:52 -0500 Subject: [PATCH 02/12] [Bug] Fix crash caused by switching in a transformed pokemon (#5864) * Force reset summon data and load assets prior to switch in * Update src/phases/switch-summon-phase.ts --- src/phases/switch-summon-phase.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index a063b6e6863..3e9cc7718f1 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -124,6 +124,12 @@ export class SwitchSummonPhase extends SummonPhase { const switchedInPokemon: Pokemon | undefined = party[this.slotIndex]; this.lastPokemon = this.getPokemon(); + // Defensive programming: Overcome the bug where the summon data has somehow not been reset + // prior to switching in a new Pokemon. + // Force the switch to occur and load the assets for the new pokemon, ignoring override. + switchedInPokemon.resetSummonData(); + switchedInPokemon.loadAssets(true); + applyPreSummonAbAttrs(PreSummonAbAttr, switchedInPokemon); applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); if (!switchedInPokemon) { @@ -131,6 +137,7 @@ export class SwitchSummonPhase extends SummonPhase { return; } + if (this.switchType === SwitchType.BATON_PASS) { // If switching via baton pass, update opposing tags coming from the prior pokemon (this.player ? globalScene.getEnemyField() : globalScene.getPlayerField()).forEach((enemyPokemon: Pokemon) => From b803f6f18a9b7a921dff2910bfd440814032bf5e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 27 May 2025 02:38:30 -0700 Subject: [PATCH 03/12] [i18n] Update locales (#5875) --- public/locales | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales b/public/locales index 42cd5cf577f..e9ccbadb6ea 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 42cd5cf577f475c22bc82d55e7ca358eb4f3184f +Subproject commit e9ccbadb6eaa3b797f3dec919745befda2ec74bd From 999cbf911e900723a433a8d949f8cfb2084421d0 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 27 May 2025 03:56:52 -0700 Subject: [PATCH 04/12] [Bug] Fix Pichu form weights (61.5 -> 2) --- src/data/pokemon-species.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 59167ba47f6..6f05d17db6f 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1697,8 +1697,8 @@ export function initSpecies() { new PokemonSpecies(Species.CHINCHOU, 2, false, false, false, "Angler Pokémon", PokemonType.WATER, PokemonType.ELECTRIC, 0.5, 12, Abilities.VOLT_ABSORB, Abilities.ILLUMINATE, Abilities.WATER_ABSORB, 330, 75, 38, 38, 56, 56, 67, 190, 50, 66, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.LANTURN, 2, false, false, false, "Light Pokémon", PokemonType.WATER, PokemonType.ELECTRIC, 1.2, 22.5, Abilities.VOLT_ABSORB, Abilities.ILLUMINATE, Abilities.WATER_ABSORB, 460, 125, 58, 58, 76, 76, 67, 75, 50, 161, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.PICHU, 2, false, false, false, "Tiny Mouse Pokémon", PokemonType.ELECTRIC, null, 0.3, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, GrowthRate.MEDIUM_FAST, 50, false, false, - new PokemonForm("Normal", "", PokemonType.ELECTRIC, null, 1.4, 61.5, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), - new PokemonForm("Spiky-Eared", "spiky", PokemonType.ELECTRIC, null, 1.4, 61.5, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), + new PokemonForm("Normal", "", PokemonType.ELECTRIC, null, 1.4, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), + new PokemonForm("Spiky-Eared", "spiky", PokemonType.ELECTRIC, null, 1.4, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), ), new PokemonSpecies(Species.CLEFFA, 2, false, false, false, "Star Shape Pokémon", PokemonType.FAIRY, null, 0.3, 3, Abilities.CUTE_CHARM, Abilities.MAGIC_GUARD, Abilities.FRIEND_GUARD, 218, 50, 25, 28, 45, 55, 15, 150, 140, 44, GrowthRate.FAST, 25, false), new PokemonSpecies(Species.IGGLYBUFF, 2, false, false, false, "Balloon Pokémon", PokemonType.NORMAL, PokemonType.FAIRY, 0.3, 1, Abilities.CUTE_CHARM, Abilities.COMPETITIVE, Abilities.FRIEND_GUARD, 210, 90, 30, 15, 40, 20, 15, 170, 50, 42, GrowthRate.FAST, 25, false), From a98f89759169201b671e1f17c973dce81af28bab Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 27 May 2025 05:02:39 -0700 Subject: [PATCH 05/12] [Bug] Fix Dipplin's weight (was mistakenly set to the lbs value) --- src/data/pokemon-species.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 6f05d17db6f..5c97f360094 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3121,7 +3121,7 @@ export function initSpecies() { ), new PokemonSpecies(Species.WALKING_WAKE, 9, false, false, false, "Paradox Pokémon", PokemonType.WATER, PokemonType.DRAGON, 3.5, 280, Abilities.PROTOSYNTHESIS, Abilities.NONE, Abilities.NONE, 590, 99, 83, 91, 125, 83, 109, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Gouging Fire and Raging Bolt new PokemonSpecies(Species.IRON_LEAVES, 9, false, false, false, "Paradox Pokémon", PokemonType.GRASS, PokemonType.PSYCHIC, 1.5, 125, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 90, 130, 88, 70, 108, 104, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Iron Boulder and Iron Crown - new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", PokemonType.GRASS, PokemonType.DRAGON, 0.4, 9.7, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, 50, false), + new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", PokemonType.GRASS, PokemonType.DRAGON, 0.4, 4.4, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, 50, false), new PokemonSpecies(Species.POLTCHAGEIST, 9, false, false, false, "Matcha Pokémon", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, GrowthRate.SLOW, null, false, false, new PokemonForm("Counterfeit Form", "counterfeit", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, true), new PokemonForm("Artisan Form", "artisan", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, false, true), From 6c676f1f11215a23826432bd552be5cd22c1195e Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Tue, 27 May 2025 15:41:06 -0500 Subject: [PATCH 06/12] [Misc] Add decrypt-save.js utility script (#5731) * Add decrypt-save.js * Update scripts/decrypt-save.js Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> --------- Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> --- scripts/decrypt-save.js | 149 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 scripts/decrypt-save.js diff --git a/scripts/decrypt-save.js b/scripts/decrypt-save.js new file mode 100644 index 00000000000..a7239a40df6 --- /dev/null +++ b/scripts/decrypt-save.js @@ -0,0 +1,149 @@ +import pkg from "crypto-js"; +const { AES, enc } = pkg; +// biome-ignore lint: This is how you import fs from node +import * as fs from "node:fs"; + +const SAVE_KEY = "x0i2O7WRiANTqPmZ"; + +/** + * A map of condensed keynames to their associated full names + * NOTE: Update this if `src/system/game-data#systemShortKeys` ever changes! + */ +const systemShortKeys = { + seenAttr: "$sa", + caughtAttr: "$ca", + natureAttr: "$na", + seenCount: "$s", + caughtCount: "$c", + hatchedCount: "$hc", + ivs: "$i", + moveset: "$m", + eggMoves: "$em", + candyCount: "$x", + friendship: "$f", + abilityAttr: "$a", + passiveAttr: "$pa", + valueReduction: "$vr", + classicWinCount: "$wc", +}; + +/** + * Replace the shortened key names with their full names + * @param {string} dataStr - The string to convert + * @returns {string} The string with shortened keynames replaced with full names + */ +function convertSystemDataStr(dataStr) { + const fromKeys = Object.values(systemShortKeys); + const toKeys = Object.keys(systemShortKeys); + for (const k in fromKeys) { + dataStr = dataStr.replace(new RegExp(`${fromKeys[k].replace("$", "\\$")}`, "g"), toKeys[k]); + } + + return dataStr; +} + +/** + * Decrypt a save + * @param {string} path - The path to the encrypted save file + * @returns {string} The decrypted save data + */ +function decryptSave(path) { + // Check if the file exists + if (!fs.existsSync(path)) { + console.error(`File not found: ${path}`); + process.exit(1); + } + let fileData; + try { + fileData = fs.readFileSync(path, "utf8"); + } catch (e) { + switch (e.code) { + case "ENOENT": + console.error(`File not found: ${path}`); + break; + case "EACCES": + console.error(`Could not open ${path}: Permission denied`); + break; + case "EISDIR": + console.error(`Unable to read ${path} as it is a directory`); + break; + default: + console.error(`Error reading file: ${e.message}`); + } + process.exit(1); + } + return convertSystemDataStr(AES.decrypt(fileData, SAVE_KEY).toString(enc.Utf8)); +} + +/* Print the usage message and exits */ +function printUsage() { + console.log(` +Usage: node decrypt-save.js [save-file] + +Arguments: + file-path Path to the encrypted save file to decrypt. + save-file Path to where the decrypted data should be written. If not provided, the decrypted data will be printed to the console. + +Options: + -h, --help Show this help message and exit. + +Description: + This script decrypts an encrypted pokerogue save file +`); +} + +/** + * Write `data` to `filePath`, gracefully communicating errors that arise + * @param {string} filePath + * @param {string} data + */ +function writeToFile(filePath, data) { + try { + fs.writeFileSync(filePath, data); + } catch (e) { + switch (e.code) { + case "EACCES": + console.error(`Could not open ${filePath}: Permission denied`); + break; + case "EISDIR": + console.error(`Unable to write to ${filePath} as it is a directory`); + break; + default: + console.error(`Error writing file: ${e.message}`); + } + process.exit(1); + } +} + +function main() { + let args = process.argv.slice(2); + // Get options + const options = args.filter(arg => arg.startsWith("-")); + // get args + args = args.filter(arg => !arg.startsWith("-")); + + if (args.length === 0 || options.includes("-h") || options.includes("--help") || args.length > 2) { + printUsage(); + process.exit(0); + } + // If the user provided a second argument, check if the file exists already and refuse to write to it. + if (args.length === 2) { + const destPath = args[1]; + if (fs.existsSync(destPath)) { + console.error(`Refusing to overwrite ${destPath}`); + process.exit(1); + } + } + + // Otherwise, commence decryption. + const decrypt = decryptSave(args[0]); + + if (args.length === 1) { + process.stdout.write(decrypt); + process.exit(0); + } + + writeToFile(destPath, decrypt); +} + +main(); From 2deced5565c92e5f9d99a6cd8fbb683d767ce105 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Tue, 27 May 2025 16:46:56 -0500 Subject: [PATCH 07/12] [Bug][Move] Allow gastro acid to suppress passives if main ability is unsuppressable (#5854) * Allow gastro acid to suppress passives if main ability is unsuppressable * Update gastro_acid.test.ts * Update src/data/moves/move.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Add test to ensure unsuppressable main ability is not suppressed --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/moves/move.ts | 2 +- test/moves/gastro_acid.test.ts | 29 ++++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 31ad3337926..8a0da5f35c2 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -7521,7 +7521,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr { /** Causes the effect to fail when the target's ability is unsupressable or already suppressed. */ getCondition(): MoveConditionFunc { - return (user, target, move) => target.getAbility().isSuppressable && !target.summonData.abilitySuppressed; + return (_user, target, _move) => !target.summonData.abilitySuppressed && (target.getAbility().isSuppressable || (target.hasPassive() && target.getPassiveAbility().isSuppressable)); } } diff --git a/test/moves/gastro_acid.test.ts b/test/moves/gastro_acid.test.ts index 8247d29c0a0..333619d16db 100644 --- a/test/moves/gastro_acid.test.ts +++ b/test/moves/gastro_acid.test.ts @@ -25,7 +25,7 @@ describe("Moves - Gastro Acid", () => { game.override.battleStyle("double"); game.override.startingLevel(1); game.override.enemyLevel(100); - game.override.ability(Abilities.NONE); + game.override.ability(Abilities.BALL_FETCH); game.override.moveset([Moves.GASTRO_ACID, Moves.WATER_GUN, Moves.SPLASH, Moves.CORE_ENFORCER]); game.override.enemySpecies(Species.BIDOOF); game.override.enemyMoveset(Moves.SPLASH); @@ -40,7 +40,7 @@ describe("Moves - Gastro Acid", () => { * - player mon 1 should have dealt damage, player mon 2 should have not */ - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.GASTRO_ACID, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); @@ -63,7 +63,7 @@ describe("Moves - Gastro Acid", () => { it("fails if used on an enemy with an already-suppressed ability", async () => { game.override.battleStyle("single"); - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.CORE_ENFORCER); // Force player to be slower to enable Core Enforcer to proc its suppression effect @@ -77,4 +77,27 @@ describe("Moves - Gastro Acid", () => { expect(game.scene.getPlayerPokemon()!.getLastXMoves()[0].result).toBe(MoveResult.FAIL); }); + + it("should suppress the passive of a target even if its main ability is unsuppressable and not suppress main abli", async () => { + game.override + .enemyAbility(Abilities.COMATOSE) + .enemyPassiveAbility(Abilities.WATER_ABSORB) + .moveset([Moves.SPLASH, Moves.GASTRO_ACID, Moves.WATER_GUN]); + await game.classicMode.startBattle([Species.MAGIKARP]); + + const enemyPokemon = game.scene.getEnemyPokemon(); + + game.move.select(Moves.GASTRO_ACID); + await game.toNextTurn(); + expect(enemyPokemon?.summonData.abilitySuppressed).toBe(true); + + game.move.select(Moves.WATER_GUN); + await game.toNextTurn(); + expect(enemyPokemon?.getHpRatio()).toBeLessThan(1); + + game.move.select(Moves.SPORE); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemyPokemon?.status?.effect).toBeFalsy(); + }); }); From c236996a02f581f9fd54c873d4aba5cfd4836eeb Mon Sep 17 00:00:00 2001 From: Lugiad <2070109+Adri1@users.noreply.github.com> Date: Wed, 28 May 2025 00:08:49 +0200 Subject: [PATCH 08/12] [UI/UX] [Localization] starterInfoText adjustments and clean up (#5859) * starterInfoText adjustments and clean up * starterInfoText adjustments and clean up * Update starter-select-ui-handler.ts * Update starter-select-ui-handler.ts --------- Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com> --- src/ui/starter-select-ui-handler.ts | 41 +++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 80acac6a6b4..a971ba86479 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -108,17 +108,21 @@ const languageSettings: { [key: string]: LanguageSetting } = { instructionTextSize: "38px", }, de: { - starterInfoTextSize: "48px", + starterInfoTextSize: "54px", instructionTextSize: "35px", - starterInfoXPos: 33, + starterInfoXPos: 35, }, "es-ES": { - starterInfoTextSize: "52px", - instructionTextSize: "35px", + starterInfoTextSize: "50px", + instructionTextSize: "38px", + starterInfoYOffset: 0.5, + starterInfoXPos: 38, }, "es-MX": { - starterInfoTextSize: "52px", - instructionTextSize: "35px", + starterInfoTextSize: "50px", + instructionTextSize: "38px", + starterInfoYOffset: 0.5, + starterInfoXPos: 38, }, fr: { starterInfoTextSize: "54px", @@ -128,21 +132,16 @@ const languageSettings: { [key: string]: LanguageSetting } = { starterInfoTextSize: "56px", instructionTextSize: "38px", }, - pt_BR: { - starterInfoTextSize: "47px", - instructionTextSize: "38px", + "pt-BR": { + starterInfoTextSize: "48px", + instructionTextSize: "42px", + starterInfoYOffset: 0.5, starterInfoXPos: 33, }, zh: { - starterInfoTextSize: "47px", - instructionTextSize: "38px", - starterInfoYOffset: 1, - starterInfoXPos: 24, - }, - pt: { - starterInfoTextSize: "48px", - instructionTextSize: "42px", - starterInfoXPos: 33, + starterInfoTextSize: "56px", + instructionTextSize: "36px", + starterInfoXPos: 26, }, ko: { starterInfoTextSize: "60px", @@ -156,9 +155,11 @@ const languageSettings: { [key: string]: LanguageSetting } = { starterInfoYOffset: 0.5, starterInfoXPos: 33, }, - "ca-ES": { - starterInfoTextSize: "52px", + ca: { + starterInfoTextSize: "48px", instructionTextSize: "38px", + starterInfoYOffset: 0.5, + starterInfoXPos: 29, }, }; From d5789105f344abd6b6234d2b14410d03ae91e4bf Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Wed, 28 May 2025 12:29:03 -0500 Subject: [PATCH 09/12] [Refactor][UI/UX] Cleanup battle-info ui code (#5696) * Create battle-info directory and move battle-info.ts to it * Move player and enemy battle info to their own files * Move subclass specific parts of constructor to subclass constructor * Fixup mock gameobject methods to match phaser gameobject returns * Make statOrder specific to subclass * Create getShinyDescriptor function in utils * Move icon construction to its own function * Cleanup enemybattleinfo constructor to use chaining * Make flyout exclusive to EnemyBattleInfo * Move EnemyPokemon specific init Logic to its class * Break up initInfo into different methods * Remove hp bar segment dividers from base battle info * Move setMini to pokemoninfo * Breakup updateInfo into smaller parts * Remove hp info handling from base updateInfo * Use phaser object chaining methods * Add some docs * Add missing chain usage * Use getShinyDescriptor in pokemon-info-container * Minor cleanup of updatePokemonExp * Fixup setSizeToFrame mock * Ensure pokemon hp numbers are not visible during stat display * Update src/utils/common.ts Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com> * Make summary-ui-handler use new shinyDescriptor method * Remove `undefined` parameter pass Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> * Address kev's review comments Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Ensure hp number display fades in/out * Ensure ribbon and caught indicator fade with stat display * Update src/ui/battle-info/battle-info.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Move construction of stats and type icons to their own methods * Make setPositionRelative return this * Improve doc comment on paddingX param * Fix mock sprite's setPositionRelative --------- Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/field/pokemon.ts | 31 +- src/main.ts | 2 +- src/typings/phaser/index.d.ts | 12 +- src/ui-inputs.ts | 2 +- src/ui/battle-flyout.ts | 4 +- src/ui/battle-info.ts | 986 ------------------ src/ui/battle-info/battle-info.ts | 688 ++++++++++++ src/ui/battle-info/enemy-battle-info.ts | 235 +++++ src/ui/battle-info/player-battle-info.ts | 242 +++++ src/ui/fight-ui-handler.ts | 6 +- src/ui/pokemon-info-container.ts | 27 +- src/ui/summary-ui-handler.ts | 26 +- src/utils/common.ts | 16 + test/testUtils/mocks/mockGameObject.ts | 1 + .../mocks/mocksContainer/mockContainer.ts | 187 ++-- .../mocks/mocksContainer/mockGraphics.ts | 53 +- .../mocks/mocksContainer/mockRectangle.ts | 42 +- .../mocks/mocksContainer/mockSprite.ts | 153 +-- .../mocks/mocksContainer/mockText.ts | 104 +- test/testUtils/testFileInitialization.ts | 4 +- 20 files changed, 1602 insertions(+), 1219 deletions(-) delete mode 100644 src/ui/battle-info.ts create mode 100644 src/ui/battle-info/battle-info.ts create mode 100644 src/ui/battle-info/enemy-battle-info.ts create mode 100644 src/ui/battle-info/player-battle-info.ts diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 85b003517a6..329ba06fd09 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5,7 +5,9 @@ import { globalScene } from "#app/global-scene"; import type { Variant } from "#app/sprites/variant"; import { populateVariantColors, variantColorCache } from "#app/sprites/variant"; import { variantData } from "#app/sprites/variant"; -import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "#app/ui/battle-info"; +import BattleInfo from "#app/ui/battle-info/battle-info"; +import { EnemyBattleInfo } from "#app/ui/battle-info/enemy-battle-info"; +import { PlayerBattleInfo } from "#app/ui/battle-info/player-battle-info"; import type Move from "#app/data/moves/move"; import { HighCritAttr, @@ -3347,22 +3349,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } - /** - * Show or hide the type effectiveness multiplier window - * Passing undefined will hide the window - */ - updateEffectiveness(effectiveness?: string) { - this.battleInfo.updateEffectiveness(effectiveness); - } - toggleStats(visible: boolean): void { this.battleInfo.toggleStats(visible); } - toggleFlyout(visible: boolean): void { - this.battleInfo.toggleFlyout(visible); - } - /** * Adds experience to this PlayerPokemon, subject to wave based level caps. * @param exp The amount of experience to add @@ -5518,6 +5508,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } export class PlayerPokemon extends Pokemon { + protected battleInfo: PlayerBattleInfo; public compatibleTms: Moves[]; constructor( @@ -6038,6 +6029,7 @@ export class PlayerPokemon extends Pokemon { } export class EnemyPokemon extends Pokemon { + protected battleInfo: EnemyBattleInfo; public trainerSlot: TrainerSlot; public aiType: AiType; public bossSegments: number; @@ -6709,6 +6701,19 @@ export class EnemyPokemon extends Pokemon { return ret; } + + + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + this.battleInfo.updateEffectiveness(effectiveness); + } + + toggleFlyout(visible: boolean): void { + this.battleInfo.toggleFlyout(visible); + } } /** diff --git a/src/main.ts b/src/main.ts index 7db663d14c7..38bfcbe5636 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,7 +29,7 @@ window.addEventListener("unhandledrejection", event => { const setPositionRelative = function (guideObject: Phaser.GameObjects.GameObject, x: number, y: number) { const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX)); const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY)); - this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); + return this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); }; Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative; diff --git a/src/typings/phaser/index.d.ts b/src/typings/phaser/index.d.ts index f3665768cec..26fbcff75bd 100644 --- a/src/typings/phaser/index.d.ts +++ b/src/typings/phaser/index.d.ts @@ -20,37 +20,37 @@ declare module "phaser" { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Sprite { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Image { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface NineSlice { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Text { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Rectangle { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } } diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 0c13cdb9512..e4f11e1c93c 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -161,7 +161,7 @@ export class UiInputs { buttonInfo(pressed = true): void { if (globalScene.showMovesetFlyout) { - for (const p of globalScene.getField().filter(p => p?.isActive(true))) { + for (const p of globalScene.getEnemyField().filter(p => p?.isActive(true))) { p.toggleFlyout(pressed); } } diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index e590bebcf5a..f8ef5fc1ec4 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -1,4 +1,4 @@ -import type { default as Pokemon } from "../field/pokemon"; +import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; import { fixedInt } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; @@ -126,7 +126,7 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { * Links the given {@linkcode Pokemon} and subscribes to the {@linkcode BattleSceneEventType.MOVE_USED} event * @param pokemon {@linkcode Pokemon} to link to this flyout */ - initInfo(pokemon: Pokemon) { + initInfo(pokemon: EnemyPokemon) { this.pokemon = pokemon; this.name = `Flyout ${getPokemonNameWithAffix(this.pokemon)}`; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts deleted file mode 100644 index 2822e8364ec..00000000000 --- a/src/ui/battle-info.ts +++ /dev/null @@ -1,986 +0,0 @@ -import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; -import { getLevelTotalExp, getLevelRelExp } from "../data/exp"; -import { getLocalizedSpriteKey, fixedInt } from "#app/utils/common"; -import { addTextObject, TextStyle } from "./text"; -import { getGenderSymbol, getGenderColor, Gender } from "../data/gender"; -import { StatusEffect } from "#enums/status-effect"; -import { globalScene } from "#app/global-scene"; -import { getTypeRgb } from "#app/data/type"; -import { PokemonType } from "#enums/pokemon-type"; -import { getVariantTint } from "#app/sprites/variant"; -import { Stat } from "#enums/stat"; -import BattleFlyout from "./battle-flyout"; -import { WindowVariant, addWindow } from "./ui-theme"; -import i18next from "i18next"; -import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; - -export default class BattleInfo extends Phaser.GameObjects.Container { - public static readonly EXP_GAINS_DURATION_BASE = 1650; - - private baseY: number; - - private player: boolean; - private mini: boolean; - private boss: boolean; - private bossSegments: number; - private offset: boolean; - private lastName: string | null; - private lastTeraType: PokemonType; - private lastStatus: StatusEffect; - private lastHp: number; - private lastMaxHp: number; - private lastHpFrame: string | null; - private lastExp: number; - private lastLevelExp: number; - private lastLevel: number; - private lastLevelCapped: boolean; - private lastStats: string; - - private box: Phaser.GameObjects.Sprite; - private nameText: Phaser.GameObjects.Text; - private genderText: Phaser.GameObjects.Text; - private ownedIcon: Phaser.GameObjects.Sprite; - private championRibbon: Phaser.GameObjects.Sprite; - private teraIcon: Phaser.GameObjects.Sprite; - private shinyIcon: Phaser.GameObjects.Sprite; - private fusionShinyIcon: Phaser.GameObjects.Sprite; - private splicedIcon: Phaser.GameObjects.Sprite; - private statusIndicator: Phaser.GameObjects.Sprite; - private levelContainer: Phaser.GameObjects.Container; - private hpBar: Phaser.GameObjects.Image; - private hpBarSegmentDividers: Phaser.GameObjects.Rectangle[]; - private levelNumbersContainer: Phaser.GameObjects.Container; - private hpNumbersContainer: Phaser.GameObjects.Container; - private type1Icon: Phaser.GameObjects.Sprite; - private type2Icon: Phaser.GameObjects.Sprite; - private type3Icon: Phaser.GameObjects.Sprite; - private expBar: Phaser.GameObjects.Image; - - // #region Type effectiveness hint objects - private effectivenessContainer: Phaser.GameObjects.Container; - private effectivenessWindow: Phaser.GameObjects.NineSlice; - private effectivenessText: Phaser.GameObjects.Text; - private currentEffectiveness?: string; - // #endregion - - public expMaskRect: Phaser.GameObjects.Graphics; - - private statsContainer: Phaser.GameObjects.Container; - private statsBox: Phaser.GameObjects.Sprite; - private statValuesContainer: Phaser.GameObjects.Container; - private statNumbers: Phaser.GameObjects.Sprite[]; - - public flyoutMenu?: BattleFlyout; - - private statOrder: Stat[]; - private readonly statOrderPlayer = [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; - private readonly statOrderEnemy = [Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; - - constructor(x: number, y: number, player: boolean) { - super(globalScene, x, y); - this.baseY = y; - this.player = player; - this.mini = !player; - this.boss = false; - this.offset = false; - this.lastName = null; - this.lastTeraType = PokemonType.UNKNOWN; - this.lastStatus = StatusEffect.NONE; - this.lastHp = -1; - this.lastMaxHp = -1; - this.lastHpFrame = null; - this.lastExp = -1; - this.lastLevelExp = -1; - this.lastLevel = -1; - - // Initially invisible and shown via Pokemon.showInfo - this.setVisible(false); - - this.box = globalScene.add.sprite(0, 0, this.getTextureName()); - this.box.setName("box"); - this.box.setOrigin(1, 0.5); - this.add(this.box); - - this.nameText = addTextObject(player ? -115 : -124, player ? -15.2 : -11.2, "", TextStyle.BATTLE_INFO); - this.nameText.setName("text_name"); - this.nameText.setOrigin(0, 0); - this.add(this.nameText); - - this.genderText = addTextObject(0, 0, "", TextStyle.BATTLE_INFO); - this.genderText.setName("text_gender"); - this.genderText.setOrigin(0, 0); - this.genderText.setPositionRelative(this.nameText, 0, 2); - this.add(this.genderText); - - if (!this.player) { - this.ownedIcon = globalScene.add.sprite(0, 0, "icon_owned"); - this.ownedIcon.setName("icon_owned"); - this.ownedIcon.setVisible(false); - this.ownedIcon.setOrigin(0, 0); - this.ownedIcon.setPositionRelative(this.nameText, 0, 11.75); - this.add(this.ownedIcon); - - this.championRibbon = globalScene.add.sprite(0, 0, "champion_ribbon"); - this.championRibbon.setName("icon_champion_ribbon"); - this.championRibbon.setVisible(false); - this.championRibbon.setOrigin(0, 0); - this.championRibbon.setPositionRelative(this.nameText, 8, 11.75); - this.add(this.championRibbon); - } - - this.teraIcon = globalScene.add.sprite(0, 0, "icon_tera"); - this.teraIcon.setName("icon_tera"); - this.teraIcon.setVisible(false); - this.teraIcon.setOrigin(0, 0); - this.teraIcon.setScale(0.5); - this.teraIcon.setPositionRelative(this.nameText, 0, 2); - this.teraIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.teraIcon); - - this.shinyIcon = globalScene.add.sprite(0, 0, "shiny_star"); - this.shinyIcon.setName("icon_shiny"); - this.shinyIcon.setVisible(false); - this.shinyIcon.setOrigin(0, 0); - this.shinyIcon.setScale(0.5); - this.shinyIcon.setPositionRelative(this.nameText, 0, 2); - this.shinyIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.shinyIcon); - - this.fusionShinyIcon = globalScene.add.sprite(0, 0, "shiny_star_2"); - this.fusionShinyIcon.setName("icon_fusion_shiny"); - this.fusionShinyIcon.setVisible(false); - this.fusionShinyIcon.setOrigin(0, 0); - this.fusionShinyIcon.setScale(0.5); - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - this.add(this.fusionShinyIcon); - - this.splicedIcon = globalScene.add.sprite(0, 0, "icon_spliced"); - this.splicedIcon.setName("icon_spliced"); - this.splicedIcon.setVisible(false); - this.splicedIcon.setOrigin(0, 0); - this.splicedIcon.setScale(0.5); - this.splicedIcon.setPositionRelative(this.nameText, 0, 2); - this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.splicedIcon); - - this.statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses")); - this.statusIndicator.setName("icon_status"); - this.statusIndicator.setVisible(false); - this.statusIndicator.setOrigin(0, 0); - this.statusIndicator.setPositionRelative(this.nameText, 0, 11.5); - this.add(this.statusIndicator); - - this.levelContainer = globalScene.add.container(player ? -41 : -50, player ? -10 : -5); - this.levelContainer.setName("container_level"); - this.add(this.levelContainer); - - const levelOverlay = globalScene.add.image(0, 0, "overlay_lv"); - this.levelContainer.add(levelOverlay); - - this.hpBar = globalScene.add.image(player ? -61 : -71, player ? -1 : 4.5, "overlay_hp"); - this.hpBar.setName("hp_bar"); - this.hpBar.setOrigin(0); - this.add(this.hpBar); - - this.hpBarSegmentDividers = []; - - this.levelNumbersContainer = globalScene.add.container(9.5, globalScene.uiTheme ? 0 : -0.5); - this.levelNumbersContainer.setName("container_level"); - this.levelContainer.add(this.levelNumbersContainer); - - if (this.player) { - this.hpNumbersContainer = globalScene.add.container(-15, 10); - this.hpNumbersContainer.setName("container_hp"); - this.add(this.hpNumbersContainer); - - const expBar = globalScene.add.image(-98, 18, "overlay_exp"); - expBar.setName("overlay_exp"); - expBar.setOrigin(0); - this.add(expBar); - - const expMaskRect = globalScene.make.graphics({}); - expMaskRect.setScale(6); - expMaskRect.fillStyle(0xffffff); - expMaskRect.beginPath(); - expMaskRect.fillRect(127, 126, 85, 2); - - const expMask = expMaskRect.createGeometryMask(); - - expBar.setMask(expMask); - - this.expBar = expBar; - this.expMaskRect = expMaskRect; - } - - this.statsContainer = globalScene.add.container(0, 0); - this.statsContainer.setName("container_stats"); - this.statsContainer.setAlpha(0); - this.add(this.statsContainer); - - this.statsBox = globalScene.add.sprite(0, 0, `${this.getTextureName()}_stats`); - this.statsBox.setName("box_stats"); - this.statsBox.setOrigin(1, 0.5); - this.statsContainer.add(this.statsBox); - - const statLabels: Phaser.GameObjects.Sprite[] = []; - this.statNumbers = []; - - this.statValuesContainer = globalScene.add.container(0, 0); - this.statsContainer.add(this.statValuesContainer); - - // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy - // since the player won't have HP to show, it doesn't need to change from the current version - const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5; - const paddingX = this.player ? 4 : 2; - const statOverflow = this.player ? 1 : 0; - this.statOrder = this.player ? this.statOrderPlayer : this.statOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order - - this.statOrder.map((s, i) => { - // we do a check for i > statOverflow to see when the stat labels go onto the next column - // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 - // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 - const statX = - i > statOverflow - ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX - : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 - - const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis - let statY: number; // this will be the y-axis placement for the labels - if (this.statOrder[i] === Stat.SPD || this.statOrder[i] === Stat.HP) { - statY = baseY + 5; - } else { - statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us - } - - const statLabel = globalScene.add.sprite(statX, statY, "pbinfo_stat", Stat[s]); - statLabel.setName("icon_stat_label_" + i.toString()); - statLabel.setOrigin(0, 0); - statLabels.push(statLabel); - this.statValuesContainer.add(statLabel); - - const statNumber = globalScene.add.sprite( - statX + statLabel.width, - statY, - "pbinfo_stat_numbers", - this.statOrder[i] !== Stat.HP ? "3" : "empty", - ); - statNumber.setName("icon_stat_number_" + i.toString()); - statNumber.setOrigin(0, 0); - this.statNumbers.push(statNumber); - this.statValuesContainer.add(statNumber); - - if (this.statOrder[i] === Stat.HP) { - statLabel.setVisible(false); - statNumber.setVisible(false); - } - }); - - if (!this.player) { - this.flyoutMenu = new BattleFlyout(this.player); - this.add(this.flyoutMenu); - - this.moveBelow(this.flyoutMenu, this.box); - } - - this.type1Icon = globalScene.add.sprite( - player ? -139 : -15, - player ? -17 : -15.5, - `pbinfo_${player ? "player" : "enemy"}_type1`, - ); - this.type1Icon.setName("icon_type_1"); - this.type1Icon.setOrigin(0, 0); - this.add(this.type1Icon); - - this.type2Icon = globalScene.add.sprite( - player ? -139 : -15, - player ? -1 : -2.5, - `pbinfo_${player ? "player" : "enemy"}_type2`, - ); - this.type2Icon.setName("icon_type_2"); - this.type2Icon.setOrigin(0, 0); - this.add(this.type2Icon); - - this.type3Icon = globalScene.add.sprite( - player ? -154 : 0, - player ? -17 : -15.5, - `pbinfo_${player ? "player" : "enemy"}_type`, - ); - this.type3Icon.setName("icon_type_3"); - this.type3Icon.setOrigin(0, 0); - this.add(this.type3Icon); - - if (!this.player) { - this.effectivenessContainer = globalScene.add.container(0, 0); - this.effectivenessContainer.setPositionRelative(this.type1Icon, 22, 4); - this.effectivenessContainer.setVisible(false); - this.add(this.effectivenessContainer); - - this.effectivenessText = addTextObject(5, 4.5, "", TextStyle.BATTLE_INFO); - this.effectivenessWindow = addWindow(0, 0, 0, 20, undefined, false, undefined, undefined, WindowVariant.XTHIN); - - this.effectivenessContainer.add(this.effectivenessWindow); - this.effectivenessContainer.add(this.effectivenessText); - } - } - - getStatsValueContainer(): Phaser.GameObjects.Container { - return this.statValuesContainer; - } - - initInfo(pokemon: Pokemon) { - this.updateNameText(pokemon); - const nameTextWidth = this.nameText.displayWidth; - - this.name = pokemon.getNameToRender(); - this.box.name = pokemon.getNameToRender(); - - this.flyoutMenu?.initInfo(pokemon); - - this.genderText.setText(getGenderSymbol(pokemon.gender)); - this.genderText.setColor(getGenderColor(pokemon.gender)); - this.genderText.setPositionRelative(this.nameText, nameTextWidth, 0); - - this.lastTeraType = pokemon.getTeraType(); - - this.teraIcon.setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1, 2); - this.teraIcon.setVisible(pokemon.isTerastallized); - this.teraIcon.on("pointerover", () => { - if (pokemon.isTerastallized) { - globalScene.ui.showTooltip( - "", - i18next.t("fightUiHandler:teraHover", { - type: i18next.t(`pokemonInfo:Type.${PokemonType[this.lastTeraType]}`), - }), - ); - } - }); - this.teraIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - - const isFusion = pokemon.isFusion(true); - - this.splicedIcon.setPositionRelative( - this.nameText, - nameTextWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), - 2.5, - ); - this.splicedIcon.setVisible(isFusion); - if (this.splicedIcon.visible) { - this.splicedIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies?.getName(pokemon.fusionFormIndex)}`, - ), - ); - this.splicedIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; - const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; - - this.shinyIcon.setPositionRelative( - this.nameText, - nameTextWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + - (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), - 2.5, - ); - this.shinyIcon.setTexture(`shiny_star${doubleShiny ? "_1" : ""}`); - this.shinyIcon.setVisible(pokemon.isShiny()); - this.shinyIcon.setTint(getVariantTint(baseVariant)); - if (this.shinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.shinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - ), - ); - this.shinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - this.fusionShinyIcon.setVisible(doubleShiny); - if (isFusion) { - this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); - } - - if (!this.player) { - if (this.nameText.visible) { - this.nameText.on("pointerover", () => - globalScene.ui.showTooltip( - "", - i18next.t("battleInfo:generation", { - generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`), - }), - ), - ); - this.nameText.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - const dexEntry = globalScene.gameData.dexData[pokemon.species.speciesId]; - this.ownedIcon.setVisible(!!dexEntry.caughtAttr); - const opponentPokemonDexAttr = pokemon.getDexAttr(); - if (globalScene.gameMode.isClassic) { - if ( - globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && - globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0 - ) { - this.championRibbon.setVisible(true); - } - } - - // Check if Player owns all genders and forms of the Pokemon - const missingDexAttrs = (dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr; - - const ownedAbilityAttrs = globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr; - - // Check if the player owns ability for the root form - const playerOwnsThisAbility = pokemon.checkIfPlayerHasAbilityOfStarter(ownedAbilityAttrs); - - if (missingDexAttrs || !playerOwnsThisAbility) { - this.ownedIcon.setTint(0x808080); - } - - if (this.boss) { - this.updateBossSegmentDividers(pokemon as EnemyPokemon); - } - } - - this.hpBar.setScale(pokemon.getHpRatio(true), 1); - this.lastHpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; - this.hpBar.setFrame(this.lastHpFrame); - if (this.player) { - this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); - } - this.lastHp = pokemon.hp; - this.lastMaxHp = pokemon.getMaxHp(); - - this.setLevel(pokemon.level); - this.lastLevel = pokemon.level; - - this.shinyIcon.setVisible(pokemon.isShiny()); - - const types = pokemon.getTypes(true, false, undefined, true); - this.type1Icon.setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`); - this.type1Icon.setFrame(PokemonType[types[0]].toLowerCase()); - this.type2Icon.setVisible(types.length > 1); - this.type3Icon.setVisible(types.length > 2); - if (types.length > 1) { - this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); - } - if (types.length > 2) { - this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); - } - - if (this.player) { - this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; - this.lastExp = pokemon.exp; - this.lastLevelExp = pokemon.levelExp; - - this.statValuesContainer.setPosition(8, 7); - } - - const stats = this.statOrder.map(() => 0); - - this.lastStats = stats.join(""); - this.updateStats(stats); - } - - getTextureName(): string { - return `pbinfo_${this.player ? "player" : "enemy"}${!this.player && this.boss ? "_boss" : this.mini ? "_mini" : ""}`; - } - - setMini(mini: boolean): void { - if (this.mini === mini) { - return; - } - - this.mini = mini; - - this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); - - if (this.player) { - this.y -= 12 * (mini ? 1 : -1); - this.baseY = this.y; - } - - const offsetElements = [ - this.nameText, - this.genderText, - this.teraIcon, - this.splicedIcon, - this.shinyIcon, - this.statusIndicator, - this.levelContainer, - ]; - offsetElements.forEach(el => (el.y += 1.5 * (mini ? -1 : 1))); - - [this.type1Icon, this.type2Icon, this.type3Icon].forEach(el => { - el.x += 4 * (mini ? 1 : -1); - el.y += -8 * (mini ? 1 : -1); - }); - - this.statValuesContainer.x += 2 * (mini ? 1 : -1); - this.statValuesContainer.y += -7 * (mini ? 1 : -1); - - const toggledElements = [this.hpNumbersContainer, this.expBar]; - toggledElements.forEach(el => el.setVisible(!mini)); - } - - toggleStats(visible: boolean): void { - globalScene.tweens.add({ - targets: this.statsContainer, - duration: fixedInt(125), - ease: "Sine.easeInOut", - alpha: visible ? 1 : 0, - }); - } - - updateBossSegments(pokemon: EnemyPokemon): void { - const boss = !!pokemon.bossSegments; - - if (boss !== this.boss) { - this.boss = boss; - - [ - this.nameText, - this.genderText, - this.teraIcon, - this.splicedIcon, - this.shinyIcon, - this.ownedIcon, - this.championRibbon, - this.statusIndicator, - this.statValuesContainer, - ].map(e => (e.x += 48 * (boss ? -1 : 1))); - this.hpBar.x += 38 * (boss ? -1 : 1); - this.hpBar.y += 2 * (this.boss ? -1 : 1); - this.levelContainer.x += 2 * (boss ? -1 : 1); - this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); - this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); - } - - this.bossSegments = boss ? pokemon.bossSegments : 0; - this.updateBossSegmentDividers(pokemon); - } - - updateBossSegmentDividers(pokemon: EnemyPokemon): void { - while (this.hpBarSegmentDividers.length) { - this.hpBarSegmentDividers.pop()?.destroy(); - } - - if (this.boss && this.bossSegments > 1) { - const uiTheme = globalScene.uiTheme; - const maxHp = pokemon.getMaxHp(); - for (let s = 1; s < this.bossSegments; s++) { - const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width; - const divider = globalScene.add.rectangle( - 0, - 0, - 1, - this.hpBar.height - (uiTheme ? 0 : 1), - pokemon.bossSegmentIndex >= s ? 0xffffff : 0x404040, - ); - divider.setOrigin(0.5, 0); - divider.setName("hpBar_divider_" + s.toString()); - this.add(divider); - this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); - - divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); - this.hpBarSegmentDividers.push(divider); - } - } - } - - setOffset(offset: boolean): void { - if (this.offset === offset) { - return; - } - - this.offset = offset; - - this.x += 10 * (this.offset === this.player ? 1 : -1); - this.y += 27 * (this.offset ? 1 : -1); - this.baseY = this.y; - } - - updateInfo(pokemon: Pokemon, instant?: boolean): Promise { - return new Promise(resolve => { - if (!globalScene) { - return resolve(); - } - - const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; - - this.genderText.setText(getGenderSymbol(gender)); - this.genderText.setColor(getGenderColor(gender)); - - const nameUpdated = this.lastName !== pokemon.getNameToRender(); - - if (nameUpdated) { - this.updateNameText(pokemon); - this.genderText.setPositionRelative(this.nameText, this.nameText.displayWidth, 0); - } - - const teraType = pokemon.isTerastallized ? pokemon.getTeraType() : PokemonType.UNKNOWN; - const teraTypeUpdated = this.lastTeraType !== teraType; - - if (teraTypeUpdated) { - this.teraIcon.setVisible(teraType !== PokemonType.UNKNOWN); - this.teraIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + this.genderText.displayWidth + 1, - 2, - ); - this.teraIcon.setTintFill(Phaser.Display.Color.GetColor(...getTypeRgb(teraType))); - this.lastTeraType = teraType; - } - - const isFusion = pokemon.isFusion(true); - - if (nameUpdated || teraTypeUpdated) { - this.splicedIcon.setVisible(isFusion); - - this.teraIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + this.genderText.displayWidth + 1, - 2, - ); - this.splicedIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), - 1.5, - ); - this.shinyIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + - (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), - 2.5, - ); - } - - if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) { - this.lastStatus = pokemon.status?.effect || StatusEffect.NONE; - - if (this.lastStatus !== StatusEffect.NONE) { - this.statusIndicator.setFrame(StatusEffect[this.lastStatus].toLowerCase()); - } - - const offsetX = !this.player ? (this.ownedIcon.visible ? 8 : 0) + (this.championRibbon.visible ? 8 : 0) : 0; - this.statusIndicator.setPositionRelative(this.nameText, offsetX, 11.5); - - this.statusIndicator.setVisible(!!this.lastStatus); - } - - const types = pokemon.getTypes(true, false, undefined, true); - this.type1Icon.setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`); - this.type1Icon.setFrame(PokemonType[types[0]].toLowerCase()); - this.type2Icon.setVisible(types.length > 1); - this.type3Icon.setVisible(types.length > 2); - if (types.length > 1) { - this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); - } - if (types.length > 2) { - this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); - } - - const updateHpFrame = () => { - const hpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; - if (hpFrame !== this.lastHpFrame) { - this.hpBar.setFrame(hpFrame); - this.lastHpFrame = hpFrame; - } - }; - - const updatePokemonHp = () => { - let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0; - const speed = globalScene.hpBarSpeed; - if (speed) { - duration = speed >= 3 ? 0 : duration / Math.pow(2, speed); - } - globalScene.tweens.add({ - targets: this.hpBar, - ease: "Sine.easeOut", - scaleX: pokemon.getHpRatio(true), - duration: duration, - onUpdate: () => { - if (this.player && this.lastHp !== pokemon.hp) { - const tweenHp = Math.ceil(this.hpBar.scaleX * pokemon.getMaxHp()); - this.setHpNumbers(tweenHp, pokemon.getMaxHp()); - this.lastHp = tweenHp; - } - - updateHpFrame(); - }, - onComplete: () => { - updateHpFrame(); - // If, after tweening, the hp is different from the original (due to rounding), force the hp number display - // to update to the correct value. - if (this.player && this.lastHp !== pokemon.hp) { - this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); - this.lastHp = pokemon.hp; - } - resolve(); - }, - }); - if (!this.player) { - this.lastHp = pokemon.hp; - } - this.lastMaxHp = pokemon.getMaxHp(); - }; - - if (this.player) { - const isLevelCapped = pokemon.level >= globalScene.getMaxExpLevel(); - - if (this.lastExp !== pokemon.exp || this.lastLevel !== pokemon.level) { - const originalResolve = resolve; - const durationMultipler = Math.max( - Phaser.Tweens.Builders.GetEaseFunction("Cubic.easeIn")( - 1 - Math.min(pokemon.level - this.lastLevel, 10) / 10, - ), - 0.1, - ); - resolve = () => this.updatePokemonExp(pokemon, false, durationMultipler).then(() => originalResolve()); - } else if (isLevelCapped !== this.lastLevelCapped) { - this.setLevel(pokemon.level); - } - - this.lastLevelCapped = isLevelCapped; - } - - if (this.lastHp !== pokemon.hp || this.lastMaxHp !== pokemon.getMaxHp()) { - return updatePokemonHp(); - } - if (!this.player && this.lastLevel !== pokemon.level) { - this.setLevel(pokemon.level); - this.lastLevel = pokemon.level; - } - - const stats = pokemon.getStatStages(); - const statsStr = stats.join(""); - - if (this.lastStats !== statsStr) { - this.updateStats(stats); - this.lastStats = statsStr; - } - - this.shinyIcon.setVisible(pokemon.isShiny(true)); - - const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; - const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; - this.shinyIcon.setTint(getVariantTint(baseVariant)); - - this.fusionShinyIcon.setVisible(doubleShiny); - if (isFusion) { - this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); - } - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - - resolve(); - }); - } - - updateNameText(pokemon: Pokemon): void { - let displayName = pokemon.getNameToRender().replace(/[♂♀]/g, ""); - let nameTextWidth: number; - - const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); - nameTextWidth = nameSizeTest.displayWidth; - - const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; - while ( - nameTextWidth > - (this.player || !this.boss ? 60 : 98) - - ((gender !== Gender.GENDERLESS ? 6 : 0) + - (pokemon.fusionSpecies ? 8 : 0) + - (pokemon.isShiny() ? 8 : 0) + - (Math.min(pokemon.level.toString().length, 3) - 3) * 8) - ) { - displayName = `${displayName.slice(0, displayName.endsWith(".") ? -2 : -1).trimEnd()}.`; - nameSizeTest.setText(displayName); - nameTextWidth = nameSizeTest.displayWidth; - } - - nameSizeTest.destroy(); - - this.nameText.setText(displayName); - this.lastName = pokemon.getNameToRender(); - - if (this.nameText.visible) { - this.nameText.setInteractive( - new Phaser.Geom.Rectangle(0, 0, this.nameText.width, this.nameText.height), - Phaser.Geom.Rectangle.Contains, - ); - } - } - - updatePokemonExp(pokemon: Pokemon, instant?: boolean, levelDurationMultiplier = 1): Promise { - return new Promise(resolve => { - const levelUp = this.lastLevel < pokemon.level; - const relLevelExp = getLevelRelExp(this.lastLevel + 1, pokemon.species.growthRate); - const levelExp = levelUp ? relLevelExp : pokemon.levelExp; - let ratio = relLevelExp ? levelExp / relLevelExp : 0; - if (this.lastLevel >= globalScene.getMaxExpLevel(true)) { - if (levelUp) { - ratio = 1; - } else { - ratio = 0; - } - instant = true; - } - const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")( - 1 - Math.max(this.lastLevel - 100, 0) / 150, - ); - let duration = - this.visible && !instant - ? ((levelExp - this.lastLevelExp) / relLevelExp) * - BattleInfo.EXP_GAINS_DURATION_BASE * - durationMultiplier * - levelDurationMultiplier - : 0; - const speed = globalScene.expGainsSpeed; - if (speed && speed >= ExpGainsSpeed.DEFAULT) { - duration = speed >= ExpGainsSpeed.SKIP ? ExpGainsSpeed.DEFAULT : duration / Math.pow(2, speed); - } - if (ratio === 1) { - this.lastLevelExp = 0; - this.lastLevel++; - } else { - this.lastExp = pokemon.exp; - this.lastLevelExp = pokemon.levelExp; - } - if (duration) { - globalScene.playSound("se/exp"); - } - globalScene.tweens.add({ - targets: this.expMaskRect, - ease: "Sine.easeIn", - x: ratio * 510, - duration: duration, - onComplete: () => { - if (!globalScene) { - return resolve(); - } - if (duration) { - globalScene.sound.stopByKey("se/exp"); - } - if (ratio === 1) { - globalScene.playSound("se/level_up"); - this.setLevel(this.lastLevel); - globalScene.time.delayedCall(500 * levelDurationMultiplier, () => { - this.expMaskRect.x = 0; - this.updateInfo(pokemon, instant).then(() => resolve()); - }); - return; - } - resolve(); - }, - }); - }); - } - - setLevel(level: number): void { - const isCapped = level >= globalScene.getMaxExpLevel(); - this.levelNumbersContainer.removeAll(true); - const levelStr = level.toString(); - for (let i = 0; i < levelStr.length; i++) { - this.levelNumbersContainer.add( - globalScene.add.image(i * 8, 0, `numbers${isCapped && this.player ? "_red" : ""}`, levelStr[i]), - ); - } - this.levelContainer.setX((this.player ? -41 : -50) - 8 * Math.max(levelStr.length - 3, 0)); - } - - setHpNumbers(hp: number, maxHp: number): void { - if (!this.player || !globalScene) { - return; - } - this.hpNumbersContainer.removeAll(true); - const hpStr = hp.toString(); - const maxHpStr = maxHp.toString(); - let offset = 0; - for (let i = maxHpStr.length - 1; i >= 0; i--) { - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", maxHpStr[i])); - } - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", "/")); - for (let i = hpStr.length - 1; i >= 0; i--) { - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", hpStr[i])); - } - } - - updateStats(stats: number[]): void { - this.statOrder.map((s, i) => { - if (s !== Stat.HP) { - this.statNumbers[i].setFrame(stats[s - 1].toString()); - } - }); - } - - /** - * Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary - */ - toggleFlyout(visible: boolean): void { - this.flyoutMenu?.toggleFlyout(visible); - - if (visible) { - this.effectivenessContainer?.setVisible(false); - } else { - this.updateEffectiveness(this.currentEffectiveness); - } - } - - /** - * Show or hide the type effectiveness multiplier window - * Passing undefined will hide the window - */ - updateEffectiveness(effectiveness?: string) { - if (this.player) { - return; - } - this.currentEffectiveness = effectiveness; - - if (!globalScene.typeHints || effectiveness === undefined || this.flyoutMenu?.flyoutVisible) { - this.effectivenessContainer.setVisible(false); - return; - } - - this.effectivenessText.setText(effectiveness); - this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth; - this.effectivenessContainer.setVisible(true); - } - - getBaseY(): number { - return this.baseY; - } - - resetY(): void { - this.y = this.baseY; - } -} - -export class PlayerBattleInfo extends BattleInfo { - constructor() { - super(Math.floor(globalScene.game.canvas.width / 6) - 10, -72, true); - } -} - -export class EnemyBattleInfo extends BattleInfo { - constructor() { - super(140, -141, false); - } - - setMini(_mini: boolean): void {} // Always mini -} diff --git a/src/ui/battle-info/battle-info.ts b/src/ui/battle-info/battle-info.ts new file mode 100644 index 00000000000..71596bf0f43 --- /dev/null +++ b/src/ui/battle-info/battle-info.ts @@ -0,0 +1,688 @@ +import type { default as Pokemon } from "../../field/pokemon"; +import { getLocalizedSpriteKey, fixedInt, getShinyDescriptor } from "#app/utils/common"; +import { addTextObject, TextStyle } from "../text"; +import { getGenderSymbol, getGenderColor, Gender } from "../../data/gender"; +import { StatusEffect } from "#enums/status-effect"; +import { globalScene } from "#app/global-scene"; +import { getTypeRgb } from "#app/data/type"; +import { PokemonType } from "#enums/pokemon-type"; +import { getVariantTint } from "#app/sprites/variant"; +import { Stat } from "#enums/stat"; +import i18next from "i18next"; + +/** + * Parameters influencing the position of elements within the battle info container + */ +export type BattleInfoParamList = { + /** X offset for the name text*/ + nameTextX: number; + /** Y offset for the name text */ + nameTextY: number; + /** X offset for the level container */ + levelContainerX: number; + /** Y offset for the level container */ + levelContainerY: number; + /** X offset for the hp bar */ + hpBarX: number; + /** Y offset for the hp bar */ + hpBarY: number; + /** Parameters for the stat box container */ + statBox: { + /** The starting offset from the left of the label for the entries in the stat box */ + xOffset: number; + /** The X padding between each number column */ + paddingX: number; + /** The index of the stat entries at which paddingX is used instead of startingX */ + statOverflow: number; + }; +}; + +export default abstract class BattleInfo extends Phaser.GameObjects.Container { + public static readonly EXP_GAINS_DURATION_BASE = 1650; + + protected baseY: number; + protected baseLvContainerX: number; + + protected player: boolean; + protected mini: boolean; + protected boss: boolean; + protected bossSegments: number; + protected offset: boolean; + protected lastName: string | null; + protected lastTeraType: PokemonType; + protected lastStatus: StatusEffect; + protected lastHp: number; + protected lastMaxHp: number; + protected lastHpFrame: string | null; + protected lastExp: number; + protected lastLevelExp: number; + protected lastLevel: number; + protected lastLevelCapped: boolean; + protected lastStats: string; + + protected box: Phaser.GameObjects.Sprite; + protected nameText: Phaser.GameObjects.Text; + protected genderText: Phaser.GameObjects.Text; + protected teraIcon: Phaser.GameObjects.Sprite; + protected shinyIcon: Phaser.GameObjects.Sprite; + protected fusionShinyIcon: Phaser.GameObjects.Sprite; + protected splicedIcon: Phaser.GameObjects.Sprite; + protected statusIndicator: Phaser.GameObjects.Sprite; + protected levelContainer: Phaser.GameObjects.Container; + protected hpBar: Phaser.GameObjects.Image; + protected levelNumbersContainer: Phaser.GameObjects.Container; + protected type1Icon: Phaser.GameObjects.Sprite; + protected type2Icon: Phaser.GameObjects.Sprite; + protected type3Icon: Phaser.GameObjects.Sprite; + protected expBar: Phaser.GameObjects.Image; + + public expMaskRect: Phaser.GameObjects.Graphics; + + protected statsContainer: Phaser.GameObjects.Container; + protected statsBox: Phaser.GameObjects.Sprite; + protected statValuesContainer: Phaser.GameObjects.Container; + protected statNumbers: Phaser.GameObjects.Sprite[]; + + get statOrder(): Stat[] { + return []; + } + + /** Helper method used by the constructor to create the tera and shiny icons next to the name */ + private constructIcons() { + const hitArea = new Phaser.Geom.Rectangle(0, 0, 12, 15); + const hitCallback = Phaser.Geom.Rectangle.Contains; + + this.teraIcon = globalScene.add + .sprite(0, 0, "icon_tera") + .setName("icon_tera") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.shinyIcon = globalScene.add + .sprite(0, 0, "shiny_star") + .setName("icon_shiny") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.fusionShinyIcon = globalScene.add + .sprite(0, 0, "shiny_star_2") + .setName("icon_fusion_shiny") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .copyPosition(this.shinyIcon); + + this.splicedIcon = globalScene.add + .sprite(0, 0, "icon_spliced") + .setName("icon_spliced") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.add([this.teraIcon, this.shinyIcon, this.fusionShinyIcon, this.splicedIcon]); + } + + /** + * Submethod of the constructor that creates and adds the stats container to the battle info + */ + protected constructStatContainer({ xOffset, paddingX, statOverflow }: BattleInfoParamList["statBox"]): void { + this.statsContainer = globalScene.add.container(0, 0).setName("container_stats").setAlpha(0); + this.add(this.statsContainer); + + this.statsBox = globalScene.add + .sprite(0, 0, `${this.getTextureName()}_stats`) + .setName("box_stats") + .setOrigin(1, 0.5); + this.statsContainer.add(this.statsBox); + + const statLabels: Phaser.GameObjects.Sprite[] = []; + this.statNumbers = []; + + this.statValuesContainer = globalScene.add.container(); + this.statsContainer.add(this.statValuesContainer); + + const startingX = -this.statsBox.width + xOffset; + + // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy + // since the player won't have HP to show, it doesn't need to change from the current version + + for (const [i, s] of this.statOrder.entries()) { + const isHp = s === Stat.HP; + // we do a check for i > statOverflow to see when the stat labels go onto the next column + // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 + // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 + const statX = + i > statOverflow + ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX + : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 + + let statY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis + if (isHp || s === Stat.SPD) { + statY += 5; + } else if (this.player === !!(i % 2)) { + // we compare i % 2 against this.player to tell us where to place the label + // because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players + // this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us + statY += 10; + } + + const statLabel = globalScene.add + .sprite(statX, statY, "pbinfo_stat", Stat[s]) + .setName("icon_stat_label_" + i.toString()) + .setOrigin(0); + statLabels.push(statLabel); + this.statValuesContainer.add(statLabel); + + const statNumber = globalScene.add + .sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", !isHp ? "3" : "empty") + .setName("icon_stat_number_" + i.toString()) + .setOrigin(0); + this.statNumbers.push(statNumber); + this.statValuesContainer.add(statNumber); + + if (isHp) { + statLabel.setVisible(false); + statNumber.setVisible(false); + } + } + } + + /** + * Submethod of the constructor that creates and adds the pokemon type icons to the battle info + */ + protected abstract constructTypeIcons(): void; + + /** + * @param x - The x position of the battle info container + * @param y - The y position of the battle info container + * @param player - Whether this battle info belongs to a player or an enemy + * @param posParams - The parameters influencing the position of elements within the battle info container + */ + constructor(x: number, y: number, player: boolean, posParams: BattleInfoParamList) { + super(globalScene, x, y); + this.baseY = y; + this.player = player; + this.mini = !player; + this.boss = false; + this.offset = false; + this.lastName = null; + this.lastTeraType = PokemonType.UNKNOWN; + this.lastStatus = StatusEffect.NONE; + this.lastHp = -1; + this.lastMaxHp = -1; + this.lastHpFrame = null; + this.lastExp = -1; + this.lastLevelExp = -1; + this.lastLevel = -1; + this.baseLvContainerX = posParams.levelContainerX; + + // Initially invisible and shown via Pokemon.showInfo + this.setVisible(false); + + this.box = globalScene.add.sprite(0, 0, this.getTextureName()).setName("box").setOrigin(1, 0.5); + this.add(this.box); + + this.nameText = addTextObject(player ? -115 : -124, player ? -15.2 : -11.2, "", TextStyle.BATTLE_INFO) + .setName("text_name") + .setOrigin(0); + this.add(this.nameText); + + this.genderText = addTextObject(0, 0, "", TextStyle.BATTLE_INFO) + .setName("text_gender") + .setOrigin(0) + .setPositionRelative(this.nameText, 0, 2); + this.add(this.genderText); + + this.constructIcons(); + + this.statusIndicator = globalScene.add + .sprite(0, 0, getLocalizedSpriteKey("statuses")) + .setName("icon_status") + .setVisible(false) + .setOrigin(0) + .setPositionRelative(this.nameText, 0, 11.5); + this.add(this.statusIndicator); + + this.levelContainer = globalScene.add + .container(posParams.levelContainerX, posParams.levelContainerY) + .setName("container_level"); + this.add(this.levelContainer); + + const levelOverlay = globalScene.add.image(0, 0, "overlay_lv"); + this.levelContainer.add(levelOverlay); + + this.hpBar = globalScene.add.image(posParams.hpBarX, posParams.hpBarY, "overlay_hp").setName("hp_bar").setOrigin(0); + this.add(this.hpBar); + + this.levelNumbersContainer = globalScene.add + .container(9.5, globalScene.uiTheme ? 0 : -0.5) + .setName("container_level"); + this.levelContainer.add(this.levelNumbersContainer); + + this.constructStatContainer(posParams.statBox); + + this.constructTypeIcons(); + } + + getStatsValueContainer(): Phaser.GameObjects.Container { + return this.statValuesContainer; + } + + //#region Initialization methods + + initSplicedIcon(pokemon: Pokemon, baseWidth: number) { + this.splicedIcon.setPositionRelative( + this.nameText, + baseWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), + 2.5, + ); + this.splicedIcon.setVisible(pokemon.isFusion(true)); + if (!this.splicedIcon.visible) { + return; + } + this.splicedIcon + .on("pointerover", () => + globalScene.ui.showTooltip( + "", + `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies?.getName(pokemon.fusionFormIndex)}`, + ), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + /** + * Called by {@linkcode initInfo} to initialize the shiny icon + * @param pokemon - The pokemon object attached to this battle info + * @param baseXOffset - The x offset to use for the shiny icon + * @param doubleShiny - Whether the pokemon is shiny and its fusion species is also shiny + */ + protected initShinyIcon(pokemon: Pokemon, xOffset: number, doubleShiny: boolean) { + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; + + this.shinyIcon.setPositionRelative( + this.nameText, + xOffset + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), + 2.5, + ); + this.shinyIcon + .setTexture(`shiny_star${doubleShiny ? "_1" : ""}`) + .setVisible(pokemon.isShiny()) + .setTint(getVariantTint(baseVariant)); + + if (!this.shinyIcon.visible) { + return; + } + + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + + this.shinyIcon + .on("pointerover", () => globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor)) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + initInfo(pokemon: Pokemon) { + this.updateNameText(pokemon); + const nameTextWidth = this.nameText.displayWidth; + + this.name = pokemon.getNameToRender(); + this.box.name = pokemon.getNameToRender(); + + this.genderText + .setText(getGenderSymbol(pokemon.gender)) + .setColor(getGenderColor(pokemon.gender)) + .setPositionRelative(this.nameText, nameTextWidth, 0); + + this.lastTeraType = pokemon.getTeraType(); + + this.teraIcon + .setVisible(pokemon.isTerastallized) + .on("pointerover", () => { + if (pokemon.isTerastallized) { + globalScene.ui.showTooltip( + "", + i18next.t("fightUiHandler:teraHover", { + type: i18next.t(`pokemonInfo:Type.${PokemonType[this.lastTeraType]}`), + }), + ); + } + }) + .on("pointerout", () => globalScene.ui.hideTooltip()) + .setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1, 2); + + const isFusion = pokemon.isFusion(true); + this.initSplicedIcon(pokemon, nameTextWidth); + + const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; + this.initShinyIcon(pokemon, nameTextWidth, doubleShiny); + + this.fusionShinyIcon.setVisible(doubleShiny).copyPosition(this.shinyIcon); + if (isFusion) { + this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); + } + + this.hpBar.setScale(pokemon.getHpRatio(true), 1); + this.lastHpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; + this.hpBar.setFrame(this.lastHpFrame); + this.lastHp = pokemon.hp; + this.lastMaxHp = pokemon.getMaxHp(); + + this.setLevel(pokemon.level); + this.lastLevel = pokemon.level; + + this.shinyIcon.setVisible(pokemon.isShiny()); + + this.setTypes(pokemon.getTypes(true, false, undefined, true)); + + const stats = this.statOrder.map(() => 0); + + this.lastStats = stats.join(""); + this.updateStats(stats); + } + //#endregion + + /** + * Return the texture name of the battle info box + */ + abstract getTextureName(): string; + + setMini(_mini: boolean): void {} + + toggleStats(visible: boolean): void { + globalScene.tweens.add({ + targets: this.statsContainer, + duration: fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible ? 1 : 0, + }); + } + + setOffset(offset: boolean): void { + if (this.offset === offset) { + return; + } + + this.offset = offset; + + this.x += 10 * (this.offset === this.player ? 1 : -1); + this.y += 27 * (this.offset ? 1 : -1); + this.baseY = this.y; + } + + //#region Update methods and helpers + + /** + * Update the status icon to match the pokemon's current status + * @param pokemon - The pokemon object attached to this battle info + * @param xOffset - The offset from the name text + */ + updateStatusIcon(pokemon: Pokemon, xOffset = 0) { + if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) { + this.lastStatus = pokemon.status?.effect || StatusEffect.NONE; + + if (this.lastStatus !== StatusEffect.NONE) { + this.statusIndicator.setFrame(StatusEffect[this.lastStatus].toLowerCase()); + } + + this.statusIndicator.setVisible(!!this.lastStatus).setPositionRelative(this.nameText, xOffset, 11.5); + } + } + + /** Update the pokemon name inside the container */ + protected updateName(name: string): boolean { + if (this.lastName === name) { + return false; + } + this.nameText.setText(name).setPositionRelative(this.box, -this.nameText.displayWidth, 0); + this.lastName = name; + + return true; + } + + protected updateTeraType(ty: PokemonType): boolean { + if (this.lastTeraType === ty) { + return false; + } + + this.teraIcon + .setVisible(ty !== PokemonType.UNKNOWN) + .setTintFill(Phaser.Display.Color.GetColor(...getTypeRgb(ty))) + .setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1, 2); + this.lastTeraType = ty; + + return true; + } + + /** + * Update the type icons to match the pokemon's types + */ + setTypes(types: PokemonType[]): void { + this.type1Icon + .setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`) + .setFrame(PokemonType[types[0]].toLowerCase()); + this.type2Icon.setVisible(types.length > 1); + this.type3Icon.setVisible(types.length > 2); + if (types.length > 1) { + this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); + } + if (types.length > 2) { + this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); + } + } + + /** + * Called by {@linkcode updateInfo} to update the position of the tera, spliced, and shiny icons + * @param isFusion - Whether the pokemon is a fusion or not + */ + protected updateIconDisplay(isFusion: boolean): void { + this.teraIcon.setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1, 2); + this.splicedIcon + .setVisible(isFusion) + .setPositionRelative( + this.nameText, + this.nameText.displayWidth + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), + 1.5, + ); + this.shinyIcon.setPositionRelative( + this.nameText, + this.nameText.displayWidth + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), + 2.5, + ); + } + + //#region Hp Bar Display handling + /** + * Called every time the hp frame is updated by the tween + * @param pokemon - The pokemon object attached to this battle info + */ + protected updateHpFrame(): void { + const hpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; + if (hpFrame !== this.lastHpFrame) { + this.hpBar.setFrame(hpFrame); + this.lastHpFrame = hpFrame; + } + } + + /** + * Called by every frame in the hp animation tween created in {@linkcode updatePokemonHp} + * @param _pokemon - The pokemon the battle-info bar belongs to + */ + protected onHpTweenUpdate(_pokemon: Pokemon): void { + this.updateHpFrame(); + } + + /** Update the pokemonHp bar */ + protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike) => void, instant?: boolean): void { + let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0; + const speed = globalScene.hpBarSpeed; + if (speed) { + duration = speed >= 3 ? 0 : duration / Math.pow(2, speed); + } + globalScene.tweens.add({ + targets: this.hpBar, + ease: "Sine.easeOut", + scaleX: pokemon.getHpRatio(true), + duration: duration, + onUpdate: () => { + this.onHpTweenUpdate(pokemon); + }, + onComplete: () => { + this.updateHpFrame(); + resolve(); + }, + }); + this.lastMaxHp = pokemon.getMaxHp(); + } + + //#endregion + + async updateInfo(pokemon: Pokemon, instant?: boolean): Promise { + let resolve: (r: void | PromiseLike) => void = () => {}; + const promise = new Promise(r => (resolve = r)); + if (!globalScene) { + return resolve(); + } + + const gender: Gender = pokemon.summonData?.illusion?.gender ?? pokemon.gender; + + this.genderText.setText(getGenderSymbol(gender)).setColor(getGenderColor(gender)); + + const nameUpdated = this.updateName(pokemon.getNameToRender()); + + const teraTypeUpdated = this.updateTeraType(pokemon.isTerastallized ? pokemon.getTeraType() : PokemonType.UNKNOWN); + + const isFusion = pokemon.isFusion(true); + + if (nameUpdated || teraTypeUpdated) { + this.updateIconDisplay(isFusion); + } + + this.updateStatusIcon(pokemon); + + if (this.lastHp !== pokemon.hp || this.lastMaxHp !== pokemon.getMaxHp()) { + return this.updatePokemonHp(pokemon, resolve, instant); + } + if (!this.player && this.lastLevel !== pokemon.level) { + this.setLevel(pokemon.level); + this.lastLevel = pokemon.level; + } + + const stats = pokemon.getStatStages(); + const statsStr = stats.join(""); + + if (this.lastStats !== statsStr) { + this.updateStats(stats); + this.lastStats = statsStr; + } + + this.shinyIcon.setVisible(pokemon.isShiny(true)); + + const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; + this.shinyIcon.setTint(getVariantTint(baseVariant)); + + this.fusionShinyIcon.setVisible(doubleShiny).setPosition(this.shinyIcon.x, this.shinyIcon.y); + if (isFusion) { + this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); + } + + resolve(); + await promise; + } + //#endregion + + updateNameText(pokemon: Pokemon): void { + let displayName = pokemon.getNameToRender().replace(/[♂♀]/g, ""); + let nameTextWidth: number; + + const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); + nameTextWidth = nameSizeTest.displayWidth; + + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; + while ( + nameTextWidth > + (this.player || !this.boss ? 60 : 98) - + ((gender !== Gender.GENDERLESS ? 6 : 0) + + (pokemon.fusionSpecies ? 8 : 0) + + (pokemon.isShiny() ? 8 : 0) + + (Math.min(pokemon.level.toString().length, 3) - 3) * 8) + ) { + displayName = `${displayName.slice(0, displayName.endsWith(".") ? -2 : -1).trimEnd()}.`; + nameSizeTest.setText(displayName); + nameTextWidth = nameSizeTest.displayWidth; + } + + nameSizeTest.destroy(); + + this.nameText.setText(displayName); + this.lastName = pokemon.getNameToRender(); + + if (this.nameText.visible) { + this.nameText.setInteractive( + new Phaser.Geom.Rectangle(0, 0, this.nameText.width, this.nameText.height), + Phaser.Geom.Rectangle.Contains, + ); + } + } + + /** + * Set the level numbers container to display the provided level + * + * @remarks + * The numbers in the pokemon's level uses images for each number rather than a text object with a special font. + * This method sets the images for each digit of the level number and then positions the level container based + * on the number of digits. + * + * @param level - The level to display + * @param textureKey - The texture key for the level numbers + */ + setLevel(level: number, textureKey: "numbers" | "numbers_red" = "numbers"): void { + this.levelNumbersContainer.removeAll(true); + const levelStr = level.toString(); + for (let i = 0; i < levelStr.length; i++) { + this.levelNumbersContainer.add(globalScene.add.image(i * 8, 0, textureKey, levelStr[i])); + } + this.levelContainer.setX(this.baseLvContainerX - 8 * Math.max(levelStr.length - 3, 0)); + } + + updateStats(stats: number[]): void { + for (const [i, s] of this.statOrder.entries()) { + if (s !== Stat.HP) { + this.statNumbers[i].setFrame(stats[s - 1].toString()); + } + } + } + + getBaseY(): number { + return this.baseY; + } + + resetY(): void { + this.y = this.baseY; + } +} diff --git a/src/ui/battle-info/enemy-battle-info.ts b/src/ui/battle-info/enemy-battle-info.ts new file mode 100644 index 00000000000..e8f5434dcf2 --- /dev/null +++ b/src/ui/battle-info/enemy-battle-info.ts @@ -0,0 +1,235 @@ +import { globalScene } from "#app/global-scene"; +import BattleFlyout from "../battle-flyout"; +import { addTextObject, TextStyle } from "#app/ui/text"; +import { addWindow, WindowVariant } from "#app/ui/ui-theme"; +import { Stat } from "#enums/stat"; +import i18next from "i18next"; +import type { EnemyPokemon } from "#app/field/pokemon"; +import type { GameObjects } from "phaser"; +import BattleInfo from "./battle-info"; +import type { BattleInfoParamList } from "./battle-info"; + +export class EnemyBattleInfo extends BattleInfo { + protected player: false = false; + protected championRibbon: Phaser.GameObjects.Sprite; + protected ownedIcon: Phaser.GameObjects.Sprite; + protected flyoutMenu: BattleFlyout; + + protected hpBarSegmentDividers: GameObjects.Rectangle[] = []; + + // #region Type effectiveness hint objects + protected effectivenessContainer: Phaser.GameObjects.Container; + protected effectivenessWindow: Phaser.GameObjects.NineSlice; + protected effectivenessText: Phaser.GameObjects.Text; + protected currentEffectiveness?: string; + // #endregion + + override get statOrder(): Stat[] { + return [Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; + } + + override getTextureName(): string { + return this.boss ? "pbinfo_enemy_boss_mini" : "pbinfo_enemy_mini"; + } + + override constructTypeIcons(): void { + this.type1Icon = globalScene.add.sprite(-15, -15.5, "pbinfo_enemy_type1").setName("icon_type_1").setOrigin(0); + this.type2Icon = globalScene.add.sprite(-15, -2.5, "pbinfo_enemy_type2").setName("icon_type_2").setOrigin(0); + this.type3Icon = globalScene.add.sprite(0, 15.5, "pbinfo_enemy_type3").setName("icon_type_3").setOrigin(0); + this.add([this.type1Icon, this.type2Icon, this.type3Icon]); + } + + constructor() { + const posParams: BattleInfoParamList = { + nameTextX: -124, + nameTextY: -11.2, + levelContainerX: -50, + levelContainerY: -5, + hpBarX: -71, + hpBarY: 4.5, + statBox: { + xOffset: 5, + paddingX: 2, + statOverflow: 0, + }, + }; + + super(140, -141, false, posParams); + + this.ownedIcon = globalScene.add + .sprite(0, 0, "icon_owned") + .setName("icon_owned") + .setVisible(false) + .setOrigin(0, 0) + .setPositionRelative(this.nameText, 0, 11.75); + + this.championRibbon = globalScene.add + .sprite(0, 0, "champion_ribbon") + .setName("icon_champion_ribbon") + .setVisible(false) + .setOrigin(0, 0) + .setPositionRelative(this.nameText, 8, 11.75); + // Ensure these two icons are positioned below the stats container + this.addAt([this.ownedIcon, this.championRibbon], this.getIndex(this.statsContainer)); + + this.flyoutMenu = new BattleFlyout(this.player); + this.add(this.flyoutMenu); + + this.moveBelow(this.flyoutMenu, this.box); + + this.effectivenessContainer = globalScene.add + .container(0, 0) + .setVisible(false) + .setPositionRelative(this.type1Icon, 22, 4); + this.add(this.effectivenessContainer); + + this.effectivenessText = addTextObject(5, 4.5, "", TextStyle.BATTLE_INFO); + this.effectivenessWindow = addWindow(0, 0, 0, 20, undefined, false, undefined, undefined, WindowVariant.XTHIN); + + this.effectivenessContainer.add([this.effectivenessWindow, this.effectivenessText]); + } + + override initInfo(pokemon: EnemyPokemon): void { + this.flyoutMenu.initInfo(pokemon); + super.initInfo(pokemon); + + if (this.nameText.visible) { + this.nameText + .on("pointerover", () => + globalScene.ui.showTooltip( + "", + i18next.t("battleInfo:generation", { + generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`), + }), + ), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + const dexEntry = globalScene.gameData.dexData[pokemon.species.speciesId]; + this.ownedIcon.setVisible(!!dexEntry.caughtAttr); + const opponentPokemonDexAttr = pokemon.getDexAttr(); + if ( + globalScene.gameMode.isClassic && + globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && + globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0 + ) { + this.championRibbon.setVisible(true); + } + + // Check if Player owns all genders and forms of the Pokemon + const missingDexAttrs = (dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr; + + const ownedAbilityAttrs = globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr; + + // Check if the player owns ability for the root form + const playerOwnsThisAbility = pokemon.checkIfPlayerHasAbilityOfStarter(ownedAbilityAttrs); + + if (missingDexAttrs || !playerOwnsThisAbility) { + this.ownedIcon.setTint(0x808080); + } + + if (this.boss) { + this.updateBossSegmentDividers(pokemon as EnemyPokemon); + } + } + + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + this.currentEffectiveness = effectiveness; + + if (!globalScene.typeHints || effectiveness === undefined || this.flyoutMenu.flyoutVisible) { + this.effectivenessContainer.setVisible(false); + return; + } + + this.effectivenessText.setText(effectiveness); + this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth; + this.effectivenessContainer.setVisible(true); + } + + /** + * Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary + */ + toggleFlyout(visible: boolean): void { + this.flyoutMenu.toggleFlyout(visible); + + if (visible) { + this.effectivenessContainer.setVisible(false); + } else { + this.updateEffectiveness(this.currentEffectiveness); + } + } + + updateBossSegments(pokemon: EnemyPokemon): void { + const boss = !!pokemon.bossSegments; + + if (boss !== this.boss) { + this.boss = boss; + + [ + this.nameText, + this.genderText, + this.teraIcon, + this.splicedIcon, + this.shinyIcon, + this.ownedIcon, + this.championRibbon, + this.statusIndicator, + this.levelContainer, + this.statValuesContainer, + ].map(e => (e.x += 48 * (boss ? -1 : 1))); + this.hpBar.x += 38 * (boss ? -1 : 1); + this.hpBar.y += 2 * (this.boss ? -1 : 1); + this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); + this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); + } + + this.bossSegments = boss ? pokemon.bossSegments : 0; + this.updateBossSegmentDividers(pokemon); + } + + updateBossSegmentDividers(pokemon: EnemyPokemon): void { + while (this.hpBarSegmentDividers.length) { + this.hpBarSegmentDividers.pop()?.destroy(); + } + + if (this.boss && this.bossSegments > 1) { + const uiTheme = globalScene.uiTheme; + const maxHp = pokemon.getMaxHp(); + for (let s = 1; s < this.bossSegments; s++) { + const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width; + const divider = globalScene.add.rectangle( + 0, + 0, + 1, + this.hpBar.height - (uiTheme ? 0 : 1), + pokemon.bossSegmentIndex >= s ? 0xffffff : 0x404040, + ); + divider.setOrigin(0.5, 0).setName("hpBar_divider_" + s.toString()); + this.add(divider); + this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); + + divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); + this.hpBarSegmentDividers.push(divider); + } + } + } + + override updateStatusIcon(pokemon: EnemyPokemon): void { + super.updateStatusIcon(pokemon, (this.ownedIcon.visible ? 8 : 0) + (this.championRibbon.visible ? 8 : 0)); + } + + protected override updatePokemonHp( + pokemon: EnemyPokemon, + resolve: (r: void | PromiseLike) => void, + instant?: boolean, + ): void { + super.updatePokemonHp(pokemon, resolve, instant); + this.lastHp = pokemon.hp; + } +} diff --git a/src/ui/battle-info/player-battle-info.ts b/src/ui/battle-info/player-battle-info.ts new file mode 100644 index 00000000000..634f89b7922 --- /dev/null +++ b/src/ui/battle-info/player-battle-info.ts @@ -0,0 +1,242 @@ +import { getLevelRelExp, getLevelTotalExp } from "#app/data/exp"; +import type { PlayerPokemon } from "#app/field/pokemon"; +import { globalScene } from "#app/global-scene"; +import { ExpGainsSpeed } from "#enums/exp-gains-speed"; +import { Stat } from "#enums/stat"; +import BattleInfo from "./battle-info"; +import type { BattleInfoParamList } from "./battle-info"; + +export class PlayerBattleInfo extends BattleInfo { + protected player: true = true; + protected hpNumbersContainer: Phaser.GameObjects.Container; + + override get statOrder(): Stat[] { + return [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; + } + + override getTextureName(): string { + return this.mini ? "pbinfo_player_mini" : "pbinfo_player"; + } + + override constructTypeIcons(): void { + this.type1Icon = globalScene.add.sprite(-139, -17, "pbinfo_player_type1").setName("icon_type_1").setOrigin(0); + this.type2Icon = globalScene.add.sprite(-139, -1, "pbinfo_player_type2").setName("icon_type_2").setOrigin(0); + this.type3Icon = globalScene.add.sprite(-154, -17, "pbinfo_player_type3").setName("icon_type_3").setOrigin(0); + this.add([this.type1Icon, this.type2Icon, this.type3Icon]); + } + + constructor() { + const posParams: BattleInfoParamList = { + nameTextX: -115, + nameTextY: -15.2, + levelContainerX: -41, + levelContainerY: -10, + hpBarX: -61, + hpBarY: -1, + statBox: { + xOffset: 8, + paddingX: 4, + statOverflow: 1, + }, + }; + super(Math.floor(globalScene.game.canvas.width / 6) - 10, -72, true, posParams); + + this.hpNumbersContainer = globalScene.add.container(-15, 10).setName("container_hp"); + + // hp number container must be beneath the stat container for overlay to display properly + this.addAt(this.hpNumbersContainer, this.getIndex(this.statsContainer)); + + const expBar = globalScene.add.image(-98, 18, "overlay_exp").setName("overlay_exp").setOrigin(0); + this.add(expBar); + + const expMaskRect = globalScene.make + .graphics({}) + .setScale(6) + .fillStyle(0xffffff) + .beginPath() + .fillRect(127, 126, 85, 2); + + const expMask = expMaskRect.createGeometryMask(); + + expBar.setMask(expMask); + + this.expBar = expBar; + this.expMaskRect = expMaskRect; + } + + override initInfo(pokemon: PlayerPokemon): void { + super.initInfo(pokemon); + this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); + this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; + this.lastExp = pokemon.exp; + this.lastLevelExp = pokemon.levelExp; + + this.statValuesContainer.setPosition(8, 7); + } + + override setMini(mini: boolean): void { + if (this.mini === mini) { + return; + } + + this.mini = mini; + + this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); + + if (this.player) { + this.y -= 12 * (mini ? 1 : -1); + this.baseY = this.y; + } + + const offsetElements = [ + this.nameText, + this.genderText, + this.teraIcon, + this.splicedIcon, + this.shinyIcon, + this.statusIndicator, + this.levelContainer, + ]; + offsetElements.forEach(el => (el.y += 1.5 * (mini ? -1 : 1))); + + [this.type1Icon, this.type2Icon, this.type3Icon].forEach(el => { + el.x += 4 * (mini ? 1 : -1); + el.y += -8 * (mini ? 1 : -1); + }); + + this.statValuesContainer.x += 2 * (mini ? 1 : -1); + this.statValuesContainer.y += -7 * (mini ? 1 : -1); + + const toggledElements = [this.hpNumbersContainer, this.expBar]; + toggledElements.forEach(el => el.setVisible(!mini)); + } + + /** + * Updates the Hp Number text (that is the "HP/Max HP" text that appears below the player's health bar) + * while the health bar is tweening. + * @param pokemon - The Pokemon the health bar belongs to. + */ + protected override onHpTweenUpdate(pokemon: PlayerPokemon): void { + const tweenHp = Math.ceil(this.hpBar.scaleX * pokemon.getMaxHp()); + this.setHpNumbers(tweenHp, pokemon.getMaxHp()); + this.lastHp = tweenHp; + this.updateHpFrame(); + } + + updatePokemonExp(pokemon: PlayerPokemon, instant?: boolean, levelDurationMultiplier = 1): Promise { + const levelUp = this.lastLevel < pokemon.level; + const relLevelExp = getLevelRelExp(this.lastLevel + 1, pokemon.species.growthRate); + const levelExp = levelUp ? relLevelExp : pokemon.levelExp; + let ratio = relLevelExp ? levelExp / relLevelExp : 0; + if (this.lastLevel >= globalScene.getMaxExpLevel(true)) { + ratio = levelUp ? 1 : 0; + instant = true; + } + const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")( + 1 - Math.max(this.lastLevel - 100, 0) / 150, + ); + let duration = + this.visible && !instant + ? ((levelExp - this.lastLevelExp) / relLevelExp) * + BattleInfo.EXP_GAINS_DURATION_BASE * + durationMultiplier * + levelDurationMultiplier + : 0; + const speed = globalScene.expGainsSpeed; + if (speed && speed >= ExpGainsSpeed.DEFAULT) { + duration = speed >= ExpGainsSpeed.SKIP ? ExpGainsSpeed.DEFAULT : duration / Math.pow(2, speed); + } + if (ratio === 1) { + this.lastLevelExp = 0; + this.lastLevel++; + } else { + this.lastExp = pokemon.exp; + this.lastLevelExp = pokemon.levelExp; + } + if (duration) { + globalScene.playSound("se/exp"); + } + return new Promise(resolve => { + globalScene.tweens.add({ + targets: this.expMaskRect, + ease: "Sine.easeIn", + x: ratio * 510, + duration: duration, + onComplete: () => { + if (!globalScene) { + return resolve(); + } + if (duration) { + globalScene.sound.stopByKey("se/exp"); + } + if (ratio === 1) { + globalScene.playSound("se/level_up"); + this.setLevel(this.lastLevel); + globalScene.time.delayedCall(500 * levelDurationMultiplier, () => { + this.expMaskRect.x = 0; + this.updateInfo(pokemon, instant).then(() => resolve()); + }); + return; + } + resolve(); + }, + }); + }); + } + + /** + * Updates the info on the info bar. + * + * In addition to performing all the steps of {@linkcode BattleInfo.updateInfo}, + * it also updates the EXP Bar + */ + override async updateInfo(pokemon: PlayerPokemon, instant?: boolean): Promise { + await super.updateInfo(pokemon, instant); + const isLevelCapped = pokemon.level >= globalScene.getMaxExpLevel(); + const oldLevelCapped = this.lastLevelCapped; + this.lastLevelCapped = isLevelCapped; + + if (this.lastExp !== pokemon.exp || this.lastLevel !== pokemon.level) { + const durationMultipler = Math.max( + Phaser.Tweens.Builders.GetEaseFunction("Cubic.easeIn")(1 - Math.min(pokemon.level - this.lastLevel, 10) / 10), + 0.1, + ); + await this.updatePokemonExp(pokemon, false, durationMultipler); + } else if (isLevelCapped !== oldLevelCapped) { + this.setLevel(pokemon.level); + } + } + + /** + * Set the HP numbers text, that is the "HP/Max HP" text that appears below the player's health bar. + * @param hp - The current HP of the player. + * @param maxHp - The maximum HP of the player. + */ + setHpNumbers(hp: number, maxHp: number): void { + if (!globalScene) { + return; + } + this.hpNumbersContainer.removeAll(true); + const hpStr = hp.toString(); + const maxHpStr = maxHp.toString(); + let offset = 0; + for (let i = maxHpStr.length - 1; i >= 0; i--) { + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", maxHpStr[i])); + } + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", "/")); + for (let i = hpStr.length - 1; i >= 0; i--) { + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", hpStr[i])); + } + } + + /** + * Set the level numbers container to display the provided level + * + * Overrides the default implementation to handle displaying level capped numbers in red. + * @param level - The level to display + */ + override setLevel(level: number): void { + super.setLevel(level, level >= globalScene.getMaxExpLevel() ? "numbers_red" : "numbers"); + } +} diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 5a0978a934d..6dbbcd47300 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -10,7 +10,7 @@ import { getLocalizedSpriteKey, fixedInt, padInt } from "#app/utils/common"; import { MoveCategory } from "#enums/MoveCategory"; import i18next from "i18next"; import { Button } from "#enums/buttons"; -import type { PokemonMove } from "#app/field/pokemon"; +import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import type { CommandPhase } from "#app/phases/command-phase"; import MoveInfoOverlay from "./move-info-overlay"; @@ -279,7 +279,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { this.moveInfoOverlay.show(pokemonMove.getMove()); pokemon.getOpponents().forEach(opponent => { - opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); + (opponent as EnemyPokemon).updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); }); } @@ -391,7 +391,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const opponents = (globalScene.getCurrentPhase() as CommandPhase).getPokemon().getOpponents(); opponents.forEach(opponent => { - opponent.updateEffectiveness(undefined); + (opponent as EnemyPokemon).updateEffectiveness(); }); } diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 18b5d2384ef..d8012a58875 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -8,7 +8,7 @@ import type Pokemon from "../field/pokemon"; import i18next from "i18next"; import type { DexEntry, StarterDataEntry } from "../system/game-data"; import { DexAttr } from "../system/game-data"; -import { fixedInt } from "#app/utils/common"; +import { fixedInt, getShinyDescriptor } from "#app/utils/common"; import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; @@ -343,18 +343,19 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonShinyIcon.setVisible(pokemon.isShiny()); this.pokemonShinyIcon.setTint(getVariantTint(baseVariant)); if (this.pokemonShinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.pokemonShinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - true, - ), - ); - this.pokemonShinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + this.pokemonShinyIcon + .on("pointerover", () => + globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor, true), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); const newShiny = BigInt(1 << (pokemon.shiny ? 1 : 0)); const newVariant = BigInt(1 << (pokemon.variant + 4)); diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index f93a1826b3e..24e790f7c61 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -11,6 +11,7 @@ import { isNullOrUndefined, toReadableString, formatStat, + getShinyDescriptor, } from "#app/utils/common"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; @@ -444,18 +445,19 @@ export default class SummaryUiHandler extends UiHandler { this.shinyIcon.setVisible(this.pokemon.isShiny(false)); this.shinyIcon.setTint(getVariantTint(baseVariant)); if (this.shinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${this.pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : this.pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.shinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - true, - ), - ); - this.shinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(this.pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + this.shinyIcon + .on("pointerover", () => + globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor, true), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); } this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); diff --git a/src/utils/common.ts b/src/utils/common.ts index b9111578e2f..a018b49da3c 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -2,6 +2,7 @@ import { MoneyFormat } from "#enums/money-format"; import { Moves } from "#enums/moves"; import i18next from "i18next"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; +import type { Variant } from "#app/sprites/variant"; export type nil = null | undefined; @@ -576,3 +577,18 @@ export function animationFileName(move: Moves): string { export function camelCaseToKebabCase(str: string): string { return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, o) => (o ? "-" : "") + s.toLowerCase()); } + +/** Get the localized shiny descriptor for the provided variant + * @param variant - The variant to get the shiny descriptor for + * @returns The localized shiny descriptor + */ +export function getShinyDescriptor(variant: Variant): string { + switch (variant) { + case 2: + return i18next.t("common:epicShiny"); + case 1: + return i18next.t("common:rareShiny"); + case 0: + return i18next.t("common:commonShiny"); + } +} diff --git a/test/testUtils/mocks/mockGameObject.ts b/test/testUtils/mocks/mockGameObject.ts index 4c243ec9ca1..0dff7c48c73 100644 --- a/test/testUtils/mocks/mockGameObject.ts +++ b/test/testUtils/mocks/mockGameObject.ts @@ -1,3 +1,4 @@ export interface MockGameObject { name: string; + destroy?(): void; } diff --git a/test/testUtils/mocks/mocksContainer/mockContainer.ts b/test/testUtils/mocks/mocksContainer/mockContainer.ts index 5e739fbe3cc..e116e7d151a 100644 --- a/test/testUtils/mocks/mocksContainer/mockContainer.ts +++ b/test/testUtils/mocks/mocksContainer/mockContainer.ts @@ -2,199 +2,253 @@ import type MockTextureManager from "#test/testUtils/mocks/mockTextureManager"; import type { MockGameObject } from "../mockGameObject"; export default class MockContainer implements MockGameObject { - protected x; - protected y; + protected x: number; + protected y: number; protected scene; - protected width; - protected height; - protected visible; - private alpha; + protected width: number; + protected height: number; + protected visible: boolean; + private alpha: number; private style; public frame; protected textureManager; public list: MockGameObject[] = []; public name: string; - constructor(textureManager: MockTextureManager, x, y) { + constructor(textureManager: MockTextureManager, x: number, y: number) { this.x = x; this.y = y; this.frame = {}; this.textureManager = textureManager; } - setVisible(visible) { + setVisible(visible: boolean): this { this.visible = visible; + return this; } - once(_event, _callback, _source) {} + once(_event, _callback, _source): this { + return this; + } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } - removeBetween(_startIndex, _endIndex, _destroyChild) { + removeBetween(_startIndex, _endIndex, _destroyChild): this { // Removes multiple children across an index range + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setSize(_width, _height) { + setSize(_width: number, _height: number): this { // Sets the size of this Game Object. + return this; } - setMask() { + setMask(): this { /// Sets the mask that this Game Object will use to render with. + return this; } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } - setInteractive = () => null; + setInteractive(): this { + return this; + } - setOrigin(x, y) { + setOrigin(x = 0.5, y = x): this { this.x = x; this.y = y; + return this; } - setAlpha(alpha) { + setAlpha(alpha = 1): this { this.alpha = alpha; + return this; } - setFrame(_frame, _updateSize?: boolean, _updateOrigin?: boolean) { + setFrame(_frame, _updateSize?: boolean, _updateOrigin?: boolean): this { // Sets the frame this Game Object will use to render with. + return this; } - setScale(_scale) { + setScale(_x = 1, _y = _x): this { // Sets the scale of this Game Object. + return this; } - setPosition(x, y) { + setPosition(x = 0, y = x, _z = 0, _w = 0): this { this.x = x; this.y = y; + return this; } - setX(x) { + setX(x = 0): this { this.x = x; + return this; } - setY(y) { + setY(y = 0): this { this.y = y; + return this; } destroy() { this.list = []; } - setShadow(_shadowXpos, _shadowYpos, _shadowColor) { + setShadow(_shadowXpos, _shadowYpos, _shadowColor): this { // Sets the shadow settings for this Game Object. + return this; } - setLineSpacing(_lineSpacing) { + setLineSpacing(_lineSpacing): this { // Sets the line spacing value of this Game Object. + return this; } - setText(_text) { + setText(_text): this { // Sets the text this Game Object will display. + return this; } - setAngle(_angle) { + setAngle(_angle): this { // Sets the angle of this Game Object. + return this; } - setShadowOffset(_offsetX, _offsetY) { + setShadowOffset(_offsetX, _offsetY): this { // Sets the shadow offset values. + return this; } setWordWrapWidth(_width) { // Sets the width (in pixels) to use for wrapping lines. } - setFontSize(_fontSize) { + setFontSize(_fontSize): this { // Sets the font size of this Game Object. + return this; } getBounds() { return { width: this.width, height: this.height }; } - setColor(_color) { + setColor(_color): this { // Sets the tint of this Game Object. + return this; } - setShadowColor(_color) { + setShadowColor(_color): this { // Sets the shadow color. + return this; } - setTint(_color) { + setTint(_color: this) { // Sets the tint of this Game Object. + return this; } - setStrokeStyle(_thickness, _color) { + setStrokeStyle(_thickness, _color): this { // Sets the stroke style for the graphics. return this; } - setDepth(_depth) { - // Sets the depth of this Game Object. + setDepth(_depth): this { + // Sets the depth of this Game Object.\ + return this; } - setTexture(_texture) { - // Sets the texture this Game Object will use to render with. + setTexture(_texture): this { + // Sets the texture this Game Object will use to render with.\ + return this; } - clearTint() { - // Clears any previously set tint. + clearTint(): this { + // Clears any previously set tint.\ + return this; } - sendToBack() { - // Sends this Game Object to the back of its parent's display list. + sendToBack(): this { + // Sends this Game Object to the back of its parent's display list.\ + return this; } - moveTo(_obj) { - // Moves this Game Object to the given index in the list. + moveTo(_obj): this { + // Moves this Game Object to the given index in the list.\ + return this; } - moveAbove(_obj) { + moveAbove(_obj): this { // Moves this Game Object to be above the given Game Object in the display list. + return this; } - moveBelow(_obj) { + moveBelow(_obj): this { // Moves this Game Object to be below the given Game Object in the display list. + return this; } - setName(name: string) { + setName(name: string): this { this.name = name; + return this; } - bringToTop(_obj) { + bringToTop(_obj): this { // Brings this Game Object to the top of its parents display list. + return this; } - on(_event, _callback, _source) {} + on(_event, _callback, _source): this { + return this; + } - add(obj) { + add(...obj: MockGameObject[]): this { // Adds a child to this Game Object. - this.list.push(obj); + this.list.push(...obj); + return this; } - removeAll() { + removeAll(): this { // Removes all Game Objects from this Container. this.list = []; + return this; } - addAt(obj, index) { + addAt(obj: MockGameObject | MockGameObject[], index = 0): this { // Adds a Game Object to this Container at the given index. - this.list.splice(index, 0, obj); + if (!Array.isArray(obj)) { + obj = [obj]; + } + this.list.splice(index, 0, ...obj); + return this; } - remove(obj) { - const index = this.list.indexOf(obj); - if (index !== -1) { - this.list.splice(index, 1); + remove(obj: MockGameObject | MockGameObject[], destroyChild = false): this { + if (!Array.isArray(obj)) { + obj = [obj]; } + for (const item of obj) { + const index = this.list.indexOf(item); + if (index !== -1) { + this.list.splice(index, 1); + } + if (destroyChild) { + item.destroy?.(); + } + } + return this; } getIndex(obj) { @@ -210,15 +264,28 @@ export default class MockContainer implements MockGameObject { return this.list; } - getByName(key: string) { + getByName(key: string): MockGameObject | null { return this.list.find(v => v.name === key) ?? new MockContainer(this.textureManager, 0, 0); } - disableInteractive = () => null; + disableInteractive(): this { + return this; + } - each(method) { + each(method): this { for (const item of this.list) { method(item); } + return this; + } + + copyPosition(source: { x?: number; y?: number }): this { + if (source.x !== undefined) { + this.x = source.x; + } + if (source.y !== undefined) { + this.y = source.y; + } + return this; } } diff --git a/test/testUtils/mocks/mocksContainer/mockGraphics.ts b/test/testUtils/mocks/mocksContainer/mockGraphics.ts index ebf84e935e3..1650d2f9f60 100644 --- a/test/testUtils/mocks/mocksContainer/mockGraphics.ts +++ b/test/testUtils/mocks/mocksContainer/mockGraphics.ts @@ -8,57 +8,76 @@ export default class MockGraphics implements MockGameObject { this.scene = textureManager.scene; } - fillStyle(_color) { + fillStyle(_color): this { // Sets the fill style to be used by the fill methods. + return this; } - beginPath() { + beginPath(): this { // Starts a new path by emptying the list of sub-paths. Call this method when you want to create a new path. + return this; } - fillRect(_x, _y, _width, _height) { + fillRect(_x, _y, _width, _height): this { // Adds a rectangle shape to the path which is filled when you call fill(). + return this; } - createGeometryMask() { + createGeometryMask(): this { // Creates a geometry mask. + return this; } - setOrigin(_x, _y) {} + setOrigin(_x, _y): this { + return this; + } - setAlpha(_alpha) {} + setAlpha(_alpha): this { + return this; + } - setVisible(_visible) {} + setVisible(_visible): this { + return this; + } - setName(_name) {} + setName(_name) { + return this; + } - once(_event, _callback, _source) {} + once(_event, _callback, _source) { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } destroy() { this.list = []; } - setScale(_scale) { - // Sets the scale of this Game Object. + setScale(_scale): this { + return this; } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } removeAll() { @@ -90,4 +109,8 @@ export default class MockGraphics implements MockGameObject { getAll() { return this.list; } + + copyPosition(_source): this { + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockRectangle.ts b/test/testUtils/mocks/mocksContainer/mockRectangle.ts index 7bdf343759d..f9a92c41904 100644 --- a/test/testUtils/mocks/mocksContainer/mockRectangle.ts +++ b/test/testUtils/mocks/mocksContainer/mockRectangle.ts @@ -10,34 +10,47 @@ export default class MockRectangle implements MockGameObject { this.fillColor = fillColor; this.scene = textureManager.scene; } - setOrigin(_x, _y) {} + setOrigin(_x, _y): this { + return this; + } - setAlpha(_alpha) {} - setVisible(_visible) {} + setAlpha(_alpha): this { + return this; + } + setVisible(_visible): this { + return this; + } - setName(_name) {} + setName(_name): this { + return this; + } - once(_event, _callback, _source) {} + once(_event, _callback, _source): this { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } destroy() { this.list = []; } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } removeAll() { @@ -45,16 +58,18 @@ export default class MockRectangle implements MockGameObject { this.list = []; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } getIndex(obj) { @@ -69,9 +84,12 @@ export default class MockRectangle implements MockGameObject { getAll() { return this.list; } - setScale(_scale) { + setScale(_scale): this { // return this.phaserText.setScale(scale); + return this; } - off() {} + off(): this { + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockSprite.ts b/test/testUtils/mocks/mocksContainer/mockSprite.ts index dcc3588f127..b8ccfcced1f 100644 --- a/test/testUtils/mocks/mocksContainer/mockSprite.ts +++ b/test/testUtils/mocks/mocksContainer/mockSprite.ts @@ -1,6 +1,5 @@ import Phaser from "phaser"; import type { MockGameObject } from "../mockGameObject"; -import Sprite = Phaser.GameObjects.Sprite; import Frame = Phaser.Textures.Frame; export default class MockSprite implements MockGameObject { @@ -21,7 +20,9 @@ export default class MockSprite implements MockGameObject { Phaser.GameObjects.Sprite.prototype.setInteractive = this.setInteractive; // @ts-ignore Phaser.GameObjects.Sprite.prototype.setTexture = this.setTexture; + // @ts-ignore Phaser.GameObjects.Sprite.prototype.setSizeToFrame = this.setSizeToFrame; + // @ts-ignore Phaser.GameObjects.Sprite.prototype.setFrame = this.setFrame; // Phaser.GameObjects.Sprite.prototype.disable = this.disable; @@ -37,46 +38,55 @@ export default class MockSprite implements MockGameObject { }; } - setTexture(_key: string, _frame?: string | number) { + setTexture(_key: string, _frame?: string | number): this { return this; } - setSizeToFrame(_frame?: boolean | Frame): Sprite { - return {} as Sprite; + setSizeToFrame(_frame?: boolean | Frame): this { + return this; } - setPipeline(obj) { + setPipeline(obj): this { // Sets the pipeline of this Game Object. - return this.phaserSprite.setPipeline(obj); + this.phaserSprite.setPipeline(obj); + return this; } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - setTintFill(color) { + setTintFill(color): this { // Sets the tint fill color. - return this.phaserSprite.setTintFill(color); + this.phaserSprite.setTintFill(color); + return this; } - setScale(scale) { - return this.phaserSprite.setScale(scale); + setScale(scale = 1): this { + this.phaserSprite.setScale(scale); + return this; } - setOrigin(x, y) { - return this.phaserSprite.setOrigin(x, y); + setOrigin(x = 0.5, y = x): this { + this.phaserSprite.setOrigin(x, y); + return this; } - setSize(width, height) { + setSize(width, height): this { // Sets the size of this Game Object. - return this.phaserSprite.setSize(width, height); + this.phaserSprite.setSize(width, height); + return this; } - once(event, callback, source) { - return this.phaserSprite.once(event, callback, source); + once(event, callback, source): this { + this.phaserSprite.once(event, callback, source); + return this; } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy - return this.phaserSprite.removeFromDisplayList(); + this.phaserSprite.removeFromDisplayList(); + return this; } addedToScene() { @@ -84,97 +94,117 @@ export default class MockSprite implements MockGameObject { return this.phaserSprite.addedToScene(); } - setVisible(visible) { - return this.phaserSprite.setVisible(visible); + setVisible(visible): this { + this.phaserSprite.setVisible(visible); + return this; } - setPosition(x, y) { - return this.phaserSprite.setPosition(x, y); + setPosition(x, y): this { + this.phaserSprite.setPosition(x, y); + return this; } - setRotation(radians) { - return this.phaserSprite.setRotation(radians); + setRotation(radians): this { + this.phaserSprite.setRotation(radians); + return this; } - stop() { - return this.phaserSprite.stop(); + stop(): this { + this.phaserSprite.stop(); + return this; } - setInteractive = () => null; - - on(event, callback, source) { - return this.phaserSprite.on(event, callback, source); + setInteractive(): this { + return this; } - setAlpha(alpha) { - return this.phaserSprite.setAlpha(alpha); + on(event, callback, source): this { + this.phaserSprite.on(event, callback, source); + return this; } - setTint(color) { + setAlpha(alpha): this { + this.phaserSprite.setAlpha(alpha); + return this; + } + + setTint(color): this { // Sets the tint of this Game Object. - return this.phaserSprite.setTint(color); + this.phaserSprite.setTint(color); + return this; } - setFrame(frame, _updateSize?: boolean, _updateOrigin?: boolean) { + setFrame(frame, _updateSize?: boolean, _updateOrigin?: boolean): this { // Sets the frame this Game Object will use to render with. this.frame = frame; - return frame; + return this; } - setPositionRelative(source, x, y) { + setPositionRelative(source, x, y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. - return this.phaserSprite.setPositionRelative(source, x, y); + this.phaserSprite.setPositionRelative(source, x, y); + return this; } - setY(y) { - return this.phaserSprite.setY(y); + setY(y: number): this { + this.phaserSprite.setY(y); + return this; } - setCrop(x, y, width, height) { + setCrop(x: number, y: number, width: number, height: number): this { // Sets the crop size of this Game Object. - return this.phaserSprite.setCrop(x, y, width, height); + this.phaserSprite.setCrop(x, y, width, height); + return this; } - clearTint() { + clearTint(): this { // Clears any previously set tint. - return this.phaserSprite.clearTint(); + this.phaserSprite.clearTint(); + return this; } - disableInteractive() { + disableInteractive(): this { // Disables Interactive features of this Game Object. - return null; + return this; } apply() { - return this.phaserSprite.apply(); + this.phaserSprite.apply(); + return this; } - play() { + play(): this { // return this.phaserSprite.play(); return this; } - setPipelineData(key, value) { + setPipelineData(key: string, value: any): this { this.pipelineData[key] = value; + return this; } destroy() { return this.phaserSprite.destroy(); } - setName(name) { - return this.phaserSprite.setName(name); + setName(name: string): this { + this.phaserSprite.setName(name); + return this; } - setAngle(angle) { - return this.phaserSprite.setAngle(angle); + setAngle(angle): this { + this.phaserSprite.setAngle(angle); + return this; } - setMask() {} + setMask(): this { + return this; + } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } removeAll() { @@ -182,16 +212,18 @@ export default class MockSprite implements MockGameObject { this.list = []; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } getIndex(obj) { @@ -206,4 +238,9 @@ export default class MockSprite implements MockGameObject { getAll() { return this.list; } + + copyPosition(obj): this { + this.phaserSprite.copyPosition(obj); + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockText.ts b/test/testUtils/mocks/mocksContainer/mockText.ts index 1f3f0ad792f..dc648616fe6 100644 --- a/test/testUtils/mocks/mocksContainer/mockText.ts +++ b/test/testUtils/mocks/mocksContainer/mockText.ts @@ -107,42 +107,51 @@ export default class MockText implements MockGameObject { } } - setScale(_scale) { + setScale(_scale): this { // return this.phaserText.setScale(scale); + return this; } - setShadow(_shadowXpos, _shadowYpos, _shadowColor) { + setShadow(_shadowXpos, _shadowYpos, _shadowColor): this { // Sets the shadow settings for this Game Object. // return this.phaserText.setShadow(shadowXpos, shadowYpos, shadowColor); + return this; } - setLineSpacing(_lineSpacing) { + setLineSpacing(_lineSpacing): this { // Sets the line spacing value of this Game Object. // return this.phaserText.setLineSpacing(lineSpacing); + return this; } - setOrigin(_x, _y) { + setOrigin(_x, _y): this { // return this.phaserText.setOrigin(x, y); + return this; } - once(_event, _callback, _source) { + once(_event, _callback, _source): this { // return this.phaserText.once(event, callback, source); + return this; } off(_event, _callback, _obj) {} removedFromScene() {} - addToDisplayList() {} - - setStroke(_color, _thickness) { - // Sets the stroke color and thickness. - // return this.phaserText.setStroke(color, thickness); + addToDisplayList(): this { + return this; } - removeFromDisplayList() { + setStroke(_color, _thickness): this { + // Sets the stroke color and thickness. + // return this.phaserText.setStroke(color, thickness); + return this; + } + + removeFromDisplayList(): this { // same as remove or destroy // return this.phaserText.removeFromDisplayList(); + return this; } addedToScene() { @@ -154,12 +163,14 @@ export default class MockText implements MockGameObject { // return this.phaserText.setVisible(visible); } - setY(_y) { + setY(_y): this { // return this.phaserText.setY(y); + return this; } - setX(_x) { + setX(_x): this { // return this.phaserText.setX(x); + return this; } /** @@ -169,27 +180,33 @@ export default class MockText implements MockGameObject { * @param z The z position of this Game Object. Default 0. * @param w The w position of this Game Object. Default 0. */ - setPosition(_x?: number, _y?: number, _z?: number, _w?: number) {} + setPosition(_x?: number, _y?: number, _z?: number, _w?: number): this { + return this; + } - setText(text) { + setText(text): this { // Sets the text this Game Object will display. // return this.phaserText.setText\(text); this.text = text; + return this; } - setAngle(_angle) { + setAngle(_angle): this { // Sets the angle of this Game Object. // return this.phaserText.setAngle(angle); + return this; } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. // return this.phaserText.setPositionRelative(source, x, y); + return this; } - setShadowOffset(_offsetX, _offsetY) { + setShadowOffset(_offsetX, _offsetY): this { // Sets the shadow offset values. // return this.phaserText.setShadowOffset(offsetX, offsetY); + return this; } setWordWrapWidth(width) { @@ -197,9 +214,10 @@ export default class MockText implements MockGameObject { this.wordWrapWidth = width; } - setFontSize(_fontSize) { + setFontSize(_fontSize): this { // Sets the font size of this Game Object. // return this.phaserText.setFontSize(fontSize); + return this; } getBounds() { @@ -209,25 +227,31 @@ export default class MockText implements MockGameObject { }; } - setColor(color: string) { + setColor(color: string): this { this.color = color; + return this; } - setInteractive = () => null; + setInteractive(): this { + return this; + } - setShadowColor(_color) { + setShadowColor(_color): this { // Sets the shadow color. // return this.phaserText.setShadowColor(color); + return this; } - setTint(_color) { + setTint(_color): this { // Sets the tint of this Game Object. // return this.phaserText.setTint(color); + return this; } - setStrokeStyle(_thickness, _color) { + setStrokeStyle(_thickness, _color): this { // Sets the stroke style for the graphics. // return this.phaserText.setStrokeStyle(thickness, color); + return this; } destroy() { @@ -235,20 +259,24 @@ export default class MockText implements MockGameObject { this.list = []; } - setAlpha(_alpha) { + setAlpha(_alpha): this { // return this.phaserText.setAlpha(alpha); + return this; } - setName(name: string) { + setName(name: string): this { this.name = name; + return this; } - setAlign(_align) { + setAlign(_align): this { // return this.phaserText.setAlign(align); + return this; } - setMask() { + setMask(): this { /// Sets the mask that this Game Object will use to render with. + return this; } getBottomLeft() { @@ -265,37 +293,43 @@ export default class MockText implements MockGameObject { }; } - disableInteractive() { + disableInteractive(): this { // Disables interaction with this Game Object. + return this; } - clearTint() { + clearTint(): this { // Clears tint on this Game Object. + return this; } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } - removeAll() { + removeAll(): this { // Removes all Game Objects from this Container. this.list = []; + return this; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } - getIndex(obj) { + getIndex(obj): number { const index = this.list.indexOf(obj); return index || -1; } diff --git a/test/testUtils/testFileInitialization.ts b/test/testUtils/testFileInitialization.ts index 15635289e6f..ba90cba7d5b 100644 --- a/test/testUtils/testFileInitialization.ts +++ b/test/testUtils/testFileInitialization.ts @@ -70,10 +70,10 @@ export function initTestFile() { * @param x The relative x position * @param y The relative y position */ - const setPositionRelative = function (guideObject: any, x: number, y: number) { + const setPositionRelative = function (guideObject: any, x: number, y: number): any { const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX)); const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY)); - this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); + return this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); }; Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative; From d8c00616fc155fdf5a6b90a48a2cc3bb65c80819 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Wed, 28 May 2025 20:00:54 -0500 Subject: [PATCH 10/12] [Test] Add iterate, fix each method in mock container (#5882) --- .../mocks/mocksContainer/mockContainer.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/test/testUtils/mocks/mocksContainer/mockContainer.ts b/test/testUtils/mocks/mocksContainer/mockContainer.ts index e116e7d151a..b392e61f9f7 100644 --- a/test/testUtils/mocks/mocksContainer/mockContainer.ts +++ b/test/testUtils/mocks/mocksContainer/mockContainer.ts @@ -272,9 +272,24 @@ export default class MockContainer implements MockGameObject { return this; } - each(method): this { + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the method it mocks + each(callback: Function, context?: object, ...args: any[]): this { + if (context !== undefined) { + callback = callback.bind(context); + } + for (const item of this.list.slice()) { + callback(item, ...args); + } + return this; + } + + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the method it mocks + iterate(callback: Function, context?: object, ...args: any[]): this { + if (context !== undefined) { + callback = callback.bind(context); + } for (const item of this.list) { - method(item); + callback(item, ...args); } return this; } From 86fa3198fd897b3aafbcba7abf5d4dc6e972738e Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Wed, 28 May 2025 21:47:27 -0500 Subject: [PATCH 11/12] [Test] Fix mock text to make it compatible with method chaining (#5884) --- test/testUtils/mocks/mocksContainer/mockText.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/testUtils/mocks/mocksContainer/mockText.ts b/test/testUtils/mocks/mocksContainer/mockText.ts index dc648616fe6..8f72cd0d34f 100644 --- a/test/testUtils/mocks/mocksContainer/mockText.ts +++ b/test/testUtils/mocks/mocksContainer/mockText.ts @@ -159,8 +159,8 @@ export default class MockText implements MockGameObject { // return this.phaserText.addedToScene(); } - setVisible(_visible) { - // return this.phaserText.setVisible(visible); + setVisible(_visible): this { + return this; } setY(_y): this { @@ -209,9 +209,10 @@ export default class MockText implements MockGameObject { return this; } - setWordWrapWidth(width) { + setWordWrapWidth(width): this { // Sets the width (in pixels) to use for wrapping lines. this.wordWrapWidth = width; + return this; } setFontSize(_fontSize): this { @@ -351,5 +352,6 @@ export default class MockText implements MockGameObject { return this.runWordWrap(this.text).split("\n"); } + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the class this mocks on(_event: string | symbol, _fn: Function, _context?: any) {} } From f9e6785c351d07e7f2a7e11299831aff476c6db4 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Wed, 28 May 2025 22:18:06 -0500 Subject: [PATCH 12/12] [Test] Fix mocks' add method to match phaser signature (#5885) --- test/testUtils/mocks/mocksContainer/mockContainer.ts | 9 ++++++--- test/testUtils/mocks/mocksContainer/mockRectangle.ts | 8 ++++++-- test/testUtils/mocks/mocksContainer/mockSprite.ts | 8 ++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/test/testUtils/mocks/mocksContainer/mockContainer.ts b/test/testUtils/mocks/mocksContainer/mockContainer.ts index b392e61f9f7..883c3856c26 100644 --- a/test/testUtils/mocks/mocksContainer/mockContainer.ts +++ b/test/testUtils/mocks/mocksContainer/mockContainer.ts @@ -214,9 +214,12 @@ export default class MockContainer implements MockGameObject { return this; } - add(...obj: MockGameObject[]): this { - // Adds a child to this Game Object. - this.list.push(...obj); + add(obj: MockGameObject | MockGameObject[]): this { + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } return this; } diff --git a/test/testUtils/mocks/mocksContainer/mockRectangle.ts b/test/testUtils/mocks/mocksContainer/mockRectangle.ts index f9a92c41904..c11af824c56 100644 --- a/test/testUtils/mocks/mocksContainer/mockRectangle.ts +++ b/test/testUtils/mocks/mocksContainer/mockRectangle.ts @@ -47,9 +47,13 @@ export default class MockRectangle implements MockGameObject { this.list = []; } - add(obj): this { + add(obj: MockGameObject | MockGameObject[]): this { // Adds a child to this Game Object. - this.list.push(obj); + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } return this; } diff --git a/test/testUtils/mocks/mocksContainer/mockSprite.ts b/test/testUtils/mocks/mocksContainer/mockSprite.ts index b8ccfcced1f..ad70b6ced07 100644 --- a/test/testUtils/mocks/mocksContainer/mockSprite.ts +++ b/test/testUtils/mocks/mocksContainer/mockSprite.ts @@ -201,9 +201,13 @@ export default class MockSprite implements MockGameObject { return this; } - add(obj): this { + add(obj: MockGameObject | MockGameObject[]): this { // Adds a child to this Game Object. - this.list.push(obj); + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } return this; }