From 193b074608aeda9f0ce7d3aa37948c0a1a0ee117 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Sat, 17 Aug 2024 17:22:36 +0100 Subject: [PATCH 01/63] feat: update --- .../images/events/august-variant-update.png | Bin 381303 -> 379435 bytes src/timed-event-manager.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/public/images/events/august-variant-update.png b/public/images/events/august-variant-update.png index 58d29adbcfc35de6a0b809e5c8b4fa54b104eb9f..1c78aa2fe148607383b9d5026980418a41f2abd6 100644 GIT binary patch literal 379435 zcmZtt1yq~O7e0y>cMI9Lh`~yfB7a% zh)W@gZ$J41 zJj|cQtA#I`ZD_N{6wD7Glv#EJU|Px%t7$BP;~M6J_$G%r3$};D?k8>1&bW{|5c$w#Oytg1XxK<$i1u zyn)19i?4c?Lw%e-W*EH#%Q*?kB@a~0$Bg`vl8woRzz?;PR% z@NDtu39l&Ne`fAcy@vesEXxPep6~oOkMg$vEC7f`|8Wqmj~ z%aj1_ZO>K%ke|{Lh398BG@BAqXU3!W75UY?JMH;C`BYY8Ckh{8P&Z{RDo^V7c5a3% zH<A=?;tQK^!R2|0VEa8m&$hn@d0A^Z2bH692ZrK-h|1|Q z?lTGTKZt+{jX%F8Zf7p&Wy{x)&kzbE7#zp{s+!EZ*`((k9QvDZ;4rNiKQ#7o51Irq-RWIa@^0B2SHB{jy0Wm zo{rCKXJ9}7X0N?v(RO-GliClTz`4;wAEXra^6v_b9}7pXW=CXz&qTo}18aEgwz6{r z;Nx!6Yee3t*S~<=3!nc3<^Pu-QQJYepsbe4wwchcB9KU5wS;3{Sk}*I*nw?w5(n{H zvrbrExu*0uORPu~dTid8t1flRJt#e`6icNq`n~N|to{Hta11+`zTUeza}UbAIN5o& z8GV#(ET)eMzPMhC&@4vkj*?;DW$g-^*1YErzL#)XZ-o5Mk@d*m_lzWK?=9Rack)}W zye;l^`TX2(4uADBhSc$y4wT=#aQ!7-a@1Y+|(rUlDEo zkkq=r&uh-I#VO~@Yx{qE9@!*D#uxRsa0A-XIlJ;y2X$bCnQg>IpPq~*~YQq4gD$|>0Ji@sf4`$BC^ zK68Szfr4-T_HEzhY~hFCL;{}L|KN#R4C(A2OB&Ry@9fv0wQ);x76GpCy;4WSKd%0y z(aMB7et%nPwjrUlTrR$l{Se=xd=d2w!Myjl?jSEl+1{={?W)W2vPU3IDYw$cbQ>FS z5FR@!qKroExdg*4f=W^m|IXi)cV@J7=HcI*d-vqu`TScugA5{&_MXT49t+)oVRk?i zuuUfY#e_hMMU>%@r^kkwh*bdJK=5mLer5H8;cZLm&Q)K{1%~*&49LXBoBJ=n)}ljnG#!X^7tuHr`$9AAI&DYGhDl>2tAh&#_NbGN6U zJp9W|A85X~_rLiw$j;Tv7=|_ zJ6g=xRGrbR%g=|a<>q$>o$sUT;lswn2|?yu=E}MM&c|wxg68`iVsp9Q(Eyqv(y>#(ae{#tFuzgKe`D2shs&~vO3Z9;aT%hLb~oox-KUu zHNT-iI*`1)M$g1hq8Oqfv_IS1?9)(5JT9@g9LqA%r36t~lps3$!$fuJvb{DQ6V*A9 zCv%zo3_JD`p{6hK-*bYE#P%Vrj4cgmF76v^QvY67;;v8JU4)qY_>2e4^V`j4ICa?y z8V-zjc1mrELwoQQp9HT%w<```BTYp$Vc`z)WjK>LI8>lE2~FhfjyPCQY;KL*hiZGRwcb4lQ;nSMw0Z z32>0I>r_a!)MCgz%`G+J^^-|Gk0#j5nZMlRaDdQ#U@L0%f8F9XltR{8UPKY;Dm){{G$-`f%e%jtGV%6<5a}+ zsB-D8$Kqc*!~eN?Nc#4RuRYCO%M-wsNHyzG4*W@~h{6Ym-UEhqO;58>L=%oVJxfdb z{~kg2v5HEYP{%D}a@Fzapc^@FYr1DhVjxsR2Dhc!_AEtK>!V9xxh2{-_y75*YytL= zS?~Jw7>|R#ZTcUnj1*Cxa(f@s_a@hdc=@9&^YK&u=kor~CN57^x^8z|Sik!-t;l!d zB;G?2^QF7r^FPhGy`APGJ9E7^dv;g$7dtRI4H1@ROLDEvKK<<_0g zwF(KukA*R}atS3m^hdcVY*RQV(hWJCdAQna1}x{cVG@+`4=QAjo$6n!N@llHO_Bt~ zk;jUz?@Vj>cDi$~R;@x1+wG?*?)($_PP7{le6{oSWkPVH)E)eBi8d=g_AH;+kyv1E z96GlKO;(lU2Q2hUS`y*cv{>s`{fFZwnK&ySzX{8LJ5TQbf${&o+*2Z6Hxw6YFY=K@ z4|&Q=Zh5*;KRuTJ*y-xwMQ~4*->iu~*2GyLY4NAoGTgDH?|C|t?=9s|)c??lh%|{9{%wxuC;X;icbfNl$o4)|N?K$ItCErTY812_TQF#N2_M?fiulA;PHT_h(BKmr zA5Q%GD2#%6Y)(0GvuyuUtFSlziAr7+_zU^w)9he8k4#P{vex$ZUo*E3X8~va9Xf49 zwXYijBv#W;2JX*SZuC0|3LOYGxgUuFY@`#{{uK7{C)k`0?OxoB!QyUOQuIy>OKP{e zht~R@1NZYkkd-&t3Q!B$z+IPOXuR6=s%(4EAeE>n;*)Sjhv&qfvFO0iL2=_6mSD!Q z--luML@jweUgzxRoZ7fqT)(mCTbL+GF81Kt*E$c%I{`D>_!KS<&Wge7L4A*rPZMuj z^<|q=&1Cn=atnGcw&8?pV`K7v?P^DkcV?qL(Es22gPwm^NdKO{8~-3XocrGY%Zs|s z?~%=MsSZs-#JT_bZ;3jaF}|amr+bq|4*|zMcu^R-dch7VxXyPQGx2AK?;Q z;h!1dK^Wt98xx1;5a>Wd{-1`z@nj#xaLERj`MmL9g<&6KQYfZCh}=z^t-k|5Tid#m;RE zPAB+&4R~WxyByi_RpP85KvequNq_kw%FX*=inW}iji|-co60AlASdZ48G_E}ZoKaJ zXNo|)XW{EzPPH^GQlfRdgQryIl9`V}>sE#dsGm0IpO9$sKb!qu0CTvtmsdNxSfe$b&edT&$t!zg6Kl9gF zNyDgk4BDM(|JJUBB;<-%&g|CAH+V@jJFUggO88jLopjE3+Q?j=NJOJx_`9B((YLi@ zz?Kf>gS#=p!h%|j<$R^gQ3GD1KDq%zIS2YES(x6IS}Ix*Ta$bMj8c-O$78>>ksX^e zC&{hIjC`#_*a^2=qmfYY|5~r|Fi1m~oC;h~GlF{XpfvA&(2nv(7^>-cqy)(Xt#e1hG zgZ!KQYNoyAnVpgRd|=`=qci-Vj(<`Q?pMk;kGf<*o#)IC8?gkGPrkQNH(S>9n_A&& zG6RMDx37X3jUJGm{8J*jjc=qegS(*-7i&Y^L=#~8=b%;a4Z>rsKbUYLyC=Bdkq+~D z@1~t>!k_$^e5l^%%#=oXZ7`TNko-CDlJ)_Sg7q+&;&Un!#l96x&>i+HB_vu+CfG@6 z<@bH< zT+z)%O#UFnYBdMu)vwH}P7G5{)p-Y4YS$>DgMCpQA2c$2suh`(^BtLfGu4+}zK?z7 z5jdw48ghfT=@VziN0FSbDFhV<6mGFZEPZvJTj)s2bZYh%@$+sg|L|mCtg&O0KLDwm zaGR1HR||;h#LXW)$dhOi&$<>Ne}vp)A*lJtT)AUWK76%drUE@Z7(YB({G=(AXbPCH z(<+zJQl>YXN$^s!P zbKQzwKY7?2)J=d9ibR7O1*45C=FbM2ibp^k$-c`YoxI0dwI>bwq$K-?P(&SQFFZh{ z!4j#QOhc=12Q#-yqEXnmS>PxLhuF$nFXq#z*v~~VXyZziisJ0WSe{L;) zirS_BM#E?Qw8m#^{}{1(V@$A_2d4XVi;zjgp%1{$lsw1f3%>L-y1h|r-L2GfTX|Ev z6}h+C$IIUpwPbon=+kwFb>jElUQ|yakp-+#!6Qn&4-B-`2Jw^ty)PY6GG&O`1>7)z&t4$h-Tw`2*tg z3ZKbpr4YO(;A_Kap<&PMn0_(U=mR zJkXe~o>6wSJ-!JD%#Cnyek562J?HG|Tny>VBk)-KQdeSkQpe|% zoeivp2emCUrHtTenK-z^C@-(v}k_HVfo5!FS zu`p1-=O@J zOFsd(UptZFcw+7%$)gKk1w3GC88!A9Bvb z0e8?H;oQ{8kPP(NQmn*?wSB<4{5-SIzbydbGOK$ZYWTgcg!^<37d6KVH7W-)0gu_; z7kA1siby7iB*r6&IdH>o*uR!u z-Ryc8UG~qlZkNMd58%N)JHdC9dQVq+Mvw5|Uw@vjZH#8Hf}h`fCp~MC*=h;CPmSn) z!s>oJEOe#a;3xb3JXYxXSjfA4S}qgnx3QvcXWj3agf})0`A86_B*L{2+ z9@lF0r`A_5=ndabt!Hw}3~1>Eg%t7y)5{p&@db6fD1__O(#=Vq=-CRI%X;pG$Si#CV}8rK_9q8YjY)K=)Ugmi z;UYxW=WvB_s`?nzVbo2)pMzNUyKt6tS&p%ZmpE+yU9wh$9>#P2gGHF?YvE7@M$}OMr4~7LlKjZzaHjWd1k&NR=JpC5CRHrmQ3=#Nh1TWZd z;I=2o5iTB0E46~`M>k-?G#NyHje#OY$c9WSrziQDXkVS`@sh8aeQ~oPNEdR=O8$EeH}9gy7|SiaDj_d&)kQ;=7GF zMd7=Z+E6ySfnL&U>PF4$E8A7bGWuyuh-RA!XFr;YmcjQ9t$Tm(P;nTHKyZAIjjS@ zxN+i2cK5;y1CAR~5)?93MznBu6**Q(O3y^uxrN6dv`fc=^D}+F&+}lGQgoKmEPdIX zy3u}M*a?@#iY~C7jqsp~$=wxS45Vn)w9b&w$4|gU>?cuQxaF1^Z;LU|Mxy>JT!j$+ z(Hs(vj2Gh!z~W&6p+f_{dVq0~CAB$}TN3 z6sm~}cCFG4C0-L^aZ6d&+K8JZCR&%fNAKMryc#wG*;C0bc7d_?6tzRy1IR%uCeN3W zlOF<-Iy=U+5fc)b1tg10`S+*@qAB=GJpW+Hrs-Lut|=IGy5sYsxX9x8@Wro$R7{}= zdzbm<-&BFC^gqmPc4Hv zLQql&+bpy_o0Q7If}EGTf~iUs#zOKnqo;zQHE%*`DeM`91jA2nIEt0=8NH7%H;0ny zQ~tf+p2_13ZP>`4$X(AUw(pM~^k(UscGpHr#cBYG6;(~wp@=PF73=Y--CWX@ARYrA zaSIC+pzoq@Ql^tVp2DEK{Vww)Kt1RzdCS4PDU>61IldL2Odx|`i7W)iCO9W`oZ>2( z24p0-Cv`s1{4((?NVz(jGeO;eIq+}54*9oW)V1rUxi25X+Rfpm+Kpj}+O2&Fm-YR2 zmpURhrmG=oUuqj7>3}Grhb{VUjJ}1!4g#ioA&ZIATV*jsT$0;KCjAeh%Zsi%lD)u3 z&WY!{H+j#$_r#u;CbKzQdwopTL*ZQm5o^H_IKd17zg?%2Ot*^ZyFb+z_tx*3WD^qX zGEyWD3pmt=tlcAIHvV-#y%6v~&*(PF)OGMhyGUi8@iU)qnE9SJz(&_AFKj+^aXlb6 z-I$*2>R~Mmh>VkYAR+HWyyo*qC>Y)R#b`ZEK)CjPgKs`$uKv2^?})i52&CPUe&m`6 z+_cWSn2!^?FWPgv4x8M#>6~1@k&V(-JS#cqB!JH?=$nP8nsJLnWD zT~oTTpG$Mpr#x3PkZlKIpYu+eV#mruVpRv^g^T5ZtkuPU_uBZC98ExUZJ}Z9a5*(0 z6#^9%f?;(rmG{{dj#7Zl6*7wz07V_=qLXZetA<)cM1~<1}56V=(3MzE6E0tRSS8vTX2xBACBhs z+#M$mt&#>S@zQp;Eybr*y@uh;4(tM+9clTyn(%TD3rd^R0o1Yu4&$(N}2 zo6~e$?WE2{9DQb9FuXptMh#ecdYtz@g$ft1tVA435wir?1j~5i;rB3Y@Eu)EVfw^H z|Ij{379ORIs|TIYVUv;%`v!9x1=JaQW?lu3+RZM#Fwj;Ihmk$>L|EuXowh3nDR`xE z*#8GU(^2@kYbp@}wlC0U$sFIKjGs`Sa=t&Mz_Tss{g-GUk>0vwH^yVaqEy;%bwQ;d z7(aTsoKKSAAa25j`5;@3&k865UKn)L$;S+S8XeP*7AJb{6V@yCJ=Rr!#bNA&NA1MU z2zB4`;_=Myn|nu6vFgrTYUpB7baZ~)BHOj~k;7*dedqg9P2Dy4q!Bgj{=}fZSZ=Es z{30(mE26FYQ7$~@8%wpW8!e`rp|#yTXr_UQ7u`2B$LyQcGAxe^5PcY~= zml3N&Z{b}@9;<%jdmXp<6G2-}G{MIjc~|GuVuxSn+>UPb+>RFXTraaTUAHUA-EPkI z-1evTT=zF@1fJGEP;@`Pi(k1HQ-b@GF#AZxr!3L+o$?Zx?U&sb6?i2GBabTwgSnwZ zMv2$^0ttW_+t)>;K`V5MWm}&B>-)Xfntqtfzn#tlV)K{*lH9KUaU@=cxc;O`MT96g z@e+!Rf8z6Cu+&_PZ7crjC9Ps5H&Mc{rz>mGTRI%dph#Rnros|km0Tv9zBUKIQxW61 z)g|FD4ON!=tJnvL9}jViK@SvsA1L^xQxG5p2;-nr2M~QWbcypd?J)c`s>I$9biM~z z!TuaUM~X%LMT(0}L7_oep-QhX+_M%bQkwWcnwT<@sv*$J>i%%}N>sB}C5$@=eD%Lt zfJ*V%+4^Rms!ET}Tzsb3TMJ#+wt|KRk)0LI&Dt)D z`uRgFMP714j-EVsjBA}rlI&#%;zVBF6Pk;PeSBqe-+Qxx%andD5vjxwQ!V|;I`1&W z?U?bIWyeSj>QAk2f6th7TjTsKl-+EpADpo5eUsDgMC2bgI}_kcrQt$+F9l{x0q5*> zrYp@6(3o9xE^vSyN&~@KqTZL6jmpbD*9eHLM=#}p51vJf10mRe`BX?W5A~G@0FJ1i z@)cpC$F0-8ecWKc4_6Q)#CoIsqTsM0yEN&@lTzWN4)%1QmUzUfI#uTa?wvd3<<1Ys z?XK=Dn~O1wQALrV0M=Oak)jfP_o?-+_M$Z((fIq5dRMrVz)2?t+XDCm@~+je$JnR8 zKdZ<+?YOY%^CdkH1huO#*0Vae{HKLLIcL3X^R0{9?>foS2r?BFRRQyz~UHq(}$+ zxuOxx4Dolk533B3k$xv~3Y4KouB`*oemt>E_kB2pTTOa6%vU>!U z*$g5UmJ06C5X2{7t358jJR0hMv8e>xo-w8jZJzshJ3cDR>v3Tl&G-|Kdb8t2;&5b< z=`{eh?S{xpQ(9UqMO3%bSJHe*maidMtHB$n$<gpbO*88-_^?964xWbJJB?<8L@v~Tf`)R7a4E3O!Ufqd)=O_=r!GbZ&#Sq z{M?_YN8?8^m~aTn3X0hLaRY2iNiPXwMaskzaRZy#Qr4=a@9adnyh59rqm~agrFaY^ z!o5_c>13y%T_{AmfqBXN4ov3PR%0 zUQXw%Uh4AlQ5g(!y#V~#EPP}|N)<)`fsoDv*XSi(VQi?fVy_dUOa+571t^*IQj1}x z97;SLh)sr)zuHtharJGOhq2+2Yd6-YJ5mH)Xq!z=*;!WE873bD3!#mWBW8*X6DBeC ziv02|@yj3me?id-L(Y$#Hv~%^uwgXvpuq;r$RP3|H4lInQIM=#x(4 z{e`)N)j+BJm9?<0$Ig8jSQ6wr5-LVm@)zAnun$V_ zWsA$>Bf_%~l^L2>A6@UDu{vS+ zZl%;5@hQEdWAKFKe)XQ2x0HRO;fUL0;Ny@rc zg?im=Z=VVa%MHg!DA}+W0=&i0Q4@nA{B=lv+OEH6z{WU|*f+%FMPd|%GR?_Qda(W& zbCcl~O%Ft4kb#=NdtLE@tRjJml68PNbUjCQ%Bgr?P}{wwXIePTh-~ykoJR=c*0OF_ z{Esqpn^Ihg>7_`iXg38duk_5)c~7-xF#6R~weLj1E}|NpTZ#GfZgV@Fn9KwY9OlsY zNMmfG@Xhsu{#mw-AUEB`{bz?kpVLN_0^fyJR%Bt)cjXsMBYTt48Nnqhv53>gEb?0J zhMCUbHitC&Ny7k{S{LU^I!&~rrFNH*?yd1PeQiQu$XwpfjFfdRhnG}C&Xs<*x0Fcr zN(kPeh{aZ$25#+r4D2ouon@moPEh%)sRMC;Lis6Lg;NBgM(@CcgMLDTuTbM22?E zH{6}9(D&*}uepi{zcbNuF;5lBRg1=`_|Wu*5#3y)ZLDtf_c)8*dE@6XP$l~c7#7KP zxV)6K)P190H6cevkp?cy4FnREhGALtQ<4-+tzRfXYU*fg2`?H9moI4Ucn zT%sXG{s#4JRN}wI2!O4fX>G_(Ac1*4rVHUsvUx` zSPQMB6eiJTV>&owl3umMf5FU*2ZV)xafp!RS>sa8T*3ax#pR4fyP>U31iGp+JFTp^ z(@_aRLLzmqi%7<1t(J=+^sLa1#T0-J^6q01`%j0a2=*q6n3rl~IZ+7A@Rs6Iyjywk zhbb`VkT8WCt-pE{*%VK>a0MftDkuy9W4PDF(fJtagRGkrd%zHc2$-JP=`5Y=psE_f z9r?Cp#R&Gw!$fItL5^MPK~?8~U{ye#o6r^Q`%_vRt4Z=uQ;%6!f>oaHuZm z(cf{t4r0C)i8tTs#w_Br82&p~)N(9?cfQSwyV+?a_IRn;eCYak{--5|_sMdMal5zq zWP#LtyAS{M@k-p|{q;uA)1#R0`m46KHrUEaLcxji<@F`BwuSuh@sWapqG!G5l~Gt& zba)@k3NNQruErL0j=i0S{Fb?d<{Olz5=!zNN>T--;3yd&;wd5FDxu*k0epi3YN0t5 zvLhp@3^vvonRywXOsoqsyF-g><3r2iL)+s!;)adv1kqK8`B{!`iBmjVMrC(SGd^Wk zVUd!`8%40vsBkE84P%U{T$dXb%T@DI`CfmqU6)^*cw!~OvrRzJs-=bm0r2Fb?~7G1 z0K*Y8>OvetI2D=zylQQ*FmHcfxLA)OasyQnFPZ*8KBgo}%54WObFI3P97L|JuyClp z-~$Yu9M7N+lJlj=eTqS|7=rqiODl`5^1G)uWl8N>2+gv_TKOXj5;|Y-8RLzcmrNMoORgb2`5Vo%qkG*18|^+yd5z^vxq~J<$ZM(CUjl6y1zmCIW2+Qkefj+o9|&j} z5yL`5B2}$JV>$vZ#|$WY*|Lxf;O@IIJ(fj~V4*Z&S=kG`5uViyi81&E@8O?LFSM~xq$o=h2H(f zLRGJz>7^1PDvGg`(utyD5u%7^z(OS!2-CRp~-W+=+OKdDK7^s(Pl}-vJ$l0zIdCas;I+dt@55UmPtXE)HVm(c+QOCZWiW6 z(T1OTQUpfZzYM^k+9~G(u^a$(SUHe&-l5B-ri*wgqD2+iF~B5_&8(f$M_`_Wo{CX? zhcH%Jdu{7J$d?bG7(MM6Z3bwYXT@EG({{`0%>z438aS@Dl zIC7yjxypmgme(NAnRkemT*SH_h!s^w$4*F8@HIgm8Ki`FPwdhNh33dWMNYUve-h?l zPW$K8PPu_?0@cj08<=I`8&p-F$=$!ILz!m8r0en_`V_15k7k|WcCOMXmXkYO!*Cl} z8Bs8;|7@t7JQAb1U{)m+#dIoKsDCqLq@tvNadxp{>dm{ET|tAC%PUCWk8KCmW^s8t0=;gV=?P{ z6@$V{v4MUh(65oTfo^XOzy#tp0g(aNkyFv}P)bT`v7I>~!V#9QZ;Q4|K`g24+*Hx> zz4jz1y9T?O+UPpn)PHM-$`Ys-ID`^pUCLATUV?pKgtN$IN1;*<0bQd~wq5woT7t*G zK;n|I6iiPI38b8=P$(BR$)`x3cga<{I^3jbYOEwUXxkodt=>?Uet9>rpZ;=z`S|HL`TL%M?-x$>R8*ehP$^LJ2nPDy9*PFC-r!s zZAIEXwR2&zJxMBJ@xGFgo?J0TB4HMcNvc0lD-9q_Y9P{|8rSbo1vD&`qWh4s@K6D? zm@Kk{D)9`%4W7uQs-*9ALzhG4`ykZ`@H$g*yD6t~RZ?L!1kU2Sj+-?a)^bHNQUm{;-KMCDVv1l%s@+Z zIXKbWLzSwkI54Wz#mtJfPq1TA$%}BQ@Cpb%0|5G~jsrihr2Wf>z$D^5J7O4JD~KV~xBT7l;^pwiTJROg3gTnOShV4wsXoh$T3 zRA)m-bQmLaRLt+FoeVf|dr8bl4E7HEzuT?Q>tvtyoEJUFM_%Fk>){ahA;n<+AjZ!~ zVpvk@)9a}?b5#DWMR7$oeE8nlQJX=6p z?GH%nkG57zvK>@zc=4s>gJygWi$Ud0ft**eI`B+l)%S!GIhlVkgK<%(zczcxcBL8> zBK?W1j26r{mHg5H@|!Gh)S@ba%l_JP@6=dSL=FbnNrC#0w4;bf2<>|?g|jGnP$4%0 z_Gjj^#JmGhQ!4RLB6>Mq!2u9Ks)`vF+DBloRZ$3PSkXR3WXTq{jenn`a>i{m-0?^! z6p6@CTWH-*S?Ff0)HY@z8uNo9t*<1V612aF(4wA#`3$&=b1SK;NJUyJTdeKy=`+(y zzLJFmR^h|$N(6~RXQ6SOg1+bbA;}3h5{dKViU2b8u2SPi5n-aPU-@r%x9{;%;o@Fe zy1EjwpeFmuqOR^;Xd-upP0WCe_{ed7z~OKO7Z-ki|F*qHX8<*aR`(jl>rsZ>-%!wS zi4k9sYN#A{Ux+ffE0f8$>@4gDI_GziFt0wVDOnO+j-1{^`=7Wmi;eFgMl}u1MHQ&J z8AY7fp7y4?)VOH}nWlek3O`ER}NI;G2 zLn0^Kwe?fE#VwjYPO+hiU;|Nh{LNb~P6CE;VRvC0ZZYifF&;Jm!+`V}S}F|7q>AgZ zn5%&=gz<-UI}l1q_-CpMonFH(QDv%C!YJN9k+{nN@XmRsLYUa9plGP1Y*ZYu_f-*% ziUTq6)Y)VWT;qAzY-HQIv)DNi#gSCX?-UYBs*Bj5CVzWC(;#x~Sx_N5kIU2dQ1myo zz2kNQn3Q<_24R{znpGfTuCy1CQ6?ESM*}1{qg&}bl5v>;@L1BY=#cvMTPOsjm!_7} zy$gvWJ5P&NxxZ}3F`wq`7gk@{Rk(vVgqbhN>h=2A(o}G?i5u6cYsj=_Na7`9(E2M# zwNUeIh6xmmcr+85&x-@FipWCQSPDfTiVPd<@wWUvw%34g^GVTJusBn@{v1U%nMyO6 zKoOe8J`E$WQfovs)*Ax_-j52rCJIuYT9T^_k>$!DpPM6$h&8CGezH+5kO^wcVjZ9> z@aih_eu{dhGHd?JUI257Dn1%Z%AzlN)-2os_Ft#MA3uI{=8_nC2iUG0ZrrUkUvL8e zAFZOh=_)K4&0+q?KadLF%Q7LMDB|m{hrS}lRAEs`G*F2z&Zbd(^E%ewlj16xl@KHZ ziO?2$Ic_VYycPfsWt$1mNLguU>9=^(a*XFp8h*Y=7j^F2)yS>0zWD68%p!=MUunlwxdXOB>fW1LRg4Nox)%BS~OvSTrz ziI~`NS1F%S0Tjh6Q6QCQTP7_f^g^Ce4Q6EH1;zf9F{`uFz5MCmG&<1?hW(Wtpyj3I z1R_yHiBPJy1Li8V@b=kLpaV}YJP9BtdMZN6tV$U%LgaC1WMx_#ckjro2^ClXpHp4| zPhva?@bSlUTM<`N0r%1lU61Pw#AqtA&;VZ0qA>iyCRYCRw$+T#JTzL27lMjXg%gWT zh=!s$aCk)}4l!ky_#~7SEhNTRRYJNTS4hz}D(xF4t?`l%6#7;lt?s={eXR?~0_odqD!K>r0)7O~f-t7BIx z%B4`8d=`$(Tdpv62*cqeF%+p)7_$exp-Lk;&Q_0ee8+*oQ>@8SyIsHgs)hW(AX>4z zY*fJrGk#SKD(K5fV#wk9%~AN}Tp<{SR*LS`OeEwx7nbza;wOckilP%O^8Nyf?kMYBTj5ckTLHe9JVQK<^@IR`cX z$`A-I%8S@|5QxP5i6!LGZ~HlFY8byLr5>aus;wogttO(aMo1;Fg_l(?9$$eb^*)O3 zdq1XOMpUuk#h*i1XaGc__wEozhH^Z38ScY-_O>fz&AvI{tam}bOO}!M{V*Y2C}r6` z#2jbJT-e5m6a!M}aJOZbWeknqrree=kad7`}6I`n;@&X~_N zkg^4{X7j&O0uH!dCFsb9tsnOClb)L7qhe6ikrPN-cA0#rUYk^V6uUA2X!)o}u+fzC zV_M(O`?CO$hzzJ`%e2j3kA_Uo5Lxdn0)c(%#YhR~h8ve|WJt0puY?jphS@ZD%~H^t zIZ((7oB=7qOPdf58vRhnI1_1f#}~|$$-R`{pHo!7vNiFiIK}!yIgkvjT-e;Da}P6o zVFq}R$6!m4SFwtH2Psv)Dm2`%O6wwY8$(TKgNbP1llS_lh z+@n3Q0(Dx-P#=LJ==;wpc#V;vm;h&64Yam$gDP1rJw`p-8kC$e*+WWO0iDAZNHMw! z>bmXoujoB{;aLabZV9#+^c?&eQadP_&afZpdnL#~8GFSr2J1Eo06SP`w?JJv< z->iN6v|JWjm^&Ja&`d38>?C%A3?M$xHC~5J;EpoDnk_4l7Hd0RDxZj^3MBiCDNza7 zHkRnaY)mP_zz_RNJ93i~NS;pc!6zpi8L6UF+x3&{p1DKiI+^f&Gh8<@Swx(tfC!;O2MMq#Rk@4kB4+R-ZgtxJAmwu?85iH6ct9P$NXFcR`< znlf@0J+g5EdQUO1$0HfG=?|Wwn4=1by%D*;GeaukXlGptzGXDFue#;RSr>QKXtm) z{NmVNw}5c6kj0+!wN3I)+>sey-p92$BZ|?OzexMv)>RHuRsf1V1|Wm zks)uv3}7fxPz?P3bxb-4rQ|3Ghqj-xKYQ0V#IFG2MO(5?WL6NEEe@_;m@2J&%N7rRKqagSy{1}@*FM8GS(ovvuF5++GyvX10~!D~09%2v0;*!@u4s!L ziY06#Kb8x_W{bDL6E6aVWxT05v?KnS9BUzqc3hL^VR$cK6Vph*F?`tqD`!wxAM&Vw zSg7O~Q&TK6?Foq;4~g~c4)yFFzvk1r(oNa_#;|G#Y?MeMj6uiva(W!s+sPgdSz)1S zT}rVc(Gbb>!YOOdthIx^6LO`!>{%j~t>ceBmBn@Q!G5PjW@n1@^A$N>X@)ISKGr@t z%ND9&eg7dBW;a$@jrGQ+IOB~re^v##AxCz_8;Xid+}SZ+9bDXld^8jQu{|s83u!}1 zJ7tM*Nk+_KhYtiiSd8>-anS8(?H3o-a8ugDL}zO{w!&uE|ikQlX zjzamb{hg6BtNVL`7`LkUtTtR%UmI?qo&G8$Jt8FizYr@tp5BS4%iuE*FfWFfpXQj^ z(gO1#6Xwq_biswj8`wa3YhNYK=_Td~&xXLyIE26*8^DkW(if-6mBX!qFXgVkhp}%P zBG9clwkB4y7V7n&z{h)~3IgjshFjXmqZ|@Do)m*8;qk1_E*7dwy%2LVg0rC;wEC7G zqg8~EaWmF^Iks^vyx>y{>oD#A8y1h=o)DB2qto^3$2ZR@I45d3JPADWG zI+XOhsKYr4>r_OoOnHq+ZXcqO>~mUf&~RN2j)KB z?3MaM!hPGnZOLaW9>Y*j51Dr#cEOg;$7$5TuKnNb6WZ~_$`I&U8jw2y=I51my) z`%5EjT_|#J5{Ao2mqg$KiwO4Dy-{nqI7%@6E%UBNv)nhEJpssl4U{GW4NYfDRjr9U zzsk%B5gsP=!71&W9Eli4yx?IQBLr&2;cXOaf3*N^ZDI!y_!&;WY-xd3ekW~QNV!Cu zFgu=O#h7SL4BSx6wEj|1MmI&QK0-3QfVXJOu$K4fhv5cu=+~N*%OvCBYUIW+J=m+C zx4geG{zz6+P2lKb@sX9=p;htOV*$4yIT9**Hj~T};5~GcJ(86TKNY{54nqzvH~}df z7eX&!rhF2B5v!t2qhPk+mpVmcmLxVR0T|fr;3YeIrnt?>?T-+gT_CaEz@A{FU5HN< zqc0Jvti5w?ZHbS_Az=1UE z5O!=YM4&sP3dMBmfaZy}`w=WHAVz@aGEh*5`Rek3lY4c2H@g7j9h)GaniAcIJx(5N zXwt=fo!hY&32!K~mklHKxy_cj%$3i3_w!Yl!+}1wkz^gcSSCXX1f&e*2+i67M4XK;4<3=U-k(9}z1oXWKzz3!r)y zsD2Yf>pw0E^uQE)H9 z&H+&#IB04#62pB)ms`=PU{xF^KF4p>hGN3>B^RV{?s~VvJ-|cO21T}Fw1QPTF_SqB zWlpyZT@S!KvR?)L7w-g;h!fC-Xon(*Ul6nvJHO1~7fy@1^$V6O5)@Y!dmlq97hn(| z3^Cl)9a#7XX<(hvb@dH}7vWI|_s<-oOFO$5mm-}?0Y`+;J>e7 z_Nu1wUyg$}n60-2j@MYJ{A`xJL~4mVYjr1utd8Uyuz@fBKm?eb<*j*n&>`*Oo765l z^D(M(_4f{^eSTCSs2hF!HD4ebi`5sJpfzzBZoX$SkJ9DzUaC`jlZ|W#qo4RsQQ(-n9Op%kH)Q;vpi`>u!ts9Pj`eH5V_L(> zk)47a1{mo;qZ>nHYojJEo0MMh6$2R=u&ls(CEKzxtb4Hzyw4)o9=jx{&`gGb^?wQx zUhPFZ({Chw{bDAp&`&3HnN6h%wrA0{*VG=88R_tT0O0aPBkf8?_GQuqrmqq^7(lHs z#(j8xoE*PljARtSOTKf3kY8qCNz5)~?P+O#3YBAerd2|RRLJl8CPhD4xHaU9gI-;X zULA*C-5)(oN$m33Me5z7TW;Uj_f%urv_6%h#;cLzr7|B+p@y#*RkYGf?ywca*d6Sb zW|9}C#XZu14$2F+RXf{n?O#+7gGg<*&j>}mQHTz>!Cu<|5vbB1$rA{wk4IGs;RGoX^aHUW^$UR|B*M1 z6a=IuyqY1*xyzg;%ba#Xo^_I$IWPJ$Qt*AMSkRwSg1;$xSLMa}`39)5r|vp4DDHhu zg0at{o+m^{6+TZWoH2Zh=V!;Ghe4;(%2?>)O?3I9vsD+0`7jEb6#h7+(6YY0DmKm% z%v&TT=00T2QREaB7Du|p696rk0>|Ldsv4#-UA8*Sah5I!+*@tIgEj@v_f`DLdWZxm zqn=OEp76)Q)0`7$xf2$|W7nFn$a(Joh&>r%9|{Q%g?QY8c=$pZ4s^xd24XHRkxTfT zb?<_@Ug8mNB|B{w)rkPw7d}_n`<$qksN)xl(&|V_C!P4Qe0y3U>o;-jGR`&ygD7eNU|478t7k6A7h*5~u2 z@ufynW6F+c_&pZcC7yKC-24W^3!+kkriMQa*(rN*GvuIb^bKZ#^HFRq&zFat^S^WN z99P@+Cj|=&gaqNn#ycVC8jteU(ru8H;+RzVIA7fTJ#Vwk^;iG!)n5#ek zF?u^f>1VdOhBn1mbkov9AZCg^zEV=~Ku<^($bX?h_`H5#6X)xg4u}3j)0QXyrT^3) zb~a_du|q#zAIa>N$_Oc`XppMRF`FrL!di0Q?ueQ&Wt4&7$G^bM5<|nc2USWwI}7vM*+```u)(+++_Ozi$%%kj%2i9;*wXdp*Y$YWUCpUvU{&R>E9? zbKvXrt-_A>b9}R0?3+>$6iX1_tQKo~pZ9Ht%*Z--&^b}So5Uc}1GolqwA164UcH-S zgSlXXuV9G1bIURA_za6Pb<060X=_;d7uuC;O`)LP?p*?)F<>?%1S7-)eaTydeO}Ro zJu6)U;Jr2~Kvs(O(_>Ena6Tr)6tl@Ww`V_eDiqToLB*L=^K^Fk#K`QEj;{T!KK-q$ z{m@2rl5qy>Mh^A{^rI;KNA>@oFsttWrf=MI`l!JoycPuJ^k0g-xS!wsva=m_(GOCj zPA<^ZrRg|yp<7haXS>j0MCDLp(q1xS?Icd__%mCgqf`iemhOh^3E-kNea9z;OKXwg zRbTwRj=sxji<$c>mesxhN;HcaSpa2lR#~Q(;67?6#&#YXm|A;l;LPS;b?|zi)!K2f z$Ov5A&@G<}G@;7jh#A>KUG@eHswl@Zzy zJhLqP$aYBXrYdY;;)C2q?CU3!rDVq#jKVxmwh}CvFjXa_{OVl(&10q3M~oE?jQGQ@ zdSaX=hDwd|z}j5%5jEj1PNbTabxs)ddseClzeIG4G&x-8zOU+D@JWREnmmm6fyUVO zX+ti;A@VXjCTN7HsDBI(*VE&!p3>pg!RQp$`_gJj2Vq@KBmm%VaX*x3dBJ`4WVI1n zrCLS9dg(%WMRmB(K2^_10MQ_bUH0+4YxGnl+a#JI|D5!k`x?no^*udNpgasbo=Xj~ zH&m1>N~e<&-}fILyTgoey%wF6I0+*#os6ZblIs9<#i1OR>)6hWV=MJ(_U==4az4*h zr?a1ny$~K(da#N<@J5IFNXujfk59W`OXj;}1JW2VPjB7Gf7|a;QVooo6Vn`}%um|j zTPEEK*^+ct#_21T^p!N*Vq7L6hU026TLKVc;QW#h^S4c^dGBb^0Aa{D6&G-md-%1o zfCFap9s1BZon5cIeq2-pN{(F__;+dUuJ+ryXUkz+r`zS$(VXg;A3a;wgY2^G=G@)G zHrn>9?rqF{8_4ZAK`mw!GrB>EaK(g+a2#Dm5r&9@=}SkQNZ#Sv;kfmT#}RFq$m)51 zaMk0gr*+P!PpvIOdBZ(|rv~3yk6Slf%H4O&S1dqVlZv@V3%He>3kRgT7=|S{DugOy z3irb*axdyX55yYrzEwucC$RUU(cRnV?qHg^dMqv7P@YbdryJ^E`xM=ng3)nmu^68t z=569;N!kwS0Tm)}Q6`CsO3F0(0u$Tyd*ShW*vJFHnQX)fH8MF;n&~_W;UDRn zI)yuo1Ft{c9K1{n*zii*Kh=C%HuU7ytml?F`Awoi9|^zWitqt>8BSW^Gu0&Y+fVA`@X?dNoyDGBX!i5f!{AQB;+j71ZKecy?3gR|DFj2mt5i-3% zDWOqR_5BC?C$)6~75riE&DXqLa)@SvfrdQ09?o+r#RtM8F5;q{6U4b;+}uZ8$1~F2 zEz;g?%e@dwo?DiW;9^01;j2M>yH0!!PJBXdG~ayrDYLOEyVoh3_=Rt;ZvGR6QIud#{{ zy?4(98lB~%J>>O2+bY9xBr6W^#p&9Tr#{@Sp0Qh2qfy;TSwO2HteS7bl4H_}W5pet z7ucMpq{)aCvFT;z$ud_;Per_wz)n5t=l*XyQ#PUTA`_V0h;)zA(iKF@RgsvVI-WrT z>Lv=KCJ&vlX{beXXPy1jh=`MIUn98uqxu74|keQuQS1x%DJH0lWWJmn8#5`FIE)}^ME9a^rqhcv zh{H;Wdffca+-*9I01fG%?W_Wl65Zc^>kQww{it2?)KzlYf6JmsXFufFx%ck}`+wD{ z;8!iLN(YCDgHF;*?Z>-t^~mNc)6QK(4XAB#hnAO?!Q!=f^J2CJCrrc)_x2t5C^n)j z8+cSF;N?`JDx!GxbhHfg;Rp7SDw(=G8Sb&5#A(a7)>d8C9%5D~A*(`nE0nucA>5Bd zP;_vZJk2PKAG1V?ykqp6N9%LfN^I3CZw)I45vU_q1e7im|G7|nPiao}vfjgW*~{y) z7QY{l+2x)wfQBR2jVJ)jJn^1QjbO1JSm+akl8hcnKUKQF_gW{)wMDt3l1J zH5+Z0urcRQav%?2Wk#dyy@xNVUmE5x>V7IGJ1ZyKCI?5kiH#wi*+QR@C3{RH!(PVa zS{e1)7!lA&UlpWVL9TtszU`Zsil4GRMFsKo&uiIc{3bRqZ&YO%%hvo9o2CtYpE&j` zF4JxtFz<#eVVW7rkHqedm#~DfUwH=$=HWo2`CYI8VoO1r$3{?O7>co33 zu7hQ%sq2S}(~lOliPDzEZ25*(1Jd6IP)n*ZW(H;V+~G0qR$r8qf&dLB&;~NJ!31Ef z2`$tc#a4RJ`Ia;7uw`8E3-pYKCIA7G!zB~gYs6>j{zK~NIO>D=A12a^R|Dnf0rIdr z^044;{$N?y3k81uD>Nn@m-$}0+g+$D%KCOG_nK8r^49D3AhGwR%?&M&Bxc`4HvK2g z|IUYUJ@(apz5XZvy%eLDEvQKMWxF?8m6FwWN^eft%~hlRbL}ij`nvn!g=)9`j9epz ze+h1jK0Qy!y(xn;YWI}{)OK~ga=jX&YT)W6I5uFKD zpJ^Q_pPGZsw)ouobD41mrp3S7a4GC$lm1<`zzV@h@V0w@)4BSy?$$}|U;{U*R8ZqN z)Xj~emDM6b^AR(Yi+KoS{uWxLAjKY<2E@n3VX*jTQq8%ShB7|Av#*7p`$XN(&*oa{bXC?{)&$}z+2y<7z9`a3LL5l!dMkW-C(qD9hr_!lHuUB+tRxs17 z0ggee^mddes6kJR&`?sWP7;eTt+bDg^N{sTwV}oO6)g%5y_cKDsT5f$71%1*btYLs z^SIY~mIAN3=b3Zl5A|`v5>Ec{*Oi=?jkup)^(bNUOxuk%FNWk@+hPh|9o)@>SCs8- zXmrRW2Aoqx2>ED0`cZ$>*IKPb1Reu-w*LJU3uCL!7X|v4ieG&2sNvR^O4BAzrN{$C z_Ukt#BHroog-v{IIc7nv|K7R@WSM7!@3q-siEKtf7_nWb>OYICw)JdAVq{BTlPJ)Q zMBe35g>odS!jK^SQv)UddBxc1bEU^OIsy29S;HDfd1deMq~CdO*9zdVRx)qB;bcd+ ztud#Eu%ZW>nQ^>ATB6+4f1$F8#{yBj1ksio2?rs+@Zt7irSEppKRI(c^7jv5;=6`= z7EUYJ8gRT(tV94kluV5mmjHwV8JDr`DQn`$72-P^4|$y8Rb$2L##zJIGt*cND`TXs zu`0>)=gYzfQU0m{ZqHhFM|-Ik8ATO&K1Q9I>%yvDN?}9O4vx+Hd%VG$A>hf5pm*Aj zC^CX$hd?VxnmLC^7EsNwri~6CUC4U$b4&cqA52L{h@Z%QNdT2wp zDgdYkv*Kya^xJf9S)mtES)7*LulT$5oe7`x9Gtry_`7HM-ESH3j|LF=g9-c%&!=4C zrwZd)=wAMBf}rgSgaeGv^JXtGbQ~@-u{_Ng`+ImgW#`d@$PHWd`CuFUS2wywH*bAD z>%xpF_~vGu3{`L3F8=P&*2FLW*R6G!Z)P_V?i}%GDl*C`MKlCCb@WWZjDlPr9fTA-*T9$CfKY}v-@3Js#_s`=UVr##?926=}`Ujr>oR54*9AE zmamxzSmjQ*Pw@|kpK8KZ>e}sjwEsoQ*JicIHEib*ov7igv6=h0XHQ#rMl zhVtcruW`U7IN*}9TU^Z0IA(Yp^T?P+bmA0~K`Qqnf`W4Qa|3AyDH zfNLki!YwG=L%V6UlFq4X->W6ple z=kwo-O9;{R+jX-Daoh1j4&{cZ5gz&e?NKwT;&U^S(|4fvJGS%2X_xuPv+CfC0a@uH zhHMo{nD6-cWmNsisCpdNG)^on%Rbg2SyQxg4kJd87UhXsBA)PZELQqy4tbu|E*(Lw(#9&mEe zCyxj3zef-Kh=J2>6WN}nlHfR{G(-8cI2YmKw1m>M!ooZ745<{Pl5r+E{SS^)Kk~rg zdb6aet{?A|k$93@XuQdrbYSuqJB z=mwsCPL?=u(1RmfZ0BYgq%BeNl9`2c7iGdZO;=eCrwA{wt2nH3(H6{yS#*dKwfLveqUikTO{x93I?b|EyciS-mwpvUTWM?$(9avhEOS}y&w ztOgxz`if#&nBZNQU|*MDUzlL}D&cZ5rEnIDD~y=p{%i=a^oiXyl(#ggES-2ks z1P9H|i?MVRNM?;LwAL~#WtdqL3lqkJYBgwdECKfU`yV3zXBUv&66o3^P@or8*^XLv zfZR7-kL(Huu*{4;^1x? zGE@4bw9m8hO%AtlouILcs%j6TP8O1F&}Sc@TjQ9`am+9xGt8KI*O(0KrCoKRWnhSB znJnt?Q)Kdu9`s~R;{6(ZGnsgLq^G}2XEDb8uK+iaAAEfnE#HuDdpfJjj<=ErLoA-5KgEjtns5d zeCJzda$indS0h{CrD=;!Z97)GD7cMqct;J;&2WrNa5ny zU3J5Aq7RLu=f6IfT#TLh7LBjz@(}8{R#B6wEH1Nkh1z!g#E;2>ABWoyq#oH}V|mLE z3gaMBAy4`=V5}_aGADB>O4yNc$w>MIHc46f5o6rD@RPqIMTW1w1?ZzyNjf3KJy<-d z9P*(1j1U<57J2o4)N7IInJ${7lKq8$7kBb|_I~-5P#)>IH_vX~{ln;o?KwUuGOefV z87RC(w_tes^-T$`@v%h})~II%RN1UQSED1r57kb*6~smbn2FEFuEk5crJ~x+V|1g( z&U9o_eBUA6-l2RIWxQ217W0Fw=z%tAyA$;7$;=BRvqsXT2A0VwSA&m++7kr1S;7T> znXgP4ujev2p_Z52g&qz6Uewa!oq1Xs*%JD=W#TM4kAx~dK9`P=T$LDf0{!&r#Yy2N z(kRn9B@6c?A1qtLKRnUQt!A%j+ljireq!H&`dgH%tLcsC=)%{b%$k3}66W&)?f3fF ze#MHXOh$%6a3&6%&PYn83c&kD=I*yNKDb?yktURRfIJ2Y@1u+m1ZE!PGH0zs!3Xde zxZ7$t765&`!mi0vn5VAAZTLaj?E#fxaN_MZ8`vNEEzX`32*VS&=qIYRrgV@h=&cOC zjtZ-%BC}*b*{<|KaDNHLP`(F4g2V_Eeyf|_ZcSubdVLpiwSMIjFV;9!jST0|z)N1j zbC|;(p(6>O3(x^u5Z4zZ0wEpE9n`V4pLh%VMd&wq?A$ zm%LV_y{4gxSGW{k@S1TcnsIquq?`+e3Pg*ErgT^9rG67U45@duzi%O;I66w#xl?;B z+$3k?QtvEB*T@yB&ZKch&7LL9_;lwtX0TSqxrxl9{s^VR-E%>?4a|)vSE#2GHgc_F zPcoz-maqrtL{$1(H^RLSA=HP^-bZK;Awu}T|ADiq_oJ^mMe86fSi^$FK8YGwl$OAM zuJ!-9V(y_HYl!9XulmPk`%ueWsfn)CIzOsFn@IR2&hv!1a{7zo)5&?!{6Vuz50`rn zausbALd8nZwi_3R^?HmKJ<(fQ>9^8LhC zSXJq3CI;k77l<7!B8oXYb%(k-npX{#uZgIXpD#fqrQgV49f) zJeSJ%@P3rqEz!UgaJTzv%u#F(F?WF^)C`DTH|u7 z<02R-;dRNx@?>I5^3}!|kCGUVmgMkP$@cZJrp>Xm7jgA%ap|`B5qqOq2i$-aZXnbk z&=nwN^9`XCUq;wJb%03wqX{>SN0@>(MEIxGr0esI1J1{^U+0eW5F;!^2vN5iPBuRA z-yHh6kjGQ*<@6s>273K3*U{9Gofc%iu5-(ezcW}tqFO&-g9}zeg$WeKPk%OP8SM{! z(f@lJ4NOA6m$T|j#2xP@&t%bYY|rGrSaN&C;kdoZ9kFGgJW$~}tkX@HNyK4yI@CfJ zmkc(4`5#m~IjEF6sGPIVJ;|QS7nyXD4cIm`I4}0+T86o0zq}^&At*}=l=FDrZp^`O z;4*H&{7stJ=MufoC1L_4anZFDYAxje|50GBUbu^e{j505xr0i*;3}Ak=ee*Xsop@x zG|)#}{ZW<9UMN2=l<^ssAzxUC+j0conbrH1gVufNWyw&QU-511^jPouinL$2m}ZHp zf6uJZH$7!Xx8p~4R^-_wNtJN6^?$b9U(wa4{zf zO+ehTV+o1(Xyw7t*}>5*W(D7$78)ItkdI1NIN{+V5ZVH~Z2^8y(%@KqJY_Nb>(WI1 zJy-Qtt{4MX%qLfj1Gjb`!aDq3xY}osyE9dwBb78(lR~mmv^91LK*4XDr-?5O*Ip#e zBISN?wz?-i+zqtj3A12rI8}gxeXj_8V}9osVU~^c09HQ-3C?hb80tG=e7VR|yrLE} z{P7t-5h_REBERz;B1?Z^MRO;7wiz>BjOWCYw^~;C-K1~nt<+mv2^QdGjI@vYzMuR` za_ozyl)sx;jS-1itNqXQh^|unuyKU7pD%g)MPCYb!qkwCn9dE=@*Kt&VkQ*#*q2j zb1G^O%IX{EXVs*I*x`W6)nO~I!P4#A3|S|m zzHFlwb}8oaJ<6LMrCGpr3#4%gZcNmeo`mX_<8P$X-^;jsKzb-jcRZ%Ul}wVX-5j;Q z7=*z83xPiaW|!&Mf9KVLOutl}{-`>g#Vh6}-#yJVp6+iI??1EJKegHq(k^Zmdzhj0 zutZ5<5<9tDbEa2GKrBw_bNJqK6GWAQKQk&`^c{^^5MP5#-Ha5jLqfgIga2KJ%uOPj zuU`mwz1Oif0{Ht9IvXri;wg-Hy*-!-RQo$3b^Q;GKQ8}8`;MQ~gxb%wwwHUaHgn`S zE0Kh5v_O^YOW8Q=oXpL44wS>h(y;=aX8=@)vYu-@W7=fZtu+*{aO1gfE! z)YEm&ofEwxo@y~M+bd?qWoO29X8mE|l<@_wry>AAw(+*;VaR}_8+bH@HE}mu!*l)f zukT3DtF=4y(X^(W_J#2NA86aVtSgPs4%h|4>Uy97eC3Sa)2Au-zNoYoIf*(wfva#h zP{bL`K0WMkdHhd-^Hk#CIkv8Xl-02DbI!q;x~0qY%il9+B<1|$wI`6KlO3l%w+@_g z$>j_)k~Jw#wJh3S&t$CUGQQ_&+UF_8r`(V8#}=p!7HH6y5&r63q^m1tT4?iO9`oUC zLBU(ExE(j(e*4tnAPd&5i>#VUBv0D$TgcHYhZp+LH(e!*{sUQ62}WzZE2E@f_KsD`d&<2YFk23478H8v-TUJT`n~7alEJyBA_Ly3jYM%o<1|;Q2gAS| zT=UlXjc~S2mTTM8Ggk}vX!E^|bJZPzW8Ne0^mtk82IHXP=;(klDd>;;-b}F-XZf|` z`TX=1{&blKZoPB@)Z@L(}_Br0RC_V_>{Sy8;1M={j#7KsOrUSoS z0rgd7bm8;px~4c&Mx1v|%Egu>|HdT$s-)`$rSu=QKYkLpDs8#kFG1xzg^cbB0SXc& zY=|E&6DNvYlu@qAsJnccahmHyu-9s@6I#YyS=y@~->8JvUCSBZ&KWm^kzq(`o0HWT)uYaf7`;FH@Ius>bn}2qlea9 z7ymh15(h+$MkI}UpAhEqiMV$R_&{Aed!iEhK^^+79sDa~s{^SerD zxN?Jof$sMOA7gWNzx#9E?GLp6qM{85mJI8(Y84H($SN9iOr6wstw3JNBoBTfsgM7% zf?Gh>Ai;t?3WaW7h6S;jcP?13FysXsbw*wS2T$37cI|=%pI!4RaGR5KH{-cvEbji^ zpJ}VtEL0Vfn4&bv)-{dW)u|7gesS{d)4OxkL5})B?WzX~9n*Nnn2n-~pnDkVIr}~2 zG_OlHQE$>|n_RV5@i^t=lemUdV6|sd2}6dLCF{#kAF|Q9ELF6e#n^c2w34q$q$m9}sn@8e*Q;sNsA<$!PtYW|SctQ{8n>mKJ9T?SUJN5f zhY>#8PP&&N)Q%HH9VZ5`EBhL(m0k6fUDo9AkK2KOaVyq9Y-)1&67KBlx{^J;HmR0R zszsy7v@zm~kA$}Co(<6B9o9{ZG}l-mWO(akr0=n&qt8m6Ax8h5bCr6eQFJ_*lb8Gg zrgJy-3_#8Il+Qcvy#xI=1l<)f%#(I&qB68jr1k(xhk08&fPtwGYCPMHE4m3B-8wg# zTl*Y)qGJW;zodl<TJP#a;6MUTqVt z`D3>-w7XrE4P?(%Hlmoz@X1!+(BNghrpTfs(m$FIDH8N4gGA-#A9sk`XaTu3UgTK?zDv~CR?J#&B`MVQg&7Gxee54TjKCl+($>FaU0|0%Yt8k;aRGOFQpED zO96Xc8@?W@x^u01yla>%3)56Z(=Y^rebYb@P$d z<1{S+IX6*2aq=12WYO+qMFJE|g;-L}`Ay=akAsDwdu9Gn9Gzxt6C$(I%5-Hxec+fj zZb|hAj~b`$^_fMDmW8HJm00*JPR0iR_VSx<2jdGdjyD-@ z!yVeB5!MaQz824qV$k$~)Jq>{+m}WOA77nS$`F={DSsBLRO;ea;Ne%Gcw5M~?Y(Pl zQrwi$_%!h`YRq%xcj^dnyzZ=bhE5)5Rm^lsS+HXS+(#tjaa;oraNa0}^&zB4=SlJ% zyMI!_ViQugFN{ui`F}6+Y6HAZ&4^RSnmtqDWrffX2Fs!MDjbjh&LjUT7ui6-@3`C5 z0Kfr(@x0DgR;C}UOdB)y&2}7JA#H-Rh%3ET+0J6J-)LcEirF_?D*W3Pq?OxfMfJAXe#MD6;**Y{6CcUQ+NH~PNM9+Rl|a61P4 z%xsGCln#%{!Kv?D29O8$XhaTLAKqNP=oBlY<fx)#l$Vru!q#RSm+*qt@7I}j_ET~pW;|zOe2S`^{fcm#+iB#HUSx2lG} zoF&_WcSZe@Q)$quO9~J}N$Zt#Q{qn|6l3-7$W! zv2>Nn)*|KxXVO`cx_wH5pK60Fawdi1SSyfEkQVn0s#z~PwBuhu9RMA zFfPfK)Hg$;wCb0Na-~;cd-xSouW3PkNUz!RZW(s4qq z?w+m1)hS(m-Z{3WmAJ`ol==0TFPo=GQgz=kKDL|XBd$MQL< zlAdt3d2L?$`}uyWfLHCGF!FNKvHyhM$kdV%9k1FdC{>yh;vwxCC4?!~13=^e9Y3~e z{CO}NEgL^td;%2{3DPO`>4sO|NvnOO2fEQ;c&0Tir-|^O6Xnvo1>U)c3f&db_Jl%j zaHy2UHqII8ZYx^{I^NlUPhR`{~NKP$LD`-Mr?<#=(|cmxWR^A-cD zA%*Y14)%lV$9iFj6c35n9*p{VtLPzX#)s3SCY|aBH;?bZs9*?^ zI-fKgOOH6KNllHU<@j%M8S<-_%wv3HXLDeak?dD%H}&5)ih|1Buw>U6c&nQs zaz9_=%8>+LuLc+R-*aX45cGfq4;c+?XXjaF=b2Pir$VNo+b{}L@Y+SoQVI;!)J=u1C$cS}0<+8p!pNyTi(p8l?= zLP&T;7sct@V$GDT2A_${t!35?qvJ=O(Z3Aa5Ja3x>LImtG+u>4C4BXyI-26Eo(x zl5%WRAv;-S+&VqxOwW{ z&!b^t_R^iZcF7zc)sS#HKa^F=VHXy4f;IOCBxVE)8D%1uUPa_{3pM&y^nfy$hUyYLu zh1G{4XZ{17=_i1s*XXduBc!0tN!c7OHi{mSZnuD4JpETC@%(>x(0{+Zd4qxWW2XuN zrQh&MzfwRoo+Nf6@YCsr6S=sKhsJO14P&bry_2M(`B)YfPcD3Wdf3gC$KrZHPg6V0 zo}A!U@2j+@Go6wWeMPb%xW&__$YL8Do-t9ox?oTKP7d}v#u7TyXNz5bF1(1@@C7ZZ z&KucG6)Wros2K7Y$h);V4Gq7zWS+XQSo?kZUWBIM$v>BH5{zn17+159b5w_CFG<41 zhStq5Mf0PkNgc(59W4$nN*uR6K^D^yg?vR+h!jFb?6%STTxa7WRX+XdKG!R@cPME7 zv>Se95+1w{4<3R9Z$Nl9AZGs@km`N7fCPM4LKjQGcu^?D`eGp$D_FvAkq|owt_&db zM%TAfFrF3vX~E3$J3H~!&tJd38=YnLAUImI?R=l`o??lT;1Q=yjfMJ4;Lj|_WUV7e zzE*IbME)tBKKA@~BQLxE*gAi=3aqTTJS@)kAWtae)f0)Mj8K$h)tO(C3z>oOu4;i) zSH8ekJ>ZM_rMkQ2p%(+c8MsCS*6Xz|2E}qjL#RE`IQdRPSDn^56KOn7TW}{XTDX9b zoNZTQaNSdih7Nbu?WVJy8P>S&=KcNaq)wv6_&*VH@+BSh1c@3c#WAlYrBb_`{6q}$ zh9)qf@fw?S&wl->XBTQ}C-VPk=vc&@%PYORu&2BL)nD@vm&ld${{ToGA1u!~yXPD5 zO4#|nT-_(*zh9TeR9QTra$~F|huU>gOUE{pzfC1$w}dT8J@k**QMt3z1cU=;D-OKQ z-LrpWcZ=uGx6+Mv)6Df_b&8~NjAK|b+?YpBwV5%tmBQl6Pl91d z08y};1gW0w&s|FyX#E&xqNa3=%u~}kbWDIPkyKbu9n=GccP$(rqux35J(=UrGNF&% z)0)Pi{kh%iP7RZzY3ZBy-r+`kilQcEM8tM@fI-WYz-dYt>tz#EGjJLic)9BYmFq;* zRilqLh=Vq`PuGk-IU036%LY^d?bqd}=j6jLi?@-u{*XmtLix70GP5|74&m>=LEiU5 z-XEqr<_q;^ekHB|&aMFTR>Egin(fISv&o52%x_@!RiUaBc^hNAT$OGalrWv!>Bu2F;V91rnt@R zi?``Z(5&CBO}>58 zfcqXK6aD(|^~zx?H$E`xQyr?-SKNgx?s7|{8%ez51q<$-*7e9duffwNaklGBpUVT~r#x#99|tEq{cP{jz`^TqDnjYOItR=+T%Su< z{uOuWYrL@aG4A!G;Cs*h25sQ`Le)+#=?BDbx2Hw_LwHg*2(dKEmE7MK1J}>aEF^D8 zh(yM!rSS0uMlb?y1w?f{_Li;*93@Pt|L-C!w)>6ZB5khzte;cz(Jw@}ZFv{D+njyy z{{j0z1iwIFW`SlJ3@Pk-z|ddUj0I*MsP`%2fa)7)DGJnjk%U@`iXld$2nK^2h5@B1 zYzW@J_>+5|kGemA#`any=&!q`3H|%r)8=Z=e(I=?I-p~1J?(WKJd$bfum1?gfA)ts z`k#LvhkyLLSpEKQyBU}v*4uw;Uy2@g_VUaZ;QuW zoWFWSbqHSK71bkn`I6NopvVC-5cGogHq(G2447eHFu-gwf#W#vJP(^Fg4%g{+-{Zz zL%%gL4C1jE`~A`HuvjRt!h}jHf>N`9QVKTB0x|^1Bv>*I4pz{kU8gx@DCkXt!GMZ` zQW3-kYPBjeDDwF%l8HE?(J*9Lg5U3j$L-qqd+%c!=uHAT)<3KN4C$Dn4XCyOi#QNO z7Ii@B3S=JK_4`!1F37CQLLwYPI+{Q>kwzhzLpfDIHC09-pBUnXKs-qQX zpyjQj?P;*+fR3kyuD6A*zlDL^#W38%DAva)*~hXv#i~BTsxiZ1dx3-290$!gyS^+< zvB*y_2z4=#y6F2l=(#)SI9lk~T4)PRw0RY46RmsFwl=X%%i3VqXl(LzH2E6pY!{ov zX%R&(2Qm$ERPd3DA!e2lHcK1P1-mo^?y}alX`nyfKE7@}?xhj@Ycs@s4mN{gAUI7T zTxJ`KLU37Za8s0$S%i}?39y?4*o-_x1Bd+o_^(yt;NR@bI0(Gp_VX`Bp_Ax$JX7&ko z$=or;opDYvcTTZj=mhXJf_N>Esqor;Uc)hE^R?Glx@NdU6XSEN+$x?qR-QQy2rsd~ zfp3AMz*0e4;#gYZL|)-EL>%BedbH+E>=+kug|~?l5En%J7;j=ncoS7PiyY!COdQ}O zxKfZ-IQB1bMEHmW4m}GTFy=ULE38~|T){cVN@Yo-YjHEq1yXZ=@q!1dnhbD||O{ z3XQk&F)o6~cpE&$Tj>-Rfm2+t@eCLKGh77J(SMG&s!2fO+rS&V3tZrR-~wNq9-rX! z=olwQM_>j5nFxo6AOm4-B9MWgng|EWC5X#(1|j8)ZOI2f9duE5<>;&pJ4;@NBh<0_BZUiUNr@3eDEnGk6NqKojFM>V^3B zIo-Qy?)G!~c@I6l$uzj`ed%BS)?+owfSCq=`Ug1rli$O^AN>xNzxP|rG$7-E;Gc8g zU+@r~69PmwTG@5Vb>_a@UBN@WIDP&46*hSFiWM^?13@o%Z!-;Op21*%NlQzxS|JJo zs|`T)GJIYyi)aa{DG6j)QR`1im7$awD%44}H>eH=rPk1Io=i0|05r3JOoGG10~{S4 zZa~*G1L4v%m|-%Ru=E6qSfF|al$tFc183xClC60*p z5{LCU4k~l3iZk}iNbX}8Ac04_zLdvIyS;66g%-N}B^|znyU^unNBA1l^*YRuXrRT{ z(BP|R+N!A8s6Im;C0iDGA%&DRhL|OUuth?^=vf;F*9r4oUE4MR?t6aS`!Ia@8m8y_ zu)HvUdu0N@XJ!a{7S%`~Gl63U0ht7ezxP8V|KV>V{VTtR%s=@ydOk#KZLj;inK9-tSN=OIg65|fC^V+W==z>p(Qjf%>sLeiTQ!8 zi-En1p{;j`y@w&;=wsv@VB{WPA|ffY`q1DpmAa4H|*JbZ*V z5#ktcqQ`g}JHgwy!u#YY7^zddOPs8EO9q0D^Y9^Cht@ii4{;_d>z@SF*VJCyx55#j zz9$;j@72A;;R86J{PQgi-7D;Z&rK}rcgiPCmuE&?&x-o#E^FIldo1$5-J4d=)-q(D^UK-{AXE;sPJ! zbG(<|;C=8M?}Hb3C%wUY>0-@?zy&@?Z`XV!y~7u8PS0?DdWy4?6EFke_!y_hS4{*m z5-18mi9}G012PX*i%SDxIh%o4Os7~-aYYrXkDx^&u*d_7IM9kKQg;T5Hc%rDw3LMF ziXdwD^oD_UO!wB&2F)fbh)B@}B-#>G*B}(yFb!@Mz;}o`&>{@9aeKXOL4Vi#*9rIS zwLbOyQB8wC`$HW6=^rRj27mC|Sp3cpH%tTTcQ{y|S-}%u^5DOG{B#5oru+MQ3VVC3 zh~eJeYf$6>83}sRfR6PddRr*}#83PLG+2}Y)iKbb4D@LU@i@}yG%G|%ze6g}Nl`Eq z4Wl;<=Cc`#D$tCAOd(ET9g45Tcj=x ztb2$oZ~Tq=zwbWB+n>d4kp>*4ZdkZW5@B z$v_v|+}9Ae%lzw11G={Nofp`D_7Y?u7@zOK^kN^*@BXLo{NS&__aFUNkp8p31NpE0 zLxlgvuOj-l{{`ZI_cxII@BS6izw*1t{OTVf`#<~%a+-1QFLlPj4=0miob zvlhjAf&3}QSA_L-V*75_G~xZtjml2+%t2!I6CpwT5k4+}?;?^PXAbQm@09gUwzi}F z&{5e5zao0C6T)}AwsOv}Q}n`m2ghsCt%>hX9+lnYhlt*LJ)@Zc>UiW?g26=i3di0R zE8a$h+XxD^J`E_GNryNK9^yQBh&Q1lh43-nMo;iAc8Yg#g%8OyXnd7EhlX~I#`lR+ zypJo;vlnDIgcZ)^BQSzT?6oP>`;_pj_zpn%;SBEqPSo&lEliw^TIe{9?rUJX$ZB}G ze(nQ~PdtbCT)C@IzG>bW?WTV+H;C|?#Q8_AuZ6oN;CD7sYQQPpT*HO`REY-gpW$sl zMLNSf68xcadq%I0MYQ0D)3X#YsnFg9UKqDCd`g84?-Wb>x z_P5>JHVU?%-SzpSnFjjQ1QuoRuQ31ZU*9kdEZ?@k`fU!1c|Zoj-P)erCNyumN09+W z!l*#!2E+cHMfA2%)(it0wc>}gd#}|ppokXwtx@4aGOVb!28%MN)j&}&^cyCliy{Qb zFjy`YI669DM#1UnG0x6THlS<7$;lC$cX+sBH4ex$phAdL1d*Z)sQUudN+_4h$mjD& zr&EZ>V+e;skfgw!|K8h7gze9QOaskux$Qf+&%KZ&BN~bzLD2=t6bhLv%K0K{r3zY= zI=b~X2F)%;%|0g0A!f}n7R?EkjVYFuDJZ32m7ie}9$*|EU=kW&A`dVP4Ka-jF^i8e zPff7MPO!{Ran?D+S?>^M{X?7&k8nOX!dd?ar>#SrG!Af5U11&{V-_J{H^hW?eBHED z+{e(N?i|x@ve;D+x)@%ENONvxAatq{fB=8 zf&b*cLGVBS2MGU{{}|D~{m&8qJHL*^Klm-A{?YFs^Q(V=>_7cue3ZHUgsca z@*-sNBV_a=Vw4awhLA8tkT%DVu_TeVP%1(W6|R69Uq;S%L~T@ zJHt6qL$n_%Xs&KV9|^Btq^P=B&WR@OOmEwD2lu*<9$ z+(+&uK9ytl3J=1w!tr%nCy2MNF`;|I^R%W{g9P^B8kU1idDt3$B@g>7a0G^QgmWTz zgf}eY`WP1>g?Et?yd$$9dWx?S=L*Sle3d-McT;Z^(r@s+%*C4Z_0$_S|3l&&AL3_t zA3MX_$O+y?PVqK;f(w~A#+%@=^7`vMa3vg^Lc$q7P0$|V)O(dr7rWZ}4wTrr}#no6hBCvD%Y|f@XMJG_~rCh_suS4u8PcAr)CW{t92qU*Y?qukZ_@ukgjYiwh8Mi8nd}flLGyB?@6P0)eG3 zP~^dK$)FAl>n;q`#&I^k?7*NI25LS-E#R1GU;+1x1NY2w>(29i1n2f#lgY?x4^aI9 zvsuMt0$ta{?sjCswrJiK%6ij)QWL0Sf@T^>fdET`iEWt%RG5=e6X-WhzjONCQ@Rcn z8eOecIHHuGqa&P9l#gcAsUw*Pdeh+GV95$0Qayvog#P`IQPu&~N}wW(#bN>3Y=(7A zP-+zi{X@^=;V4q^gc@B?K($y#lgxrf3xie{f+j@=tZ-CWVwM;>eO&z-3Uh=1}2_XxOS~+3V;!nrPb^ zmyreb9{b+uH$c1oOuReCn7T;J>#AtGCYTfM3FaOW{8P;RQ!Jzzmhud%$N~qk1wM4% z;zRc>KJ?zK9JWQTs686jZ%?L6yU)f;i!%*V3Ku;CSJh zVzahoh~vv(clpuny|t5k zx9clVhuAGgIPqO_>N~<3{}E1aLO)M;tO#qh z*qT;!O&bHpIFm?_>j<9UP4EO4p;KIh&hR#ThIipJypNu*`6}@S-%S!13aJZxFLi;h z|3CKLt2vS^P0y^$`2$0;#Z*_9&Ptt$gb1w_fPmIo1EICnfq>Q;nOW7<-80jqk?fr% zhn(gJOm($;Lv_Ii!~V=v#`?;Q7lhi5=!BC5OAb}t?~E{-2R?%@%@`}%jj(=MSS zf(#>yOve@J_6Vz+w1<(fg%C3bIi?_@rXV{XotL5WBSdH=X#5C?sQm~D1l4|Udk;s*SATtpH)gcUC_(|YU-h&kv zgJxf-ng+s@jWjf&IwXOa1#_62nZ@k%3}&W;84_qnfoK*8Mgfia9vL2Hq1;15Lm()u zdw6)5Z6`zEI`cp@4M?2PG5vjgECC(MYhbZ3L8nrwK;zHfH@|^s42Y#@7*Hv0yU7^1 z>prR{Hyj$dE{`&x^_$w4_WRmpF`t2SXu?1K9hUx3J2Zir20wp@#~(k!laC+c@h=|Z z$uEAG90nv>A3uHs8e9M5iG;_G*>f>6#J)a0 zG+}fU)02~IXbuh8p~xH>?n8zF4GAK1j)n?}(0U-?XORbDqyd=*G;;#YnlLjng^39= z$%ZjF*pJ@cZivGY%x2RE8wJ;0zjQk-OYb2qf2dI)9%nV0(QdWF>EO`?G!$WUUropogIG@>J ze{6>Np$@vQRZxA|iq_AYsyPiP;@~DD;C=ShGXiLvw2kZP(Du6+22@9G8hredpX2d- z5KmX)c;U~XDY}Z5)E3$bhfuAZL$m!Y^asC%@$BEg{QCDS&w>3ne}Ln!|A89^|Ms6* z!~x|wU}nLSHt3!zVR)v7`MD0Z=LXoG8Q^$kM*DLsI-XkLeC9y+vv%}8bE5xwHwIty zVff_$#+yel)iQ=@N?O=7#v)8uQ~?paV}y{w=q zyM(#EX|8a?65OU`xGl>_PQ;L!j3YHAVKTak`1=ZE>G4-@g~hkSjVP}& zeBW1$H&!S&R(MxMwnRL?&$j9tZ1GL@2bI?dby2X(%Am@No4JDsmI`GO&N9TY*G$xE z{RnFVjEF7(k*HoU35-F+2vZPoQwT|mfHj1)JyIp(h$7q0$#uqX6WPufvK=vYY|0)% z$`(Pw97e(%V&|Z9MGZm33_(Qo0=gig+5jR_Gyy~;)QDnADkmVVL(4VwZdsQfd;fJV zzN4BTZsRtQe%tZ4?T=|`{CuOiy9lo**2TB>4Jjo8Un=(RvP{DRm?=QUfG&z883Phh z`WTM{pojot0vS^R8A}3LYXUiY0;SFj%3T?hdon2Yq)_Tjq1>0kk$V$Io-G`?w@~g) zqui55xhsv5GlPmVkJZjRR@?I^STiVCGANjZ^8Yai3g#@wlts~;MbVVSN2x>tL^2*n zA{MI}2xKIPQ3!naLJ&cJ00E!B#xxLTTM&mPP(nnO!$8PmFi%khl(%4d2D4-qOip2H zVv?H$6O_Ddj70{FjEpd2fI_SXXxha7{u*c-?PKP_$Ot=*q7uk-5NB9m287Ti)uUs2 zdV0{&(ZTZ?7z|9@!?TSk4<8JY6eR)^Ki{C!Lzsm|Dp%MWiLWYK7<#22+#Wwp7kR%=|gDDhwz9G z?v5q6+n3;REW>46g3Hd=y6y?}Bg8jrd#$@%a!E3n3&I!$>ZKk(di1HWfs4 z+>gkJ4<5%7+}0(yOp932EnrDChb0BQHJ-&{D+$I~EH=+F@p#uU&+Lsbo4QIIBhACi z=Y*(*Y09wQL_-vYF!EvmgD-l~_pA%uPutP?#0J|VBa9EU(0-+W@{1OvZGf<)a@1&lA$u)NU0_QC*1lL^iyE1WNF=y}w#WWj6+2_F%ZF z52H;37=JZ{$>tHvv`t{HZ3+vNPoQ~{8AUWKV5xN$OD%ICLtuqyBNljOZ!yESv=lOZ zyVZO;Fpo}{H{84epVfu*WCEF~1Tr%TWJRWveA`3<>9IJxrWJT;{&1QGOufve0CQ6o zZw2QzVeM{RLc_SH=&g=r7RNMyKv_4Ox?YI&UAI-ksP8V6eKZDJhA6ygtaIbI3hS1J zcz@_}y>ROLYzt7R_Mey_OB6=Q!Ww{72sdCkM2X89$bCYl-#Jzyc&ox!?MLK&kqGLl z*p-NG65&x24+mQP;kca zE(sLqZENRMy(}3G)RrxZ6rG1Kh1q!%h7jU}J|rZFqa<JfLl;=y z13yoc$fjy^@u3Mc9D!y{pkW9zvzVWr#az`Sn8eJ)1j|D(B^U-YgkXGBFbjr+r&CQ)>7E#PFH`8>BEl?>H zpy!K{Zqke$G%SX4YS6Pw&mu+9h{F?D0>tHIHZ*}n8Bm0QWJr)`8i=!+uo+91m$9(0 zz@}-W=^Dv!qez^-zP_5-5=OI5Nu#WZVfP7a~Y4Mvz*HAiW&rEJTo;2_rEPLVPp`U;7HYwqCg+Jl^Do)lh&ifB%32zd@pq27E0-QKTd2@+{$g}<-PtYCVshV7*u9j{Dq zzOlPoU(c=m*J)C;zZl~<5Mi7 zvAip!<-+=|>wbj`jU=FOp`j?<2;769(vAD$K~UKkLMjg$ix(kP;|QyKXe1G}5BKK- z1hzzwN7a5b3`&mHKw_Ez?v5a$MNzE_BCaD5&PnJ)d6tK86n^tB>Q}7~;sj zgJ2E_CPB`SK;9@|N}+7cGEu*3&!ghVqtc$oT4w=kT?JISxEVmEz?pv!XMsJO2lsFh z-sc4OaY6X^apB#^xqBb$-36>W3#^UJ&N8+-%GhWZaFns>C}Yi<$C|Z(ilxBHkMfx; za_J1R=`=GBGRY)}R6K!XjLd@=;*khqp)kUMAVL&rK(i~jXn4X3pFLr20gJQqSeTx{ z+~hR-XMbjV64T=om>L_$#3;{2FfQaN7#SYn!w)E`fQ*8^J|?WXySv%+bk5FB(A@SE zAwbYFZKJogG~Yd$2PDF12m%Q)5>H~nL^2V`OpuxebgbQOhuLI;R;z_d$ZH@Sq97H) zH<<Mng(7F@nVcLS z$L#bpi^ieo92RMC&CmqOaX_<{&~&GiSd@|<(rgK281Os>!z>!7r-u(quu;NKlL>mg z4r;Zk<{IUK|E6{6_1;vkQKmspr;xiq9$hfI0QcfD{4Os-9zUYKAYy?q5`idEff!Q$ z7}DMt(w-R7D^aB8x!6xmg%RxWAlT(W!0Cp+!v%k*3;r%QvI`01S5nBkQz&@T$SlQ> zUE$>1apYFw$S%f^o{bf6 zbq*`cOqj)T^9+`nr?J2i=uv)zab_BflWFj*7yVDW(EYd_9p6}Cdtij|D=oBND4_hb zxoQ^3MYeqXu10~hp4=R`ZoSc_0htK${y$y_^E?MELE;)(v%64~-c69$^34mV9yLS% zQ~}d-4Qx#YbiOj9r^SZ8W(NjaIx*7HjnS4KOtkc4s$~FEErXbD8NzJq2xeNxFxxtg z`L;J|7kE(EkL z1ZWO%qnpnUZuKB+_af}@BHZCcX*PYuOd7?hG>Q``Uf1YGP)`}eT?nXM2#6WR=^Toi zX{=awA)x$l?k|)ZA+~GVXslRntoRPAyl5o%7s~e++YJ-SqUhH65p5867s~ZTbzBob z!_fv2zXu6z5RK(ZL?^W&E_QWcBn48sFj9H}G71b4q>UUB?hGpz^?7?71xFmEjwDK* zNoEX`ohgW{I#Z~0U9sv+qLx&3z1)!mCxN0Pjv}>fk0Vd#vc!-hU}#u%xRroM^j zBS=fpMUWPFA5ktI(~z+k{I zL{m}w9oF|*==dubUfl*3?l zu4))CqhNF#lOto87#_v=@CZf)aZe(j62h_J2Yr1ks(_*i$PA!2vXpI}@(+-}7sa`} zBm;r!Q1KV-%)MW&t7QMId8=A{SWLHkk%yGjuxLJ5dH?9?*G25iCDvz4iaE zng*hYAl@tgHTet{|L`9$_aFX!jcM@cXW!s4%W3e#3`dX-O`zr0))ut2wxX>~ptY6d zvmgUOE_mhQ_&VV%k2HAkf|4QfXoH(f19}eW`KKrtO8!YxkJ8KuZkLPaG@$$ilsClh zhu`mKNfA9B56gK#^=QZs&A2c!;%|C`o3 z?Ct2HX%xG9Fw{4|q6?L1!ZLg-ZUj9(MEpU-0}&)cQKZ9hWFtvr!%1XA zN#p`aLfsy=TwG3}=+2BEOPA z-o+`nlPJ*gava&YD6&%#WX8e>ceoLbK_v~)fDEN#xe6^6qC<~F!r<$Lr=TW_qYRH5AAR~Fv0S*9)>SeRkJ{x zH9;=2p>PiTC4rB=ucfW`J=&zx8 z*aYp9R+yfvV1KDc=PMKXS{)cvbYi5f8{>)|OeqF1qZq`Tav1Z95iGQgF_sk*SZbTZ zvSJD=iW#_+v+(Pd5Y#OrtXqL!wTOUn2?6yA0;&}Rl`9Cc(uJV14hq>el?x$_8)2;* zVZ9q+qX$uw2T`jBQJWVrhYzuKA692GoS6((r!!ccN~1iHM%3&<#OUG2QX3jKLTWcc zDmOw(!u5fO$2X=7E8S=m5tRo&MxrV&J{YwR(FPJz`_L%jYCrCU#*g?9KtdD1kAI);J0_4rOvL zw{t3F4meX->$+mSD-A|>8tWo#TMFx4DXdd{qLWkUNMMzqHtlhaErFsX&M27U$eW_b z8?VS2q9C$*IT7Ua(Hh>ZBR}Tmb$NUDUC--ds81YueH{#O+t^W+?_$UJE^>@-Lr3^7c!Y0#N7(HxVYj=4 zU1tgVT@~y*E7NUGBAjt{s9d3^<%J~=P3|} zA5g>qGYdL8*nIY66j-fRHXfTI0_q8M>9($}E*70oV;qc(R1E_XXta+)!zt2$&7g3L zX&|;QH3Vo`+%A?k?H5J$T}n}S-=*%4u@39MFf_qeC!fLG|M+j2X+Q}OiAO(sfX6@o z29H1fx*Kpgi^!jhAD?gvqBv7^~pjN7&*JxqV8DKG*;jq|*SrKZ@0x}q9CZ@0;4nj5R>BNIy?7f&Id$e<9r}d81my$L_58R z*gc3?+z1(05Y#LqpjzVMQL%^s(Y6Txd*EwZfUk7{-c~XV=HPCg!OE*?EWet>0y7Op zF!_7{V^4cA_}GcwM-Dh2SYZFk0P`0b=s#1uV;YcoAU6u+>vuH^-nZT#!!+P|4%~P& z#}gzz_h)&6#Pqf>v%&?NSwa1%8HQ&H*k0<;*D6h?{(f8$F2WJ&0;Oye(=|#fd2C{MRGayI<)+RQ2J+R30>nxXO!$q4ptu4-#r0 zei-~ns6ULP#*apl(gg5hA*~JK$3{jQLLIiK03apZUffK#snG%iR;F(YE0sNshCpuAy_k|a77wxrVPiN!G<}D9ea_n+g`+O zry%ybOW5x#W4E`6-GL%@hl==B_z2%ekMMo`2)~XWUlBXT_mN|KA3DbO{$qCBeoqX}h$1lPMtIFF*FjDDHo#K1odjuV5OuC<)@13dZohZ&9_6|J)+Qjs5gVcZFvrOg2XJEBIT=@71l4Heb@}s6BQiK zb?ACwLjNl}Mq8YiZ0o^nYabRALs(W0!>t;FM>P(gY6=1MG(xIrgw-<$Yi1GA%p;~< zKwP(kh-wB=#Ii&S&Wb__nbsi+t%SftLkW?)rspKRS%eaoDLa0ae)hkG8TuA9$ zNb6ll8(c`6+{l>S$XMLSSOsXAFu9R7x>;R1CZ%;DO~=#ul>&+tuyfFP-jkGK1wS^@ z3Ku>Yr5ou6l2N+RNU}-~?uE*O>^;e;y!f$_SNqTi3ThuXeiYQ#A=Z(X*VX^9?M1a8 z?@s_lb$v>j0Pcl0fRaF28$?6U1yR-ovC0UcVhE#RBqCTdMX+v(V#6B4hAoEe_9V7D zlGyI#>^M`{?Mh*_U#$$w`XwBnZ-$e5vPMC zoQ;%mFp$R4P#Q-gY5XQ}gx@BP@!R+@j)yZi9?amlFN5QrG%osAanW1GMb9dZ+H*Lv z=W%4q;mDf9ktHvX!!a$JdHK=i>MAx$WvrJSuohshyLy!^g6rH({+`jprgHm4LzVY{$v!$#Wt-| zz5$I!Q+J=dzRhZ7?NJl~83Qz2fy{&ItP4V(1d2!?gFzhcO{RgoE$O=4Ft|&kf%F(@ zTeSQ`3HBdDyEUf4|ME|8|Ihybmypk3;cx$kcT9svKm7`ifBrR|eEa~9fAQc4$zvcD zu113%CZnMWtsC@O=(Oq^1@`-x2GZz)|LcEihZN~PTJG)b!O+kk#>Pf5JvE8BxmheO z%wuJFiRCSz$O1A8Xnkpsrd6C{=ECIU1ja^bc99_r4D?AN4D2kzfD8kjPJ81u-6Z}+ zgP>k{({Z#4UEM!JN}R0$ig0ye^Vta&q7bEQ#PN+CNKKz1O2 zOurxLUOy`{1Ab&jgUC;Wk)MhnKNH19Aa{j7hjniT>(s`45|!yVR>z}AJ3L5PT}T;M zkkl_Du3ki3xqx_^KJW-+Zg#o=UEf{WY$9QWOW)!_x zPz*4`z@;38Pc;F*Y7#;9Br^-5npwoObBOEa5!Wpssb56eu#ALe775K9lA3ws3?AeO zqX!wy3NjiOGHPN48Kn%x3eo}@g=`%7aEyP$8D6=e%y_~9qZlFo+g0uJy_KQAX3o;zzL$F5zq!vX#i{5Al7vC2w_e4foSU= zx2_Lk!^nmErYVXoa}?XwIJRwZ?AYVj>qug+GlhL;8v9*W9Cl~G=%F%=gRV3V87Uk% z1v*pMb;Pl2=j>QxU|3?D7NZhh+<35JN07N(o4Cft#^)VT)l053_lcg@5>#oW!n%#J$4Ln z+{UgUfxEItb&YZC8538SlGqoqq;OzO;n1GOQF|Ikof(|>7I869#Klkv$Neds45V;6 zn8sg4kE@&xq;b-h#%XUFr#%_G?l0qY?yYaXYTJkBh<6qjlJ zqwPusTdNgpmRA`Y#S+#j@*rP8Ih{ozkwP|>Kq?eLjF|>r_?BI8%`akMigE!=U}AWL z=)}kaJNmvd!}*22CU1Z!(&fVcHgPYnFJHgy z`0Mslf5d%qv44{>aMM0{JMzAY>yLi%C7yr!4O+f@3e|%q7#_C4{zQYW=SK9uv|;pB z2c}wjFyGdXWyK)eiV^sfWAG~{5LA(2FomdQ8gcCm;<{NRbn{5*=aDunA!}MjQagvV zb{-k+Jc?!yN@gF*Mjvvz738%py3jb>C@338QR&9LQF&0j2PKsUjijvd z;>XIW+K2m6QTuQ|{HUluj5UoPjUj+FP2*VC1VA*RZ|m9sZel|l!j0%c*pRTP3xUIh zGYROe+b~41#gNt2g|T%V)TSYfZBrCGgqgEzi(}uOz`i4a!_G90oM{|&WpGS%b544) z;AC*pBkb#Y~Z@puwZN5E$149A_Mk0v=Qxb=!B#ta8 z99dI1wx@C2k;Y|j0hj#+Tn-j-+Ly#>e-dW{Dg1T#2)~OQ<9Fd>ob{)0)|bM0Pa5Z4 zX}s+%<85~tZ@bDkx94zfBl65NIJXvXVaYQtCFMsul{GL{*RWl#V6#a7pqH?oD_}L7 zMJbg=E}ld>9Ob5g+Y2uxK%ARnQ3g{ZqZl0+tVu2?ie+gj4n5H8_3wywX+2t&i}rf! z;xUv5flL94CLr^GhCdKuaz#q4NKpo4G8ptaXw~YP^Ve%zx=lQfw3P0bE=%i3m*s|m zxPD*J{-->?8f8E^4a9r~WE%YAf5zh9Q4+*|R}*RQ=qF#|(a$(fKm7(zK5P6C1^Rr+ z6tG(@Xt&$Y+3rARhl7_62ir#bEO(faP-+~=Me~Q625g8zU!RZ=aTL>&lWZmhia4Oe zhy{d3gSJ}i~c?0|94eS**u$NoIUaErKco{pv0=B(*Y`bzOjYd!$ z4x>06LUAa>mq)|cc4b+e9e@u6bzqojAEq;sLHbu&t8H;AI@ zCR`}02sesUSM5ew!;dfP+$ifsJSgiW&^|)zMoGiZ!_G%-DLEyj8w`aTrT3()bmKNk zN*C@9wdZLFt4a@~+}6+A_OGfukWx{3@k1azhkUuw=UY?x@V>08{iw&9+J`Fd(eAp+ zhbn3x)+KDH{dhkD*iZ-R_K&vLMH9eAJ+uLA-i9WCO?Ipw8yXI+-wAa9n{{}nkM;U? z>$V^^G(l|2*wO^CttCPnT?pF(JGwC5K_AAB6hjz0Rk*0$HAKLW2=3}Oai36<5EsR_ zw3MEMj@>gwv2TuXEO8v#6C6hpC(blZyE2^a3{JZn@AYhE)ph_GE zM$Vxzjza_Iz!1lQo`}_jwa0`liCb!4KyuAB*Ty~r@w4D%z58>Zi=j%*xyAlmSH^It zkKs_qInYHR<=u19=W`pke}1+1f$l~9`^EZ3{ks9W*W&#@G$e4Szxq6A`;j4zV`Box z#w1S6Nt{@cII*U1>PX?VJ%zK*G|sv*cr#GM8%l^cT*P^Al5x?S#M_|~-VT=VZGQ>h zQe;AB4j1h?T-dX?v}JK=&Ee9L!|Q5Uz-wy(Z!CGdwG{A{A`SM}H?hA)|BSCQc2+Cc zDy?E8PvO86ZID4B!A*m>KZFpO28+vBo|(h!1VtGP*BA!kOaxNVOv^g0md#$vOs zP1h@JLw-JKf9w`3i!kcz?#6K60GmB!W?~YHGqZ3lEW)?qLdfl7!<-VK2-1-_a`7~Z zDM?fTizujIt7;T%VsC8=`|DdcSl?zGu5IIRbqj~3EgTj$ahTn}L2?cI;S%=zMeKU= zsEo%@8I3SjM|erwXy2~Ch`nHu)jx=>f)OcWpSJmn*mvhqp=0{PSnUp?WcQ+E@t|mQ zp+Ik!)hoy=myuTxOUSn^A>X=qJ1vXIwJadpvVctUJW{V_k$5$OSkn|jFUR43J_`4< zK>*M|FTX54>BGz;C&nMNWAG~rdOkOx{Zln8pR~PW9LNRqZ9@Mp_3u*Wrt`?fKCRzm z4qUgdUOV;9EA20t2F9;jVSlJb*JC{fo|rNE+>WUiotSIt#$r=1R$leP(>w@&+bDv{ zF=iYD+J+HQ3?r->MUdVi)uJoXa z%7b-*4V4#nVO`}#6{Q#J64sPnTu=S`AfEr-QgR;YIpzISd$A#~rS{`CHq|~bR6cAn z{Mb;5_^_ekR1E>CIUrjW>s}r2$EM1UEke?lZFK-rr2E*icubvgTkQu!4Kj=o92lcln4&l!%(WbvV>mR$a8QGA9JNVp>q(r3YM^uP z>%%xOP55%V2zPmxWI3{e~!VmLAq@hV(^CU9&b zF)G_`NZ^=6DxtsPNFN6$h9i9pM>-C>9=aw0QLrECBDg#J_#<7Ew@vNqV>Rcm_DSrU zq<^eGQc*4#2UmT%{_~K2PW!qrq)7MCve;g|QoJA1@>mzcbx7;cvS@m+l3j~%?}h6< zqR)|*jd7fq6F9LXaAHf~)Xu*nXPqg$>CNL!e;#iK@;L8~GcLLkc-vpV+r9$6?J3~f z?jkPR)3~r_@YfT9Y>K%kP%#$YzH{S@IKk20Wk>a{Q3COwz9EZr|%7WYd_ zxltfpZ*tKm8n!KKTj{Kl!re zEwxm9zR$8+sf1pug~e!u!)k@o;Xtp`iGG@`psx=@0)xH1ATdirXXs71-D0T`+)`mo z%QuPW4~;bF>}W?%cNhBmdf9M;(UD<{kBwqte4IhkG18Qwlq`{qg}%OCba!{LDHVCb zLkmnMW6gaNMZ6dtAis{guHSUM(l*5NiKX#ElAy$ffd-hr7HU08V8gJr=u@U{-Y*E)iLas>XC0R$9-2r7pWQjZ|28%IJv ziIi~~8PhCsmN^uxi&%H~u+i?vmOX%Vvj-bSFV+dYhokjiUE{%;T7t@hHGvu-sP&UM9{ZVwZ{D8ez<@SGr6hhYfZ==$>$a z%*C@HrbSU*uM~u~c${c5h$e!#E|%5nml_p!To&7?ihNmrw$wgwxImYSYZBP+AP8_S z+WGNf`{MboO1eMqvZ?ZdBbpAplo|oNF9GbRC6L(Hih`e)qWBj3DHq)0c3w)36-=$JRKGEkq0_bet)MBNK^r-YysG zBucqB6^#UTZbO9CrSs9TbdFPd3TKWK&f8OX-Ic|gu3VMZ-8sDO%Hg#$E0DpZGmSGx z0%!IFPV5P={+Q_+cpr}F8VS9KaQ(V44n(wJ90#{1$rLHM3Aks=Y;Q* zwn*c>FtdS-2QneJX~Bg*e=el=c3&I92O;}?5wDMo1nD)f z>kzI%?3=W#sjKIGX8oqV3y9Cju|5ihA&O%IeV#G)ouu#ZDf@oKaoV2X->vQ}-t=T~ z+8)JOM-*qBF}&^0<85~iZ@cn%>&)ZAp2DRyjY~@guNi5)F=z4ClEt^?9KK`Z@hfWq zzp@tby|svsPPTV(vbBTbEp8r&#=%axf~`UcYuP+XsSL8wI1<4SLM{)yG}YqtEK7hW zADSRH07L<;Xlp}TYb#n?S{iB^Xf>1}Uk9Us65biv3<)%4BSE&1Bx3{dT8q?sxzx))$*FX6b-~7erc<}M(HR4w)KHqoQq}MYO!0Bjb2{_3h7#SGA*w7Hh zhlZK4Me9SoeQb<9jkRyL+WzRKLA%4wq8%vuVW7VcLxTe>nqXvj2*mKvATtwas?eM6 zfhgFi6wLy$lnVU!S-!7nP&EvOhQJJinHjhim*97M5b*~!dG`fb<_&QD#8#qgE;w-g^v&05J)?dc4 zyNJ!<7&iMN*ysvj&F;sV$;aO)Yu%`*-KeNss3=!ZQCzXASO%kQ8LMr}C^ME&Y9kg= zY+Xd5bpiR7dE{E=kZztq^3@b#FDDUtF$UkWA*?*AFo;8GhYZ!ax5Oz&L>>4Sg_{s=a*Lbn6Cdef4aFc+QUTmtp*wS#ewLV;n z#)oYUiC9sf(OYm5aBfDeNWL-?NThC5@nTbX4OQV+D++7dB?G~AC$7%P&wnK>z1UI_ zKE}4n2RY(CswX{8+NQi;_14!EuDa%dw4F_*2ONH1uFfs?%a3i9A3Js6LfD7xs#qtn zEbVjcy_5=Wv7WRq*DZ^6uPgce^j7cVj@l2AU9}&(>HuR;9e{|qjrNOm={gDNJ&-;x z8%i&3LhJ{XbWaGe?Olx@oB;MTL{J9bzN-nadQ|7CkMAx^+t}9xv9Af?KpVn=j*tjO zU6_dm`X`*jh1?O&r=Uf9{22*!^PB z6BI!qp=u%ou&d|n>4VtQhp?{?Ro}3afF>b*WQ^ii;M5eushNl~&MXO>*^)T3Cvk31 zvbT-&#_^KIMR%m}rZdZU-I>Mf&I~Sz_6#l@DaN@Yi8C9$;UvR>il_JY;#h4}rTlAb^5dUaXy>{g#W;rTn%hCv)@BRJL( zT=<^oqBzyZs#L|UD2$oVByr1+=O%|BW;G%9e82mhxw;PCk0AE71V4`2VEv)bgFP29 zoET%cv}IT*`Wt%|Z|ph7TSpFW?KxbUQn)lGacN58!j!^=G08YLCUI^c5;)g$&h*?k zIMu~)Lg=Fme%+#BLf=2?M~K0`qx3zMAnv1jM~tg`C*CJACIXk^rs!hW$n-EVGS zL~tbB2l1TrTT#7VlFzdC{_@|Wt9tx1;KyDqAJFG6LHhaAGr*n$_ACfuUljdf$(|AM zUJ0MS;c*oY-SHam4W2ndZ*eBC5cOO3a>3GyfJ6+)=Y*$2H%;p_?0D(Ut0?JwWWyPS_}9snFi-O zdpO(KWsrGrw7G@D^$qM-*03!MQz)ls7KH>i4cuOM7M8F$HNz5{Q5Z4}Nf5ctG$6rD z;+aIWR8-6B-z3V#ebVFADixb?frcKCc|ef|G;Je6(FHWkp0vK$#$8M4v9x^Caq_yf z-rCv~~6MXqE zKf%{O`xIaO?3XtRj`2g^qS~cXgt-r<+9_ka;jL&<`>SC<1|!cv5tM{2Ha} ze{9o0YA8sfENGc>L^wOzd4vHO1``uln4N=rX&FJU53x{~B{!tVg4JxEc%vyF??7S1AT zI15y8>M3J;IF9YUD7L#I*t7+(Y4%~m;KhcH-u7~_#)S%rs1>X!R%i>u4lKOv#`3EkthDrE`BfKOt=;e_`rua& zBBUEe)HH^Kc?uiTQS8hmaj=laYWoV-9WHFxT-fUj;lL5bzCDBkTL}A>5cbVM?3;qv z(t5F_^)NOy9&D-!ZW3^#fZpnoxZ(n9N9Dtg#s?kk}PaN@HP|5lx zegCGO)+gb)65A66*S|xA01nha9BPRWjv z^^l1<@mV8*Ej0lozp>TtIsN|LMC~#BHzB~DWjYr@0`*uM!HF({Q!)y4QJm>wjB{NK zgt$&6?WekQ%rTh_LOb;R;NJ&npKHIX;&--MYW(aP53~Vrg3Lr?qFo#4!Bad(GIlLzEXiDLYjMv5_7=|P+4GG4DK8|xHsdJp-1q2$UCiy)Pe^;cX z+$5Int6dIYR~5h>LBB`BH6Ch$!t)?L6ZBlvhwc^qb{%QL>=DZbsR6>&%$I zg(-p8#uVNdQ+R7m<2zFZ-263I{)VPSXz&73efGK%58{;FX>#(~@f5ZCJoYT735 z7t5POxwuc-77cfxp$}vph}+3Ppa=wl#=DE#sTA9|YbibUw&Ue>X`S^=t!Bms&D=nJ zBSe$nrt(K^AP7+gmXlw@eDo`r4&K7BdkNjrtKl#Ot!dNPjZ(DX4&FHqbW6;@+vAzLJ4~<}s!sEv$u{bfs%DK^TObv~&{X<uxao;oX$>k&@cvB!b9nL zBTNIS5kSi~MJ34VN{xdK8V=Ikh2g;g&`b{tv$Jq7FC*mhBOZw$n@q9kTi1&vY?s%t zyS9k~G74y@0Ywe$9^!oO2p41qkSTC@iq}V{cyoMK$ zCwQ}Ygg2D~yeaPEGQEw<#1<~28`z)E;b1O{gV`)E7jigQ%;R-p3$Ih#c%9i{yv^_8 zO>P%&(mS|}ZQwGrh6`^6dm~Bg^~bT>6~VSWh;4HK+eSaObo7s%@XwyggH4qin@Um4 zaB;O>H4p^zpmho5Rx%70P-vM)zIhJWSF=brO(XGg644iA8VtkpbO1|_doc5`1LI%Y zFz}`E*2n^>V5a4IqWXQe-PESI?|s{>X8_!08q_lm>YZ2Y6P4;uUqJuqE0{lTh2skq zoL_3t`?Vee4@?+-Xu;?s3nm`hF!{uenHL?Hd+Ef&t8UCSbzq^n6U%Mg@TmIX*9{_U z97WtRiH(^kcIJ~fSj=FpV+HH&E7)pxlhVP^z~?GYT>LpZdCaX`j_DZ~u}jR#v2 zm_Z;!3~Xxzvp{&8NN-{H2rcL8p9B&pT(t6k4zC0W2{KWHh=NUCiu@D3c?a3{=wbBzmbm61L*Gr2lwH1-ZCgtjA3QL3}Gb z)&7X*ke-_xcHFq*21h+JL;Q|Xc_o7BzOggp_2tF_H&L$ct$2UA5#z_6%Fl$gD6UCh*C4!cqc?2) zt$yuw&^@7RVCHDeb5MIYpO55m((9oU`fpjCJ=;wl&iu*Fcrl6OV=Pi6ST|_ z3w1&#!PN&^4P z6vMeWjtg@fm*yni+S810?HPR6k>ikY(4G~@uzp_J$TUde+)N?#{PQ|7gmG-3&x@M_ z;+x|GZ4d-AkC<2^!6tpy1+geRKm2*}VMpl`Oi95|C4-V8g(OCqxGeo0<-eu;_q6&u zQ8niH8+B$LFyo+B@RG=8Li-(oE4&dGzmqJ|K{O+!ztQv?dc~DlC~Q-Eu|rh)@Wzn^MHzh8p2M#kdAu>F@s_=9PUEd9g>Ox1d}~bOtuc)^ zh7{wqA%#nQ5*HM4po=pT0aK!)D=H_!Jw{w{-WtFEd^th|IOrW zSDyza^y&J!QBsYj5DhIc@Gm#;H@2`}S!cNoXox}~nPSr}Mm#=v7niUwHI2#P zQ4ICoZW`1R)8aO{XugY>7muZqhCHyh__ACH(mHo(^SV0Hc4+yo^~B>?1cY8+9X>%r zCy}Mr7mMtFU znPz5YoStT8W@ct)W*QJ$wpg|-u+Xx!wj{4fmL>D<#-4jm)?3}xuey3bGg`&I5gAqW z7CcYUQ<*1EW?DA(!lJelrWGxFKm%)w0GOM2;rtnw1C3#=VSF?5&Q^BtvUfqCn-{{o z{SoOOf|#Ii#D_#6KJ*geLLv|y7=}xJ!3g#8M}V6byd7N+1PxTWzdF?#)i(_qSXjW; z+Db}3vIHc<6j<4T9(p%d7ZEZLT%4Vx5(u|B=={|_ajNat&CYAVfP?ncZpV2oXyEDY z27g~)ga!vADk4GvgY?u?Mv7Z7l-r2Gj5-Xa)Sx}E5bZvBX!XcJ zvtuTjZAm+4j45MH4Tc-N#5Bg_Lz0Mw3kj$fLn$7$=i*Q!#ueEHF{nHnjq)>5C_5dA zlG70=I&~5GC&G|(JOmlX0+B+N!C@~%J?w_?2b>XjpB=pSDYK|GkoTM4g|LxZf z|GSyvepR4>$=yd`@y+9~`POMT+;a}j-!XyPcTM4WuLZpCw}ij24(t$o$R2?YTO;_8 zEkcjjA^eylE}e2l^jSA#c|;)3Hx|W#iKqxmL+zz(G)LtXx68=@03ZNKL_t)eHMSUC zv8CvZE5|@=1)7|a&}^TAX1gRb+a#jdIuT7)iD)!W*kK&BSfxS4Ivp+a3To)Y!X7Y9 z5m2C&-XXIzQFawCg`)V%{Eo3l1xzuVM41pJg2s3v8brxap1%ezUr0nF4RwIgm z*(6y!X)SEiNW{ZtP)4~Q_piS|Logl+2u7eF77BZY&-4DmXPw*d*{?kpFKht56Ka2& zE+mQa)?zRuc|OLXDtPQKw`YH7APcjA{Slx-=}+}pzF*2aCT$0SfGvvypD?Of-hPi=6dte zcV1t)Hwxo|_n*&!a($D*>&yPNi73xihgmvQQJyP$>Xqxy?RgIJ%&7NY7$(~LuXzU4 zXF+o=a?j86p2y2LsNQoPm)BDIBhUEW{wUA8a(#`jsd8PFYfEEEj4D z5Y|hEu~9aP&5AK>RgPo3dJsiD1`!?`{ z{!KhHd>Jo{KZ2JgAH%SFsQ@%XP6TWS8k877gF+0`+bk6IA~7K8c^(k}p#VeH`4}Yg zz={Sujd`*Gve0Foi5Et%;rY?4cy8p1$g?AtL3xHUOxfN?l=bSi>b^YA4|>++`e?7C z$}|`d;6Py=NI!(xq4ZSP5FMj+ke(|y*KY#gM?3H)$^OtW% zjQ2Mjn{7y2O1o_T#i_@3zH!=b2*U;R;wV&bR*Wbr4-}nH(eBv7=fA=yzxXwN|Iu&p=`VkWKm77{`0Q7o z;Pc;nia-AL5BSq3pW)BH{~Uk*^pE({|AhJ zuPi);KC3(oSmg^)G%BD$DW+`81TdI$sKmTOCGHyS=*CD#7lzxrFhm+~OFR0STF_PB zg!bBcG*wiiwzLf8`2{G<%0^als(=PD7Zs)fWVuIHcyO?{mn4l$)M$L(`z?QM zK?5zzppz_vVPP3qHuS)}x*aBEjUc-~6)ST;n4b5*xzkPu8p8(}$_K4;x3Y(?gDXPZ zd=Tj!gxG*^BnDqXa%dD%LZgrz5{dZ0i-_?HMTA!Xf?a*!>)^HrG@$ohYdC8Sb7SND zWN+j6fb-hEY5RP$^I9JNw5%QD6&)BWZ^vj!D@JmgFr3+d;gmXb1{R{jCm$Uid1!OY zLYrMCTCHjHDc-0Z@2{ZOic+f>3p8#N(16N64Vel9V4yGz41mE&0tTVTJQjr1BmPJ{ z?1PwxJ#gtkg=OIPU2AymQ)W@mfY<(iGsgUlY^y!CcK$~8RkyhwXrQh)W*?~kt5fxO z+Nrir7yk7q%r;PMeN~cB?$|^ww18A`0HBpQ_dF}+PQVd8M!K%>MR*g3rl&T@D zcz$l;Ba$NRtHmMDrjyZ~Px{sl&XW;VMU9FkI)5F_%dUy*z7~aD7hbWsOPYrECkqtaG zWRSrPJf)HE4Q@ay+I2F&a}4E}%CWcbgCRxOwxX0@Mu%;d00(Vmsq)+iSYV!xPV;nh z7=+IgmDpCHWGiFX_xm^S-1t>IH+c=uO+SL?XCK82^N-`D#V7E?)tIy;0M_#}ikG+I9pZpQte(Dvx`}C`L@7dS!{tIv7gO}dM`_I22K!h0ld#6{H%C5Y;^8MZLAo1!YLj?)OBI@wr ztMB2%*M5eNUVk4SzwrS+e)9wT@~wZvzrXWy{Oa8g@$2_K!moe!F@E#@$N23BztkxG zzrm*;8x;RveS*(^{d;`=+fVVwPd-x=|4%>HDE)uI-~aqq{QWO~!+-qk@7Pc2|H+l- z(e0Eg2K|6@0ft0M-gSdr;L;DGl+p+67X z6=B36qxQuZG03nT6R{Ntz(BB}+lq1WjQP&M>s!z59N&26a^>W%2mV6R4%kQ#?Cr;Y zWW4zuU7m|?6YzI0aIhCNPyhplB#^#NZ*-a%g?F@LMh749DwlAPA;%(+`7!EPq5wJu zz(9Zl0Sk&SVqJt`>jIHMD*^`e?vq84Enor9qti0esD&@T_~%bP6F`N>C&1Eck&Qk} zN)GxB!e#!?YfA8tWAs>1^_Oq_HXY&p=iV@Y_XIt6L-IH#uI3HgrdGcEVP2m5p0GxE zZ+WjrZHh2%TZ}3DGR!(u2wmZ}=mm6d~e z4Ol@To1j5#9Bu|QP(u$mH8!e^jb+sc-*0NXukrGJ$KUTbdjA<8PrIGEPWzvBUR|%9 zG8rQ)II#31%RsuixQMXy9_L-0oMoNyHBgtouAspV%b;rvHXURc48f|Y4;FP@Fsp3E zg_8Omz<|Jkg{e18&bi^tNrxLUl2v2*hNo7J2ypN~xSJnhyhD%}5P{U7C}f1hB0VGq zX~8i_4va*+UpS(?f)M8FE880z<66U6Yna~*XrT4NbKcy<1Qupyu(Gg#4RagVu+oQ( zfCo2ve#ZSgsBhYHxZXSgfa`6;^#_3lK>-1X2n$18bTm?vl8}>`iQ<9+0Sp>yYS7x) zh%SadwRd2!vm3)beHiWS$5{U$Ci;g&CI^Nw**}b_fsy@Xa1>L6hIRcTnCctGRL>Bm zItMY?K7h&QeoQv>V!Wyo;{*aq+R&R+jow6!B-fxXr4|$A9hj)-#6+bcQ`Oy=nt3>;`u6Vp-Nj&;gSjdhPDJPjAuJ<;SvHR8U(@$TpyHy~{G7q0VLPIS?!& z+k&2`+xg@1$TZMiO*=z_q!;d!Khn_FbpO=D=_6%iD{oI%=%Vi&c7CO1PcP|uozM=vJ}#QMM`iz z77XCQv~Lv%957^In3WDBDIyaT=Hi8kM|4k-paH`LIt?KseO5UV6VF(A0s{mL#vF=w zWYoS06vk5%=pjRd01!RQytfQLczyF(-S)OBCw6k4C~Uu7meiY%zNEX~omepw*CL)} zju-M=3JXR7wPb&tW4q7%orgmHPc-pCUz45+W zX4yxA1q2BgukPvLDT(g9y$lKO7{l)Bs(=Uf4zOo=NJ}eNn(gL1_}T#nWElw4U|b1J zXd8xg%K(IBP}2d^@+O=ws@VYz{^1|~0cICGasG@mPM@&5BcOqgr4vHzJrU^|fCTR_ zr1?i8D<}pzA#unFiAQ#D9MS`#knDRAu^z#QaPdR1z2|kA23mt!Yp5T@G%yAY%r0Dz zQlDfSsK5b36>P2dmQK7LfS?5qw0$uKG_-v-o;NoBjo0ff8}Fw*$MBF4#6(6SIUxbr z85t2GAfG zO*Tnrw2DWAMLg!S+I7F%1Pxj&Q-!g@xP75*(;yWuu;MYLM@6M$ijv91T1=uONwSm} zO*K4$OoGcble+D_yz-PVUl=;07{aRYwi}|L80kuw1C<)m>7VFX)jj5|u6V3{Q2;fz zv13FUsOBngum^x6J^oxgUS9kDtu}c}`^{%`qV9qcQlWwyDsUi%Hh~^PSb`doK!cke z=da7J%QasZBgVji03Q#+ju88qnZmY_7y-3k|+dVz!4}NW&&@zzqGY9FQxq zzU_9In2u}GYYrd3@jhzJ;zep0HXss*YSTDOChLO@x(B>ND_+0)JUSe+(CwUqK9_t9 zx)ox?T>%ZIJj*fTQ-wL-8qE9EVll8DOTi6T4sOIsXp_itXcLx08nG18h{fOr0S;#T zsxawODLD>?nbW{U2~A)q#B*a;bt%3zImK#D66cAW>2T4Q!Dt~<*MIh6LxhWXFGwe{LfCjcoE(3-q2xwqa zj8SW{4GJ+Vc@6R<0int=kaM61-7NXGcmGeHe7H*2TlCU_2#%Y8s)Vb`gTRrS;-|vTWPY8%bP==u=WE+raK+s^$z7mTL zRakba#a%PKgP86az*NtG0XXQz2$PYuwo85k2~nu5Ms-msN^b!P6=dWj&Yq#I8P3`{Io7W!8xb5p5+jw6tJ3A?W0h8SkDDd_6 zfgel%`TD}o#}~d{-thA9gom3uT%BFuMBuK+Vd zG1Nejk*p?+WH(_Xrx~+#eS4+053^N0m@VtZbbdRgvRW~j+JyeVQuO&0qtBgnqVv&X zpNAgXTqVYm@p}@BsCe%f7u;fqX{JFWECWe=s4@(8^A|82A)V}kBfdyD8v+fY&wC)r+!q-(K?-OPnTO8UV$``Mpusg6O)kmka?e4RYc@KV2+<)^ zVvL(@Qn8TJt@}YIeVcL4OrXhxRg8&Nm7yJqH7S?|p(jP9UQ*elmzYYLYV6Tlu~jv$ z+un~>p4!PTKtoGH6%29vG|(t&NCFLI#`#mxeynRr_n5c3;*s_RQJ%=ep^>dJ4tOrA zNPi4Qtok1PaOJ66ZSt1(n@#UP_1QS_4lz7}38)0z*^_@kVMK_*Z2($+@ybtcsl7X~ zQ-@3L9>dzW|6EpC61*3@Csbl@H)udAJ;SqT$nD&B69u?p`_d0BvqY|Cyo7}5T^BM9 z_-qiI<^5soI+koLz*7*KG%HoIOn3nDGSpH z`o{l9Z@iCci})R>GR#+5#9<;;e?Ptc->Lrz8niiP3fq97!H`=KMmLr9>%BKqBUS&{0gC2(*$;$rh z=oQ^l`N80pB%h@X(Te49&-o% zc_eH|R{HBpYTpAQ^rPqxmX-6LF0)c5qzf^Su)yWE2`CVL=9vj6f|z zS-#3&n{&1#&||VsCa+{D2(LS@KN$zZWE|KO3Ro~=2u&EW%EurR53=%u;d?}&m*XJ6 zAGiDWr{90RGj8zPpn|t#Xh=weA-qGF4hF!0V?v)_$?fjSEg$cv&%G|sBN?a6YbCj@ zm=OC+B&IX<9SpbJ;4SX>(%ci0^zkY`AN;H(sYMYxlq2 zy!LpU*KV&KPn~Mlao%`eF1xw93A4b*+Z+DAehBmr0O{Pp0f7ke4?uvQAN;(1;7#Db z)eSC=&TzD|hn>~lM2TM~&|nYCpnZ5J0itBT zln?U0U-<5ESUq?a&POcZeaare=iLx#?t=vDV5HiIBh&E`vYnztvK%9kW`7ZhHo=Io z@W(|{PXwLYTRnlE{DX|>8wCwmW>ITYo1Qxdv-9U+e!)b5gM-fLpmkb<|Db*zv`%}B z>wyNw+iK6r+tUL<0sgoc7K*r-Xr!eiBQGZ#WyQs)t*SzEL&Gj$FgS<_f(2van4Or! z{KOO%CZ@4CIfJGBWMT$O#xgmpY|H=0XRtIjjir%kEDcX$seb}Xz2jKy8pT4(5at^P zF<(D`vAkA{`K?%J9Kb^3pfYV3z(U;s7OMNOP|<_A{7%efwP7Z;1%rVV81N~@ zfJd=XH=1#{^Zj+NvwAYfpB_Ze7!2H7CBieP^`P&T|@LY}A2B!af6lVW&6z2bO3-S(9vGhbv_ z1)(-P6U~?M&>3BXIv0WlNoaO9fCesE=y1$LyL|>)Y*W!_m4f*!eeVH5gX;6D0hJ`B z*{BpVZ$YQcAKZqW^r}=qYACg575=4jWZtx@rRB&@0cxh=)Tlw3sZB zc@EU1eY;5pxt@RlOM*Vqv8a2@TU~LjeL*US(CZ=wq<|PoKUA=Q{UQ*;stDYU3f7Cu zPu^;ix3u4MM!O^~Rj(I;7WR)ut}1GOcMR@xvH1Cq-@T>w?!-=QE;+&+P(AX}e?uq= z0U9pzym+l?(9^J|k;P**ZjaRy`mA$=;?6{SBaX!wbt)FXfXM(!*Jo`0fNLRoUGmWBlr4rf z^IPcsK6>+gRG7zpLCVZxFq+b+x7%0#|7%yDLyLX7fFM0CxxzGH^@9noa?E&FVa}%p zi~e<34yea!a5L6Jnz0_*ij8nZ*27z|7S@8*&}OWVZ4lUiS>GB=`BY%cqYOi?h3Iq4 zMVEb+lyrM~WLx(fzdx`cU?hz^8vgVO6U<>|b|qH2L^88aN;$VunI99-ph(yVy;ixB z0iWMiKC67s$ePmotyBz4_#YDt^P4MjG939Q!|>xP`e6-v$NMt>kH*v)p3QhkP%B|M zn&h2YmJ-iP1#18OonL&JW^a1mCdW+FnkGno4krI(-Uz-w3=1K^Bjxu5EMWD7e4(t< zm}J>V^;^WTgkv_x>&kPnH{FNp?eM4He3qF17%F(x24;s z=z53#%GSU8>}!(vn$KqODJ7>B=gB-BOZ)nOjxWtUF5o?N5r%#cG~hcqV_%MW2Zkop zVAZ)EcP;jfV4-gW^L-hfKH4c61_BuP z`5`bM03pG_2n`NVBq$icfq@A0H2??ho^W?|fwR3M9Bgd&Buf0+fCl>{K>W62Fur9U zfN$FR;%+Oi9fpAl7!WiFy;K0d;BW(JB23s7BAfu{O; zbhfslzq?x)1`{JAn3cA9MdMB~eF@~kK5iGR~W3sptlSLhvEHnt`i#uf<*Do~DG~lxF_FTSM(16=(+fnDW=V%NXXh8zb z6DZJ%9%ztk;)^WHVAO|Zp*12O-BBe14z9oe03ZNKL_t)jcTPl;a|&9VlF{XwgD&T6 zv^x+mNJo=R3hFGAK%-Od_s-L=DxTN#RDu%4gQkE6O7?ettXV#aR9?o7QWQlkd)KpL z0I2w^(K}2po8IrGmG6l$NFz&(HnuCC{@wUW9!CWXXxy>7$JLH`y+hve|Cih5t z;DFbSfCcY8r(9P1LQip>ZHjI;{_yKh#6Tp-Q7Hgaf|NF7ZV+J`Sm$7X<^6<-+av=~jU~xoKF&dRD^GQIIW%7os2pSYi{dcAI zJL|ufNiBHBPt&u_cxqv3yX#`P>tspyZqgkubol<3ae* z_E(z|WiYx%##{n%H7cu0t;%A^fufFeG={ky$GMN+{x`kTyCeVC+oz$D0QQA=uzVlC zL+t__DER`EZ;+DoaQ8c;eHG&4qePdYa8-)TMD2#*2&OVH__h7KC13ir`XsxM3Lv;-*ic687os0C8RK&-` z;$m3%Z4FP*8r+;WHq2FnU7c#T-w!b0f85siIQuPYkEPCQx6_6Ta9+Dk-QIZW<>@Km z2m%-c1xp?K@X$~JTf##^rA%Eg83(?8@bU11r>h%W9i3onV)3;E4R#VBYRW8r%OMEg zwDZT^Ha_@QOHY(kO(VB>2x&PTh)=0UL`>Oj0}8Z8HS4k4-FFV|4_hGMm;)kCdm#S2 zAJWW1kY#ZZc~+4qu#QH7brkZgB9U!z5oxBuNI370$kUz(Iqm}ABer`&6b>@D4+=@p z0tTGd8rUYM&cXovKm)(z^jVmmIS12o=WqF1XpQ)T`gyz7Y1=af4T1v$aOq+=;^Sh$ z@{0Mnxu_^BMSX1z+FF{?OTd5(gRwEpPEKKAW)@3xb6A;Qz}n)HL6)&Tzl8NUMb_pP zu_LpKSo?x3U~OgrYtsu@o0`Yk!x zL{{6zpvqduIM&+7vBv*eMzPv3jMeHvESL3TBC!b*(G8fmSc}nsO0aCth`RzBFvIYm zy+Yd?keEv)d$3R_4as+?jPs*KC7d5RdO4`H?B*`;K;%QNxJY)veGUk`*A{-?v4Yn< z7I6EPDV)A}9(Mn#FbvH8`6w>@KZo}KM5`>(d4oodhP zWmG7ZGLqbSle zR#(c0b=8&^SDq9DiwYg-krii@Qi(LsC^U*`$niKd!W5t@3|nn8y2rfL72EBziUE0w z1|$tWMG>Sype<3#|GA!CnSzsHcy>WQOZ%<%<)HmW)0$CuDqK-k&qgUFBn9Nz1vqGM z(?iH)r($%Uj>HEqe|6`1S8a>83ZC&$R#t7ZQZELpr?B ztXVmMpn*e?FbyW$l<)+C2BhsXG@;Wu8?BBRXs}PgaBPikdjt&%Od|G`{={0{{l4lI zuU>r?4Ynz0bI1g%C=9q1V$`h^lO7eA^{&B!PaT&18?YMCg!RB?Yy`DnBcv6ZA+5?Z zxCQG$%~f?7e^{5|S+|*|%eEiB`$Lz6M2J$J;ON$~!N;j(1-AiO9Pz{RBV# z;Tw2Q{R#mS#*FD#*0jW(a7j0Hb{7qjtu*kKXz~_mO#GW*h6> zGrF?TJqxXD_RN8@)iaN+-g#{IF5q(S0{%OXBE zdIisqUPG^4uG|AjHfSiTsIuLj9o&|3imcSa$}Ox0!{a5G zSV|6S$FwL^n8aZyt`2=M)##3{L`P&9S}&ELIid)S7Yk4yUVysrJk*5cqB=AOm7!Uv z49P-&zW%rSn@ z(BzjZV_?qlV42d1q&%wuIB5KM`-eYK`WBRl@_-DK`K6)MHw7i$$td)X_4s;SAe#<@(-?a6^-PYdthJ`x{E5?ys(2wMdR>UM$BRsO`mJMYsNMJl~anDIO z-gg0BthIj32~np!k$f%ynWmx0Gmk)#MKp>nV^C}vg+hx+YRctO9WN{Un^UFK3 zF}H*-$|5#q7qKz3h>ht5Y)ma+V{!qTl<|3Nj?7_WUOnM}h`L^tzsnLiPDL`ACzc!Wd0HPh=I)(>83)TFLpMWV6H-*#`uus7TX$NAD~R z{?ap1SSlUVRW@H(eG+-6!ccJfB8pC562O9rD!p56F4;;M#rQ^y#MNUst_}mSHRy}3 z!gkl3D8f{TDO8dbrCCv;^%QNbg3WzIp?>KNIo4LkEc&9WF&JBe;kbH?#x;miO=@_% zTdom!5h0)(6|Eo4UDG|kfB)bky!GO%c+*Jq`p5sZhQK>7Qu*K8&&A3ijHWhYCa()C zr9;@No5Uk+^LVm%6@C6CV#F{8S?d|6Cw-}GP?T{hyI1-aak-buG8N@nQTErmr?J*G zjn%FxtWY{9vD`U{Pk-}??)g1BvnkuGbWX{Bt6e;XVm#1D;PI(wUoj}zkM=L)v4K@o zna88-bfka+d`<+IVJX=2@n97TdWl)yQC0S7M6lmi`xdd)HH)?ODJ-{)W1(RLv$cbm zs_Mgdc{j#NJ270;hQWds^yfCAH>)1q>9y!etwCpU6*>|t(Gg#Pj<|Ak#FV4`QYqg1 z;hXr`58uT5KYB~#gCD((4_(e29L)Y z>nzLo_Tw+3(;`E1&kWe*W7t8-YapQst|b_8E0VH-3{7Zv%0iPv8tQFR&>vZ;+ukqU z_!+X#ha%^E7;-LX|)U!SBdthQZ!vGKwWSSs{Arg;+c#B*EnQ5L?X>P3`yoe zh&}Hs4vXMJ4ycbS)NSv@N1sN}VF!d9bwube0D-jt0tT(v3Tnev za2vLR+hxjS0tu^rjac?+z`R!trrpai=3FABD!Xm6(Q287dh;YyUx>rweJi@>z~_o! zB*!U^S4`r{ICzd}V>U&Yv@MkcYcqD`GM%zhLKGOf!10a-D(UB>qx0G2nDxQ|jHB7I zKBOG+lkh+03nHtJVSovTyzu;{K0~2BwF*J^+U=G5>=1mPy|4g7?sGus{fdO$?}mr~BLhddE~*c(Yle2{X~U%-_=e)0#s z=Fsa@fDR_#HB|E9l*|trluT}__scxN64HKhEqG1h9`-=Y!|sTdzOX-r{u%nI^wAB` zYCj+LlxxWn)V!aC2aE%M{M}~~7C|zVOB%fw@Xu9(yy;H+`ue}YQ?^we3yH@c3u8lZ-_?+-w@OfbME1m}vTl3lDbI7&{ zU=bwHf?E8ap{m^pRl4oH^vKh~LS_FHv6VLYyeiM91B{mB>B zr{vRO`|J~$4<)BA$#Y3iSpf~QBs^ilwghwb6qH(u5n?ONks zo!1`Em}#JHqn&DxXFRVx7U#L2cAJCxX1p)UDY9CE7BmPA34yQ-2pAYZgK&Zdfk6oL z^@o54t^^HSU}tKz3mTk0|MdY4x+h?q0Fj{yciZ?1%itSkZpbekK}K#j5>gux8CQ;w zi+ML}C>sL<2Q6FOa~dx9nZoB`8-yNpLF_4Sq@E2#j!8I*%py^05rcAzSd>}Bpu{X% zyad_jLXmPh0CC5?aq);N0w1!!?Vte}30kJXg=426z`+RxI5_B>jMr&_1Fb=Sr{=Xl zfi{N&=e6e)dFdjO5}5oj4TY?hP+o?nhI({$v}3TZ7vrNNn3_I z0b3(;*czV0*5E9bnuf8|I3lvyHv^I08EjFyr?J^FiOtptY&MKxy?O|1rTv(SZ^Be$ zJtjkIG45B1QO|OWx|LzXsYE1Tb2K0ES z0KtA!*Ke7?@tfyhZ(tV~8@uZAenztPKXtpCnW_f%mz^2|0os1u2xwruzZOJL=Z*WQ zZ9|>cZex5Mj6s9_LKNKZHG}U1RtP!dfY_6sNI4&X9P@CLSVyDG>JqALV$ooih)$Pm z^tj}p$C+g~Gtg?Ch6c+di47&opycc&3?|g+Dgtjm^9l;+#THLHv&tt*jshxV1P$nA zWBe#HRgvf$S3@$UPZ~{8Qm5JQX4P z(7U|VpkJ!-iHR*yxMLso5JgW_w89JuG{b6wMY*N|qX_?_BF1f~tZ*MHi9ANaVJ|!~ zq;F(gZJQU5H$BbtAd{s-g^vo?_viGpwD%V@ivs8WU2E)$4FbNaC|YFmP!vVW&R__r z{iL#|^pi?06qHQ*~(#HLWXmsD6~`>c@DhBS|wF$uuu_Y8CTM?3r`xD5(a>X{Z)m^w%(85 zPer+Q7bTd=Fx%sOrGiRjRlVQ4Q^mkyZWi8mDyU*iJ?xHzBi?#Vfk_exwn!;j=6>Nl zKM^8|Y`$rP?tTZYV3Nc(^E7l>Wunhk$qGN@Scoy#QjD;Af=dwwTno_SlqxD(!pKJJOgqwb<-gdTQA z@F7P8K5UPGhwR|@pe?Fn^y$+tKK=}RAF_e}AzK6olwA!Vk+aU*o&dPaDyH{e~vj)pP^;q+3!bU(dwgTI*9oUY` z!4v`qZSvn{U@O*q8?o$NFZ)cnmSfbp1pN*L=(Ng2vqh>Ta;-QYgGYPxlchc}ur7u^ z87&;In81~kXNi-xDF#6T#!AzRNnwWeDce#36bPCUjAw#j0`c-qJr#lH=JgpzQ>8s( z2=Sd0WA%`yj5{>qp51st_ujUqR>=Fs_fVBx1IemTz3GL9+ZnbI%zX$L?MAVUE&A|6x#4FNT1 zoNK^?xIm1Rvo79a*Q?*YesUVj>@G^i=; z6NO`hV#q4X>UwU=F_VTj0UtX1^nQQ*-5=!H;PXKt5JPZDz9EM3SSf4mFXK9o8TFu> z82B91c>VaD@cWK6yzj9T#%HRdetSQC?JWr*B{P)Z0iPG%501$UHRbszM!ARdoxl~D zF6jc&1c29u^BkuMDDXaX#_5-aBzQ<5Llw41u!7Gg+f~M2j=j6!0nba7Z~>K+Z=7Vll20iM%yL$#( z9aGq9nZR1jFxJWju~yWFsi+1_h1X#ss2bzm<&ykq#I;zmZxb*WV$E+uXaWaS8gWG6 zNiSz;0?}@Mv`DYbIUa(vqkad11`c zY$V^vvewA{GV{hpzqXIJ0vhbcHZbm=wheV&yN&VrYx5VV^Tv4$JicoVzXxm(cE}NN zC%ut&E)WIg7g1pyi%QFA)Z50R*)~Z4gIhfCf?@nGAzML#ZpJ-4KGJTbW`N?+82uHwZK!_i1i`<1gs8HOIcddR7u(f}Y3r1qOiAw661 z;@ML3mpBPvz=Ws%_u7cJ%KJNtqWaU<-qvj|%_#!hj*25e5mia${m}NAN+1^Qkm;{HEtliNDr8*j)|5o3_m}wF!iatG-djSJ`1l?!9zTR_z@R`7ytwRhiu{dpf$W7utIrMwr+bbJpK$kAFzb?gI0UM zgODRmxOmJ3Q71g44FVKtX9GcJNTJCkl$*t%#ykN{R;lQ)$wD8Q7LLW3a4y4)Yb6%k zYq9LnfK{(Xta~?O!@C8WzO9P*w94|jXCqcU8?fYFi+R^7OgWWf#GzQOBQxwbnWv!U zLcB1gu5~Twp2OpVYx3-ojl*vvSpx(`m5l6a?e_}IIaFfSz7jL`6=047G7UJ^v64)S zNvbdv7&=7*`qhh*kG5i{a{PIE?J?c`T2jm5{T&Mtb?lIF!{FWJ`=){h zDsVvHPaWSBPyb#o^E)rRrrX{?RQ29*?wAt3NU-wXexhHpHOo0lj8u*RyGEnEj42!o z)P6)f-~v@t16?u54XlHQJP`M=0vvqy+u!T&Nh z3GWL59bOOig@6@v&hXli(L;cbtROlm$Os~^r-mkMx;EmnTQlxjW-_p*AuKcvVyuNg06_%~Opc%a!nHUEIQXi=5^j`fz;jZQAJ$Y=prxq+J)NBx863dW_!#DAXB5C- zZ53M^8@Rl+g{#}!xVC-SAe`UEwe>ArRe^(*bzELqH?R&?A#8&krhz70fguV64d#}x zHM@lE*(F?_S;pmQf(Oe29$cAR2IblWWeL~DmT+x!5m$#7abLYh-_!`Ts4Tf!Dnj2z<~E5rU(fU+pf(HCh zGiF{s)aTHL0^+oD2f21D|6!3uF+?*4kSg9G+-S4r3* zVD!joJTTk+`V|?r+h)ahq`|8I28uU^hWF!B`U%&13z|fU^Zd5CR37oV#~f7Xm{^ob zoz^?E>p>)VpcuR2turtqs9aIe{qbYZ>0XyfNs_3PbmO~jOsm&=w)TJq_dAJ_$38HR z34s95d(0&~>D^b~)NL=-=^}V;qNIM;O0GBiETF-I&Y}d989*ga3mVWECwNH(ntddA zK;iP|ztQ(Frd0o%u_j2QD3TLzsbOK!$im2lrh&$

mNRw>T}+6fwv@;q%{E`R~EveT1EwgD3&(oj)AgG>o)pdrKOme2DKX7w3I ztNILu=9F?V7-=*TbX3O-dZ0O;?L5~8pn&g#Dq^fZpn7r% z9MEWV!&}e4s(WvHBP(_QG6H-8Fw&qs>f2-LJd#Y zXG#E={i88X1NsjKghe&lrS0S$;XU9zrze`;{J;N2zrsr5Q6I!UM23MI*xvrabq0|z z3bG;g3ddoBKm_UZeyps(XH3R6mf19v+T^pThC0!C!|O~#oxm#3oyVq8&FjZ|%zMuJ z&rs1sJAJV7z1QE_0~+w#5_GSvJP!mSc+O<2DPDXfG=bw9+gF850|hitDrmJv>w}dq zKK6|Ci{A=<&)6Q5W)sBP0j-4DwU=2!phf{~l&}v188L=?&aqVm4EUYpd&TR;_mtx% z^N-LO#w3V*Px)T1IMrgqnJj~5Ty<~5U8{{FSRs|Sd00x8tqrn_*%)SfhcVIJkHNN1 zbTzi1nV>;wg~BvQ`y$i8*oeR0vTFQusv5(_(}N6iZF-=6ZNj%EVMWf(!1Ts$qBk8Cgq7Qi>^Z~~kW*RUgK+7ml zD<`N^?K&;fKtO~0j|p&a5J13nT4upl4H)qJw4ed!wdWBU8jPr@OGt=|MMhdG3i5L$ zETOT!7M<;_7%+q-%uY{XX>kE-t1H;rSlqYSFYgED_8O8?*EKuizSG zW);^aR~7JJbP3l+7ICG24wrjou-!g|t;TVzR}5jTs2?ji-IB{-EU*frKIIr@EpO){ z#XDtNfIjP7DMduEpxc76ei=gJVy)#y6Q#~MQsAQIPY_>6@nkMN8}+_ zq@3~>MZDB33bodWsJDzmi**t@ZBwQE=Acs{2Am4eX`P8yi&Qk28bE_Hmm~~;$&d7Y zZ$0~}81DR7Q^}!1M$n1R6Z2#UeV2*CY?YE^6SfLyz>o#WC~lT68T^?KfguiL4ons4 zmw0?;^>M@>@dlN-I9sHo$? zr0NL~FU$ij*y^3ryDXA;kxC3b&3t!A-=u;=&&Z>b8@l`T6gI;B+oq!M(YO}n-{6^7 zlq}LYRfd5QrXc;iZx`H9l<(b;iXT0yU!skb6{wI>(NcxWN+LmpYRq#W^;1<+=|SVQ zB$ZfIQV9akvqjI03DMA|>YS9bbo zphUA|q24dmBv_0uD%GU7Djux;r>gNJlx;(-wH7qs{ycBJA3+1&YsP`AbX|JEsN^P` z^3&Vx!2fw}d^Z|Rlh9_NBt`5caA21w!eoA(cG+mPNk_d^GO8@%g_+nAq#rKu;X5B7 z@uZI!>8Ym`#(~N&JkuBv`x$4R1e%xPx0mF05XPL$!r;6dg%Yo_928nV#{;c!{N(#YgLYRGFaD>$*3YFXDw8oTN=`K&&8$jS<2pb$7WghH@AK9_tZ`TQx&2HtlC z1Y-LHsyT-8+ezU!h{E=m!ywg=&w~A8E)CvK0tRG|Fu^jJv#gpy#?Q2U8CW%e2@sjf z;EG!-uDQ44uJxu-tTm5drDX(*EyLItp2o`HIOh9DFxfMJp|&n`3uw@Qsxkv;AmItO zhiPy-Km%jIfXl|9g4WR28u{A))p@Sh?r&_ktJ|ql?eRG8;_M7}H#a3j!OKf3Cv+t&jOjE{L+Kn4S7AS{FS5m>hl!m_dV3!p)E;Q&&y+7O#m zgYc+g1cYY7(>LLcfClb|ED>2fih_=U});vjS&o-JT%arw9`JpR5 za|t;oL*>PZJ>-G#2c2)qP}c$jDp;USwd=ITHs`Mg7O3n0CqM%&P;gKlgNTT5#KpxR zHCau5Scux{O0+gNqPL4IgF#G9j7#Ff)#W8@uCL+p)+Vl9QNV)7u3dx3)oXa{ssbE5 zvb75uTwW#1fPlfWR8$~PurfW5<;giLPt7S)!~6g_vy0f8Re*!bvn#kd zw~A}Ct9WE~RRImA2^y^6+SoF#k!jF3i_4ue*lwA`R^2Gp%KEXI-;1S;E{q0OVZ^rr zL!Kq*cP>DmLjihhbI@&_CH0G0&Wo{`EFsluk}4izmK;(lCNP(QQZa!aDAKC=!R7}= zHBeQ9RXbIU_=Bce!&q;AKSNpjpYidv>o~6(+&4S@-vS!=-DiW)ha3@o*j<$I{PP!4 zVHSf1>tr-pCZOFq1>Lq87VQPl@Dns3Yh}PHSKMU~+FxQA&n61=L4&7PA4BwE zPsAPZlKAq(BR*oFr5yFceC2?yg7oOrhDHH*6oZ#av?^Ld(RhB(HU`6!O3p^_tZsW7 zt<&Oxp<+V?M`B_hVqCoou8r$wY40g&62O4vNj0KJtuiKgZKr6h&1Gas@n~(n9 zZ~yoJ(7-vu02)|IcmlmlR2r!;a(p2$NrRiA90Xk$BB1~VsxqyB2J9mhY(94^S*Z6T zXu$Ya#VAsZBLmIVC=Qw1X}489yX>E0Y$-;ZUR(e5AOE?d)XM!f#6a_yF(NI4mRtg|7=KX(zu=M}xD&O8Y%7Gzjt zVZbI2qjtr@6qt9e!m?{E*4!Gf>E48Gj}~0dq|Z=jNvqfam5uBx^kE1C9+UWuC`)?^XRUr7YJN zF>ZN243A*{Nb9FJUNIIG1Ce7Vh4Jz<7WrP$kffo`@j@$~{`z;i{j9V}ka2`#30ZNR za_r#v_SZlCMR&i1-JW&NO*e_l)ULUeY)MTX{Ojat6i$Y0MD!B|CYq06U zu!I&|b8o|A9v!&r(Sdn9GBl5?Lvz?3p2gsop`UpwQFQispI)Xpp~u zP6MrxeIxT)#1mkY{pHV)~fHywULSWZmXwvs6LH zSudBF#)&+p9}AR0ipt4BhPoCA;JgYD>^IeJ`@a!1h>ng#a&n>}`C*B+nXD>dU+dZoG;rznb6qd%Pu{<$r01p--%OK)m?TyRg<7kqLs1 z7j)<<9?xHS3XzB05PjGKu>=nedm({Y#Si;nrb0g#0=@gH*KXGcRFi)hvUM9N%)4GV zda3scjnMTTeIsM7by87wsYn}?M^Wk?aKhE`Ro(OJEmFc0$S|PyXD9Ceeucu%b70$A z#h!7_ic!4lnG_?}uR1ksJU6ud-@BiNS{{7c~{+B4e z;%PL{hPglYi#(>E3t``b8U7?_!23{jK32Z_t>&rn&JZ}DG0kLttN_qpo`fosIFy`^ zl(5BmU;S`_58wU(aYsERtTE-dAJR_-BI{Hza!!XLk7dgY!sYDKA;>rxh}0AQvOUL> zONU$$_K*{T9v`&_sugj8hjH`rbs@*f+%Jxkg(0$D;D(C8&McMl zv&!VDS>^K7Y_H8Km-Dkq^WLPTG=_k1WuT zAHb#EXMj1N^A};pfwT!5bWBm8`S`NXG!BtJeDJ%#{oL{d&JyGKW_#=(1OXmy1+pQj zzAZawlx2)#Ms3tL{&Q}(gi##*?pGgpBq;>xY7O_x9J*eCuu1y5UYO?|WK3ZE!{cw1 zU?x#5V;kpQ$K)?ekZqHKa~gd6t6x`w33AC22AoIk2lgLQg7-S)F=PercN4rP-Boc}}(5bE)y5Tx>ol7n%>s z`PLpe(@Nd*PC3-jCf)T-(o$I?HN~Y;YDt5DM2LQ%d%JlT+`7QlPP@RIX?J<1U4r0F zrrq_q>vF%h)9&v~+kLXVU5?(rEb~*RPL-&rD48*1hRm8ZQ)bVeC6EV%D-5)}|GRI_yA-1Mhzq(%`=$9Kj!w5Kd{ZdGkiu zu_IOz;&)4WYKr9NW=nZ#vDDR=Tn0AzAu5BDN*bIRkTke-;euQ||CEL)kmKOosnePy zksJocdk)Kyu3kB`ze{@B_Dgq5yL2|S%KnCyQ0r`Lm9C~X>27Y9-j@AxxV>AB?eCQn zod;EQprHx}j>=O#$K*WW30+6!eEShO*K$bCHXP8Z2`7u&s*Uw&+RS!;=)ep{)wGYkIuq;$ol;GN*9-Ir| zV&^F}rVO|?p5}o8Bwj3IKwBdi!-i!6fPF;5G&x?=9cXMGE$dKY$gYF`vu!}~+14Y0 z|J#>R8uAnphYWDwKboK5eiPHlI@w3t>^4ICd0&6e`pu`F3*267Y>66WmNY;PixEa> z5T* z@I;cIfO{P3ymM)c2at%D4hEAAl{<4iFpk`Rs>asyd>Jrq zJh!NZY)m?U6Yy(6uHN@ba`sgTc>B3m1NXCJ)m{bFc>EcEc%JPz_qEr8bDJd1+N25t zmgRo{a#vxbVDX7QposLG?-+lSymaz~@SFnd-w!hmB#&RGIYzK&I9_^kj&R(+4@Vk2 zZpJyz3*!RI_mP^*RT%)Nwhbp)>Fe0i*%Bd02-5!|MbxJx>!hZjt;E zTlC(;VTdx1anXX>tVUrc1WITJ1FO>>yTIJP9{zhLM1ft#U6&u|`+xKQ&bI76+1~w+dmMIpYGkBLn>tl<8_bv;QW_U<{-TxX7PA3DUs7 zjd1fHS2@L?^%9=oCkyPntC-lneXGRB?~;_HM9Im_kdnfDsjeuO#`;=mZ)uVPo%`i* zZ;u>zLK9r20cwM%2}?MS!r+`HL_CMW;P?qSdGweZ>p3KcyLzOzy;Hhd+hu=ai?r1@ zN^4z%G*{P4bIm?&Ewv5OR@W#U`Ip*2IWZR5(X9 zh1NrI2Ew4WOOBVe$+5g9Ih0;6y@}P*7@aNkOVXrfev;O$FPXAK3Ma&9LaFSLnHT+2aMEvDlBAIA*-K7zBVNJQsKfEik3GG66{~{12k*WBX|T{C z4ajNWB_EoQD1;((MPw*paDW71Q?jH}V|`Plablv5Y3hOVNQ2#jmPva;MWB&-{oGac za;|zHN}?Z#(qq&TTo2Ba_SE38hKpUN)Gz}019TZHF{Ux*jQ6Nd5{Y4Gjp(hOC(atC zAz*%gR9MpBNLfceubuTc<5@e?5?pnmF|Ay^_Ex@WjcWD6Jv3L7ky`1d-B0E*Xsuz& zvGtK0QS#FHYk}vpHMUrdTtGOUd=i6Um|+~Mf#{Vsv~}1SD=_W=9c&jb5!)h6f_-Lu zc;}V30=E}GYlBK*Aq+StTm#-+cop%QF&_09s_PYGSwofmvipJ303bnJZ8*{(ZWPrM zxYkH+@o3G}YfAzzj=_2!**1-NzUQ9i_>AP*BtioaF%JI6hyO9)@$tP9ORD@ZvFI4& zoEPNyALRpS!1+e`1yDd0#`8rPF$li$F>xBU0MKS^Pae8jAOLb_2ZQ+Uf9*T6@sYWj z3n}*T#j<LDUxWRo7h~z#7=mG=*v>|WpAp725 zuD|JhuVB1yEMdHR`?*&F_p@kak|qZ<)dUPN3ScGV;JsIa!<16yZqxDD5C(Hh($mM6 zXqi$gHSZ%YO(g-w1sjsYa|%#p>>vjUV}ZH)VzpWprFw}JoL z`UF6naToOiAyb|LN|Uleu$n3^09wW-<^lZdC-xLzn6bo;&)Wts3fvZ?0m?qE59?r^ z)_Yz&a=TXFfOvwGr-BDzGLTT5C&o?2FSez`!TmFo%-u0LxYX-+-~FbN(&k>7srv|_ z#63dz7i1bv06;kvjsWH~rg;V!k06!VU#TOk z95drRjDI#W001BWNklqj*}l4Q2YG1GX482`XPX1zMgMAP&x-JFB@3 zo+2FK>{&T?=8TqKJbnCxoH%++jvhQDhdK|)f%g5fzqwV~_cbX&&{$O~^%d1pS5_&t zrKZ)DRmr}JYT>t*ntjqy-y~fPt<<)rcY@iOXX6Buyh6we4iM5{ke}>DXPY;nX|N2-z0>LE_K55dxk``|7 z2ih(Oznf`G23Rof_V%}M{he&fU8kLP|K~rJ+mQzLJZyVxzJdt6czL5XtCYEMN|Llr zO_Tjm>C!qSMH|Ec$uXg&_^D9lt2c@1Lq(PQouNc>saX zk`hcdT4HF*9HWT4;!f|akqGrk5>nKCXbZ0E0|WG zsUByOfDzf~>E__73(cN~(aQEQt}t$OKOK#0I$l5=UBMcr}tY85{ z6$2P!ltfk#<80sV1NWBout9iY+yZpMfrXu8Rx0Vq^(HS1Mm40U1y9zi#WB&`um=o& zWXPOTt2*F%h9eEQZZt>{OBiTu`GZpepP_I+KpJq27}Wq0&Oy)+LUAXFeBk#geTm6AGiwf;Y6#3l_5C>XUxX!#?zXh}i{396ew zE>Nw6|89afcwmMmV9r_*TypWXXI~Ns19C2{C2s}S;ju;ftn*G{zw>O)hB0wECNxY) zkd{d%UqJVi49yXs3WI5Q3yVWB$rol;sMqk)tSY%QyGp?Tz0S|7lBZ`@$oUziayqJ5 zj!n&%gHy6KzPX72P(iQ0b(U};ryN|2__9LwVcpsl~rP_QaVRZsv=ntShu zBMs8#ZP)P$JA<)}?Lyq74?$|aLGSZ|;ae0qG7fOg0h4z8u|SpQ89>kT{qr9LlLouT ztx}-MxX80iPs1VdyI+40_^iYXHpB$mG3U{E-wn70P%}<$RUl2zJa#$1bH3gEWE>%P zN6_bYzy7U~5|q0o`5|Ln!3d8e922KW{ZQ}$lJTf>KY;@nE7=}lTZTAT6e14dr>qUy zoP6)SZ>b_d!zLb@tM5UG4hV~!p=^7L5)}}Xlr1EwAU*Q{cXeD2Td!dYjHeI|6>EZ3 ziEljflD-omz!{4f*Ahb24jA({>+x`093R_*3{XN~>~6Iwuq((@KqLGBl7Pwx5Ob<( zoRliv5vGy}xkY#mAq?Fd1`r0%&Z(8>=GM#e^Y+O-&vl)YYn{jCneO9qsq3g*p!PY5 z#)uuZ#6YL`2Bs$&*9Gfx9iH{l{{<-`(Z?`{V!bKqP?spMic4`<+!8RJX~* zN)jNNstIHBtL3v3=gVit&6ZD(o+1A_B2xZk=p@-3(^oaY<}9$iOCs3sY;Q?`yX|*O ziq_{9&s>(}cUu})FHZ@46m(So(Z;u>1d`M0lJ)$8Bry&n0xp<1Q zi>Ku5sZ(KuUe?qym#uiHBrW`4q7cYe~c1Z5z?UFHeqoj;nCrLwBDRA8R z#9}qp)Pv?F6~f?GFDe;=J&7UZf-sKp7ytx_LBqpANwui|GeRbR=1Cd%sV8K_KR^7D zNCOB3zf!(S*?aQ-g|3Y zVT=JXFhBv;kTaZX8q;<^S;k0r`|=LpZG7?Uvw`QOWk-nuXuvX{6oVHJ4_+OTy_J(F z)iV+?P%$L&mLk(mA~f#*diqsy@F2uNl!E1V!;l84^R^jK<9V7e9C?3n91s?OgJLf( zRkzPRj3WQacHJ*Pvo*;1AHe?ouwWrt0fl;7z4Hh-VS9MeAVL6gte2j7zUOzp!Ou7e z5%b}P9}ajv30oi(frcu}c!(#e`eNbz5d;3`c3=Mb=f4a+U+fe6$2A~C5w9D4;m9po zVIgDaTG^|heyL>73_}`x<9o7|xN$un%Qbh234hqENl7X1$TO+eo!mF0wyVN{vZySF z7nSP{$!rOu+!cEQ59N((H}yGP```>EE7&f?HP0BpNYxW~49D)0`tf_Di4v_5sj5io znUXDsBLUxNtvlOeahB2Oh(v))RW4@{Dl)0Z#kIC8(0>z~n5WfS6XGqyfYM`^$cJ zPtKIqi75(l07KkofHJ_{<@PY7L8gy1xYvd!Oq7eg!3u@Ogc6mR;~i(bVoYFsaJ|Mn z$F>1<4IyZrY0iTgM+{g7jKB44Flms#DpAKb#yCqD*!%yzFkwnr^W)TB4G{)|`$#eN zjdR6020YSur*OY>?zv~|^9ccH$K{`Y|0jXhZ^xJwePt1CdBpn(r~_RAxM|&me%=D1MBm8z4`^^KAh&&#Ku^6j7{afj~k8eSZI&-^%VMmTEXs`p~sH z9+e=uAG1Sh6(lD}!}vsL9G|3M8Q=_wz`0?}=DcXWjK`NL*~zn+6uBX2bMo(B`%Z|s zu_1=$_%`Y|!1)KTvmL-W>YRpgdlbA|48pyG!h$iCb5yw|IBD{m&%Ug-CZ)S|+<#() zstd3+ibrfyBCcl4E~y_Iuc3{E^|Vaft9ArcNJuK`w*8C|gg#Er(CQ^rETMV{il5_D zNYL@3SV==dml!Lq%&C!Q=GMt`^9*5deSU-7bG`SpJl}gtuJxRhD?P{MV$V@I*L6^i zlYp$rkOp-nMzPTPI(_x5+U z_pdKv(j-G1pg5R3xgSBnvi@Van|c5K__ysR0Q}4Qe-AtF<}#?F%wn@lC~XiDAdbnc zl+R9>E1wxVOFlI!O8#~D6t8N62~AkMd{-#Zp(O@B4$@%HjJ1+DVYOsV+$@EYVx%Hs zm()NQOiGZ(iAmZTCM2rVjjZ>)@G!J6czFo%NQEN}AP`*Q;BP@1_&xo%+rCR;{H>y?~t|z)CKjbET}FiQ=*_GCtnJ) zawI<^Tk_JfwB@H~OHpR7l;jjhMSihV7njMtvMOn=tdsVd2I;JAlJ2?|>8Wd#o|;za zt!j~;k_PF{tCRg1RnnSJBF(V{QokunDp#jU?u;18n7mn1$FGyb5vyd^lO`6G+V*&c z);~m+-5F}QlcNAq0I!&9>;i0vQO2{OHQ2qHztcRzVEm^B$*6yMREGZ3gMSri@Ykpj zT*AOkyMzJL7GT@n1>qlc+6DDYTcW`2KgzoO>t)_uk39z4yQG0VZWJK1K0ihYo)z~+ zDzL>Pm@s&`WDHxUanHmFH%BJR{%IM~Jw03YN2Y7TNGHp;dj3bns4UVNx8Z8OLmI?A zw#YN6*Y+9I5Y-TR`Nz}*07m`!7HRSJ{)Oq zNtWI>MccCbrl^;bQnMUyV^V3Lfpn$ktey|+wFhkCRl%SJ2pCB|;Bm9pOj1x1Pxbd0 znb=JXvg1|3N`u4Y?V-Br7}JC$SkLpRrh|d|xj(zk^Ty0pFwTDB)yJ3v+*s)*gfR^- z6CfT?zvcO^z{-ms18DI;m8N?kq4EAs#X&NIhHf;?p1029b2Jh&hJrYsJk(6FUiu zd~|{46De33T;lP~Yp99W#_@oSdb30RR9b zFGDGCc6zBGFLu=hkONm|*C<&)d@>ERI#mfLb9NksT&)w z<2BpkS~E`Ue$0@$DN{EG9vg}y^1DE0Koqf`oL2~12oUbsrU^-AyB=T%yaVR>jb(U# zI7Y~9)=?FPGli^eLcKgUZ=YPB*C03MH_8k1o8+DskDQYmN6yOgN6yGI zhfm6-gU97u_hC8S-Yvb&tOO{6`%7P_vADJ|8$pxle^}(FcQ)JnM zS+Z*6Y}q_^k?b75Qc@b8RB8b zu)%P{6XF7QKQRBOq=EZC7o_{A-EA}N-~QinejsAN|D79>uzBMKiHq4L3GurmHD#}= z42lZ!q@t`uYO5lz}mXn$x1sT~=nv<{O zL2YrlG(aAd*GgMOy|kCrOGin)bQIM}TTZpKrjM@c~0G(r%l@jKJ2 zyAD|p`PpF-@tGkq{!>pVVKD5U9+E--c;A4efd#Q{Z-Kq-!x08|qC~LkaeH@rOk03$ zdl!T=&G-KAZa41-_byprr*F58fqwU|_jaU#|5%xy25InbV`SkMC#q);5Qn@P!wS*> z1D$N^t&u6xIW1FqrsqhPk_H*l9+9f?!?ojftLz!@Y>nIU6~W;NU%UCX8dZ2<0AqMO zszy^eAyGQ0Up^&E4)J1-%9Eo}`Pxp*E|SAD^QAi~OByC7O2yb6QZQ<(#!n{v}jOi0q!HEzd4XiQEzF9*W0o z8n6=<+%3A-#Gudr!UUQ7`EfGuOXCCgG29Q326&AjJuG?T%D0hl1NO3%NLi!Tf_=@J z9!whi=$rqpAw}wihAi^D{p3i1Bp@_^(4ppud$k#xBSEUi?otH;3E5B_Ku|zD5YAS# zYH#3SkVub2rIbZg@?%J}ZWHjwHAh`w;*itSV+hFz5I`AVau*l?Kz;(^k=0}9fq-Y` z)XB57xpi`FZoM|9`R?kRS`AmAtQus)si*b{9PUk23+%6YHm4WK8FDR5FP2l&i!@x}U}Toy5j8m!;uIKj?~+tB9BI&=Rci<+ zkA$*B6!+J~1Hq(0+ulk~?hipm&H4>GCZiew%mVfxht0EPJk~sO5OpX@EE&kSgXfrV z#kZabLmEUUYWZ5q)Eb3>QQ5G+@7#Pd@SZ4KvPb3c+|z_4FqSap)_Mta0mOuUPb5Pu?>CWUiZz$&V}yOCH9IS=O%t4r8-zzxhQlX%Iic#OpKmbL}CFP!rUR z+pX81{el!?AL(^JJ;xr)u{{6d|J?gKhb#>|CzO8VnM~JYpj)MkM4%HBw8{|GhW1ZR zH@Sf(X9?;S$S<~wG#|jtdEtEp*~#@|Oir7&C2)H`{Kof`P~|#96ybnG<;A_t*xx#F zuXIl0naq%$$(h=40&q=QCM2mMfOiq{!h8LuI66z&KN$ znZ$)u9XX_9016|c8el9q5oH>RBO1>b1Odqn$!|gk!a0vr>>DRgAJxh=M_Hg`!Gb1v zaY3`Zw4hn;dHMJSdGXkJxqkedTswMNE+0N2PxT&=6Z;*~ptMX%bMhoRIaQK&{@0QQ zmI%0;ejuX}4_kVt(z@2xu{c({7eqtcpyh|FyY}+dFyLL!&Qlez0r)e&O z(&7TCDle1T>MA7-$Z62p+#qeOEz;iBs-+h@+S_D*d%NuKXqV28j(&~rJKEZ$t+_>7 z8k?lCu3qY@s->!=OiJ?$r7$~Ja?&y+V{b|zVE~zs5}zm;Nhy+>njwW5IZ~QaAXWJ# zQd3YS^#$e9P*5R_xfRlwRVMpVillx|zSP8KNx{;1$(|o488fy@@{|p-d(0|{8@5!o z3|T1aAEP{$NmfNR{WEXfkYlerBL{ChEuB}-NZZrLrRm&Z*>|c(>W+6y^^yHjd8l2c ze0HdYAP|NCQ9%BJ37;M$V?Xt{jQp2JWY|AFD1-m;K6&haeNooM$H>Z;10jTLpQ-|QNCC*1kOreIX^^U+3BA)z2{OF?`zI4FkgUnaNUnzQp~meK%cXpI zFlq4hn_ux_u8p^dBuN;c01Ze3av6}doDylrrx(ic=>>9fcCj3tRUkdnv!!WLk|sSX z9KB64hp(5!AuFXVjMCt_lZG@PMjFx}L>wq-P#kEmJbUoGf?Dzy09KVS7`ongjYh>N z5Y~9fvBXNodmiqc9)NT_>z?rk8FR8axa1+awx|D#Ta84 z@_-vaF2EK85#yi6H03RWJX=UXUpgI38no{!4-pe=2O=8ajPx2qm3Iz?sWFO;fy!@q zDcL7CuMYPba_0AL1}hB;7RMXUmU=;>)k}r9idb2W$9kIB9>yu#$0!DLv0nfSLsl5W z7}DTp-wP%UQX)3${b|V;bBt8?FeSOTPpt%&UIDV_MMH7H^5!{Mp)tDkXRhlh^yKx3NkxTj6>wWX37wJmTTfBdcQ zOPoFjC|Dq*HfiiK*A&|VIeo{ZG}%8XUFE+R^27_P5{W7RD3SEMtkq`;uXbs4@EGyc z>#ysxXGt*BJL;|X>Zk)wOwuw#78q|~Nhl84Bsnzs3Xm5A0+1NvHB_Qtp79>yL8Ji? z_?~50{^IN^IX|;p!Nt+3`3g#~qj;7$7S12ahm%FYq`{T8Q>v-~=m4y^e=KQ0dBqdc z3XF$ydWoE!UZQFPavVS?;5Aj!z^m3^LEYuHlY!T$BfD0KMzYPj4KRMOJD4=+OsNi$ zjocHEO5|SvYy-Lt5KmLG1HwZ==fu4sN0gE%gr*Hyt!fCo!r@4Ryy(P`O0gel@TCZO z=cQoMpk!H+f@nZLWF_0R_aETfm7Js20IagFj1OEl#(}^MJhtPq z?IGrZK8Yht?i9#a)JaNgjNK*86B4CkQi|>ufSQDR^kzTt#-j)}6*Ksssv<}-J!DzX zrsR)G8Z4L05gVjn^fsv+ze^e-AWrv&2>64Mc-Ql^A;pK3=lQhfg)z(C&kzvd#sSDf z@>%gdWQ=1h;XT4Th3CU25~T8gDJ7b#U>@&3*MfW6sttH9AVzA}W(FSLSD$~)8+TA` znEXdPe_T&ULym)MZSsQ@=raT}A{Y>|6jIde%~I({crGX#t`oZq)=3Ov-H)Mfb_IB&{|L%fqciO+4|F{O4clZ6Tnf9;Szc0-D zi2!%s{lDEZ?-B;pp29#011~J0s7@;;jLs^P5vc_-EHPV#>`Ijt$bUt<*vm zlvPMsaj_KT=1E>gmSiNSO3I!@N!YnNENKuQvqO@0?v~W}M9JElDtW0HQk0e>r5Slr zkx?L(=><}iS|C+P`BJenOUkyVOYz2JNuRe(Ql@W~#K~)A=h&6<=I?$aul?rxa`XLf z%k>|BO`iGQ+w%0+Usb~3=*w57=eeh(@e>s?}7VSBw4wAE^oLs)NQ zpa1|M07*naR1zJI{@2G;SupZn9+u(%{E$5PPY=kT|7{3^hyLg1W$o_mp9pDSNe5S! z?Z7%=Sz-gZ6+s1NkLAMCqift?=cfBx_M>+%2YpSSz!_Wt7~-^A>H8>?X@ z#F*mUBYqfr(y;41Xx9%Is*2vP{ zzB@QP;rUaSjncp&4J>(3pAbwMTs!oX=Yd1!jRy`X{ucGxW3(VOW}h*ZXaHsa6b2OM z11UJ(eq;OrAQ#K2sxYKMMTdqY5S9=!roU*U>n9p|0u8G}`OQl7AYaCCXPd^LwsohC zToe%3#(qu!=ps=y33B^MR6SXJIHiFl4U9b4#A_RItJM;e1(x z5zjZ*AE_~Fw{WCE@v@|lG6gR_*8mS0+XS>@I4WS6lBwX%dehh@qypE%9wXi{yjDN^ z-j4#$XWHb=A#lQel8u{nurAIW#;?Z3Mr3HOAZo&1{XKMi!}_We0p9=o$3F#bZ}FER zv^s>JG(fo(^!dZ@{~)pR)=Av_^|EWhM%lAyizF}JE*Z;qO3~V6dGF?1^7WU$BHwuV ztMaW^-jQ#=@~(X6)%WC`E3Ya*;9f?J!ZqN&;oeN28th^G(YLgVhP#_F}oCP+^`4uZI_EZH51m^CO=V<@}Pi~Cln5N&&-DijcPi;U*1K@*g0PwJ* zxaUYF3HU^M9*#7)+HqRXuaX8Mw+Xpl0BQg$Kn~;E8A?E^$FoEU1QH^WjE(cjvYa=y z*Sr#s;Yfr1Idvg0j!MaGPj?6BLg-Gb3rWoxJ5VMWP?n@59M=_zH$(?L=fYfDo-gag z-=a392|ZdImNdxsNCS8O$mc=(>Pv3~-SYZQK>^2oYsUcIJ;>jA<{?`+uT;E1bz%T= zrjm$u?7>S70mXff;w2n;2x(wLF#UZv(qQjMlg!Yn3@XRO>Db5p!@0B`al%so*39!g zzq6k#uWAF&Mvot|BJiC2@ppfaJrMjOHb~K!?NU8qw=_j0ORJufOjYb5!9PB&P>xSS z$x@)_h_M-Rl@JEJ_MA_n09zs1QQHHz2YF~z1}pV_$TMxoup}Laxj#&JkjW=Pm=MWC zxp%l{cy_tBxW~BHAb{%D1d|5uTz_5P5nz?j`5f(>&ncODJUlljjChu)j)KBS%c;() z&@n*?0*@pxsw0!j1Ts-oM&vB;k{sTc-yko{ZlaHC4b^JDUaAGb(0gNB{Eq$BGc5UKM-k*C=477Mr5OSUXWQL zE5d-nJB1we<0cJU)dAD)_C9XH0OG(;3=A}H$%1ujR?F7S8^u;jNFyvEGeZjVa;2=e zP%6txq^7b$>Z&UR;-J2!O8dH+YN@HJlA5YYsjdvuDk`L^yj&_uOQo!+Sc>xtBtJVx zvQyI~Eiqa4?%pHuu{&hP*6m?Q1G~SrPmfQMtb`QFO-z%5qzoxa$dIC4=~5JzCIy@K zO77Y{lC@%|BurZ;yCz0U%$TLJW!OS_vHZZFUs*( zo{`??FG$CwlhSzRpwt}gl=7aI5LsYJgUtFeNv|!DC;#yQB?ur1hWz9GGWZ|wmqGvg z%kudD`l3Ag5BJK})IG8xafhtgwM|xR+hCLiYnIECOJ)z~1-GEz_AcPJ-`z?7UrieL z!Mq>*+j;+T{&~Bc?ft*|=UuYEPTxWrd~SsN(?5*u*EHY2;FXd+e1pnQYmik=G%5hH zlH;j35Sb;NQ!=Ct!($wV&Q6toS~9YHd2k}cZ@gki1Aw?C4e)BUOrR8*XXr!~$jRwN zY6zU1Q7p%26w2YKJn5R6DIHTYq+xQBR7}_@`D3;!Y0wsqG&p@F6rNz!1}h$zs%03% zg(p0B_-XYN-3$2Ar3Vf=UP+E6R$S zVUz|PyUX?6VYWqR$qw}(Vf1nyj8vSsQ4Hc712U9gGUvrryWz2dxF%#J=u@^LSwrb8 zAu^DsiR}Os01Xx_sAo%)*Y(ArbI(ztEF5W&F=b0AewJ%aIEMjIhM=$@isQscW}f>1 zgBT*ldNi%45H&@3(x5M4oylillm_$e4OSZb;dj56vH$wGkSk`=rw3~&*v!w35~|f~ z7(6fNRLTcG|CNF}S1KPL_ z*$R*$6#&~@cLm$3a$GKz(ZN~M-+kfDklF*V0B}Z)1S!Y;%z4Kvk5>_p5F!h_q-8er zz$yuz_s9W~n9-0MyG_6M$b)Nh>omUsKm#u&iU799{eDt*DCF=d8S_5hWB-Gr;Jf{$1ga>f0dDeKo$&(QD>CCM+ zp;w+t$pz(4cLggHdeZmlePBsI3vxML$RE7MoNK}<=y|Ro4lJ?3K5~4aIQ7Su%3D{1 z!xIWt8>NA}e|Gw-F9wqal`GTwkuYo*l@H??IU?9Mh!`^8(*uwdtcLPYI4TjZ?0C3w zVEfqR{fHO4kMtxP4f-UHUh7?V2=Q%t4MRj%WR8Mpz%;om1_IUgd_q|Ayd~U*G_XVp zAwc92*+<@th%_zVd6f5P6rT4|Z2)V|4dWzZHTM`}8(}6q*K99$dT>J2AAkD?{Rk$; zI-YIbg@g!j?egfhol1H4#v4i+aPOOOU|VP$K-t7~ zM+w9>AovJ1upvo2zn5pBB&ZTidg|ped1g+HRzl!8S49B?qE!_vXp$Eo3Km+TphaF; z*lOCMR(W+%o4mHDUG90~>1*=pg{yM&{3W@5_9=Px#94Xz@G&{n-6Mxu+dZX0c+vn6 z8x9P+;MbA`wudzEHw%L4{p-COvVdjXb=}Fd3$*>y{{OqjbtlvQW4YbDyH5YM{qrFb zpsq8dIB@rWpx-C=BMjPQQgxe5BI#j;2}#hzhbRoZJO)Y_*sz4Sz4FAC-SX(V?efsd z4N4lIGN47xT60&VflCrF?S?S;NrQDG=Sj?{rIIjqwPa4%EX9*zr8**B8mH`)_9=!i zAaR&xACJW2lc_Os#1vVhMp?cg(fUAcd3atw5O2Nnws!%4xbOrjDY(mqoBkw7gMo;F zfxfe#+xD9_u9w*DTV>DgoszOQQL;1BLtzOOWyMleQ6@E26`@vLS+3tzl$A+YNr{ve z7fVS|krWpeN>M?Yx{)l zJ7sTdyrjh?NJd)*0u!6+!!zE(K{q{Xzw?$n_3q1Z^7ZHB;Eju_Fn};1456f}N%C51ZXpd4OL8QkB-^y&Y}r$krEPaX zhV0Bslh~|e*_NIloA&O~(1hq6TV&bR^|EL~w9NC71{M(0`vLBq5Cj7)^Vg6D;nW5e zh||0K&9ooDyYv2K?Yz6pK+|?P+Yhvi|2sb+a3}M49Z9T2(lN54*N)#UO_Va5oGuWN zgb&ati`cF*TANkeGj0d1l8P|l3EzC>9plLz60P0_Kp><65@!q#q?CjuoSIQAr)QMN zshK5mVrG#XnVv7*Q?q1$RHigc*{fAz3dU}e=oCq%;>~0QOKgsMpzxFSbb$zxGma$wj~d>J=o~s9CrM5LF6l zCTGf#$XxXXV}P?wj7YrD*0aSsuXH52d~9`(W%ASS1}hD+BDaM=lwNZ$fgPj>*VmTi z;@D8ca9;UdL8W>M?fG1%>*09{OB#IH+% zrI8m?L){BIKw3<@?veuw8s)}b2ngjP^6;Sea6tTHDYY0#C| z5Gbb)M;aW=Y)~bYA%jqT?NS1a=jU)_j>!`dWn;mM73cyEk=8>#qBbE;-KZ~2*lSqQ zU`^719(=~Uue|Vj;JsTNovz9Ac#d7L%J`-v4EZ5u031!MI`;?9D7G-qCaQ!!uxb)Z zh9eDP#u?H;6P1!DLe&t4(EZiVe-XH!X=6+x+@Srm02i+~K-UG;jLE8I(cEJu?>GyvW5&=^=fh35PV|QpsQ0L@y9j7dS2TXG>(?hgDsPG;@Z4kPCUOD#s>2ZPE zgFI9ceF$Yljp8drU7xp4tg-+_0gdnjR0WU)uP$tp zR~MW1+TwPx?VdL-KPRtUd`4cra9M7geOjJ5c}AW-0%_2zq=708%F3lQmz)ME{SqLe zG;o2fo%Vxa`#rrS3vBNv48kc7{Oi3F0>KZiZ#VA(ZFj$!cDK)Z{J-CB-u?eT)9yC> z>$=^3`$+-!IGFbTehXnxWeJ1kP-#VS7>v!Y(!__OGKx(egM>^OvLiVZmhf=&W_e)g z8YK%{uzxqxcS9O%8o5Arj9MmBdYPlC(ZnlGemX(#q|U zuz0h?&)Xn7XReWrqZZ2AVRL2GpqaAlk!kYEuf8WQ{_LBoGPwAS*W}FGFUXObSETEi zv(kM2h$;*q404;RRZ(CS2DXpONs+khhDC zK%g67{NIH%uq7Ma{&xHC2k!&TTkvoDftGQrJj@&vBMH)xzdHev0 zK_9>Zo+eGY<$3NPDcFAuQP$6PFoxB8=Xq-ZXDIB95$=MT)<0&-P z+-#5Q%eBT!Y_i@%ROIV*XMgY{v%GpOT=fM43P$Nzc5bL4hlmWy#H%GmxLcd7!ay~vWO&_sZ%xu?js}% z%iB0+yzLF+_b3>HC?fe7*ISeN%`j4X<25%PO>z(@d1K?J2S*FnHR$v8m);H$VJ2?c zNRk16fF0!4j13p?CeAh`(XMIOfh7u>G|M@e&Mi4WTyjv;W#%_2aX_d7NfC*42GDbz zx$ZpkJXerb047MR69vIagJ(MpX~39>9Gm0k{s(L$*;bW=CSfbr&wO!~8RvH}6YSK^(KtG_G=LLeyT-SUhX8_{oJYqvb zHVC7L%u(Q`=OiR?U#t0W-nw!#=+a8z+GH;b%aj^*rT<^K5lkA?uFmYYpO650KWI|P z0#hl&lcsasxIY*dAWBgqgsz?D-XXWfim>Ei?D!QX8Lby0Ms5g8=Kktu!K6X@xQ(hp z0Th!{29OM4%J~931EMvyerCD$E~sWX1FGXRSs-c_p4Ffa;|fV-jdb7S&Cs!Na)yFw z5_v)t5V~XK`u4mqCWp?8cl`+c$e+F=XmdJl+U=2x2qLiG_BZoVS)rvg2zXK5lcS9Q70)*>2Zz;#=iO zcYkM^_4~iG^X~tGrdihhX8&jV+wHsmT)4+^3u)k27(f_QdSw;M8fARRJ}s>{HV?wU z3rRp>0Aa8*MV{EcM;_Z4Cl9aLA`dQK7g8DA4N>4OdpD%P))9+j_sA8JK6bqnPS~a% zw}yyBX`hm+o?NtAPuJF$bsqE(h`{>)suEh(YWoBIxIYCaO3PVrdonmc9HUnD<7Pu zt$t5Ypn>$lvCC#Zz0d>RPtf&+-S4=FW0myiD@I0e9;Jjc=5yz~t+#Z<{jx;z{ z(-ra*`iX<%b-|>;snRavDO8Ya;*nJj8}b16C5Qr)=zdPkQ&7M=!7sT69Ns+jOyGIx zN~{hU@7Cjo$B}o8di;=GYa%Kq!Q0e)Z+ou9d$XjG75<6k5{@*eU6ZLv=PXG<=5`~8 z&GJ0X#>0p)OzY=ij392;c!!lJ_qK<}Ea;OrJvNjZ!X6(Ub<_kLA7B`dCem_x=J_7N zi+jWM6jD|UV2(#H=tCusMPKZ%Hkd~;#4m&)4gT;)B@9S7JNYw1h0>`g4XC=X`iWUV zo01RS|FxcP5}vVNgeQ`qlVpv1BZBL*I_f$=Z`oB?5wh6W53sMpjc8#7*W&(rIa z5LAz}dNfx{ZFF$f^sm44m5{o`geFjVz~lqKv&el6AOYCpIRxn24CmHkh{V{+jEPAO z*L2wh%}Ow!HXsKA$a%Qs7&#u; zM?ffGlvAw@P_)jH1`wnDTR767Zgpm8KM9FKy#nY(&yzBr|f2EKPT?hY94@HKsMkv9C;W!VP%LUuw;SlfBDn*1Fu5{q=A=rfqR8y zpm_edhafQ+qwF=O=UHL@3Hz}37`aif(KP{P7^MLUCP)SHG*DTDY9-{>F>024eI~hP zc-}9~s?<`VC;$NQY|mUjlRLxaQ7DKCRvP^5yFXHeQeVi;ZdDsWPIKQf?sK15uugAt zgFuwAU%Z=0#H+bFo?IvO(ZNcC_g;9@shC0H#Z6j`h3CR5>3CK+7T(2#G@7y5%WW{r zJYR0Y!)N9~9C&3E$zR}AMX-4bURl%@3PXT2fGl`p@&118p0}U9A#YrHPF}uvMQ)sj zG&n04Lg5L9G|-ZZIk|n+6Si%WP3zXl>J=+)0m&Bhy1fOy^e*_dYJ-7#cR4%lu9Im$ zP-fn*KCu72)7}N!?tc5X&Aj`&JvRS$c7CA$`@gfx+I8LOKC_&AF5F|V)9&x8G9Z6} zS5mPbVNhJJgu$4+$^i+3K@bL;c4!_02!s0;t&)FuV6gm;FFzgvXD%UdC(|xz;9oxC z{t+_s;qkKQu}E1nc(!aGx>yoMtdz{r8>MJmjMPjd`N>}Cj5KjfN60)r71F?Xz!y;HnbBZO9fqg%L5EmOG+G1iPE+$4|w{Mr2ZQEq~)~&L2 z(`MPUVS{W~vsTuwioRt%LE#C0(qKdMYS|RMR<^8KFI!iwlPwEZ%a*yTWb>?*q5Bfj z;GGZOm#_T!XY%Inf2^SiFTMY5dH#p*$>ndop}7o5e%Sr&SxtOcb-3deQos+YU82C9 zCgCCZ3m^+t#cfuF0bvPLO>lwjostG94+aW9aKCdy5$v@4`~ROw1IPnEabO7rw|CF& zostAB=PEml(L-sYUD80-XD>^!mO}J0F{3t6Z#7;-$}VEu4kxR4v{Wn$&W!%;*WWV| zM{8JlG4Td~;Hd_bmCCtUWpZv-xtyO>CTC`r%840;a&TI%bWBN?hDnK1Ic|p(jNT&I zqc=+Do~l42?uB#D%JTaoW!e2xycQ`dADSks9*UCs_+ZlD#S>RTzy*WK#_l7r48>Gq z1bP4&FRKNR#><_oC8qSec+&VY6~W;Dcx|`mCG4x9pyeUIJVj1~Aq`HKcN>tap$Tq` z>A;{G5QKq;dZ1V;wXIu zxOBINr-}QFN*#EVf(keBm45(Z~>C~D3HcE+x=*MRSZAw1)#jiC9DG4Z16cLty(s1*` zb0ulgy1@TYqB7)R3{?W?OX>#*!J}xw5I_ZR)c-mpsOPm{gsI+C8y%bg?Hf108VV6n zkEWMI5Rd~ghqs$;k;sg=WC#QG7A`Qc$QA%-@-h;b-KHs_u%JcP!MaF_hG+8WStc1` z2zX9N(wJ((R>G*27)EuldfHYY7<*7d6fcdF%VSljF;AnP>Cc(3zI4;O_uPghB_n7AlV20ubyAnkN zY9%E{y#%Lkh9M1#*QbVZFW71Xw*SiY*8?#Gw zoX^mHYPg3{0fllz3|c8a`F614Xvf4=fuzANe)99c{mdG_x!-<59_xMUkzIB_?R96K zF@@uBLA(XksH}oMRAnK|h@2N37uP}6ER4mPGlP5|6&h-TOrMY&o*M{Hd;M(g44yOA zQy7Lc`1$vKZ1Odbz}O2Jg51)vKdL~^%`BCRvn$1f1eooyeY-t~Rrh{jdv#&Pf%jf~ zQ^zRAP!xZJ&_IsxzT(+nUA$8?Y|P7R!#ja-2lAM4f^mqj1xi?u7DY^IwkOr1WaMcJdhz4-?1HxV`|0hKnxB%ZyyZh&# zW*I+8;Gehaq4)paKR?j1+wUwxTxMIEBzj&2=Y2H%#pZ7g3|Kp2~hQOI0`2RKYQ|=ofvmcruOCODt zb%W+e%#({Had@<3joKu|<6@;|LcFv<8cazyna87$%ogaN!N34%z(cJur8c%u2ME~K z6KC~+xXty9@Fl!;Yb4iZ|-`cmoAqzOIOOe zB`an9qLs3C_EK3pW3jB6x=8O!2!jx5@TZ?@)r41n{qJ6A!aG7}!s)lJ%b^!9X)c5M zlRc_3aESn>{iK1N_b*3T#TDB(YSKf3%+AdJ4TpFx2`1TuL({aaoV=w@$p^A#(1WAqbMGs+6Ay3UJ_eg^x zITV#A`y(^7tW@Rrol-D*t7MPfES>Seq``~l4Qa6afk?3p!azxbgm9$6RnLoK6S0{( z>n8hoPRQe|0Mdy`X3S;0#p|p_zfAx)WR0Ay2o6u^BMp!j8{)wB{1)_qh#=G~kMdUv zauYOG6(vXzsD|9YLkH=jiU`N^L%jLT6Jbb$q*~)i^W?X9^7}l_o@^Ws>dcA|5DIzH z2G|~<74O{$F16OMF30oSZB{QY9&Yt8dY(HAR;?Ts0}+D}phxb8e#hr|7|8-2^eLRN z(;-ESEIxF6p31-)q4WR~KR9+n08#T%8ZGF9BJ_9KmA$Bg2>MfQMV9UdEwSrPYSkmAp9*8%IHYs&ylKL5`y@Ghh zqlvc{(kSHVjmVJZ@lG{>C)b4q3*UVCs|K7n>KO$?le08m0)!1o&Yqo9t8vL>JJ)#R z1zzH^MQwt|@J^d%MPJye$^<-*C>QWZ0_*@C5EUq`n(g4(3-m!oVFvqs|j^C8U*b%j$J^b|G;6>uO9{Ov+VFxhY{rzHe( z8H#oO0k4SGz3aR8zQFpaVS zk2T~h?<0s?doHicsaDVmcm>3U_H$B-=EX2c|4d@ZaOB~RNnuEXABQ0gCK`o+63t_* zLdFXhm|hgR?(84?+(#O4kNL(cuYy9*Nr5!b8x;>n#+FfCYV0C`9o?@&*0TX&G3~7-okF|k?dNXD>sOzX zn-{Oh^>Y{G%8Ao*{@_tLw!d2rG_^=eRgF{^7E4iPwqzzHOX7~561R1$Y+Q@dVC5~| zc0UkiJ_rn3Vjx_9H>81|Fks#fwr@9Yfi}In-~Qurf3wr!)@_#=sJH8Oe+##+ek8yE zWQltWOox_t!V>zD9+JbLQN}xj!Kh4+Fi6Ugq460qn52i>;`>4p9KztQAq4L9zjGcK zukq*WpO_5)r7I&B86btUfi^JyMJ^R7~51eq|&Ye3m-+Z>i z16`tJDT4#v(v!QI8K3}TrJS4>17JBrxO_K|CeOW(^lq4cT<&U0a^SU3E zeeIhB*_h&{b2|$4Bd=UxY%-vmdcOUdix=u}?x;Y(&pOQ zde_H**Tx|n*=)igO z@d(Fwp+R}bqMcV$*^69kNQwfL$d<1>2Za7`EDz*-ZT=!YOrq1k-pH&IXcZn-Og@{- zOQ*tN6DJ0k&E=bk@qo=$);|Z9(e?!}gjZ0-%<8t3@Z9?|=fpGA3wnosW$~L!9I#xg zAnqSu#*C{o^;tTxgJ-xb`_j(>)R=ciA)DJ$Mhr)_oV@Xk;s4ojBatXJ-Jd|_SaQSu&TnO`!s2-?r3$+1LX$WsaVQ$z<@ERd z!!AbZpC99ON)NGJv@dfxpuheMxrNS$#O-zll(e}UcO*qe#-Cb{6ApBF9u@U?ms!bW zl!WrIp(f!pcmCJ*I@2nti7zXwadTa&$v(q7nXT4ClbifvZ3j1j@U_j~t~IQR;3ARd zKe+pycY#KpV&2c{=L|Ee`6U(OpJ!QII7UZ1Xg|`5sH0*o^@cJ-moXlF?hm>>9!%dI zS&on^Q*20~Z+}TT@wHZqn>EY)SoGB6oq27koU^X_C{0G70b~MhyuE5R9!IKQffxAW zj42TB&Kb)ICdw9`;q78^kYj##OFVUznLLap0HnNLZGYvgQR{(*;U9oxvMM;F{4jlz ziv_r0Y^MXjL3ZRmLKk2JnznnXn|eLgi+}&uVJzzRe(E1p3O(ghk*!$)=%bE`wO{;h z;+{CI%J!!nhR@?fE3NKT@|#TJy~w@pe~|mPMiBg5(I9~?l=`)2|NORl);HEQ+D~pZ zVF&f)3172yZvT>SP?*{AMW=1~h74xZ|w(5AN7kM_&pb zFkv5lm%sJ((+7dA=XRl{3Cp{N0}v?hN~?XhWpRVh#vBIsW}ZBbw|oz$g``*M5p#~C zj668^l!s!(%Y62uaI5X|fnxUlD8j2Yt52hFcO)=7jS3_+^ZMuf8Jgn>qiQIILvLAX zs66&>C;$HP$;byjNgO!e`f49LGfa`j5~*bJ7?TY%s~lM2w_pm>FyZe6WW(xz>Vs#M z49^YlgJ~s9*^|{^I{v2T^+`F1#xzm*kEGnffG^txQuwO=rokSYucSzUGM3Vw>KCg} zkcMhP`DJ^d(~aP$c9D$mEL6nc5<2h4`51pBTM>mVN0!M~D3hW}*COh+sNN?-`aj8N7LmO>KmJ z7QGbls6rs4ZY?;hx_(jbmQ|}Sk?@tq#j~X`Ixd1OZazIXNQhf+DMN;C+g@6PBvpP% z%))63!r@If2YuA^BTr!TzOv!#GomMKbA-Klo%S^*n`W?2tRh5QYp}NyKZGab?Ku{17Rv39JC6)PMbrVf zN=oUDgw$?tmBO6fe|pp-#bNv4)qAMj$_13e;I8ML!BY?BiU5~B;N=zD?|6`p+^O#t z(GL21_m`}^!Hl9Oe*l8>p7D3_Uf;S2-=#bU>;F}Kef3ljF*Hi&rSowINQ7$&NRfA~&s>%N+;Soy_n0r}>8Tx6jX}5lr$e-}q;<&n`$=-s-TQyFw=Q%w zoEOGs=WXVAN?umkA9tmzW%5Y_7B<-{0(`t8{y6x-jkbD~@sd1Ka|pu9Fao(7-B)N#fDY#j=AULop)BS2vk#XVcTwJR+a-(Hn0ZY=cjF!$9FFLfl;>9;Rc0 zMeKPN5eO~*C$I**x1~l}aho2AVF{UfF==*avg^c)Y&FHur=N~Unj%jRiH^tzf-8h| zqVi-U^#KDvm{9tkq#g~RexKDr=hFUe@M2USUN4?8H%NC)YSGA9A%~2sHz85$F(C8j zd8?lV&0z`pe7Z7LF3(96!OAisaxi`;F?r7MWrW~^d;INM3J8{K>c>HArzd4()LZ$^ z=5L%f_^;f}$lcp+)2>FjE`rgKzp=TVv3)oEFS%jKc7h;NUM2Dqjo^|2nEb$l{)Z62hu zl1S73$gC&J*7wwQn8IiSg%u!UE0eXdLCOWw^=-!3{uG8~^!J1^1fxP2KIr21(Rej5Npv{= zR(+UVV{|#6c({5fYmg$Eg+^$uGxtkfhetoHnZw%FQMG5Gy~+k}hjtN^jminx#tV8% zzNZd0nQ?`Cjy%Q6st6F&)sd)}b6DfiM|Z_j=Z8{~QR+GsGcbctr04EpCV(rqWsYdM zT^?@k6$knIhRMHfd>iQ9&G4XI;($auBR!|Vm1_ftBkx!JyJOq(Bpz^OO)@|ka*STa z!Tx(Uyv-n;I%>9uk@$JekFHN5=AmJKBq-h0YU@U%9{lIjuMl2@KM8b^K+|;_Mm=sz z?PKQfctxrukavA-0~;388}l|~C@DK8x}fHg??qnon}zb@=kN047mt<SV3M`>^Qv3+!9huWzj<4Re3_xJ1lLUJh{NP@y>2 zhX}~mFdO=7`#vi;D~UrQzIcFiDD|^ajzhwvg|bnuyazmVGa()ZB%y%ZZALvM~w@y zQ#gjgMeu}3pwW3A?$P-)6UARqGF6eNh$ENs2*yVuQUNSOrg&m_n;Rt{efBS7LH)4% z!8|dw?WOK`N}B%G_+t&8K)~A7Z(oD`7aC$jyxb_!AX~Ju%BvTxpxQ343vSA8ver%r z>ys>RBh%%gX|jWDW!r)C5D#pdrBV<^DML*laP@G!&~bO-+yuLN8cTnMY~8fk!JmU4 z4$lQ)XWk)}#IT$U=j5v;SX}`T&x6(G;)g%BcvrqbI}B3Q-*4@K;A*cl_WsD~IEfoO zKEf|B7Q`j}L|5>pG9yX>>EB*_3xiF_gvTk|WekMN6!wPsKSb^G1aPF?KJZdm@MsXh zOmAIrSabFB-zDmiN0cvL8?1VdpGwA$p9-vom(62~69783_u+LDEO=UttybD5B-lGG zX5Q0kiZ-g@|2#q34QUMFaB_X9vTTSop}&6aJ!_OC>*&vOv0!O&fK4Huw_e!S6VhE} zdh3iGq4se*ZLoLZMoHFJ{QWkD*T;ecKwM=iSuFBKOPH!5<6{?#eM=m`zV{6Rn$fC* zS3S&1GcC=t2o5(%v&R$UqsqzFwv!cXtxo)>I@xOSUqSc=b-=PvHWm|bOz6v+?APTN z-~XE4W;%GKkYegS!RHWBAi|kAVVYY%!w<;HUYo+N{Us;fq35U5JqL^n=LcR zQ(`Wynh38Cx1AFtj>?GB*HSH0^dI0ZVa8lK{(EzrX882?umbrDNY1fq*@JaQ9d3To z9qkTHA@Kn40Rar>QjPc&*bsOEO#nm>H?ap*lpG3eXChcfy{Loe3*lyN-F!?1XRgYV0hfzkH{s5aYdB+6h9avU9Yn~uk*;zNn z>P$Vp(4^h^V9~zbdPmWKxbrdPDoRJEmgeUM^3c0YG#Ymmi2u_8%AjBuOt4!|@&D6( zx<2)^bf+CNxL*AB_P3*bE$f}X)htaR-vt|ElHf>dzGzLQWqN9V4;v<|F2*-noT5{O zO21k6uTiUP7wAjGniyiAd5RAg-SH00-MjT8eLV`ZUONDc&T~h{iI|Zwt5Jt1xy4Q- zqzx0JHyPOv=_Day5)F9t7GGH&$0+NS;mBgS^mW8Dl`3ja2Cs<)J3;#Y$N?7oU-V zZUP7v(yMxU1+W%reU6FgPO&$+`-8z~VS(0Mh)=FMwgVKU)i?(^vLNP1wQ zOgBTg)LV-99pwAotdLnMY+9D*0h23hz8o#dVB+y@*?Sr)8pAQIhugs4VCH@|9(A`r z>8?5bPL1=o5zdD9c_7Al=N;Tu=N%OdoY%R^Z}0O?W(DmedDXMR=AB;$Z`(O;7#sxJ zsl^Iz(?jjJr0H(sRv&fu%f!3IJzZK)#2^5vMz?-!dy`8!@}<;Vc*5@nM*;-wgqFn% z=(R+`X;?%fZ@zjn(!P$N*^sCCVOMWaEm)AnH|B9;&z>}GBv+cWVm$gx(z-cE|4*rp zN~M;2s}4cu2iK`5A|V?rE~UylH0v_CXqtNbo~a-Z_6MmYy>psMA^Fu=Xv5D~CQ8gP zs`f!~w-uz!7@XVj_YuF1MP+xv)g`;A&dIjPwIJwCFj2)fG%^CP5t*^*H?rT?;)Oh$ zh`+Dbaa(4Lf@u*`0I8CafeDP-rGn~d^#DOJm0-q%Zn!eUktynPZQY?VhC0`Qc+N*s zbCd)kigvL^PJlbmF>NS5y`olfdC``HY{a$1+VO4Trz)1O)`f(2L~&4sj?2Ses~kYR zkgfan@{v^cS?T8%JJ-SRwDyU3I-3E547myl=Y250SZuUNh8(g{wB6AX;9#WglqTWx z;hl!99Hee{UqzXAG48D96{`V>C*y zFJ?&Cl?U~y4(@Sf!n~g)pL6aS*W%Sw*|OE&e!RTY_*bM;bDH)IkXom z3ti%MkHBsV+1VH4-2P0*=y@_N)-eIw`5Ntl;f{hO#uV2@H377^t>0Kz<3y$Wh{ZVS zgN@H)@BQ+64@%A>33Kly=vqB3?4{vUx&ipD8tQSyjB8j%5HSl|=6>%b&CH=e zxnU=-X+MgUIt=ec$G#N8idru)LBV?Gp~F|14$NP4teADUxI=LkI6Pbjo)!uAJEe)C|`L%AvBCZih-bA zD@;K+$FlFk%4@Y|SGo z9$?*%NJm9=h+Ks&diw$Y@JYIAts>d0%HDdz5doN%bCq#?a^L3NySaezI+gvwJjH@J z{JYb|7UAhHKQi)Zs(~xW>hErQfy3$Cuep>8RZZN1h_~S9Z>wL`5FOrn{*X%5x;%0t z1MltTB%&&F$LkF9{EfiohvIHjE*r=Cp@8V*o&XyGP%d7t$P}o6DV)GGZP0L?uulnH zOh6}G#IPqG$#Wnhi+6OVVVCBe;A&BktXX)oCZwc=s?#aB^jonK_U)rUOIb7;W2);= zr&#TH1#ngP{h4W4a&@xhZLmWp{Q%jueC5d5%;|uMhzk*{Crduu>=ZHd@WFxZ=0FIX z{rzYsk;MQuA)n|mY8KE0GGzH7s)jBiMn&Pd|5BeQ*o4TEzUBJE-Tjy?+On>~1a=Z7 z>Mt2lKG(}NRCQK>&RrchLsOHCV~!&=%Kcc`Vwy))xz0T++WkfqUJ`;O7Df70gXtfO z6tw|)y(webm*P5)Wi%M)E7hudbtpQarATNcR^{=<#98xpc?9o8KuEx$4;hMuRbY4)w4nnh3%2TikVA$))>i`I~V0h{%MV+@ZL$tUmXQ4B2EG>owBF`!tt^ z=|REH{(z$1l^;E(Mwm(HUCyUs1(79tIu*sPRuYMas7@@%QXphdbug?|$M>*$kXV=ShF6eW* z8n`ZbwoE(&S%0Nm-k%G)&2}SkW|4_i=Q6xeBb~*bXhQrVaDAd)^An*Oyhj&C&fJ*S zE3Z0UxRy7o0%l|%z6yUVbeXuCmqQ%e=d1?yd6w5c*H7U3nvZ220CHvGZG$%Mf{+~O zQGqvGU(CMBLD<5QMhSt3V((1dzJ$nyq!ssj`)z5ZeF#4pd|R9D5{*6Z^w~5frS+F# zdA%P#+M<0+_3^JYQDyH8kN1BeAVK)J$lFX9Q_Nrd?sFCq&tR3QKCNp;U_k5VQ7|tY zu*opcL7zbLhplpMS64(lJIA|D zbNek6@1N$vt6}uJ^vnYj|D?x!{CBx92WJ_7mkO##Cwj6i^X?teC`Gq^7M+wrvAh@vvjXZ*&m`}{L#+m|IRwQsMCTS(69WxgbvEy%`S z>pUOe*q;7q%^1HV%!*SoXuSz#<)0DlVgQzCHdA3YhPA;)iEc()m2OZndP8PP6?$>h z0(#4%$Oa(@%3qeFbhVtnjW8%1hb2Z)M zxeWpriXWH}->Fm1PV4RevjF@YVSKc%EMbQ-Psuap+QAztX?6&vEV>r@=f?D+I`J*(R}GpAex(C(Oc57K#)$wtR=W#QIf zJI}XlOsIM{SDN2nOMZ`a$k^_9cQj(B7Ha{PK7repsrj397d)(U49=d`cG@5>L7B12 zq15GSX8pVP)4i?L;`&?xCI+Ii4cW&K}lrpiO>UTzP=ly;M z7OwD|VBcK}qmgxx{2-oz&I?RF4}CBiXlROJ9K15~Kv|kD`jSyYNt<1O^9r31qC1ZQFvm$_Lw5AYocOM^z3;0O|a(%ik~S^ z2_#>?YnV|_O};<>S;GLHG0zCr7=L$}S&>=VxL}d`1q16|d4J32fP30HTl9MddP@Kx z{twnnwz2=kmq5UhEDSagh=WqL-a%_iKj?Ir&YLVUa&cFL0dDa#tlb^vXy-|WF~Z#K z5|hg8Tvyk~>Xs@@?zhavM7E~2%{{wBs$5!6^TnHr30?#}!41m9_C0Y$y(!hniDNBx zHaHd3lbd2)3fGb?f*PoMNmyok*2H0FjJ6OrhlSmEF_2s_{L1!D2%Y-w5_I_2% zhwA|!sTN4;x#d&U1v5C_5Abbd&brxm3xW=(E0y{SDP?_!P_O=YLEHmG#6X#^j7(p4D$u=HBbiw`Qd?>J^geo@)95?nZmCEKXZI9 zllOgfg&Fd|+O0?~lL@~a(rKmXtodY6d_PvYmJ!vb^R_%l-QnY0dT^OcJh7V+#AH77 z<|_1llNy7UMO>K;z>0Xt^fA>)E~p_+LCo@+eM9-QD3XFf`1z3z+6c^6dRSHlLlY!S zbhoAY}w4OLy8dU*A3JK1OvYJ|1YLeiG^IFVC~%hm00e!!Dy~A zjcO|RL~?SLgMfsJQa?8vmk~#^_#qY@+u!ExJ3KH6y^Dxq=F!ZvTC}P|h%s7=`YyG( z3V^g$yos>)rkVrzI*xGrkANLgEUCYsGKcprb+K2t8zG86s^}x0RY_QH{0Bw*?yvxtk$*HwQAMKrNk|HLw)?tWKo16EL?3CUV!KJIfoV*ckgTAOO_dLpC( zCvD*|*e3c^vUX3h=cj3BwR5D) zZSI@^4V+lXwg}(v+~%u$JNn+1*ot>{vUj0qpqRV7%63xEAIY1fASd8WAjN!SbxMBa zvzcx}^5q*gu+I#E2gY7!4<4g5G=8Xb9M)>_njYyh5d>vrbM~RpriN{!B8$=JAgqwC z989)dPA)^)IJuSg5?#V5V_$L3VtVFQa{{__*g_t7m6UH@@dpk)k`Gbek211AQ6DsF zi0rPxeV^|{E8VL4f?dn>d5h1fGrNMe z^NlCS$bA6S@(`)c${DG-<*T>Rro=Djv5}O@HC!sYqs365_oLt;r%>S(MTs1bBUi*Q zR$*hP+d2VbsxIp3w+4LmnRon#?&1#`_rAjId$ph2>}sfpBXMX2rc=er#NLjqX5y#@#*^QqTvWqC)Tw3mWTzBOHHf}0Yxr^Ft7rGy-3(exqYKIh3M zxyO-bdgn&Uui%J1xPl1$vQ6Z1k{8%uY2v|rx#|Dh4glRxzY*vn=RMj0Z~k&kw+SKv z598v8RW_hmJ=Zo_J#m&qg>F&z|0>K-)ezChtd8Bw z^69Wk+;5lYa>rKu@Uxb$0`cVfskX`k$$KnyN9&f1!f`oZZqmrP*;kC~+uy#yzw52y zwb-dBcU!X;rkT_mkVJ@>vyYQl45od5US5^3a0elZVzc@A43m#|D||c3;-^$P9j{_E zluT|P+e7%iNPafZnu&B(sqL}sm?i?kf+&>@7`FNh;i?{zH znXZu<(p!?s!d%;j(cB#m@#&q1j;VgN7J=(+EHp9(G&5^H5Ohq@`(`F!&nZ$3<9+;+ z9O9ylEV70~;q$iVjT=*LV1pnimm*H@IM0nt2E{rT6R2OJd4C(#vHM(jmpi7psYi48 zm%ny)7GnE-Ad=@Bx*AGdlF2jGEMLfN*ds=2^kgP6Di{6F78?0O!NDl{;6aK_-dieJ zEJHz@jo-AatGp%WxcT@{l`AXhM$a*PLyC1&lL#XOvdSS!2~aC>7Z&EZiG&y4!9U7A z?U(uB$#Ff41t?FbSi4yef@($3(X3%)TV-K)Oi|!_8@)dG2eP?AaShLnZ%2CTKOcY1 zne0qo!t`qxkOR@?SFub!rG4`oS->k_HP>Ba;jBvQB*6G^&BHB;*g%g@tE+N>;mbS| zpqka0h&A;W_u?V~;%LqmO(d!c1Ncr0TT(csRh(8~#lC(Z2#w>%^Bdz{<1V(xvJF#lZ+$qtdeF&aabmf3I;v6hdI*k6aO!rr|{J%lQ6 zwh>PKFbtmM_@S#@Agq&sf+-D|J{Kp7%b(&RG@(K!K`Zb3b4X;TdDQ>gH}SXkcmgZBMBtNaKM9pd7bGmzai@3B=zXgT zId=8h&_)EOGT%R$ga~Xrb)Pu%(;pnM%2sVkmIn5zpTkZ!9>@g%NYx?x1{U($%~b-UvKIfCyQT`-c{sf?VPQG;#{WJOuCpW7h&}Ipi12M~e5R?c7LPuu zh=C537qqq=r=h+xGx9{z)1~Me+(U74u%yT^@%P~W2eikd^dEW( z6IAnzwi^b^H)$1$Ah5+|yZnNX*x;defa;4tn#oGf;D|hm%f!I3b^Op=nV;xn9odK= z()YCvW06$7sGPvAjyw5l2_N^9y!<(T&EH4*ZnVF^ORA*_L{YJRhjecnor!)@(a6(Hi@LQ;t|;hADJSyzM?Cu z8|ka!Q`A=D&b;s5O5(wKr?sd@J{)n5QgwkUde3Rzjt4j0shtD~pnOI2LKWdkF)kEu zrEDhq-p9a>NJ@eVcG??3%Uto6=4fj5URSis)DPT4gphzw?i*wg8F|bNtL7_ON+1ZT zjQ+n~j%`_5k`G=*<_w*rZA^0CRnP{y{A6cZ{>}xV^d)7f!c;x3WvHQux|zedBjXC6z5e7-lCcCrt~y6=-~IbCb3ML#__(6} z&BqOBZ)Ple_>MVv(n;}9Nh3FceJk)hwhDTwx$pFf@@e_ioR;Htvu&i@;4w=E@rytA z#GOmu=Fin`kf>xGyOGvkl*#*w~o`@DHl*N?F}m^<%! zYMrp$MFULZpPbUv%10^r4%qUf(OrF9GiI4`Cs@!!lEkhd@gm&PkEPQX@Z#S-R{cJO+;>N>%?Q$4tc%kv)qmSHYZ*96PdQ3 zj)b+?Pnq{xu3iMf?b7in?u_t99l#zXGDGMg#@z{|6$D7Q8jgvlfMLORXECGW;W#lV z{SL8=r8z$PBTE}qv}8uZFsFHs5X3B+#c=Jn7gI{%J`h0sb`D2AX)O} zw%-qyMP1j~oTBHa^Xn3Mosv(H(SjX3Q6+@Y8yp)2$S56R3fVe1!jVHx#+3?Fd#{JC za$}D3&B~R*J-@fm3rHX{P?MyRJli4etMp)GTqO9&i}SZf$BYse0v&0Dm(qH>ZAvLM zzT17U>jb8dc8OI8vtMBB{w?O&{eq@{gi8VVlImAweeeP@Y~Vj%g&I+EeOn?2J(m>J z3qN^g19<7{3nrqb*J-_7REBK*aZS(J@L>>rn%pl-oGTK}Z(HxwPCLK;lcYopN!coQ zkkv;G*YGQyAN`{ArjC#dSk1`Zn4R2u7Aq@8@Sqlpspc(<(sg_}ac+OnIe4c7!*NW7cW zY_=<92Jt{a543rK8^3KYP}~v7lotWj`7y2;7$@q-6jFuLK&Y{?tJ77c@6j-oJWz(170wI~^WuAZ;5D2_cZ@O}D{D*2d^q>`lK zh9H6M`qJG?x3NZavXeA>RWQ;!|I0b4?IXRnK<4S!j~$xc)oHmG);xn_G>q7;JF{Iv zQUHzWEvLK45KU?HAX!%=j<`G-cMI;wF(qx&c65PB@~wm9Q0Yw$q^AQK1{&?p?5StqNcyy5KTde%L!hj5N#fPirOd2d_3&xnVLGVEg=i63Myd|7iL!X{ zShq(2&IO><%W|_{tAcZN4%2mI5%-+mjW2nADy+OGAl|2EX2-W-9X+QY zyAeEv@Ui5`pkb!z{{55zmCnwXxyF!%kRN*Z5mx1x$=^^24NSNz-Eip1PdUjfhZ*mW z6Zs*byn)e6{CR>V-?C$)%eT)l$#7uTk@@F4!x^YsUQb2L&;QK*GC~K3ar9;i@*w1^ zuA^#t_Pc0nWHVCsJ5AWI_S?7N3$No2pbRXHU4?rYkDma$Km7Bsl81hS1vGmD)Ui^; zxCRxMzMfv$^~vO5WnP^3ruX>4=*UnAP0VQ>e~(DPP0Z#GUrA%$Ty2&Ic8XNX8A0r< zlp`>Yn*3e@n1CBgZX?Lt>cm=m@fofWuxIO@>F0G`)*AM4YEOUXJ*^_|VymuYvYN=h zT`b#dW*J0EzEmVSUlp3!6eOB)<1h|2%K9qVI0xK-Z{u)<1^}9cG3tjd=aJipho~R` z1u#0JSDQd@fCZsN==)c1nrAHk(q9SDJz7Q zKR$>ww=Qgdn*L02bu@t1ZJLR7IJ_dA5re&L*8`{VaJLoiNc_*!S!4`Q>AHUdtlmxJ zJT?KAFjFj+m2A_&X#y}^L2=J6N}>RytgbsG83!NfFsM#`Djq% z^wwceP{YP~-)Bqqo001=W(iP!E6O|P6|LxcJ)5k1gnWxyl&g)67h-cdc@wmCHGa)#@$F1?(uJ3%#Hz{53u|A1qu^6FhE zDF=oJ=yt9(!=^R5mwuX$bLk|605(VNjeaVa{^M3qpsW$bigR8!%7F#}?DP5io#4-> z4MaTt{*v{>`N^{Kd-VWTEP&#|p&zZAO1qm2ITmU-LgEmr0d-$SUjrINcyCo~2(JOn zSf@HEn~jZ6%42Ms@snmX0jZewy@D;G+MB5>gt^0P_>+yGQiEaxJK`29SS68?M#FxF zF;Zfo7?YU}%CW%D*H$47C}T`)^bUZ!a-g^{n*3XJX_--ev5lo&OEM))Thr z@k&*V79%K_R!k6E7^?GdH(T9S4gw&#a>;Ui5NrU}+55e$q-NYb_@2l8vCaqU*`+4c ztgfHbO}7&&5$^TzSv+K79un>izSwow`<&KI5$vsQCzL&)28Rh0UxJ(7$>o@E4P~j; zZd8$piT|wKY(X4mK}0}-v31mgpfCj=wp?nZXW^`PH8nn|$EUn=Vnd4GHZEnK{jh5` z6?&coQ6GDVe&sAJZhbj{`T}`%p6DPgwwkZ{G>+q{BA=RMtAk;$@ll&5zE`f?z{l*y=7qbf zgSC|LusR|Zt=Bg^(ETI!{pmyZ&K&ovLdSIX%W8KB1qYjvv>8C{ik*QSGQcqrp*l1X zm-gM#=0eKv;?wiA|2^E>wG#EV|H~Yvg#mO6AG60=rGm!)X4Cm1AyRS^=$GRWI zIl(=)EYlxN6JhCv!`BDSZ!b51KRG5cCvzCeX$K(#o~Fua<02tc`Psq#hYX94{~qcX z*Is`kVM!Sy!SsbEGXU8L4OIP8(=2B{f=EhlPle^JTas!w9?^)+-s@37z<=P}!3u&7 z3pu3xg!`fPqwlwQ3JpOyZx~&rtMzaPZ0&)e^F+510-#r}wUm625m(VEFe|VJo&x)j zP<7RTTNJLc_v-;)^dDmBzdo=tpFhunfE*P*A;4ifi?Fw*!Z&+bYn{WueefuPJtBTzQf z9tRx}Kkl43>~hF-($;TN>|bzD(l#qsbcVFBtf~myR-$C@lY* z3R1bcyj6+gx+SIK)*Q^!{*_$VS*03yfYN3HsRqh=Bq=V> z`y_J&?e6S)M3>NEhc+)Y>w6Tzd|DR*nN?H4sJP0!_TrC)slDZ6(=dq*PT|v~2z>ZX z1d>d&d;<=#LErZ!%OxMzRt;0pIb2x?#sKGL(vbGpO@+G71p)jYK1_k|VgqC5sALRN z{|ItvtYd`Ui+J!X>0#11;RGJ(U=d7Q%Jy+&R5Wn4(fIYQ%0SHCGG}Psf9qQ5LIydN z;p|oDXrN-=zoL;b?gd{IEA)`Fd5)iA40ziKYWBqiwoRC=y&^RQ1Bh52$lDTgmHGGrh%pLRuFW;&_cQsc_-sr4c)W z7$qP&sii$+!GP76ybTciS&9upad{wzMQWirFlgF^Nh_#MCjc4jT!ZiCtApK2c?gYvod&h6R;xZPQ3&coLJJRx2!?Qv zf*MF_O}HEg)cxXyTGYJ6q}F)Q#I?7)uN~{_wIU}%KTZ{7FDviYj|94~gR@>}EubRP z`kOYetp5wQzxvx}(u_k?g-`2QQ>Mx{${10PB zQ^6F@f9w<6rKE9uDOG|G2i{e@Tjk0M9O!;UsFXKKsbT>GTszfCCe{Ii&l<#G1aD{2 zQfe4@20t_RY3;axEn{=*q9ag=4;Mfq z9Rv`WLEcq?Lg`V0eRl&cNGa0e6j}PDT;>rWNUdVS=sBn{&3Uy==)uWtu}<}em(!n} zo|t#KS-`nBBDukM@9>FOAhW-q_IWb0KH~2`ypPLDj|h4e=iua0wDwGgLvdSJ0GC$b z=2ibfUq~jjYzj`u?_(Y7GPKcSe+q40K<|40pqF#kJQHBO_;hA+^L&Lxm)c6dID!!o z!HrY{AvbQUj+ZDDTtGO_Bc%!Y3$P`0cyw8<=6@Te>mw!$Psr}QB$y{D@EM0par#$ z)!y%iWquIZ7|UEcv|F{933{=jbTC)%Xd34);XI@jw)tXN})D&mk z3d^@aagDL|y@n`8x9YvJmJim0&Zxd2D2F*2ZwR1Jrj&tsekkqXX(Xb{y~@V${l;U% z;S6lc@cmtLE-@GYq%?6(Z%2S(Nl)n~$xzCxT7d$i>kdt>O__L4Ve|>Pct_Gmp9-yA zeI(i?HWJTfQJs*_xqKi>LW?6740VMFE>Z=V2olG~@j$>$r}SV9J>z2f=N2$rsBF**LSP1=1X0%QmcRH)=hA>2Ab=(FcL$m z^epPcmW%QQ@yUrRoCvE?@Nkf~TZ7`lW)Mr8dz|;L7RwYY#EATkpsV#d6#%4wJr4@* zL$AfAq-Pva$qFZ~iOd56Xk4?qwK|r&7}(`90-vHZ1UMrZoS>2SEsY>8IS6kI_?M1y z!0&d#;pbn$;&F;zM_QHCB?IBb4AiFjJ|kL}w|VdYQ*Z2m=uaiW6-bG+?Ge zFQJUC+mPkjHm|5R07gNxUTg=2j6(rPD0Q+at>$+Zk5V#Z9S>zE>`&TO6ruTy7A%5T zN}~x*942^yd^^fXoDl>#^#d%J3Q=g-rU4LgrD@yG%}nixocp7)uhAm4ugPjNV@hP& zQk+&ja8ptBNl72O#1@HF{_0rv)#;B=!n30R|9&;1NPa3r6?vD=VL&bna~tuqr5y~_* zRJy;N?vknUr1(?$;kRQB1T7WM?xM6$BS(?q#&I|zmn!r3?M{aSD)F~QK^o~o#J#cy z*!HFFAD__Oyxe*OXeGcCoGO1s&;emcZ zZ@013osD0E$VhO=M)JDc*fYew=QVx77Ja-caD~zYy|`|@1rj1i)+*+r>Y{pVqQ9OS zp;4p$o#J(J4#$}yI78yO2x*Hz$@FU^!ICmWYNzJR%nyGnO99l=y*1C_C(Q)dFbZoS zAQta+yb`EET9@@17@6qkIe{W8D=ZV!#L(Q1Mgl@>>rysuVw}J^+%eV2ke&YLwahoz z<9xN<3+zPBTfCtR`loP=CuK#3OtZ>@BNBxe*U1BCfbkqB7z+(3uAHg?qFGrR#Qb0K z^#0)O2?h4$Ang8f^QE5vM_S>#Xh=Hjfxo>J2G`n1dMKUp;nYT`!a`IM1fxgY8hb@x>0VXM^zRl^&X~mtD z+st~XKv``tZYaXI7Qu>qZjWjh-6{@&Sa1Os9fn){N@>J|>_>UPSU)OO0?#Ee67U}< zGbs0{2*Z*vaFu*@7&Lxra=N?-3f&&0Wf4G^D{^KyR{u2kbXun|9PW#yD@5}Kt11PHH2=$c!f z%dpe476*NsaU!4tXM%dfJGh|h6SCng!hmfiRyY-6qgy$4d({c~bSkh57j*r&8agE8(w&Gg+>4yRgUIE07`5V!!-J^h z;#^+icEmVtgpJ}#2$h~boCxT`0pAwv@T|o;*D^?TiO?VkJ8DKXpW*V3V`wmoL#I_L zhU{{%%DGs`$dA1naM-U6rvkgh_4ynZbX0cxMHwFR@4$Ya=4tagJgB`2!ma@s8n`22 zHm4`JA#N4{qziTquhqQIcd=tb^&m>kB2i`n5c&Fv6n-fxqM35No#*Vn%TKFy-NpVikt%A5g zaLBhs$lbHSy`rs9F0-ypk;h(=Jmz`)-nLpM8H5JE`T4h~vxq~xO)3T)bFjj-1RFi8 zu-ms0hXOiqGPnolLi%wrbO@J12XP@}0B3ay`LD>2_sje44=K@nZbE~I8IGdtS(lUM zc!+*#)_gzYFAN0x6{SX@qK{E!5{X*VXw;j@ zO9KH7>Kfk2(m<_TtGAWVKsKkBmE!4?Z5bFaewEVC{Yr)Tb&gjaqrO+={V4Y-|9@9$ zxlGiMK)o%Op)yvM!IwY#Pkiz9AMo_6f5)d^{tF&`_8Z)N^h;d3^BfnhKEa8zcZE_e z93Z9_U|vE7W=AAoMsOs4;uHLxS{kU8UU^$~Rwu_YIFMn19M`pMMq|egv~=$l;GnH{ zpYU%$9|r+G8Di=Jrz3c~C&AM-UM$h*><|G5+Yr5l0fB)hOpIJ$^@F*v{J|Vp{9w*^ z0u7W3Jkv^Oz_e2NH{{FUPk{!?DG18zsI3r`qx&(@(MY7VL2@!OGt$L0g~I$i6c-kv zq_7Z6i;A$cs8GOy!n|DMWoIEPJVWCDwlp9#_~s7i z&mhjs7b&Lx$S@5=u1OH`mIR}43C#!TOq1Y%76)FUqoG#zWhn5fSP2cLJ63t!>6Gv3 z6l?WyZwdrn=XfO~_%1<#^4_O=Hl=ber`5;F|I4xRnsQo(12>ifG zbbiw3d5e#2omq@f(8nC|qz;%@&16U8d~h$Wh7RIp*a&V#ECV~`w)pMD2kUu21MOp{b1lWK?0RL!YFpsHn~-Z z&Ks}QVU;X8d3TO#J3y0^1qm8VIOb!$Ybkbm)!=|{6OIS8<7{v@&g*({QP&45tY?FJ za3Zinf?3{mLfKsI#7=PrS}YP!X%c~_w;#QWVtcD=CK>x8VupiINC*s~XEHd8@Grmn zz2-Hu7x^P+fj{yW1&X#s<*RfFr;>2QEmX8|?#re%**tI2;Z9okcGDAn^NVj$ZXAv# z3qk`)IiV6JloP)e0S{j&Cmd;%-ox>L4$(2+=~XLa43!fCK`JLhVcKTNU*3Hz>ILNh zJN$%Ho7^k#v3EU=__yJ7P&Y1y4B%SWu#iu8Bgb(+N&*J#;J;~j7%hQ@`;im46FDwG z1nV!Kg8-GlOZf~`u-Yt>u%lWV8eG|V3{B>7=(0`~pl!8tF}8YCVy}0DkePf2*4InA zegRXMZHXXemlqwtmI+0W;Di9>$bdF9*gddTykmlY2Et)ke(W65h6XoJU&6M5 zRoF4O20U)}$a?G<-H3f-n{i-bD-JE+h9j$X;^^vKIJRatj;z`)!r_(Mad_o69OXWS zl{;{FVjGT3Y(rmk87eKKQEeH6TFY3}TgIWmG9FEq@o2P&M}v7R>dc}+MX%iW1vt2I zE%ug zSkJV6Req_6o8=6cF zJ@IAeO(;iyLd9g@Hvi{-9>?Q(9?$1>YQnP(!oy1A2sB$Hh;}uhD3`;2Es|W;mkY~; z91d#7Dazu| zeq0J0z~#^ZTnz2UIbAPK22IV6_enWGdE6hW4Go^$eh8L5fhWOd#(W^CizX_w~7N7lpTcJ{B981t#^}v0iS!nFJX7vivg0*LD9EiUx#vl@R4%l zar7!Yj#-6IV^&Xw_pTm0jx+lX;LtYuG+2wZqsuVT)jdTCr!uNkX63Z(%Yd;`xt=aP z9W;;?Uio^;_)VaJQdwqNtF!l|zH-0v|96#EmVsP8uNy1NL52qO zXYlxo-{ZlPU*q<}U*PKPXE=BHF^-Rps91GusWcR13E_}Eb#G264nJ=n$guU3V9`i$ja|VYE~-}QtQy#F@oC0 z?kSLf_oKEhP;M)gSfx_Vv=Rg`tpo?(1vKdW@Be)Yv{9Fx5(cR6?RB9+RAdBVW1>Na zhy({2>1oK$%s_5VHfT}6ke8c--0V#8e@0p=Qj?RA7#}wU9H>EovfR{QK&kwz_bJbN z7tkQp(id44{>ZloLa});O3idAGu5HgBp4+|0mxtMi>w7+NS^EZl7#@3{pldU+x#bk z16ko!#%hI`+sge+zYYYL?ii)XzIy-v$To)^1(!lQaU-G+ccKRIAbJ>&Vn^{wj1(TmjEMj4L=E6(L?5n% zb>Xb84aWl;vEQ!-JH5)V!MzA8oO3W_pN1}*1TfV%4Y593BUg4Tim^P4fify$GuC}asSc{Jh*fd4=>%s zqszDOi3qpx__7qF?OS+s>6SQ#$33`s1NV9Uh3mL`;ToQQs@>V#zhX1uW;r5$wi6QO zI8O#{Z)zXWeD=E+uVZW9a%}5gfgSxTv2$P*b`7q^$AfF|@bXQ~^X{L!hW*3qML00B z0S8Am;LylM93I_-;h0j?n1!LyB1*i2KHDUWIHY5xOAa==7h$J&8TR{C<5*w=&gfc2 zow**~gIkgPxEnQqyHSH+9k~_Rhil>8xDe8glR-^5;8%m~UZq&;mX9&V4D{M2qS-PU zcMZ&C-dNBs>gupV8dkaFVv9!!_WD-gs3PyH;oZ0v-Xrq59M*|*tdl{klhxSfxfH8i z^T6{vtm9B?7LKPkA83}#XjzM}N@B*MS^RvQ`=8V8`r zC;+8Pf>B`-f@;$+@oaTw5vVZ>N0n(P*yf6j0+6@J7a8+Ck+%5lpuul{`73dKwnet< zRW5nh=2?pUzBM==*o5=Cb|DM+4pkrH-@KitBacK`po#(t)dC-J-nsEG#>gnW(#RnX&G=>665S^w6y4k2oeBVy+{BXOZSQj9#2Vd8^)YaNR1!cgiIg;J+T zl(|Hs!YvjJQF&;L%10yP$UIcI#GukS231ZmsB?)&gL6EZofFVxACDHhc(mImqSG!B z-S)}ou}em`Z4$a{6VPrQhbD_?)R{+!x>~j*7&i?-gG~h;qTaCVSthJcd?)<&u*|N6 zc1@P$_3&O%wik4iJI$irZ1*e!>(MgDOt37O_m_9HEskmfQjsv53ahgyL$*n_&*+&B zFa!-U?Sm2ek+t~VvR(7Mq`59go#%#(`5vN=mA%j#a$ui}|8qZ&}U<$6S~C?9U03z5FrJZ`IAKFW2v!#P>Au22rN zIVPgtH3Jh~`PdjxhTXba91U;9iO^PDi0H)C$X;BJ>cb7j5k0sPK23g<0}g4T4h)7C zY3BFY-AAG>vwU(E`k-jBKgx`QC%;YX7qA_&jSbqRigv<2&4g37=!394*uUBAQ6l8W zZtqIbPdO6MAnL_AUArhB(cg(2!2Rf9(f&V;9m8jOS@K1~a(tPvVoG@L`tcJuyYB#w zY}_zruijQF%j$EvEdv9_>T}h{^WK&J zDW668|GP>n%lCC*fqa~@90(1R{tO;``YYUe@H1S#`325ge1yX%u1`V(Sy@*r@!!R^ zTH#f0tFJHLhYSnkn0^gvnl_@gWix1Xz(D7S-tLKdSP&9;mZ9_N8Dx2RL8c?BCD(Bx7G*DiLpg7Grt22jT8w{u zBiPaHz?tA?91W<$KHo}g_gso~ZuyvS;`D-KbXdot(INuXrXeUZ4nn5^Xz={O6V#f8 zqTW0l4dxMOu!uy1Wd!Oi!ZDsuq1m~3eDw~Nng^lWDg>1_p{R9;M6-JW+Pss|?w5*I z-xRd?rJ%_#33Wd4XpYN8ZDa;k8L%|CaPS1eXWJrjwk@LPI3Rwm6O!h+AZ>vgG8cLv zdyyA%7keXbu@CYW`yg+T4{{cHBWnRiMBI@w*98f4*wM5{)J$81&#=Z=Wt-+R99*?U zyd$2IG}l>##5n{APT1I{4Gp#qtU%~TRtWpZ8j&+>L|)93@B8CnZDnD5=eW4noP}QE z-U}A{3V2v<9E@tyP&8VwGa4fl`w@pUtZ>f826rlN?37lC_kBj!Eb7el@NV3W?8E)& z0X&Eq6oKhGQT@0P(Su829XK7_j6?o4*y&x0^=|nXcgjGYZ6aD<0Sz`4cA(299=wOu zuDRIiSt9a39@v0$A+5L))(Pg%e6B}y<7!wZE`+qB_ra>rO5{N1j9qI^p%p=fZ8710w zvqhBHW?QN-4o0z&zqsGbw}l4Z{0cRup`t#FIHY2YYc96y0u`Ik;^Vy!?|5Q9juWbUx9W$`OtpK~c%5d1fR>&H@ z^V<=am(;T$haXP1Nj`3iJ~s~RSVh1 zy0pw89X$dX3~4^Y_1(t>aH9-d?v#a1?uGc+yBtRX>Tou=MaWHF|5ikgcovr1wXjZH z)Yo0gA_jWPMC@`yvVdpzpg;?d-h zj8=~nbb6$s!zCF#F3IR~NyVT`8irlcG3=aI33*dlH4JzWLx?2 zj<&^7T~I0#=QxW%8O-*`_Q|&T?D1!s<(cU~XkdkKA&V(L9KEjS(4ic3+QxE|GmThV>E z9o;9rhls9e>-4At2NmKmYycX3e(w|UjpDbJ16!;k>>IRM#h}|J0fTnQ;C0y7Sm}~2 zH`rfc8BmU}-LWt8FlG>sV~6o1ZWLcomL!bh zdBOyqCr;q2#N|`Md)H5#!np&7aAe0$>{_=T>&M2itfv>_zbuf8_7<>RNbGT^>9fd=xmBdu>I{yF%k6rzXfCeA<1Ph0VGB98)!vZ-jt67PPx;0`Y1+J!0QNIQrE^)%q zp_@~*@Lk|!7Y2J99n!Mfkd)ql*rX~%#+D)^G9RTCO~@~<{!XBQ8XyoRysf2yte`Vi z0)y|$(tuV6N+nvEAJgHXp@@ozKumPhOV$(0^WtM;1T2V-ia=y|*pzFk!GQ8S^}g4I z2FhzpmsVRMD7Tfz$9e}N**gS@);>tL@kg#zAd0MlQEH__g=GjTEkaOXEE)L_)8QA1mfIa@@I2K%o^I7@X!1=&TRcaCGqJ`HG&pnu zp|h8n86jI=BMCA6h{7kp)6NvK0A* z&$LG5EL-dtT&bDg*3L1c&38k_0(Wu$`9?k{F%Ce5X)x+6!o)jcCvwO!1rsirSnrXC z?cOEW>sO8=K{Yt7Ys7`HR$Pnh#I5Ka+>7bM!`J~liW?N+LF@qT#`NK4R5vb%x8qDm z6AlMfW0!9!HhAP?!Z`zd_K6~&I|k-5Z!YdYw{09ool>#JEeG4Yi?QFo5+{P|aXz#K zS0g%bBeF~6b0extZ1cWO=^Ah_pb9&DmSU}Yt~kHbCRWtLr?<2%4N80o4J-xZiJE1L z*xB~tJ*3QYLHc|*WG-+=)cXiT2FzcglPhB-3(0$PY*C99pG$pX)k?5joEu zF$gID-Mkb`DjioL`z~JS`&*<>yv~A z?<6#NC!@nR9o;?|==aS;pJzITJToxrnTc`FY)p7$W5PWf6KK5hsqAc5RI;0VY0;{ppXQ_~3 ztWW$Vv3`AFV470BE=`o5T!w6uadR9*JN@z#ZD^3?s6*%sDA7V|hB|KgirEo8bOInZDeDcbvpW2&etly_{GCq=t#6LpF*nDvY?<@H6@ zXV78JEJ_guJ>H)s4H+y?7AYkH>LC zcoIL1rwOC@B5@g>C5_>E(m0+ckK?Q4i7DZ|Tc^(8!lA=Bwre*&-mnoH$CqQguOB_l zt!S*OMtNc3l&K0zrB<1qPMMegQ$mC36kw(D&1)*RWu;w?l!ogm(O{0(m0`x=+7KgG#&_i*6ol}Y7XR@jxJ z+uuj}eGfn3KY>#snj4j55;z6dC&=XR#+z z7q}vJj{Qqh6sEHpc%A>0%BwmpE4Xs3RD$KStUSx{s}yzaS1R^$`c;+&@^Nnxzs|jA zJ%{`}>N1i4mt*CAUP~^kSH;Tn_&%xVl$ivg#X1Uuj>%Z#o+Cc6>`A7rH}&29g39H^&~)vuqJD z(^`TC<=XijTC)uaa~(xTHHmOyo--J;)4H)u+YEZ^&$oegcmk)UeqCN%KO$An7;`t1|ZW*vn)21XdS zlypu}7IyehS(TIpp{z!Biq0?K7;8 z6+sV``S>{ws!qR$C@+>71KSnBLE3y*eW%|+oF{`K!knK!(}o5a7Jd>inByQo0bv2_ z0mJWp{Tt2utg;Lh?}`c+fdQY5N;b>1&pttv*$ahCho#2;C@}Wbyq=*Qzx&m1L|%jj zBZLN&9lj+v6j&vcGAg>)qB@0=a63k?07pqM@nlGYkO_QmYdvzY%sExu+h~M#d;aR- zX96biIavQTc;;c3U#WmqXF{8BC9)lNVtPcKBg7=sq>Or&Jcef}V|bo2{zif4@LWm0 zjo@*@kdT8^J}*bK2_QR_AO@I{VIAoA>jQRozkrEXDZh|NWFLOxoPi_o50g7&nf=uBIR z?({PBq?MyTy#mAOmFNx3#DISmMgp?2BDfH1f{U;|xC9%6O0bzBuoxTsi?Gro8)L2n z2g&HRk3)-1lmL~6EDb0JsO*n9r(>N*-sHFIR7j&}@7JRUFS|uq{(tPf_fuQhwl3OL z=RbJAzIyfUJ!ju@Pj~OmZFf6IFga%g2$Um|5IJW=5F+P{$u`b8+c<-<4bC>kIJ?Rm?3!~kdv=>IIz+gXiyZc zW$T#?c@8*u4jSCLE4W-t8^WIh29%%5l5U{Afq()sf(f8aT;#`G3R67YUgLBKmE(W| z0w2HsMi@LSUL$6@nm|s~cVQ4X7(Ghb1=;*(oWn1R8J#FW;Ew{I3HVkRi^MBbRTq z^W*t`zVYr1G~n08`Kca$dA^^^!@2ylKf}-QkaL{@1Pi4Jfd;qkeTS>Jzr>}hPjGgU zK7x1+dk>Cd^Y)|Y9oU7&)Ow0Do9yKnn~ zpaB5~hNNof6Kw2efl^ljsXCv1>@X@W?S*mhfdKM50tNgqKd<9>`NrrU1sd?%BR~JP zfnypU3~&Sr_+fs&mw^UB0RadJ3Ic%#j(`GxyrPJ31}=n$g(55@_yr)q(P-y~`E`)r z5h&n?9rHR1^V@LrJ1b{e6@=u~!AM^ff=mJqmWLp7Suiuw5f?1!XJ{!S#DwwMIL!_4fZYsg&{j-s_9l)1*j z<{?F`j|zQ@Ua*4A9*rRK}pwr-z5Wb4PxG24bfY4)1Xvv z3Yb6GvZK4x^e>rn3^2eozO&?&)w zZceL2%{mE_*?uoFR#R{wBpW9p3UNNF6c@!-)(>iDI@X3uVk^d@%WyKX2!}#*up=N1 zgWe`qzG`h8idIBA1r0KTWr%)z6~upC0|I@B|C$fnp#RW=fkO$4eCB18Re=Ka#f&Zg9^vQv@8ZiD z7v-y?*_b-qwHWkCz>dH)91hFHDN!*lh|5_!q^s`E>#7Ip7N(~jX~jO-!fNu9sqa{!2iEHDWZnD$wnr$B1v@ zyuQt6YvBT|pEw&cuE@Y5`Mnfd`CN9n_DFWy-R(Nm*-eAJZ3EDL=+1xxl2_7G3^;h- z72BNLI2x&Lg?y14)Sr4mx7-h=)qzM_ABGgy2xNFhBilC)Wy&O2HEFQLXQ0}Ug<4|{ z>P$IkH07Z=As=lC1?WmBLUTj{+9MLt9g&2=sB~Yc`@DQ3IKuN=?oYTWMPV@bON3!KeZ|4?H$fQ1IxM?wx_plP+`E^$YhlC zH0eLmgQO2hwywri*=3BUA1NQnv|Yw%T}okd0vi1A^|!FO%h2SbK~GQuHixHUZ&V&m z#944kY{7)Yipx?PuE?rzOyFLSxFzXvpU)%LhH{w$XR z3pjTnUh(7jAOXKm>?4TtHx1Z7C(MHe7q32M|D162>$MJ;Ajjku?2#(ixI9%@_hNY}>bp{|vMA81=Kr)j~g zx(Rnw4Y;YO!&O-|E=ekJPF%|BI~bmWox$lC@lQmLcRZThl&D%C2g{l$)P@WHAB$)E~M*_pt{Ii@cDq*ark=B!BA9D2YBE z_K7b{i+vFPu@^hQ)2#&Qd+QPV?pj3ubv0U@fCh&Kwm|;A3o|V-jr5nBtpH9@jLV@X{Sh}`92u&j<^b47F3<)z1vpBdYN zQn4>A8%IS2I2}{M=3!?@ zI)?qt=%^EoC=42mX4+8WDn*-z2K~M!Yz<1qf$$uhh$_N)aTzX3DlsLi zV(m=Js&GkKiSgKSoQy8Up@>}U2u{PGUji#%?IJb3 z9XAhi!25SNtAVv9Q z@4GM=AUPm_>btML5$Yxi*GIGUY+WZtt*ex+G2&6XrD;3RJmBP`V}>c`L(_ zzC2j4K4%F(eDfXhSB9f1<4Fn-heC;pQzVDliU#CdT!#-fUG zAUqe_g3>VHYoCW2R~cHPg>M=>xiyROwPGe8ot`=-gFAyWa5y3#r=u;HjI*+KZY%4V z9%8ym*M`Tsc0AU%|ThovN6(FY0M-`?H*dxy2_k` z278Xfx-J%tZc1h#kN78HcSt6VMB2x2A+7>b%)qJ^ zY?I_+XIwt^#1&v)YytL*^RYK3 z7rR8+7zs*3pPvaGURoxjw)wrm8E7z?QN?)P?xDeeuZig-(gU=Ajf>0J{zH2h$sZZ5 zmnD^$h%IMxcQ_&sJA%`h9FaWLyUJ0vCI2T5mq=#vJl0LtGQy4Tz z@rq)3s2t4)?Pmmlr!5I&4`_0hhazu9*mI&VJ-8u#Liq@UrgEhJslB*&*Ezj$WFe4z zeq9n@xOI6lsu<(qa>f_p2ges$rxZ`=&t=*-0qvd|re|#)GC>(5@UYTDh9=*6&>$im zdt>r<bUOI147ER$P|ba7A8)Yw~L5Ugq?%V|yMN)VN5|5+w{CKDspv;!nwH5gQ|| zr7mwhTZ6O@>+?7bRAM^5kV0+b^cK*DhYsDjd8y@T1@Pzb8d^?`Tcl?IlxPJCLE*?LDQ~M6!;MQ%}*58l5 z);2U(Rl{0bjQq^3e+V?-8?y`fIfI>_#>J8QGO&P4=gR+CpaEC^pXqX70l9o|K*;~f zpaK2e;_WZN2Mu-~IEPJJkFclt4K4jBuWWh2*miu<{zrxX_QdX(pm#QxOrJ#9l=R3ezJoCGUlC zI2z{sn+1-3eqP7%@(oaDHx20Nz9Ue;5AzLmetYEqM?eGah5^5yD-xM07=%(H3SzeXtfa!5WnL$*|GMHwGq-j3M^@wUB-!wQp zxD|>IU7`GF11m%2h$uW*CJY*EY3V`O+sj{|@VA#E;_VgKRNpRm0NhmF%IYV6Q-5hJ z`K!ZGzCH$ZZZfocY0&3y#At95c86!+uqYQN#YH$TDZ?dsC9W!~aZ_D~8LeGr?&+H` zH&6F;O_ z{zhyKNx^~0Y@CQG#Cb_6F3GK!QrK`sS%qmu732%oZK`p ztqX?q{q?L(`3Ej`1BHx~51oSsC9YzWt&2vLs|1bi3O2rOA3b_~4UEW7bJ*anfXyWi z#cM>!UKJ`R56%+ko$CBm;jErkPqkftgr+h65}zj|<+v=b#1%yqt|_aTOW|=zIZld; zaWFC$+e6YY=%2v)RJ%cj))--9;mPfLs8}y%@fVp z2~@hovbpK;(PL9!B6f#m;Am7nTMLuY3QWswxXS05tP&HFGMtPl!okQKrlW~xWL(pl zJlr7s*NOW&1{t8K{n#BEMsCmb$2KRgDQ&6ifOd%&jLZFyxH<@FF5$@bh-M#+Ef3Sc z7G*$Hj0v@IiD;0fpeM(Qjd_*m&#%Hzeigb^S=gw|#-K6>qv`@|R~KTpstCKJ`PeJT z$Nso{9E>f%0dXGoMdx65WG1$TrC~V8j2^#uw0Npey+MM~bexTOGIIc zC!Iq1X#b#cq?gqnxq;gJ{%c|Iu-q*c)vgk>d8*l7OZtxV9$S~va$HuBuCBs0RW)-d zJRvQ2(2ogd_tv1+O^QlSso)&^_|11H-ylYvmjayudJKgoVy7q*hhy_`T4uoog%wlk zDqK}pS*6;#GJkf_v4%Kkm-4eqTAmoFDgl{Eh}FA2{F)cFyI41de{bvCj34bNQeFSJ&&hj{W3=0sOWX z^7HdL))N%q4~`tu$WZ6v_`rappUd+qF5mcf=69^??|IkZ?Kjsw?-%7$uk?X#g)ib) z__9NSVVMu&mv}+5*aM1>H$eRUT133N5`k|o{Zl}L??3+ud~!5?IiuLoeHEa9pT`j- zSSaiW9B>A|qY?kIFjwwXT*q-y*s*^8I5@v!IY+)xn9Iw#{CX3Y`XPT!II7&@(BY%S zaIhJ>BQkJIoR9OeQcNjrxS_4Z9eo4l49$38Y{4T_8y=h6@q|Z@&24y`(1u3|ZFpd6 z#eHK7W(`fat*>Y0r_?q~$jfm`QjEhfdDtD9flVQa==G0Bv$vA9Ul*pw-N`Gsb72~{ zC#G;~;xcX$jbFm}{$r?8Cd1}H6xWeaf}0bUSY9eabmzhpW+ta`Zp%KDZHPgYrxcC8 zs(HY`h`xwK3`8cOUzCjA$Ru<|B%mookNQv@D*WZ>%M$)KgUO>OA^pe&ibWfsS?rGZ zPrYDX>WkFn0mxhxjGWb>$XgSRf;AB+SQ~--H4!XKhFSWGAS5sIN5T>x=s)pTx%|k;x3n0!Ji66n|4!hpU=uR_3&%gvrFth;$}@U4A;$ zd&p7YDt2xxWLKfaU5Yjz4f+F3*cz6~`g0<-5a(p2xTv&ZN@ZhxnpW9xNm+?;lEJuQ z9E#4xj_`C01|^`~SIg=laB23^Rl$RCag>$;M0x^3a+|^+yTpNj!bt06m zk4BkGG;^swiqBge2FjPRJitEhi#=IAvJYMG?7<_!_Dn9pkbbxxlu!Pl3zGo?sffP& z>TAJrr5>>;cZp$RYW7lr__;B_fPp|0qrLzmy8ZNM@m8bOU4}B37$%?8zxYo)S$k3M zu0rVB%MkeHrwD#`xnNsAe)~PsAGQr~X!TaJ`geq<;c#>=PRAAFg1j74x4M*M001BW zNklKCZ(2l3(c04n8ycSUzDob^c?xQ;I=<0DzQ;mxX zE12vuSxUoDPy#xAwW#xuVS7QHAkU`upMcd>j7Cqz3u7R?NIWCnTvk@%ipqv7>MD@z zQd^{t$6^a{Fe(Sz!crNp+kG^sb(i8$gYdth?C%_cZm|cni`=1M}0N*M}k3JsQQn5>$q1Q5S7Ovm_bK(iF6-GSI2X!e&c7wv;wvTX_?9mN#R> zP>9j^B5c(cV~?>6`witdY$(S;RSAx$EI6jL;FzKW$7IDg9G8#%;#};A%)sW*WNZvH zvUOeSA!D*Ueb5PLkX?mpHwoIj)gam48k&NAqAVO27vLPzOBJ}Rs>GDKlDU)03Y?dh zVl1u*2cvVaJvUX13|P0*ysMJIG>G!_JK)-eg3D_He8t>?{#erZs=-oQ&)>yMEW|A&X|dBz}@%; z%o-XoXKccKV>2F@TJX@+f=3Ch?2Plo+{Sdt)5LZVJxlDsXNjGR-nesN5?4;0!T6D* zIKFE)_Ka*|-! z(?Ej-UQckmY4Fbi4P;6K-g#>&-g{>SK6r06QZtH>nN!AY8{`*Pu^R^j9?&s#?d(ay`X`!?+?5#K(J7L$A0pG0P-&c z7I1O=ypHt*`uic!-~R=oZz2%!^Ev_r{4hV?%lv;g{?|Kw{Xsb2Z$Sh33Qwq3ctW$x z3)-b#&@AzQ>JxX!7P%t!!*z&!e>H;sx(vQ=ee%kn0pB=X$j=7}9Q_L!zZB$nR61^n_0_4W6}y$V>s<#8O>LZHDyd4%}HkLQn#^K;`#Um1uJmnhVG$Uu1-w9}N@z^Q0HmG05r9Mbn;g5{f!N^@3 z#`Xgqcjqs%o1#V%1OSQmlp)uBjR8HB`TelRTYX24u`zE$XqiX+3@p`>?< z7rQf%f`AGl3J*GYJz+;jKce4X%_!#mH4t<3!CHtvSc_O5#eKLAk`LEI{*fzowFy79 zJkzlmJ%I*n3QNXLQ3ei)^DrhY#<;Q^mo+wAqXSrcJ!XtexMym?{e)H~HxJBh%ujKY zb~C;nSG3ibR9V@RD0(7A2E$NDB04#F*dWG~6JudZZZ)bsq-gckppOoW;i>G2<#9<7 z&MC?;Nk)RE3e$8z)l}h<+Q#~MQd+|LP3;Yan9=U1MUAHn7MEzJph0P@;qL&^ia<7x z1?wVF>KY9zJ=JrUpw?4{I!_sMsc)5Tacu63)}5PrcauIRg#MZefspBKm_&=?8kym9 zNnMFEG7B3kjd}RF?8=>k1_#F27#irQtiO(xqw>UyQ_>QQE6PE26Q788QyLpvCp5kj zk|OMn&SA1nbI1%`PnmPjpnDjkt8|}uFw%bF0nI1wP=DeM0tSSBJDYouv?dT4E@8;? zh(ZYg2Ei&c#w4JfZWgFB(W}iyzabw(rXuXAYRA5sP8_W5!r|H;>`bY^o}>!wPqN}@ zY8A#(YH%vK24jW_oQ}8Rw7vqTwdFXaDa8q8F%C-$ut%JQt&yo12sNQ2K#O`GIV#+o zgNJrKAVG_-8ht@VwukMF&cd;{0-TmxFrlizMRg@EX)2j}K~;gXic%bx6k>l&4z@<5 zVj$Rrc0UbUx3r#}eGrxO0O?-!VmGK3*@*yTTBCC}ZVRy!MWITVm-!-XWgv3bgrRu7 zh>fj=0Bvst>p%5@BN`9IQ#$dW*hR$3J=Y;iyqtoERv#%VOZtuW*&U*E9FEPy04+h% zzG-<0hzC>JDqPdou=PSNg(;rWDIeu$>(XC~IxiV)KEgK*e){fvlzYUX-cO0nU;~CD zlCevig(I>8oKcrzQd@~>eKoEbYH;09i)-;UnATO{f?BveXW-$JnK`!C5?>m;?dyof zNM{O~(_@lCHutnI(cIJ6uIQ@mupVe;I6R=v!-U;Gc{u_ z!M=YzG`F#H&*S;C&(nEb@+`RvM4zSD>GPCsyfJ&}GOnLHkICaFaB}Z{>>J&J(Ty9? z)6|5tFG};L?;7H}Gf+IQRf1NPbXL4Uw zPN@ICH=f@%`S~{pUd7M9Wk7y@KltA?xcl%Ya34bCzn(zfG;n-9fnF1MU1R!n^UD+l z{FOk1zb?o7@2)~}S^@h@L;?;75Xi~5G5~@4B5V+@$NTTB#Jhi8{+|LG{Of=F>kEdm z<81-cM-#Ym1>k533z|rqm zr%-sIdFSU{DE+r_1RAV;VeE0s+#y}+4%ren$Ub$0bnynneY_sgAFe^f`zsOj&NBGC z^$Fbm<0A$dyzJi*IHS~=>j)I^!+fKc?{_quIV1Rwbe;A2b<#LM;AO7kn7HslZE&MY)FA>UE zPCQNP!n5@51?g#e7fYvn4^!G%xx0zYxRua=D~4K3>MC(sRmu(%yTw`99GQaN5F=Xr zHK_KI!r~TP>3s5l*4;xaKR$-r=I8a75Jp*_-w=12pof>jvE7QSh4 z`NSF4C)09YB(DlU=9&=XyF{R5Lo_NpV%azdq^S2*qQO_m+*)rrY+e$SyNel+k-N@5 z#-x?@G4>Wz3LZ9(ZrZ^>3OeL#KJ|D`6do)WzG<+lYXET{t%Ky_^^Bw+yFj+c1@c9% z3zA~-1}Hyqa|#-q?cRcoAtp9&G=GPs`8cJtU_xufl)ehrjdi%4&b&KQS5pVa1o<+WUyUj+ z36q_TAx4ZwreLo)8^>gYIHM|MbzjoiSidgot8h_QiSz1mjLo;VBii0xdw>qL-ZGTB zIR_0YWeG@J;fJ)Mca66UjlN3OkM;m9s6KK@rs;MIrCU8>QL-Tl_IVFt z^~C>gaQ4}K;hP4D9^q`B6pLL!bHnCmu^W_&-SF*~UkUQ1!dC{Hr-b#1c-a?f!bo@$ z2Wt@i-U@_&uu8D4pT7SAg)Wh79%#%o ze>{cA-)>djJ0ge$)$O}pta(((!!oZ?ugF7Pr4BC#41rYejZZ8%2&g0>9D zRK?gY%f)ta1_mP%(HX2~ytI18V(O4{JwUpZ_OPB{14bf~K=VQS*qE|}$;E`W0>o3& zQ|C10IHj_%dD|14#dx_f)QFaOUXmWT=j5hAnbgE|u=-PXaHRUgjjc~-pn)Y)!*oXu z>5dIisPwdh+0<@lke=;>v{w7W64=~QpGcl)j!9N1Kb6Z}AI9o2ukdsFZIeoWInzDu z^D?$0CWGl~k|W~9lwp2dn(Em4q%g%(I_Y)FPqNAMv5y=!U*Veu3^eeHL%qKeouLK{ zi;}S`E(=E#g=}so<87EW)!>?`j;$Ti1Jet%M|z+$P|wEO5-WVu;OX5t6wT{j+GD8< zTSrmp*dLdR4zJpdPX-B8bCzn6WX_Kn;Y5sru}O+ zsfF!fwB{eAw6XKdqf|NrbufKkKL^>*LY!WCjDLQ1J@a7z<~vv>j)S)hWUm+8Q%QxLVm9QeFacW2v@%ZaoOPIk=hQB!_ zmjMTtSE++uO>hJaq$}JYTjmDYk`0h8afS4g^@v@x7EvFrdgYr1d?0}{N}aiU zkigL|WB_xLVb0~^{}I<&pI;}9zyf}LNAQ5_vyjU#%lRGi3h{{_zYs6D`p9hw zP+}n5fSux098=_BLRX6GrYg*)G~h{kE569;z&APF_#v+sKNa-hmx6x$S~ws`zZCZ4 z=Yl@`n7sv^A@8iK#tB3 z4F*LfY>7$6E=fA}%d>Gvm50NcJRDNzVXrb9+hyq(j!i;OTq2r9dTh=YHsY_II*0VN z0mxn-%=%g38G~9M3FBi|uoiux@fZv@VmKlJBasQr9SAp~H&l;~APt)Q6{z-(L%ByZ z3SGmIwJsRLCDnrC8{4uA#^qixG4h6KIY(aDR4M%L2?u(IpPZsi#AHAr45gSl#_$2DAo{u^opiPK?T$i<<~GuUOVL%_q$_&GnY3B-Vebb6a!@3)B45cu2Ns z-mAQ0S$V1_V@)7Fck&^`3?C7jJDNX^;+J`X=-V&86r7`m5EYZfo=`o8BNMPgoQi#t zOdOKs;D|gIhvhjqAkD(A*ffkrC894Z9<6~&);C&r>1zU+tf@cU0Lh|ti2G!{U|T=` z@FT2VF|0iCk#xvWMIOd=7F;n^;!aW>=2Dy3+NbqTG?&_l+ex*UHdcb>>Zm-I^@Vgm zN3aGx@>Ie0KEL+>js9|U)0~UU*b|qI`r`>+k+qSH{$1l ze*8lEs%QXzD;j)lqOw#6)kSrZKBP8CKT@02HuZt}LVcpX?JE^tmsgLRLY=P^?Llhv zhZ~-+r!iFl#&xBbGFn-^H_bJ;l~{ut=4xCu*_h5et0`gprM5PU%uJ_{{yy3)d^_k! z|7NB`NskiI8YeQZ^uex{9zk9o?izx{I~q2BDH=o7=!`O8K$46t>MZOw7T{n~DURpW z;Z$)G&X%^~tfdv_%i1te){e>Y4op|};F`4uH!6B?v!E5X^V=|!+lsq6t(eVj!E9DD zX40E*JGCCylB#jZWW`w>jV~9w;?gi8N?^RC`6iwT{dN@BvVDWr*l?tY$vesVDRm*6 z8{#L)BFz=?k;0SuGMv#AGuhi6Yo9k-FUY<~b198%oHSP2gC3@} zFrs~n*0Z?&l z-`SixOXJt$ET28i{%Qh&2G&OxPRE1XwVU&!AP_jd!?B;sVT&yu>v=fYcZGJgs0hU_%gQ(-xl=Z zhr*5csi+^n6c6Cnk|F#}fPO6*#4p8z__=5RKNR-i+x%X9mDi1D*&TS0(Sn(jdR$4c zVLZMJC)5SlC(UFAeP6f%twAc(_)1Xf8HM}}VaQw`gp{@Zu!w{YEDvwrMdBJiq^%1? zmTL$K-6K%pEk>=s4DBHr^hFvlDo(;KI+Q7Ma8#3za{cr;a$G}DgBnbD)xqv&=IZ1slS#skBzGy^~va+YhHJy1zW)#D!DW_=AYThq{LZ`!dQ>*g3Bf= zZY0%UCba?g)0^=)vyIL5=Q*8Bc1V7{$mzsq*&TSA)sBZ5EtpMh#I2-SOeIv}yxxN2 zssbi|o1+s!d~6C-z~)0w7*7cHWqV02>iuQt2+?9lWWtWPR2)*|;FPuq7YyaBZZbxw zZ$#G;t61E)p$uc1LL881V_R$r`Xdc!4OXGXPXcG4L0fzVN<2iYUyT8BbcAX#5NX6{ zOcH30_sKF@od*@!AfhmVR9nQ!47BPB)1i^ZZsPqxD_J|k62Wn?Lz7$u?Hrz?A$6Q7e9%Z)TQC2H+ zDSSJnj-{WEx3K)gr{Sms#?xL^nqYejGzgHh{?gd?NbSbSgrSTXp0jCscve6+9LTPStC70`jeC2eNO%gl?-5# zHIg}+BPz37n!)&RMpyh?c8PyP(`FkpsEMZ}w%=ckrjE1-f79UT;3%6=)V5+yK$w=qD0N}pKVn-cyPm0C?Q5?A}eyo$(&5$R;(3U8;c zCp5_uQQ;Lcud_7hk2JErk_;bGjwVPN`>Oq`ivh zE=OsNY(3MNhxRZ!r;yGf-q5+_v-!P@&M|bJ`L19iek|(8PelVvH_(}f&O~oKxpp1* zE?veA_KL!BjP2cr{adzRw6706EzM}CvZ1V~5V;vI{`DefwDJK1@;e%^{IH`TPT_@& ze=hEi1P%B`I_Kwu1de`wU-@JBy?(Aut~?he_hkUVLg^g;$>r+g+!sNEpXWh?uW-OnY@`pvnfl)*({>Q()kH7re-+=?Z5z86r zobk?uIhTtk*U{kThxz%)&u@dD&(ZH#j%$}(ejViJ41IDPUrFG9r-7gEWqtw-qD3Oa zL`NZ39P^tt`F(Jlw^t2Q9oz>aUtZ?#ph3lh36##BMbV8D$h~|J8E1DQ>BtBSyLu4( z!7>ECzZAajy!tl`{)n3f3q2Kg7U%fn-C5pOO>+hWP#XU!zB9jLJ+FJyfX3!nhvRsi zwNGi>m>tVyx(1`vI~ol^a%_w=U~60o4ytl-#$aKGx7+FUc#z$KXZfA@s;~#&7H`Cl zmVW$PI*4D&hVUy<`S5f4Tlp~f^lSMLekmKokCp*^U($zfihA)yK^Gq9w&PxA6KfhdgZ6ncZ43z!Aey5OJMPe!WJhVG(5F^4@|3l7$vOs0Y?x0#TVm{ zI+xASP)q_k!nLRil%c{m2A2*V7wpScOD(DcB#i$XMF!Tdyi;oa0mk%2I2m8W z+~c|e7Eip|DoMdWw26(aK1j~$DfEnV3L0bu#z4Q)^971u=?S8*KmS6opG_hi<4Io> z@g#}K9rf>ozL52e_&ugC1j*(;WftpOf3yj0VH(DR5-$-*KP0a4g?@zx)XUuk+xq3F zpJ4NgW$g{dBw(j3o$+?uRL17_PDTUfvYXl5Kc1HX3R67IKjkAi+9l6m>%TKXhhDW4 z(BS?Y%#5E!oKGCV9S>)r9M5HBA1ApTtX&r(RJ!_E$6s^6cud zQ*7PSIJzQqAerALO~rmyHje8GnGPN|m9u&$%~o7UsK9ws8Cxd=cW#QvKZskk1DL5F!rg{p+^ZkPqvlaOY1)jZjhpeLq94!7`|(*> zA3iJHh|fxT@U*BKj|)0*KerWkG8=I?E8B1~2Xu;|D5}eQ#;-EU0$sM)RCo-ZfR5P!4 z#JG1^_=BkR`cx#Z^+(cLKL%D4U~OLG%k=Wxja!2A-lk4LwZ8-{Au9An8n8K*)@CN# zA5Q9vS^r3mX}-y&{!%=x(>?M`P(SUuN{yNTDcirlbMkGI<|sYWH^dKGU&ITNE7H|7 z84b9f-GawVPj@hv!W2*Gl#lX1Uzg!JG=&Q9!2}*Q1d%-JF+$^F>#~r|C#_2Yh92a$ z;c;#Up5#$`?W}!%dz>Di{*qjGDTM!e_37*!iakZB^owQk-yLJbCRr+WX>xGLP=v9> za-2=IVKS=@Q@M?}QqYX+MQylI(t(?nPTVf*!tIJ4+_Cmzrg9@@s`@ZX09Wl0=IV#> zpm7r(HE+R_)~$Hfz8#-6jpAuu2Rh| zIQLZm1ism+ z#XD~=W5hQI|Fb~@0y-i@68!sLK472$0}j}Y1N&Vw)y!S{aiV&T`o+nBQW4B%m)p~|1z+EOQ+if;^=6^iN%n{#l6sP{us#5 zpI^r`XJHO7AeUdq!hZX!32(i*7Ud7dVVOCN!t2M7b8$b?Pj83$&=B<7JK_7@r|^1b z5!~Lkf5YIdlN(>Sali)%7V)rbdq zt$0@0i7!if@NH=yzAx*?kL82-nGVqvL-@ryj9>XwIf7rG(=bb?d_R;Au<}$7)kpQ- z$!frr)M|{I%W)#U2>aC8*eXp$e~byO;TqHi$x!ASg96V8WV(f-T&xv5j6Is2Lt1Do zvOL02=q*Bpe=O=k6zGW5V<6UyEwWVXRp;Qaz5rv!5}YxY;%s6$&Loy&%v_2i#v<(1 z%h(4crdvKA6_{AYrZVZ^#*FK*mDG zhG1m7ha%4-9EDzyu=qrw)Hj;(miSA4iYxXOv2@CFtZ$PbuP+Skz$Qr&lb3_qTsE%r z<}zGPvEf=qEpBHu;BHP6=5kwbKd%)J^6fO2*MiyHX57hcz>Um0Os7@jLQ)0e&ry9o zcB?Y6S(1$2XakzVRE)ROugL>P1^Y5;sX>Lm81*4?bVTYf6l=ydc^dX>a&RoZkkw6n zn@Fl)ZH?1GGNF|9`H(gjyObFiiAw~{A03Eoff6_a4K^m{vwl(ksGr1#UCK-x(&b^y zSj_6CHmE&v&zZ}Z9MHV)QDtFNnv9LnMzn^jQ5`5{GUV*0L3W53`cZ?tAfrirH{|1|!q={0P=Ne&(rwBvDM2XjdlNDi)~RkM7Qf44Fd!?B6z66w*a z5e5yuxc`Xtv0D_+kKs%Uw&av!SH2Agit2Ezv0|igli|y;nLv~7~gXUr?&3Kv7s&KOf5i$ zYY@_Tl;#qMRF^>PX%hwwP7Z8AL#PT}(FP1jld(gSjf19QoJ_T1BD)sTh0VBG+JPBs zFXpNT@TheQp0sVlvyScfykiGGs~g5=wZr(LW*A>q4dW}@FutlB#8=h-p zTHK9?1s%AX(~N8Bb-0jZWuWdpbqCANLm)QogO^flm`bf;>tZ^!nuTc{og~@P=3$3Co$0vFNc+A)>(tpzgI2L& zUN0sxJw-Z^t;@6;%w#t*{rtF~9Zw27KrXFQiocpx!}3vn(r>gbsm-SFmw*N#N_2_h zF+xD4G7HD!i!hOB#kKTW+|6#rgS>VI64~495NvNKHW3{WT68IeK?5Ou^k>EYIP>s1 zzi91$QQU*CEgSJ|Ssy#!{4{?adgJq3xAExOHQc>)30KdY!TBRcaCG->?AkPf;U4=d z3N_XWl;pqoFAAK|`Z`802LO=!kAMaofWWVh^K-_(W54(YJNdbMLhc^{7I1YqwoPHj z{t1PN&kLn-{C^o}F#G5icGKYc%-5K@@eJda?_=!j4IDUn5!-f+p?`QUT01wPs!)8i-@;fPqXRfl@AmTB(3m zt%6RYLA+LLC!G%QI-OHM!EucI@aupE-1iLL`j0gzpF59|JEu@^^$4;j_9As`D-!k( zK)a1h`id980uDUj0|kx-DTNmT2o{QSG|Ksg?yLA0YWrp79NYY}!j1<2 z%RqyL`t3MA$2^Yd6n4x*VaI%>zA>l^RiG;>9-GLp(B|NTu^1PUD{(cm4l}vUcu?4m zXC>YEvUDT9DeuR36$ALeI)oo9hw+nb7(d%ap3^T?n?Up{N7bA0bJZr6PWivL4zfDv zph(wKXY*QcBdZ>l(yEvde{4gqP<%d4n2K>Gu@vJeR*a`s;(Uq~r<2NYG@%&# z40+h9&cL8L9qp0?r=Y>@@r$Skh_eF|B0Dg#O_7d$+FTqbupqGvz zRp3;D1xF2q*rUnDs5}*YViQ^;wWtY}VW+KGaD1nC?nA;lKbRMw5nF>`xf3JX8Se;4 zvG_(aFog``>R=gagXN5 zF}Zm+rnm0Hwe1ISYv&Q%-F*ymdr#ou{!_T!IE-tVb-0<`fZI7uOom8~?&LP%QSUB% zacmr)AD_TyV;Asr>;j&gnq-Ih2d5`7clILgoxO zXYaEog7>Gd{BwD`dvRKjpZ%#t&*z-V(VQP7z`#_3^GOxBm}(p;Hvk##rVjX0ns&8pPyIh$+AR{0pjsWUM_J+b&fWjv0zr z8`m=Ga5uLF4+=W)xTp(Hio2M5zo4DT#?_2E)(^_RTb+$zNfOgXPC^{WW$n%UqwtE<|+(Q}IN`Nc*`9yIUZXpa%-0K81I5V^jEsc{r9> zit`y&n96U&O-mc@R`lRORX-lr4&n2To%phI7ryS=g>Slc;p>J`eABQQ-`0=f+uBX| zu68rNs~*9(wjq3D9b~}4XQe%OT-=G-{8n7gtOw2Gn90I)>1J6fdZLYNZ8`%D{%BrO zeZ6Ug$ngkcJS5;XeV)kA@s9jyu0fzRlHwAGWS0QkcXHF9+nB{WHvV13rW|!jvk=)NDmR< z-=z|MJwdP|e^SB^GY@blrrt z@o`L^IDwP<_hbLotr#8XM^9TT8mp^NUQ+b@+Xj4tbs>XRD2_Aie~-%n1$@_8Jwjjr zXTS@kbMc(P|3|o7n|xP@M~?BtYsWYW^XFipKGIEt`%nG`0uAom{{c56yz6v1lDtY+EzoS1YMuF&972f>!MR@an5-ny# zuP*TO{%3#&Z~eEoKtz2c5=G0gYHc7^uJOnJn7?sA-!=#g5xo{@zy|>Me!hXvHT8ot?SC*Vj4V zK+ZV`fe;cX=Y(>OWDr6DByt90V@%G;3SNC^hFufbF~9^E~xbcc1PG zZ>WCXZ@pDr^ubWo^$kCiCpA zf_h!covrg(({(bfMu(EhwKKL*pG?frnsKS7Ee%7WG_7B_%6pDf{`-TK@peBI4I3ZQ z9Jq4+f|C1>RA#pUD(F5`m3>BQ#=!Av95zXd$0TUYxHNq{FqigX~cOox-obtJjM^l^Vesp;qDs3``(SUM&_&BG>X=7904>OD#;O6o%P zZ|m|kih8M=NzuQ1S2l5NK_{TWr)|rW`F20$zB^FxyS(QJQ&(-DF`C*pOjG-fH8May zXaoP3_5ef}s>1h&n8b4>-G`~7*GTc)-bJfIw)6b*joKSuZ2Asg={pHJ-1u~F$mjmh zf9$H7r)6UjwQxj?<_(^x>HWf0*=v*mPEPL&4H`5hyK-!@K8noJ_R0C$ z7hj?yNfkPlQl;Z5)h6eBe|)KSOfJyJk=a@uo?^hFxq~LCu1}Z&YdQlB()tWj#EWlt zNE2RsTcpk+4W zFfPFJ>~{tz`So6kdHMa2ECMtr>oMHa*EDRBR)i&+zEU>*Kb>Bu3t2OCIcJuxIIR)>=+41fm>d9G#nWX&2dUUS0ZL)Lfe;$_wJ9;4XTShmoNXZK24^i@%#?i4f#XZK?E44q7?)xpGa zBLf>JWNCR=lIaKSLtg;s^4=R{Xo)V8z8BD7<$6x==JvSIU}nqq4;S z1z*lysjud)(${lV>Z_VX`l`B3Ust#3ZdI%9R@tLR#F@6kHgNu)tYVfhw+%uUELbb>}nulF>GR z^8B-o1LzOq2;g7R{eMOH(T=R8o-F!BMqN>rdVuESrKkx9+vh zocyl-bHM_8+}ShM`G4L#m?QqY*IclGW0xjf9a}p4^RC)rL4&iG@9Wh0yE=OMa~(W( zL%R=NRBp*qW#qOfF@3HkCDdwMRIx^m&CA=*f=N*mH90z3F_WSdJ84n}{<>xOk4KIe-oA%{A20}YUUvJiN^c%g$@K#&y0Ta7 zXR!UoDQ&)VR2xq1(~5&zwQ&0e&HZqxYL_;tc>Z){PAyY>agHK06MwLv!P7X%{(HVl zkiZ27{KwWo?=1JX&42EH*8e}}Pjk=M-@KtoFTbbcH+w7hy+NwzJyNpED6ma*^ok&iG<|GC5D{CT40$c#;}NPS%V;^(|lJx3Y<0T7|A=Ll8w8YTYQvuI_=cAi=Gp|-~qXjfd3_9T>O zZ$ha_d*X|Ab@T3!&;6nQ*j72m(7th4w4nv`FYh%{g&zzx(G8*6(~_KLXf!Xt^R?sC zwK+OhyW@*>D7iw%(`s}oqfVzYrsAg*V@QH?>O~WT?X;`AEmv$om=o<2QFsWSo6U$87w@%L2 zMjUr^Z$yldhpIlK4Lvg7>954sdxos*;r$1OcF0dN&PjN(k#A(+NJ^!l!-bp~x|};( zS8`{YoO9^J|J;W@tPD?4OQ7z#oq-0IuBf(em>C}yj*K;Wgx*2pqp8(8mo;5i^XBMQ zVS~ObY0^Ca%!-A2P|>PKm2JyaOtS_}P}7LXS{9z94N+Oz8ds?Osg*jOJx%8d=IC-sgKku`=yugY zeKlvL?#^AMZ|Ya;oBB1nSGPp>YM1Dn+Qs^&W|6+BYST9cJXm1f2Vayl89u?U^V!pl z{ve;|3c3Xy8J`$;4sHm&A!-+-d9J?!4TxMz0b~Jed8GqnFW>^PMbD zm_I39GX{(k;|_Yc0gxHM(Y|vt>WutC3*?w_1er!px5X6b!^li6!>JxV$>?`g@6r0Q zlSr%?BchBhqtoaY^4XPMQl~4=JZHxQ-p8SSfQRsjcME#CYMfUeW8;yOs*vM=TOZ>9 z;|JpiNHDYIUa6Q?R7 zx>TdWb2NB((su$H;LQ6Se)rsU_HF1tIr|>?oySnmxn*$tG=M;;dsvb{bb$p73}`TT zvO4W0H7c)X0qaAW0epWtHiiClQ@o#k5yc3jAABF(xm7pMNN#s$lH>-K;I?Z0USXGPWsi1zU z(rbzpTac-U^!R564RB@dJ+4sul1lYiTD4AQ*6D2a zbe*3vQx|h*>2ls|UCp1PYXx(4y`Ww<3g_uoQG-c$is$R|l16<2cu>}C48ptR3v{ny zfga}`aKJsci{_g$E?T2IwaPe|pW?hv$kgI7iE6|!8aQ4Ry+#Rei%WbMOQ;jf^pd?)u0~Z6?AXzF7N{%5^BEQb$s&bU3wA2U04uJF!$- zVhfBxyevFLO(SD9YjC96GD3fH@$}vUs_HXFGY3T&gL?VcWPKQ!rL8dqrVc~Dj5?jk znr>)#I%}Fv;3S!Tmdf^XNm!!hGpjOiyw;RY581yRtJW*#l@EfZg`I!~+n2180StPN zGC&Fr01j`{@X2Z!8KZ@xVoi=yz-%Hw4SfO(!9c9+JzC|xMwtX3s{4-7uC~yi!HFg7 z^+|ND>EG6vd_xat0$_7-)6S6n`$PY+xqO!48=wiar>{8h1qL)Y5VAR~sRibK=(jX1 zNgDz@-&R!0#i#wQ;FhFfvxN1E6|mkp}DufIcl8#nO^gGd4f1UUDB}xu=(L zrkvXTp_d3gyno;5C15@E8NG}~F9YL1)`?;>p8xHWuA>i_U_k`;`qLZ-bHu;PYu_hm z;L_iJ?12Ukbn3!g9Y6Dh4xhNClInHJFI%Ckf>xzuH7GWDx+Y96*O>9S8Zt8Vxt(vn z6Yo0v{$u~WcAo$?OmrPwj@@Vd&$;I=Ai#6(x&OF(&w=XEdyx4u0-GHM1q{9gXn^zY zI_`ew-#zyO1%430J$D^`Kb_ojw{DKz|J*YC$Np%7Q0J7_yJrve>(fVr2K3j^!Gkq& zxCa`rhXGLr(UFlRx&XicfFLO$UdagwN={5rN>ZZ9lamvbl$fBzgm?oUOr9LAsHlmG zoDgAvgHRC#L9Yi{nvi#HyS7|Cu8+F@M2;rms6$7t4I&&XdEo~#X#nff#)&xGqU15c#EiHutFV#M*aju0<- zUi=s}X67(&jxqRd6wK4j!Ukige_q^ZX83r4VqlXn-0ksK%+!@M>Sp0QV>sYoVK5y? zt}riUYZ&3s&KVLZ491dP!&N;xDx`6H{rpAceK162IL8CVY2L7CwT($I`xJaUDaVw% zFR9D`1xK0vYWj2azItJ2=&GBbO&F)ByP$EB!cRIFwXiPWM_Km#^3qg|ds7HbS0 zW=U|qFz~Dah#?Hk$N>(l1IdyI_EA_Ko?;w39ImzHGeY)n=jsiLeYJbg)Y=JXuyffO zHrwP;KUfmvB81GsRX3K0mI4U9t={PX=dO73Yc~F(irV*T@kXKM;EU(P7{5D zk2Z16hGajK-^XP$40r-f07&RtNzdWNu{*UVG-$9Wt?;Rhe)I&rX*c@gi_MI>>m1`y zb_N>c3>>5Am){GTZe6_=lAJR~O)@-$*T@+3N9F)GFnEzeWR#q93}Fmn69F?m%^3X{ z|3>$E4mVDwe*gQR^*ws{(8vffgU&vUvtYo&tZAlh>zwc$&IVw>ym1LZ>*6Ay0X*}f zJrcAwBHe&gIPLU@@dPLI`v48@oA7$i*}dg+cHQv{9-~jR5%2~1D(>OQ7Y_UP5orKu zfK!VjYk>m5RzO4QM!w05dJI!x_n}7C0TR~FoF9_byW3WpKD3RA*XjxB`ebshb|seT zNP3M<0|XV->qc3VKCfJ;uWH(Kf9@(htY4!?Cau+jsY~^+Ziyb&F44o9C3;xx0SEW1 z+H|*KfdQEBlr-vkVZ9kA(G{X#02%>%8JD0Tkz)rt`SfbY4t$G0>XULh00nvP4>6!3 z^n`{cbsyGFM`#at&>3j3ATHZPz*(mnCmGPpI-$HLc&`Gmk(>7hGykbo286?jM^BI~ z^aMTVEYe`^m>7?L9l*5`GbzCP$nV5ky#(~e*$0fHzBZ@6P$VVd$m%8cv)m6La!-Oc z34tB)wDmEL0JzQm0f7d$PnNRU>ttv~3|BrwMZghcr>;eLzu3P8dz1M$i z@A;N?+ZWnzDDqV_kJB5T%1$?v+lX;4EvAWw)u|%4fqTs zkqv$O4-XC+1ePbTrvdkHZ?Fghd(Arc*3q`-5qyrDz)uj|0wE86qL1#Q21TAME) z)rQmiwes*bweH-gc^@s;)a5N^KZES)6-p}0RaADe!V)Jv5d!abVl7bM=B|@%kNwWI z-%l;}YUet5As``a#){w|RltHo=P8*xA zJxQfHoK~r088teYRi{(gQ*|P%PM@XMXn%6Kw#OHlSu|$T7LJb7+@TY-B%?T#ePlM@ zn>xUATrj9HkT9tCB$nt%T9r;`O*Ii3L}!rb0309^PuI!CLV`qo#51`T$t z{ZI*S^bDF>OGAI!ZTIqZ#-U@m1yLo;7(!S2Nt>C?Be4nOig79CKl;xsY5mZNUev*W zaN|4z9*{Z%4Gu3_ZOW#+wG+}!q8<#-(;sdLNzXs@9~(-hY4+d=nm%xx>03pgQSG3? z$=&-yHV2u2F3^ZRZJIR20B!Iby&x(FexnQI7jglMrW%<*HjokMfy`KEh_3;J`sED{ zQ_QO$1WlcR26M*57#XIW$QZH)C;%V`Xhswf?V`c;45t+oSzv}fKQxWWDGh2ZhkMI!RigleSeTCpM713CL>aWdf_2JF**Ca zl=mK`(q1FXJsW2?hNSi0#jDI1ym)M)>C@(zJndoW6|>^-w0NFwl{M*$%7rwYRa9GT z*R=z|ol+n;g%&C9u0@NN7Afw*p%C1iVnvEOMT)z7TU>%u+zC!`g5=Nh{^L8?I~iji z?HtU^HP^M)-EJ^b;vB`2-Y!RouUGpqp#IaE(qe4Xt;qyZLQxyIbUjT1D3U9C> zt?Ey1VrM$_vFYhLW#ie=Ue~~L34F>AUzQKB*8xUep0ZLZieTKh0s(%^ur}!MMOgE1 z*0pCMGi+-I_v(gjfi|j>>nM0?zgfjQG_@p+$ zZb9G>C!~ODC)@3582&=F110I*6Rm_7REvw*64doW@;Iu29dcYK3F{N?748@Fnpj-S zpIhy@jq7gn)xGWRuIMoFFRtmi`(Wb#9Nyh|+4dKd1dHKvTASV%ayp!7qH1@$Zg(HFK^No|iPF4m3KWiU|e2w}9tNxwncF%ejHWQ2l}GBqbLdC@~hkLBTHd&S=t$OV+* z-bgh&Yr4IY>KGz_IbtXE(d>_11BH2ukmA9(ZX|3j4Q@ZMBLB9gI?xFU7+gUI8t$(J zI?(i#4nIw{@8?LIVdAV@a>@WPxm{>HafucmZ-B#0Ju@eg`^X1wfpjbTkAoV>y?6;d zs)#m&_?}gy-xRs+w7DgmZSi!*hb>I{*}49%HQTGe-gfxW_gkqU5;+kQo3yq4Jt@7c zamUi?M=2}cw(ENh4FPG{_g|8tMWbS3rgoI4GC?9T#M{3}$pk+iJ8#U7*Wps8tV=pb zhyEgThHX6AFWp{SowU1E``h-nllV3s_mVX^7?p|~rIlF^`;iK&YFiuGM#4}Rhh0SP zYf9w@S?v0qs&4<*UY|gtzM}?O>tWIs`C5Cq08uMY8S^_Q!D=)xISN%J@~5Q?O$Rut zskGSSj;hds`^`t1$;vsI?7J{?H?9U-IhHXh+N$D=0-4ZD%y>{Jz9x`4`-!Oe_ny7U zmy7~zh~Y?HF&ny@Dq^T${2<#F&ffLeH|c#CO1EIrI628IxAB68-&$L3o)q7E zS9n4jTiLHLzCP$ULK}m(V^QYC-ztC*L2^gT)|8anS4sIoN8cAzm4v3qV)|eFeiC+( z`>|oTfR80Ku~|L8`)b*{7V^CSlYm5v%J{wDf_f$4({STA^Z<>(O17VTk3|}DPXnOA zui(^v+IMqEOT^Hjda1Zk$pl*SR{!{OleM!8%S(q_aRCRY;PuR2L_S1Y9~_(B#YZiD zY|T7Mf)g31+fOACQevPht4KK;IY^Nal5jqo^@@`W9y2yG@1|{?-YhW>bWeDa_|oJf zn~CXw7xQ96&pS^G{#2wW)7A&s0a8S89x?E#O5HN0Q5u;VN|VRBU8K0%VkIp6`K1VX zhT4b@+Taq>@`&sY3Y~HD{^g%GvN6dAvhG^r$xL!@ouvp;mcHD-l7Upv>a-kajTi2# zi))Ca41#Xt^^=`Qg+KxCRABF^Jbsf$!}Rbr5xnG?~+VI3Oyoi@$gImw9$qVA?@wM?Qy2)rO zKv2^<+RQgNRq&FLBE~b6AnP@%A%=}=e@yNGZh~=Y>Vn|v*}v-5sl&kKlX5HO#?1oe#fV_9{>)Z_oBeiS3w#DZ$uiaPNZ}``72Uo0%^x` zQtWa|@jht3uO=%Y2P^AD@5RMyVYbDM3*`%J1AVr-#P%ugt?)KizH_Wi(J5Hj-nUx5 zBPStF`)qo%uKz8yW^Y!!>BnA$K$oUU!+U;TtkElR3A3?%Z|N_V0w4Vi_XAJ219C0I zOQ}bSdWLxX(N$mVQ!kxMJ^FMa{%pfxinY&>GA?e(i`+~h@ewFF+@?ne+WBB^{2;Bx z)l(6bwl;OQ-tG9|w~DiUzsgzqQL>4@NnH&@Xv62ipzAx_gRZz|Mwen0o@JGxe^zg4 z6U3Up>$XOPY(|5rDj!eZ#X1#=os+B;w#436S!^|#`+fCRMD09QXXp7cf`-x^k1QMtj#YlZYWjz^vO0Fr({Q**mXnn zggTJiG??R;Ni#0lqQxz(?};r+uxWf(*A06R%I(trkWu8bcRUBy#vU0_ZJR;0FI`aZ zDqh_aE>5YGZrK;D`yA1ndi? z^Bsv+Q+KF0OL)+H&UQ!eA+5UTt%mQhb6~Ao3;VM1h3PH4FIaQ`*@gprej9j`1|LLR zEEt7gaCRNL>hjm$-d}$0E)uYC3ENA^u57Nu{!E%!O<3eMrVs?e5_|Dgtr3Mw{zW3D zpBaGBNs-=lOyC*Qv{w^DuD0P0gaSGh)&PZes-C5w^@d9S=u6uj-$O@I|MJ%Z>Ah3d z!+?p13@tN@{<`P^y*_ZZ0Mmdlu?->Zlzz8=z((z`D@(jzr@X)bI2sSckx+!kLa4Zk zO4Yfe+?bs9Of1Wj{2r+87vWk-rKqZ7(Erj%+;7a)P?99?ro#nRc2lKilge$XY0+yo zH)urRsq`t1f^;dWRq+!w|=uOwYju$F9`{8OqUD@`iu8` zq8m2>#~R?}ncCV}hO|ZcDud?p1i5&3E5|DMBdFtX30@OpfDi!mS&gigL2}A%B23UZ zpfvTt#S2C^KsCVH@EJ5RTK_)oU0nwx+@qz6+eCY@$E%5eQ@@DtvOF$W-bh?y3v_Pd zZJs;7t7|`(g2OS%Ikz>&V4-U9ae>*|UdJz@;X$2kX7ab6-qC;UR5KW2Z3UZtbQkLv zmz=hl)eTTIPb6pX97{}t;u?yQ;_BAFrC40-rF41}^}J$lF49{0K4ro^I25w4sRQ!y zRgfArHODjJ>Cd>f!k`QlEHaQP?wVNub+S6&YWddZYi&?s@Z7pe4Y;gfI-rWK2n&Ha zK=&%Yl9y08EFYD8zE1)1yxdd5Dz_>Nd;wH_)FiMl9!HxITQ&gh$pBB&wM0{cCUdpz&LA1<>f)KfM=R0Anzxct3;y9|c+ zfmv2X#bqRvvL>)tC&$)M68`34G7~c=JxLBJCmVaO%kBN{Iu%J!cD~^yD4iqERuU?ZN3W=pjn?k5wN$f!CHn0w2``PdhX!Kt}HD-}0$CJLYYLS5-_>%CAA zm}^0fRy#<>{-1_-MP@haLwlVfhPpBQeN{iy5Hghyc5Ht)S}d78R`^po@$uc|TeX}v z>EiDV-;+&>e>D2Z5B`uK3EKG2?k{Y5=JZq}Wf>U|+pNML5fI;+mbHg`4Kc9k4L^)e z&u_TTAq>lfNXhRn3U@HVka;ZxT`*7w+Phw2y5H>ZWuYx_e%sV)+1^S2ztqNKxxdc8 zyJE#5LO6Gvh!IIsytj^)H8hQuwX2_=`Jnn6*(Ma$P(Hw-lv7lj4U77RLq}!ZJpv^K zOQ-Zb0JpA;5qe$Ap7m=7G{r4G>d+&)FgCMgUbVGWX=1j$W-hhbywC1A+C7(}ZFIse zXZwqgelf8dsf9Uj8>?_Qm)=9$jnwmADSUwr@eu(RlETFy2=j?QDhNWo^|6^;Mm#^5 zAmkA6?K}yAASkK-qiL{24GpMTuhF?sl9YR$7nWabE_;#xkmhD z?-*<^-Ow>p{Lfgf8P>OSQx5=&`EMe*~%dMB&`P=D+IC3=SvVVG?J1d9Bp3PiH zMk38719fpFwxiOxxh!Jw4_)KF9{>llhzz>pdm|#lLX*;NC~Z@bQO8TORKxTxylfVr zSchF7p0!x|{qHEVfu>b`9ES+-tw68v@3H}+-%<2tubZfXeibd@+rd!MWsN{yWc+>S zK;b^k3%uTVjEs{a0RYd3GQuK~QanZs8=`m36~FyY9h5sZg;)4Kq6h)d0C+CbfG`&q zz^5p`UZRlwb5c_j#b63LJf>{SYU76mA#2B{lS)U9zO_~ju0TzSlPShbE zn>U5{B4JGN6ppflO2VD6x9y5liMWwyX1Jpx~3iXcIwAF;}%7 zb+p8`(x~h%0H8FmP+}2}ShT(-IBt>t1-giw0!4C&{4RYU49gTJQ8$(xCTSwM?xl0j5&Xb)@}}i6^44f>;W_?oxzP0t z!P+`3nFd!?&JfVsVj&Ef5>jET#yrZy-k!|0gKyp>_=tEOHEc7U(Yii;}LC6(tt3{4~E=5 z5!mX_zYl-^?CVIe^NeWkS{Mc5x0Bd%OFOhLHr$#vP%z{NX8~}1u4xL5{V|ZSU=+wD z$Btb3obF+H`fr;7(_nQdf_?B=bj8NVrMGLMt_KNNm{^y&ow4Cq2)qJNpF_}6X|%%ZiAPR ze_zC8ujQ4bqflb+@7^q#n_V$pcMs>E2VzUc4GSe=3d`p|gII)#I)|{Q7&phVAV-N5 zd$iPAvEs%hL6~y1wGJql=tcW>n})0Gxi!mg;^3Wly+P+|Wd0LrFUJ)0F7bL@L~VS0 z@4Djzk*OZ257u96wT>F=Bq(u}eaDT$GMgpv;5wjmD{Ffh_fI(mWh2NnC3_cDm>huZ zLAHoWdX+4&Kkr(gexzsKYpMh#>ye4r9%s+M*B;z(!L&*ay3cM-l9;6#}Wd^fKUIMLY4-q^y9 zem?NseknNF3_R_Y?rI45qa>`{mxP&#FEGK}Sz0BGcaH7@yjv{B25p}&PQ;>+(I*VC z5O9gwG5R|+qVVm)+K7@R&i7UOFc`ye-N!ow;(AUf1C&( z3{eqqi{jHwp=6Ww0^Ix1328$y65ds!eDy*eY7Ep5=Q;-xCHO$a26(R0;Er1>3JC7K z{1)L{m;g5Oup}Y(FRv(eB8g3T$GIq1IB(wO?o3Cq8az`ev|Lc4O#eqD04URk3INi9 zH{=}XV*qVKu;hl7x)P%yI?)hGX|`;oY+3j2ZQk4s)4px}y`Ulx)~CqS6kFTjyO^<8 z&O@&vmy@{uj|Ff?T@3daD(yHPDY7#4a}NUTd=JBWr|ll*tCkY{PD9#$C-s(igSS2g z_KvPAN zxog(vJ2b}8mm}}TdBd+#EP?c`@lP`$=r@wL`chybJS>--ZBsjquAe!yPjs(udgfiydFsR?q@+VV*UyRuRbGm3Z0rYKyFG2y z1Wch&yA&|nJ8fFIk=fgijS7|)~YJvYMbaU?rKZl{>tQ-YoqKhGJ$)D8` z_cMXent+=G`1mBkUNdqX^8A#DaT<8zHC=JWc2Ko85)k<9t8YR|950xHq_lWjyV1uy zLNYt0D8b_5O4%V7g+NekLVyajo`RCW-%t@s>Te1cgIqH;&g?)!0`M35{Inzw5>>19_QfZ@08-ogrz3B0517rg@3LIQt zVij*h=$ZQgMR>m^MBfL2KqsdTHV7aN2oeS*0gC=fDhOHSy^ifvJQMepmS@6}*8h_JR z1zgaEdmG=mFeQ`_t|w`JzGQiidm{e#!Ws&AdB;^Yb;kEq4D|Ho68|iYPoH~GI2rT= zO=TgJ4S4#Z){&2Uf(8hZBPSt(jJK3y z)~GHnUTk=WIi4SVg!hU{m~?V0yLIAQ9_J8yeb|^@WNNk`l#Cp$VTzW<`U&+Y1_eKT z%G&y2`4q_|Y@FDiTQ;JIu1T^{M;W7r0p+fNm{-9(e}K|mEKI$8SAc!eHhDVL*U@n- z*upKjs-Ced^;78Qe?((q)u33pfSq2&0h=!q6g94Xt|6N=+alZh7BumE7Oaz()c*Ng z!k5sDD8Rs_!Jo=)r}@>d;qU<{1!bLc7&_L<dYGjQ*%1idheDNsVpQ;Ig1M0?DMsmaFDjn`T2PBk!5beu`p_}nJsCx+ z;o!%9XUmL#Ik)If|6m7Qd6g@uYbd;oDssDtZm05fUZ!8;%r_;_O;`vw0MC75hxOt= zB)uM6yW<27xqu4`W_mJ@JiDI7HYUDjeW=7Djy}9 zw8D#Lz9(wmsOASBVR<5X!pDx=fQ5V%h^I~oE{;3oI0Wt4q9@cDCB(FC85#HEqTP+U zBOa>bdpN)wrNI4XE^_f?0)aO$ z>5tpiW%k5pU!dK#LvkITr|-;sM81RttXV__thtpTuc&}|i`syjKKiGtu4kr;AaEF6 z&y-Q%>Rb%36N;69^cK@OJ&~$Of zuj72gn8(gRiFI!o)R1vloW;tqupg+SVbR3&9Bo^AgWsIrlpTfBG6*eZhBKbC5C`}~xJKAm9q6AHIPmDzU*J4GMHs2pN z2SITFLQvGRz8(`;7gPj zn~jCI!oLLje;efP$Y;95Au2;h`NU)J^yo=w!kmO3@ zcmaE9LDcvT!)k%uBkBiTLVurPmSBkxwwpHPu%=6 zH&ZyXg-enn2@avBMoVp04T4oBrE@B2=~g&yHWQj^@@-!)+`ea|&i9!?a&$fC*8?4b z!_I*GFgz9)gquuIb@mrzUA=#2o9n&i%dTg7Sv}%<;Pe2#5om=g$x-1QlhizSb-lsa zg;0GmY-*NRGQEy4`rPP{O!-;I9)7HI`6j%xe`y~{;Kv$mQHk}RSTWv|ZIc5u{4tf_u}5 z3kw-YNr?+!*d(1V1+=tCn4_?O-I=|{7#0c%ye8`OBc|v1!6*4B*MVKv_{rTX7wwYk zkL^zWkD1l}cV9WHef4d0x_=bKn9O#kn%Ez$AUgJsXk&pFiGrJ?lLMJlh=p zOO~1v3w%&yvRs2`{)ZhLEiSKgEkI767M}KR?oHbe#w~{b&6eF#NPGnLE84kOrn8%# z+g*X53U6JW3Ma9+u4zw$F;O-)!adaucEv?7BKt-9Izvs*n#PBOuU^d@3gDp$}A_eD1jBF8~XE$ zEXdK+4)%SG;^&~vddd5BO9PQ-GOEUoztLdsKpU0V=s@lJ#xklb+>u>ZiFF}y>~l^w zuhIU6%@L0MqY9OKMWuB6Nu$)L&te6@ci7WiEYHpjJK6yJJD zAYoA=h2A8O={l|j+6^N-WOchsZA`Dfzf^&vD!)#R4Db(3uxf!Sp5UAZ30H)M;BRiw zH1g-Yx6p2tWl-@G7s?~OPF-8XBI#kgPv3VfQJ-YB8TW2Xiy)pOevSUT9{>-H?I+ys zReW(B+OVJ{xLNm9kL_c+GcDJDPMYk)2s~e3rcO~K#*K@ui5uhgi%dJFxLBmX5oS)L zHFEGbnl4VCtddkFx4cRo24KpydYN3*@`j1O@`bGqlu;M#(_#%Ad*)2ki*@K{5@BW3 z=;ix<7aXCVJ#K+m=1JaqAa3V(`8onxz7)7*tNniY(C~6LiwC_85F57MYyuw(-1i%qW z3~+4-F2svzJ*ARK1vEC?{)u0q|16py_yi-)}gT!a$Cq(LRTDu3&-lYYm zOkTV=Y*0bpWINfE6zmK;J74!Fq-UPBdKeVB<`MLH+9nyidBTk%FrDmH$XST=`&&ct zD({FHwX&YQAE+ad&(VJ#7ngu!V#3!2(Rao2sN@w;u_;`30Ti-iUd#pBoy;I@ZyTQH zUX80@WjuR>I|$0tKCTu9zZaH^OAZ(q6v_sF+>&1v_tnvz$ewPqP=p+B1e~n587&L? zR}$*hOxMd-*=6e1P(YgAaE{$kAXUtO%)l zsa_eI>jzu22j?^vB1i684O!pDzQp8~M#RvklNHa2W5-&vnE(!x1~pvrz_PZu(N97} z`fo@Z_}}!ve+Gw6WZz9>BmSr8N0r?ZBRe7s6sO0FXY>y_KFH~@!>Sn?_FJ)&Q#U7X z>JEf|mPN~isUr?#yf`k8?DW1N2xD{8VthLEpPAWL5Y>%g=N=k{=Xt@O@D*&<8XwCF#s4fgRyh#*HqWS z*EF`$XoZA&&ArB$OiLTrgjYgbo|n?0?}I?-fURJ|j+yJ{B<+$<=yRV<3`_BoOFK~%TIz5-2>q)sro)@V*D`Ei>EJ= z<77%mDFx$7>UuEPWFi5v#1Bqj%LmxJ?SryO$NLrggSyObJ7w%M0~*^ns(ClXIxr>c zIQ5IRuFi~-^~T-L|HPB4>p8O^fBfLFf4h%GY0QPZtRG**$cs2+Vk3`W?bQ2YOdc$k zV_5X`I=*cHaURvo(XUTQQp!Z4MqKsRVM{<*RvR-;o8#eAEt^n7^|AhxP0D+p1pc3` z3s|Jrlxw-d%>M#evp$;hZ&BC!6$PfV#_<0A6)Nh&OQ|o}S07#LHA4WiwN+SF%I?7K z1{O|{!|@Yh#V`MSi?#dpYr-o&dzBskTs*M3;E7n!M}>94gL;SP%c{bn7kv}2J;m$4 zhyqrB{fVTaUdcCE<`<0u-I~6O+5BB^!D3TD%j8EL{i5nLe$ev_o#o&2+!|Ky3JNf@ zUw9r2AhHjA^U;4um)i(Sp4@WwyTFa1KKXasow)4w#n3+^{BSr$-nX3?4u|#;pYwW! znVODINN|g3XwT0hxqE-?FD&6I-=pqyft?qkxsdi9cdXU?Ud*)2x)OO=l51iZszj++@OM@^|Vc6e=tUU%H;P$o=t* zO?02!j^5>dW80}PGC@5vv!wiMZ5W|=j`LRt&g)RP@iT9qv**4i=PVT=Xv39YMiN)W z=luJ}U_JL<9s8nZ7lm7r_;QFK29+BW9Y`tO?y61byaIi)Uw|Z7;pkSwCc<&s1D-26 zb3}h?D-s+HbxSODImSrdyL8R7o0QD&G0jb06yoDtUZf;u+Ic7^#74mY^mjSWr6P!T zAsF**Of3Len~8hE11TxZjogl>`YDW1I8!@G)*PKnj@GUJ z^qe#*l}sU-fGh;>FZxe#oFS~Cy@U*{`4=Xm>#zgtSalEZv2LeXxcjcVu zg?RBC-dYa^0acFIh@XU|PaW0-4{o3EAGJxZ;3UO8w~9HUo%7L6ZR->S5ZbZfriBm* z3k2gC4mH*_qDJ9r#{P1@93H{uQtJBtLC1nqpG^F^>5e?J4X9yNO|Dg zhZ1T!f*Ja0C{t7R0VBeGUXy{+yb)}eq@y+l9YE$2%5Ud$uW)E4e$GTcW{Bz<*2Gxh zw}1Zoqk?q2-FU9@2>J0@(u6$b2*MQD9KWx=usKF~qRh5HFyB&7=J%!gZ>Ou{$JF^+ z1);YpR7|_+;Ajot!0L13d;io=HbIfN4t{##8bYI#;~%29xPPNY7ZV%qBL=1Ajc;Z~4Kv%kYenm%K0Y0WZ#(1pR`63^V?rzWYoBB%Uo}DA4@Hrrg<&FVKlMpOHWxJ z@qA(lYz||XA#V}aDDhbq^3pQG18qV1V9o4u-Sw$<$A7 z05l`cO&%mRE}R4tP&p;Lh+gDzRah?|!Cq|<8GP)aXJ1>v#rG!rmd%4r^DcpfPXFC= zKG5eYZEK??b$Bi`^{8=bI>`piHktfQ7mRbpA%U{%WrF4_^{NB887C9Xf84jIa@e5T zX3(nJN&2PA=VDg!HLZjmN%!Gh6Ps(Tn(rnL#*G&$QU{E?uh^~zZxWDGFU#=UlE7#9 zH?{}by{EWGSryAn*Emlqab7qtr@rGR?c`?Zu9$dpw7t`oWT33|H{j0Tcl0&w*k3S~ z_V;uLbdH6NeFM}*xN}wTsWa!b7x{ffSwhzvaD0Ear}k6hjuI{|qv?|va`)>o+Z?F? z)j`7Jh2R{q##K40%K7?c9fA4DxvNad@1&%x%zWC)|Nec=1>Ga()vJNWwA*+c`_C2& z`p7I4mvZqj5{(GWK4#gor6%;@&9Iu_lBwqUZ)A$KZPPQ0bi$Agn83+Wps|5R?(D#L zWTV}aI>+a3iS%3WK55DgbGQ2?C#Tay%92$g#XqEdn!)g3)gRAE@*D60^xgL1p&?u-{G(8Mr^ z&P{HC*zW@GzbYX1@Z)Tl?-x4Qej1oqdA8*Dd5u$2R1MVqvx`%jsxNb|ikg@`RM!72 zz^XEeg2(g&EaMeIsW1p0fGT|=#0xA}3f*z?|Nd_cuzLfV?shO6s8te(jn+E4d#ybg z`OkYP>2u*~#wXDfA+^C6>mya$F3yi*3&n>_MpaHzbLG}XKkcTAFYZNkKh(^GH@LGq zw-eYb*g5-zdz7Tu*?*`LWPW*=e241zbyVoS6gzw=VhVW(#}maT(IlhNWN$wAZkKq@ zw6U4E3#Qd-hbi(o+-obfitch-<4l!xCbtoXW~froF^tIu*ZSy#YghI6aiNnS z&c=hwa&#skEjm)Qy};8@CUH-Gn{ooHIZ!)vfTq&zkBcfh@3j_lv|E;Nq(`a=-JiXT zvQ&t$id<8zPJnDVS;K^{VG>ycvmJ`GtX_5|_s!t%%->0r(~na;G)Y}fXWJQMc)#kf zOW36=-VDLRK32WHc=cBMh{-AomKj&q1{db+F^Z6#N@<><^9u2MMJ_ki%jbnjxLG{v zcIQZPf#K-{!#yMPc z?utD{p270fvJKkZKjjr;w;?-el=aH5Um#~UPVr&%K4-S~YtmhN6z~5}PzShEqw0F_07n-? z{2XtR-ZK1wq0?8VeOR)}@NHcQQt-bJFsVqlhy<1Z$>q}{Sd8B z2muKzCJodP9FogdEzKz8I?i;uX`G9~ZX+Io2}_!~{bA1M(a+3g1I3|~mVym+gi|kl zp`r9{tQ44(ez!BrG*M7j%sk2Cao+8+t^wOwT@sWb{GyxNI@vAcl`G0hC<)QYbL{Y! zg6Pm)GxnUPJ%H&ZrxZtQ)4oe1@`?SgZWA8zN&=nyZzS*>6E$GiPl>jcS^vflam7PD z1G)`pm#K|0RnFI$M(AHDro^beG8jrXsmT{Qd*?-GH->anXU?m<`F+2rkdhgJN$rP( z1xC}{w;x521ZpNYw9B{AceHe=(X2~{%cwj&E-sVLKeK#fBqcAoX!gesbsC?e9S>4R z(=*)Ej){Ms{tigAAJc6%P-(#s-rDGb0`$c*<@R6WRI6D3`P0nUjv*GUn{2+E%c%k!nxlo@JmYq4&%#9qe1v!)}l! zwNG(Nx&PdS=aAC3d(CxpT)uv=n6z$(2pQDE7-f4_8^1>sW*i{YNL>-v*f!*)^ANA6 z_=<;h-DCObw>Egd+`s*_Hkr?E{QE^bA09(7@B^;DDsQ_kFZ!Taj zmtu#JpvyW13VgUB8SW7`yP#SnMR;%(cP`h^@Rxyvb!H+I?Tqy*$<&qRFNXD(zUk$U zA6P936f0oj+Q7iW)H&5)s7O#qrZv|mp(AsvkC7E|{j377hGgqoj zbciPT$?>;VvQ~9uHT$?k082Kk92Zu>MqdJ@mEzZFcPgbRBNrp){QRy(@tOF$nKXM4 zyAVf=YO+)t!fmXf0`RMlugUsD^ZcKkbkVXH(Vtm@4l1lu1d0)l?oIqnS7FTO822H% z=Xh&<@4P6!?hjFkN0vZW```kvyZ+}Xn_iWcm6%`IBuYe2DVl9sTAYyA%8pqk%;&q{>RX2 z<4m)qua7S4e}XDaYzQfB#32WGG`ZmuoF^Nk7R5BlQ>3~~`BWAh7eOlp%rJ~b#;^EY z&#w!5VRwW7?%^zQTT(Bs9$wc$#Ro5AF<~!6Eg?DZ{Fu2{-~lfzjw$9Z;8BP>`e%j? zT8`4Jn-3V+nVI#dy!HowB|XsAG@t;AdTjU-&+l#_(7Q77Zt=a<%LPT6+!fKYpPBJz ztV>7pp6pOA_rzz{XTK){%d79V@wXGUyzY=e+Ot&?i#1kQjDLb(=0{5}*v0C_Lf)@4 z(`cJS;EP>-ed%V9_LNqUZtyM3Rf%J@<3F!4eaiuAOn!iHYjLEI^Wk$Gm2qR=92@fX zmk$}=E%pJIdMrAc{T>tNYYcz>!6gH)RqB^lm4DC*=+-aX5Uro|aiCeB$ZfdwqiaLQ zb$EVYbuAMER3YmQu^l{ZyuFtdL$-v~F#6!k1sH|Z=T+3%j7()M&ePj68*d&uQO z*5YOJfsK>L&d~N9MgjhsBur`|SLpo*^q$Z&(Gw#Ma+f|ppvY;PZyufL-K$^>;jIGX zpwaai4!_IjzlEv4_jHu}E+}Eu@yHM$uO4L!nRNcEXotV@rRc2GW;32nl;^VZoT+K_ zz6k_7jw7ZElLF^DvjcUEE~I{XO-nt~%K&>rHG8FP7RE2ac!1Z_cLkIbR6p}>DXmi( z9*x!$*K#qAZF;A}jDKAD3Lpx0GuUrT)G8-TmYC-r%c&sUU%Dq!Cue>piHI7Dt0>}@ z9x1Ky(~MQj^sR`}3|(LR^47lA?{lZ&%Kka?#?8GOx!;U!|L8NM!D)_Tc7JB+YWM0- zyO>+_>4f1@Zg+0oZ^ItGrcXllz-7>-KO_56hG+(OXO148h~kpHsoCO((o) z&QJU$Pt8a$VGSDSg)R~GH8}E|mwz&iGE>%`&E}k1q~XflTRo@o*9fIZ<0bQLV7#LN z$9i5#4h*&a;NW+1y)q(Xm z&SXzUlPaM#*FvZW+m*`%jznh1g|AAAhQzFA;LQax7&?YypP;rH!p( zdg!3}ikGp$U`BkEn>Sm>uDXD4i1+q%xLR=XLj(l^bvyC<-6B6ZfL#toMZvr1%cF)BvLfDShQzueA0^0jjoFBbaTlk9I#uqIH72$CNMWawu zO5SE^s)01qXoS+rf*Cs&ObR~XizZSe2@a~3WdmE=4ufzcgj*WrJSdQW6#tHQmhgVN zipB^`*ux8srB;C1Hm7m9<}yI!h4udc0YU!0Unq|@!Y^AFd9eCu?=#isyr+zARy97+ zKV&&neb3y#z&nR_`o|vhpYeuq&V85o`EL2^&*68lgbaA8y2E>cF%?;G$5Utuy=fbK z_uCfm3cme_D1+bMx@{7m!J}KZyl8`K*JPp%*xTUD8C^VfOs5VW)S;a_wPW*UZCtxn z%N8wCV|~4*)z+xAs8HD%8SPH2b!ML>w@z=UoU%gw_ie9Rpuo+4sGvbteRaVCdpx6I zk38UDm-&*ynM?O|>cU;Q%M^AWyr^xvz5NZ=eYCe7IEad?()g$njUJb)VPn$u@Bj9u z{_S60)xZ4nOZw-3`i&wcCMYa?l7^3p=&&Eb|7p;`1snXc+s}LME=Siz;1we`;*sn` zxbQdHG4Gf9X!`%wipu|~mV$rLtn~k;|Bt=*?5^WD)`k5K?zi{Ly?5C@+44DZlqE~D zl9gpkRAiLIAc~n{5_14E!3+XK&N*j*$T{bnGe82&Ifv(6Pw!nDy$2f`07=QdJ_l>n z>M%W3)lXITOciEkyKZ?Fht@nZ<)i_FR|$Ndb}0e$WRnKQAez5|@XsI3#J_wpM?FQL zerl141Nrp?{&K>M1?p!P)khH3_Y7t}wWPsR@zCdMOc<~|QPN=EYwzOQH$TAgcc)>^ zUp~X8k7vQ*i?4BD&O#iYw+yZeSHWk=_Xu3E2_fHYLD;Ho2w%MoVXL+xc;#mJFIx}K zMQh+Pe+7wEsPDsBg#!kv&)xEqqDO15tWrQ&*EvKn{E zHy-D`V=&?wg(3F{#gBZ+-y|~#-OgrtCqpsl7Ov!-^%|9TEg%UugG};7*1gblE15ig zJs=5J{1Y)MGa6?+A~EC^ZjyU4RL!Z^h4VJ)Kt0AI8ApBlPKKi2byPpj=bTpzF8IVL zOsFF<;oJoi>PljpSQ&LBo}4G22q89{J7rK7Wr}=bNqvbK@#}O7M2AxV+K&05<)|;3 zj`*PQus0eGd!g>2r=nU%57aoiqxyi6+)#bM7LAVMc_i`>e&pSB#2d{=ebIW%4{gW& zl@8R!yQ+MF^4GwL*1 z;(4?KZ9+YnbQ3)<`o!7QQ(q6d-FcpAJ(!btX5SRMvlLvWB2U(Xas6?<(nsm5^jU=s zlZS5M%HLSh_rwOHKAiyFr-?ab+$V));6Ydh9)@TBphOvzMVX^^PgU!Tx?T250P&>G zY7Lp!4{c39Y(H+jF6gsd8#;*}bM0^qaV_y&@({Zd8`+O2kC@U&xep4l&3^hX@un|Q zFP=xAA+fIT^^R3~%U(L_>#54O70%|lKMu}Q!HqsaKjYrRHA$a0?JcH#MPYc{U#)TC zW0TCsIhOdzK0rR?M;v8e*Y{0gMH>o+v?=Q*EE6nPa=j2Y6OK{JkI9E^YdlT7c+|cU0b}{X`~9l4;K}Ujxk7M%rKYgHb;*Jsl|X zvoFuIH;N2dCu8Jk*F~Fqq;@@)>j`aXWqa`ft&}mgO8SA(7r3UlpUVCwdyaA6mwO9+ z&-sZY45VbzK!4ic`tUF=4Gv(fgQ0T|F)(r;eP`~Xcjz{{`mck( zrqI-W9<@!UQC`!lK8z@dgH1d9ux_(ER(*d0OIIDj!lipLcj0!-nY$6wXRpDA&3mwV z-8L*+x#0&(8psm{dLn>z>cU@ax4mzF-Ah7p;cp((mEBVgvkFZbHDyP4HW>5kAY;!+r4@I4@j@qw|(x z|D1(zm_Bz>Ndw}c+l}=tpMQznvlrmt+$A{i?J9V#SdXB!+Yq&R50V@XBg;P&Md2~1 zj7dU6Vmew=v(c5AhhCp(^!Y|(z%K?vzR?);jmD6VDUmSf9f?7&2n={cV9?WCdPQK! zD+*`4qcP$ei*tT)xEPRt%Rx!F7My|`p{ckPmWDeK>9`w_fqRje7GnE$c)B`%JtP%Z zgOhPNFcB95;uW6}pBTlL{D-_EEp*yD3d24odFTDd%DWwIk|(n6Yci<^W!?-s1&hp} zB&G8O|9G7Bi&gU=f6j?Sd6OX-uXOW?QM{-h=finj2};8C5ECZUk$Tv|#E1)VB%YUu zjlUTi-&hbIT~CoOC3QAoXTpy*>-PvppGP=)-9pjr8iFp@5OkglLWfHb+Fb(C<}4I| zHfL*UJ>d_XjK}3%@*zJ`*U4ZdqsJ{&$)s%RFyKkQ5u1+cX~dax5nIzXoWJ-N{e?E9 zEr}&G#oRU25SCnbq zw{+j-wbPb7k;Q9^)SuS;=%2C|a2}THv2U!h(dhojrxQ(f6nnB18?)5=$E%Zv_yPA= zeJ_=J3hp@yQ_H%NeSdU6728=S4X#{KPZ~VDavAq8UBVrH5b^9;Tp1d|x!zt3wzs3R zz8>|Jl_<%}Lq=*UVk09F=;sSp=My-%f4|j}1`>eVDA_?_^QH=y`k9b;E(UOcw*IhXDnNN7>kzg z!@O@DFlXK-?AUb#8@KGm>UG;El{7HEsvrr0$&`8`U@A!ij+J2dX_k5t!I%ut1AgN% zdu{!^snjKDV2igLlTz3Faq*Za;D6f325C| z_ULm6+WQ;0ZG9F;*8UQ^mi@<%nlvy5n#Q&suuEdVUTG_7@beEoSBZmv{%Dp;3@~}X zrwUB;l}aY?I|h6rflnq-rXH{x69l%}day6`sU!EW*J~2*3SkdC^{dUh>M}gxEz*(E8(fQ9+`$4QR%oHlZiXAS-2aU zjeBu9xUUi0?7tn8gs^L>`wyQxs3)!FgSeOoy%`=WfA+I-2zq9f=$9<2gLn zf=zg;;ysa`#7T&_5xqq=d-!rY}uVZP#b23<(Y%&(lG1n%|Z;6YJ3HKOTE0k%p9oK}=ROC^HMV4XD5_z_K zMP#vjTJpq4C%WdyzNp(>Y&w;a=L-o>@df(Wc-K(Vy2?`apuei?s2RtfJi2lPR&@0W z9$vYkk_LA#Ucjw$=WzAR8TE?7P)7&48XM7AU5&DW0%WD7AwD`9!2$koKk0(Qj*e4G z8b~1f_fQ%G^B+4=pvyDrVr=VA9Y|frP!a`tsUMf0U>sD5gL|XjH|V>jK8z@d1JkPt z9oTa)8V>uyuw`ce)^GK~nhhthV$D%3TCpGV7wyEpgD2H5D==}O2ld9+6ZH0E5(Ku! z==>iyX~6$pKW?CGJWmh4jlsGe@EecWYwPDtRF@UURnZ;c17m@7pJR%PM4!%2o4d;#jg#)X8f$fX_ZNj7h16)0rH@109 zg5ZftV_<1)>vHTR3*?xsq`~k1?LRqflBYj2wI6}HWuhuvQ<#Qyn9aA@Ij99^^$#}9`)3i5m%7xS5cR+le{2lbnmY$$7Y+l8^hT1=f_3k9#S3>Nv-7JkPrx zpM`628Mqpofh)1;iZ}U>Qo8Eraglc`F&np&a+N&t)a5ZvZv^0Ds9a}@T6@7Pi1e-zjT`uM;zUFN5+by?@KK8$Na`7Hfbr!hX9K5BGbx^&#s~u#i&ULpWZ?MQkTB^wJ`4oPBC4 z@~E@OvNu1GDOf$u{498y{nFO{Bm12_yN_P4b(>3l?7k{IC)(S_v!B@OCy#DkhlOrk z$D>=<@$lv~+`oPWcduQ-?JE~??feKX3=iQW~QPmCmp@{Sr{zL#hKzfoGmTDxv~OWC@;pP z$`V|uF2%K)GF-1M$Bp_*+^ny{?Z#@{ZK}oH=33lqsl$WTdOU1vz{B=NMUUDWAtZe~ z&T$;i^LRe_+-j)C&4w!6RJ_UGObu1)7{}acs1In@ioCxmuu8(qPCnXdWzj` z*?c@bm5#K%W_Mjj(UUTCV!z1a_@{!4c^wLGy|iTmeVq&L=xD; z*9iA**@FzFoGbpU`?264{%i|NSt~pySjl<1&eA7itausr4INLxgr%+ZNq)lHf{*#y zC;g(o*x$JR?aI@9Mwg|}jdDd6%O{m*#8S=6aNQBRS=NuiuH)I;*st@Ey6y``e~`IZ z>}R%%*oj#Fgh>J;J-l@d4{lz?z3W#@NrMY#adG$zhWq=_+tG%WrUq11lp!xS8_7ut z2n!2=m#4@7Bn?XQpGu;^m?SW^Z6yn&Pfrx+bvhcMg2$b+K3`+~NszX0JY8kjs7s=Q>|wvVd)4!hr3Ue*as% z^t<2U#ozr#(I0>NYmk2S_B8zLosX?}>ims$3CvmAN))h9u(LNud&l&ID+%)b001BW zNklR?MA)C39xj zOdL%0NdxNRux2IpZ(4_=4qM=Q&=Ec-jw8g=9WnmCNC^u;W=s?cW5ZC96ocBd1T<%* zpd&vWy@gpAEX~Dmc_GeL72`rpDK6EQ<7#6it~XcXW=jojwbtQIdp+)UG~ixGBOY`$ zDSFu5jE6lfcw~oooa1=T{mv%b>ugkf$m?!NHVX z^AWMl6Y0r$8Po)nZ>SB9+ezJySZVJnB z)`s}3UXJl!v)y(4bzC0MhW5z3Z}A*kr0;1m51H2wg`@Bnd7{I8?q?k)5+Bs@Q1!NY z+|g*FH7@51Kl0}}_tbTy0hFnT*9IG8g{^iCu!SZ0So*u06+cT`J6GnbmmDW;k!fj< zV>|sEV#)L5oT-%RJo9yc=jl2d>lVI-YYc5_&tJx~x$u`YFMEO5>uHz5UrLcHdg${L zosDxdB@J$0$0LnQNrP*aq`~zI=WyxlFh&OY(AU+Dww6XzSC*q7F9)f~iHHafg}1k- zRnov1=-O)QfvoB4{`|uKDCx(4?7C6k|5u+hu!ox^ad7s5)e{H&#)0YMh*!|uaRDWFf z#|xV6@sndlUV7VJ;6B-765vazCkc#odpz~Ak}QyNy!lVmug}$3A20CN`)y&UA2-%T zhUXj4z~l92aINHhTq$}F7xLf5aJK2ygbwuq#Me+3{3qmiy*TCrh!UhqX)n;Vb<7yt z+8U$xNkBVZFfRQ%Ut387TZw~LUw96$JpX(A>G|K|T{b){YjGswm!-zI_jn1ZLeIv^c$>OJRfVmorhHmzQS@Q48EL+g|ohR z;-rD-VoSc)iDL+KcSV%H4-&(IkRI-jyx35bB}btqBOXmTDd;FjM{j8k1}gI~Tw8?m z^`*GjSdJ^LRk+qxgIgVSxZT-+JKc@A-`j)-ea(s<4zz;w$V?b)gOTKzjD6VO0up)L z?;WLky-g63ev2IQIl@DD8fCG~VtdFm-l*_aJQ#X5%H9|rR;9RT|0EAs{s>IH+{iGx4Y^=k~T|w{Pkn^dQAQ# zcF=uG*-Y$iE(I?gL%lA?EqIQDrH+@>iJMNko~%<>oh&-jkNcXfe2#kPdg*o1k>x~s z>h?GKnL6Kqi)D-fH}a8Vws4hWQd;Di*N*hto0mREsq1r{Y+Yncr4)T>hw;|B*w(TR z%xi>g*>_lqKS(LOEoFa;vbU0D*u&(UF{Rl@Ec($tn*GPaW;_h^@q+c^l)|5Lqi*+l zO{8O_uWP-|F}xngIuU#=>w^2ahOycg)H&w8qo)zKyBiegd}W-jgV;ymYSvZ!m?d== z{qJhm5#eETAJq0p;jiqka4`9Svbn4Q&0bBya zL#}YxeH5Fv?YH{I!Q&S-@@Je0YnLYrJPFO%dvWZEp=Nwj6tIWllDsCH`%1Y8!x|r*Is;H(W@{10k8b= z4|s)%gcqJui3H<+$fd16S-`r;Wogt;aFWv2Tqo0KFKIx%bRAe1UG>tao2|AHcU$dM z3%|z7Z@$9v`E#&z?rbdjY6ce0`2zE2er7jm!0#K7Y{@nD*^=wDe+N8{?uGx!!wB~} zfw(|-q(%55CpH)*$&skah(lvu3ffCD&{L6(!I}b$G?w5(YdJ1=RN;DeEpGNU;7)%d z?hZ8J-cTzZoN2>DGd&t^2Sz$3B#sk$INT0J8Xw^|rZkV0bB*$(U(S1Qx(%fJr(1Dv zsKtuz4z)lh&V|IWB+kng$#G*TV<}toFzQEacHeCj^bVxfD3Ef8Y= zy}@S7u?L)^M)x^?^Z2_1%^=MkVXS<=^ZJ*T3hT|G4)P~*&N z#-zK+&negF>-O5TyUbmDn5D(Pxh4!W8QhJ&E^ATNqlLeDy&2m^oppRCs`Ff{F^09S z9}}NvDQidYuv(kL?UwyO>8kb%lN|bm;>mIXvWyi!G2<^jVhcCQ6FfwBY4g}*?O|(u zh&;*{+bEysdhTn)t=YSV8*HfqH zdUqX+bfbsIM~UNa^))D+?(~~*7Ayq|DRuqT9Qvr|C@4VXNz zN*Y``uaX95hX&B!-GPp_X4KYHqNp$*X{S;U9Tfq8KOd`r*7%=#TWvj{)t@k6T|f4> zs2lYiFOdIx=+_enQ%M>SS9#h%5(hpZ)$k6khF4IfN*s9jm%+`i7%tugu>L?|JD4~) zl~t({2jS5f@YkL=IB?hvJNF#>L6Qc>B!b?4l0bH{=Sm=JtDH(uKiRQAcGAE&ugT&v zm2tWZJxO4z&ar$o!Tt4LSYAyS$$1B5+kb|xXY}?{t3>u9=rLDH`o=noua~wkGxiyAx7A)UcNP}Uory(X&lvM6!<^4Q!mLj}#LQ3rf*Buw zfG?)KKPHi2lxeGNOYVUk>v3$~R=6J74PO^Wgm@l9On@s=!o86lABe(~a8zW*qCP(f zZKdhxuFAn+eIZ6#N^!oU5|_JcaILQ%w+0${EQtw5V}1mVGjwI@r?Fs2|7c{46|1h-bT+i}0~mQl4qvCOw5G zbyM>(&*={FP%_&TJ`aeMfr#6^;Wjny_UUHa9%@o_Yp@A72O4eCje!OTUGJ|~{y`tP zZl-I!b+AQpT*@2$^&r`@i`dU(Ba=;OTOG6UaMyjs7LGc87VJ20v%gRu>Lq$gDRYvx zQForN>!{mQ*U47hmY#Z_%$23dX02AfPM;RN1y?D>=LJh$N8u&DDR`(c#9K)GeWcCG zPh~EmtCfD*dgR_gq7Fuq^(cNIdP^yI8%sGZrJOHV2w!6<^7XYZdz$!$l-%cdOyOeQ zTgZ2nrE{(2 zAnAP^!?DzX*C6Ue{RBtBK*ve+=Xjp?q_PBS9cQtbE&TL(QoeDXoS$)Cf}!|^E{nF3 z_4T(Z#a|w`{2}z7Flli2+GX6hd>&WMkKo*yK@9eEp|iae^|jR~DJnolS}I~{?c2Ai1cEW}Hn#O-z~58Sz^Dt`qWj-Nl0er%PZ+SSV>;Qoo;dIgt$|NS zjY=GN2UWo{umTDdPK$yRdfs4t%#}3zn_ifW=GKTFrN|Nr8#R=}80DCmKKA zasA1I@t!1LzaG%D{-ASfM4(XF_Q)oP_wl44TJaJehu%x^(x+b^A)`N z=U4u&k_JYcbPQS7=f=983}D@uG_aL8uoave`}APlcud;*7-N0bXCGqbr+>kWPd>mG zAHR>!KYH(}B@K3LT#0=<*5SzB&2TyF0Iw7K5ae+LQU1!hliWm7Q z8fjL2w@x>zF&uYe$TXgPYWzqu?%BYD*y#FktneX^$?&m-C+9A_DfjM3vt{n&$@!3k zzsY8%dEGzPh6m?IiEYmF&Tx~`jptk&s8hIH?yUytQjaxV?5TpH?n+$fs=)cqa&yVL ziOzMD!xqVLDS1Bq%VHxXvj&%YM~QY4TTwUaNE|tDBks2FGWHqq6T67tP&W0UUZ(kt zotNm((lQ6LPl=9#yXYuBYt&~l?I+RMqF+yy!qt|~69W=;Cbr^7oC`_T$auIL^`mWc zK9nhT)Jw6mtW&{!Jlu^wrQ5;E7F_f6-3k0j)`>nZ?kBRh>Fbx+5Essce5osCo^3Bv zG}2xQour>Sb3XJb&Yd!Kd6Xe?=qt1X_Zi~O@#2e?b<$g{bf7NE$IiB>Jy7=IiTp|5 zJ1EOCr=BV`AI{-)OECtU3e`1WprHW$4f$ZnYXbXuoZ~ounV0yz?2&BKzSNsooM|mF z@oXqSUws~WYI7BJ*W|!RJl0#6tHx38P;(K6+e*gBBbJmSHX+WUKXs+v>rcwdc)p%ApzeCm{2(Dr4lEx?Y(I}${<4B0aS)$U2tIKT5RwQFpGds&;xxSY{9o|GbMNB0-@aux z_7Og7>NRKS`oMm-S;N4c4w+iH+;mV%yeD z*tz95GFk^f6bcY6V`N1sE`-rvA&%dug2ik*fs{kY#Rey z<2h^_gHZ`s_0q^k53Fq^4gT`>EBN58SMdIuf5Q83KK&;R_~^Y+Z(S$7Zk)3bC*yJb zT&e4c10xppk_IwX$8sul;~e$&jE~>N^l9(ni;v#M=O4a}&;I(>n54mEUr{jXq{}(D zV-1}4Zh-sYZSZ&Ajd0I{h!1c=TDTkX;(bthDhRdN5oj)oLuYw1`fJm1rZF4m+wyR^ zvk2FEN^!Hl9JdE6aQAc-?w_f~gW(!H9I3U?qqBARp@}l@pQ%wg+#aaF_1;ok=_ z_5z%1$;EI}HiqgmF;JI|f!cKR*QBAZ`jjf!WT z;(MvHP>s3JmJbrgU+gGQ$0++&e>v_9RpQ>6YNZ!-)Ab`S@}4Xoo-4TOSQ2OUQx4@( zu4V2W1xh#0hotnhp(E|a^GU1|KkBFBH`1JgGmTj|-H@elB36U-8HyC9b)%T}R;8k+ zDiz(8DT=x(k|ESto&+K3V<}^K9?z$J#4aL-GKHuIZFSZ>FXBks=(yX$OUF*?M*PT! z{LZ)LDH)VcUG#bBx=UT=z;W~~;zB)%9kHiB>Ao?ZO+~NqN-LWWR^n#A$(QJVv@`8Q zor$5Yv*;%nb50z`@w(5`?(|KT)R}y#KgSSnl0M#uyZE~9lY*)6q3y(?)^6|s{w zs?R~NW+{ForG8AGt8txA#h-}noxw`AF1R*GY_nh12kk3(6I<%hQI=$rs4I_iPMjk# zpr46vaP4s&3(0z>KZ>ac_`OrR;!}+wA zCZeS%4vqOSsLzW+U2Y_5b0SsAHv4&;X9Zx?zx+tAcdgYwcMWM`%!Aua|XK>=`gJ&7ZS9I?w` z$E1=5l00B(4Ak{tcB=KM@{;i)N7_>Adj74G26~c!b-s=ueWL&4l*ZQ@=FZ+WCUL+I zB#xUnC~Q=(Dll;n5u1g;&?LP6%IA3HrH}E_3xCB6&%I|iFl3-N*Ji5!COCA z(qQMtrP#miI~?1y9wgTX;U|$3=Z%uoKvZXkqp2_!ofS#wuT3)r z8f|&F)K!RUy(PHOUxwR5ro;hnZ0--&;K4`@9-ghW(4%v8_#ucgDDTecO57SK$JL%< z73d5%XJeq=eB)b|h?e3wG#135K0gX|d6B5ijZ`Ju?C0_JvP5)OrI>E$o3e1WH5V7! z^A$e^PfV7KwB+D)W0vAgEJ(b;9%{%`$5is5yI5huoAJA6suYQS#EZC{Yt5aI59e}o zpiIq;bL3og4E4El+?DQPr7!2M0-4%0^j4=TqMq!d{?t);GvPzsRNydBuIzcSvp|hg zH{R8$%IIT0mD-4yHp^7RpLST#JI7^PFpYeR! zhd0r*i^vhV3^rOz@9u_;U0hVvJ^?hRLu!Ar-EbzAt+#MVZ5F{=49beDBX9O)A((0WXNl66iS(pSgxCt3Tn6>;GDl>Lo9#l3|@%o#Ka=EQ@# zi;oav`g(bKuobb7e!{uXzo`d(nDV$@x#qYxh#bn)_cD&-c={vpk@*li>OebDXWhSS z?HS@%;!9lnvUl)&@}bXCKl({oS}+Qe{gId8gX~x@WW{(QGulIyY_p%oInH#Qh_Uz- zb*7()-H9=ECkDK(UxtJb`mL}E@Oz-qEivB$cT1FPMnvLM|^2p;z3;K zpIo!_P3ljZa19XiqLcuoC-qK?bQ@O|8`cN;*qMp>3wk1}?kL!?rNWbGA&3$budxqHiAGx%fG>DT#4 zor!~?a}P0e_5lV)_>+uxVKZ@1*N5VY4&)X!A}zZL38_VhjLpJZug}CAuY8VIU;YFy z|M9~yKgp;EhOA4{z}P>P_E+9=_Hr@zI!e|Q(~{NWwE^V~al`?4oS;@c%_FmJ&!O90C`*bC^5$9~A90cGj@SvS6}pkuBl z4OrKYF=;UEqYp82<`2SH3q>G zB@I4$|8;!y-fK|FgLhw5PdrRUj&aNwx#kc2*-9F4Zn|DlH{xJSt{9KAE$2#U#7$2a zux`}T*f!2Wc_MmiPvLY^CeF2)Zmh5N7URZ%DRID?P~OeTUmnQ-B1t>631I^-WxKM4wt)&6ehO@%T+=} z1p&RqDmXaPoTYemR3xFLBu??r`A{xp65lI5#UPKn!&PdooHH?$xwBv0^c&_*eQ2+` z{76NtvyZ%o8Z&XeJx}qb-FQAr+VMh1K2A4fsc{_7n`H(<#IQIuK=}f(Bo!q4AwS7i z;g=I{!d2ZEN4g?4!gK?k66OM-?OuT7l@}oT}vqF_j>Oy}x zWuBL=yVPY4oImxaPf=H5M_#&)m%0lT-fFFA>%^#|-q!6+eQnvQHZKz88NtdfvqI7q7KxjI@@F`;?P@@ zs@4J51AU5klP-1@V5Bt%{dH*yFRm}H4eCt06JJ}tPn~EB+JyeZxe`y}NLj-z*@`!1 zT3+nz_>%0KoFCT?=R|wc z#?+7VA+E6j#}Mgr2w|R%2=Umjt`98PWP&ttRREtAs*ZD9QpgEJ z`yEz10$umQ-(@%aoOi+Z#7_7)IjE9#5|0I(+@s`1cppSu;4y_Uair~NH}dBmM_-ja zpEjXA5`vu&<$GA^PCn!(yeA`zb|Wv&i!$iT+@I+O#Erx~m3HEMX(!?^I?p3k^OU)= zv(&c(cb^)?Fo|x_pV*S?aLRSes*zq z2qXQy=78P`S`^YiB{^p`*W z1wuh#De8ld-u^M_+!L;WAU`G!C}YFsJz%0@>5BDO@a;;gIT;fJ_S$+-Z*Sa_9Mfey zZqnf0cizUw(>}tinbWcGn|b(d#WHN#unxO-Zo?tRkr44C001BWNklM|l0xu6& z`1yJvD9{g~A%O@B4N_%DNFaiO{1M>q3qN0Pl}zw(XAf_iBT7HzeSL9hhVERDy;Yun;GQJ*bd5)|umkh-py z)CDtRTl#I4GFD3AFQw=pr7b;;eG|=<$Mx4BjCJEjAw?HsDLP3x8M*ex82Ph(;=o3D z9@~K+w|$86JB*|-7j^TkL4LDscNuCGL(? z_@y7Q6f<5-Dl5O_$cygEvGGjeam=b`B%uv+jN1?eS4z2tzduak1 z`QJANW|<)>n9Mf^%^c4@j&CbZR60->>U6EYRN->9uLKvn3URtQ8{G^7O5)VbWeI}- z21?0(iYMjP7eu3-fp9|x&UfU4=iX*A=4_1xOJd44`+59ad!8Ck`P8F~!DEU)aua-z zm*{Jm6YbZ@n_eak7!dUotMjk)j_TJ{m7?ZKU8q+^jEBN7G2{f|gPjl;bX?&@%%c5| zDnE(vIfPJ8M+CX=Lx4F5@O9n=9|i$tVnRwt`Z&hVdAGWe4|Ln7>>@TH@0fsNN)}~O zc0%w8B!xQTRHT~<25Dp3gf^$`iGvX@TRvy;pEFg;Mi)8@EcnrPXw&p)cO{ShL7(Bg zs4I0gl0FCGz_mkN$%A%a(ygU5UM1XyTXS%+yHNSXoikNdb~WlM>qdP2)=&j#E833! z(NUSK{G~KK7&-CYDwv{OXb<|h*h2JUoBce_aSU)7REy6O%UV9Az~DYR4CG7w$(w75 zV;R)YzvySWpHeUG0VG{Vjv-I-qAwB?%H?_^(VisnFWQ}$i$D2Gpr`qh_>q)j{ORN# z(4T0xaPNc49^}h8)0f1b=u?zSedy=(cdliw6Jkq@xyKQ25^dL~g6jmeemS1LNWPS# z`#&)k;vA?C=fs38_av@Ot}*TfH5UPw*OIuBmI&-$|Q>HdBlk}q5bJ2Cl78`=abKY?UR?~b=*O% z7xE(3oD+SS`wjPTCeUdk`Z#@t^W_?$PjQ|BuKVESv!ur(-sQUwcUd37i?QPbSzk2Kp17 zBjat2lVf@*`benvw@b26A_~VZ-XZB1iTDSmfR;|RgEgP|a?@l-! zJqS-XX9NcLAUrGxF;NkSi;Y4;e2k*_xER%riHSs1WEjH3f)NrDpvL?8dcxb&74EJl z;Bw*!jvw8RLyo(#Z~HncOm&>3E&-~Pwu0Fw?XwjCvd>n~s0Xda09e<UJ|`>`;_D0&`@{TCA|k*Q(ZTMB5BFB*rbhcJ z42dN%rR^DP5NqPD^fV_9Y^@93*Coi41QGpA?9Cu4HPRF5@xe%n^hIpwsLo-2E++l_ zT+|#m7ar%hQ?UUmKo=jTPcpD);7FYrOs7P;qouY4&1PzAC__=YDX~Jlh#UQsK15$9 zvCclhlxrhDB?PVYrD&`!LVaZ+>M9Bl;d@L4oU|zuG0{OMQB|6YisEdP6=tF&KLf>i z=_txgLt)M-MFlyjD9AQYPO9ZN#}?e-iR{SYB+8@gs;?}-@K7I45AIH$_Ov%DS(G<&x?jm= z;)QFT!7SG`_hTk)B+)2-#gcw+Og2&u69!C{(B|AT0^Rnj`3&@Rp|7VCz1{8T>1s!J zXPbrCW_1)A)-DJgE{flAt3F^keGJWC8b! zYgaEnv8YFn9;(CxuZ5fw_Xl2Mm^5Qh&;67MHu^Z{%YBJSl;--%Da$^4X3!#wYnq7= z*{`{0aIfN?CD#J6t*t%ozf0e^NdtZyQIZCCu3W&4OXqRr>=~RJ>{AP|v#lBRHI*nS z%2U6f5E~tdK!0Djx||r3G?1WpGUa4~Ts^>NeWG)W4E#xtQ+OoN($(G zq9;q~mjIvTL^#+xuJe()j31jg;HwIEtY1~=Fn=78uPRh_;^V(A8Iw5h4UB`ESD1RN zU;QNG-ec-Rf()|xRDcA1v`=Q><4I)|>_SYVKmp zU${bj%YZ>Uf7yWFG2jybdk#3`;873tguzLV5S1`s(Eq^;AE>7Ym@HsofC++6Uik!{ zzWOOXd-XF#pTG9GD%qEuUWSB}A~1On8kMFJ2mG}NCPO$Uhuufi(+2!S1^$|X9+=w; z;El(041TPnfv&4jrry?dd-vV9@d=X#b7o=jqHnNn?J78I+l<4Gd*SMG41PWyDq#>8 z7loAM1f-=UBO@afnHi@PWn`Q}T3QNHQxcJ!6pw`XXvD@uASyBxVWIvA3h;)Xj~l!^ zoZ;$n7{~W-wfM>Q^-Hl~)i+qZ^lL2pW+uM*@&GeI%)V26HRHoEkHj-z9WSVT-2U+r z1jZoJ7_jOAFzdQ}OKzGW4B8-sUSJSFg#QrCUFx{Q_5 z7&Pm0spEndTk!D2WcoeVyKv}kwaCHbK&BShVxHkZbu zvpNO+4H-Dol7n*{`MAV)Jo`#13nJUrwuODTj6$%MhVI#sgGe$Joc z7&PRk_#-*|Bx=fXaPjuDUkx`ao)JwjRR(JHTzP$#+xyQP2M<^VOl|Y_%r2 zcXU>znAUW%pRzH>U%GJ4N>+PI9cVZ1871k#XfBDz0G~EsaLMn?@aZIN-=&XnPv-ti zTX8Jcd_`86Y0di|g}2jAI33t*C1o??8dok~G@dr)_M=CSaL{3mN{-UrycY5r z!$b}DX_nm2=`*y2$FUvCpQ|g1rY!69P`{GJgeiIP`os0ZJ)@`AbS>aMz-u3`1+=Yk zZ~O1oo>bD{?$t}UdFcYKo*PlWpm2Ji7u_ALXsoM7SxEu1GORy_C;_dM#^BgqTLM+R z)PrSPb$zU@x~+4hkGkk}Te>~XM1juBC`<4fuM|C5N?@;-w&p(BKAn%$^>g*a!Jy?E z2Y1jtcoQ9c*I@ZM#-`KiR~0_}XgQ|+WwA;eeDKaZM8;(!I6M`6tlz~w1V@~_vCsTS zKLdO9n!<|pSh#o<_=*8PXgFi`e0)CrD}3_VZ2as0`B#-NP)UQ2XN;RP;P(s|tn-%) zm^9$43H;swW$`rvzD~eb5_|$;5g3-NUO|wA0h0wx6fjBf#p_>S`s>p%{f+6E@x}~Q zvM)2QR(@l=UQ9Po()^5UG-(+2yT)b|rsuiLI(kgxhN{iM{!ZUDvJv9P>`REyxa_AXQd${JsGLVaY#yxMqErdBEtg^8temqUsrgZ z*sC5nJGyrx_HAE-9UGQmqd9S~Wc~~+`0|qTj@l%|dKh`|X%>j6A+uJjd=BNdoAl%v&$@|6d_5jsY_QOyOO2Q;@w^8Y>J_hB444PXaJC~KeGM6CE=@pbMhMblJrU`51YS-% z;q9`2$~SF1f&YnhIk*MhCw3yxeLq6I4#Jb{fCqUnMs9(Z|M2 zoNmogJUXjWQCkp=yktMb1v|m-PcTe zFF{^;qS7@h-rM3wCmc5+H#2F zARSl_*K2Ya`D2V%*!9vkEYVoblP;RjUtal5=I6r}~>RJ6NVr*22Lqq)A?iqFts zKjzK;7+=r)NYUI`(@MPZrL|brOQ_r5dH03MTnT%r6!0c19cXHq0`rx{!jjD1Z)Va|CN0sdv*zer5 z+)B=58&RRY*tuyL939r+*uD)4%j5eu;?VAO*u7;1HmzQW`r4|=va>txsN)Xo*sw$; z6A$nHUdcPM=X;g(-mzgR)_*r27cZQ*%VRPJnKYo@;v3u-Blt>NkP{L@oz-5+HhqTI z4JO@rUr^1-GtTR3AgUFnk(kP7k1`y93RQ^{6Z_MQ%c(@8iG%*(d+0rVTO|%$eT&i3brB71XHnfagwLm~#3vsv!?eFF!e8I}260IR2#d~8 z-vi)(=AHPO!eMvy(}kP2?N`4%z^4QF0YkoG@XXJi!7qOL3;g^4{dfG^|M|BGlLj+q zFTj^`7pW%=$b-E2Gl)z`FloSV4oK2~^7+&QlNi7Kr|0mye|{d%{mUQmhkt!hB@CD> zV4`5=pJ!s$pJ!p#o3m8Oc3yEavhwRy;($*a@RuU^6O&9t96jNyDRemNUU7JrNN->=1Phpjk%#1Y;eE(igsY-RhFW%q6B571t>1cMSgxJaLi4gS~vvKcggIrC%8 znK=!!XH3Ja=^t5*(Sv2yC8*U)NftS}VPc2?Mt23%2^D&zKBg+cTYWZqS_&}OS&HG_3Y;IT!R6t4TtC-@ zn-^Pg`*IuZUG2dAYn^y-y&I2i_E-qFdNCQ|Irp!1;qH}o#rNV+Ee1MD&{~&;ih_7# zBn2Td_#`}C_Tk{(O*nGU!Rm%=vJD@P6WFC@+XZOHC%aoAc4zT8PfZJk(d5LSa@ElA^s4;B^E} zhj-xS%^Nx!RF)OM+w}lq!rYLX9;VLeZ!f}y!5ZAW(1N=P!!A|cINz-L``U`sxZJcb zM2EVm`PWpHTJgPh?TVU1kk2us#QC8#FIMSC-H0K12#(aBw&t8W+MBKTbau31;ryBS zcEL=ww{d-Rb+%iLd0LI!oD3}e_DfL4qHks?nf!0C{#R6xrRK|d6R(DfG!QTP2JyOg ztrHJ#bX)nC_|ff4ZOTVacbB21HVef$(MXK)f{*(_c)1?d#XNSswWSeT)-O|j<91>X z!ULU^f0X5${Dat2SK5+(t*;H%X>ZQs(&;)3b(NvLAxEvboKvC7N2u$ugWHt9rY6Tu zSx@@knw8&R^Y=>?5BfL#{=n`H*z2$kJGOj>L;JUl;hT~e0e`Q<%9n{-b9IKo{Y+0e zNVEa_c#QtevC-jvWB43)+==g&&BLnY^VJ^f=Y4X_n5WgTV#!=ATV(Pl`fpNVj1_Ap z4TuHj%(d?8aR{;D?#N6ILQ!@UXfw_yD0km!irCSe;+>n@EuJ1>)VQ0 zud1?6;`R1)sy&J_h!6QTRi&%_g4l82Xsk?A`$dA;ClBr0jI(Eltz^~JRw(-idLKn< zyr0?!x!0WSufnx+O%|Wx8j!t{{pSX%)V{<$DL*p;@sXa&?>Qe{-`1>LXeDQ|jUaz7 zWyg(cmtfnbm1?itzImncFJjC4p{mNV$+ELMZqLrm_-^?;tY5PTTQ)3L@~HcUwTo3h zZG8URS-U(YdvN*UuM}Ti^XVI0%RX+7%12nT&Hmln*MM{9Jwsk@)@0dR#`X90s&ly> zxdwSHiwbd7*W2onWOW@G>8r$*kp^)8qD{GeTGP z93yopjRF2dZ8?vnjMe+}emTz4k~mOL8;pM6z}>GDCw&Ux?3st-Zdq2}H{gd6~J_nyq{~G__-0c?ncJXQz zu=D8!ewc8Z!y)y(0eL-v-!tG757fn&H2C7RFVs^7Dq-;EEX;m$HfFyyTa`>66qUED z#6d=GEt1np5gnfcejL%$H%h&tut6qu>z3)kR>b#^r@5?VR_sh@m_3Y2^ z<*ZMw0&8Q?Y)if*3#8;2sgGA0`55JhZc;8={54iBUx4pdFUIEYmt*_pRoK0K9ro?q z0LML>acJLG967MfLWlQn#i4y$;J9a#8nb)HIyh`uZ8bOHt(V4xfKjg>DrsQEL-!}v z_d0wJ&dKHIZg{&MM39dYqC(t}6yuAGk#rwZo> z>Tu~yBd(rp!OaWpxP7@3_pb8hwFeKb_u=7YfH5eN5f#+LOfuxtBz%gxwSDo)27v1<7@*tm8nwr%KtLcOt~^1kw|O6_4)bBAgqj#r1QoxO=5bVZf4Y_7n5U zqGX&(2t<(2aU4Ii1LdWKR(!8sy@LI_H^S590Aj;Ek)Iib`igXQZeLpoD5I$=3q{$n zNR0A@kJ}+NpO)qZD?aUQEtoyyV|+FHQ_TNrIu^{G0VWcDh`*fd416KZ^rfDbVhnaxC}N#`JjVTkV}t!Y#_-v*YYVe}4UCMQ^_GGRjJ=$8>jfVAr;_;5`HPt-OpV z)Rm`!`x&ugDYhnlu1M$&Eu>eV)aq?p*Fve)Qma zuVwF~&kuD~ptUX+W%&t6jSoa@gpW$<_xSO0i9#n(6!<4oU#ij7h}$X7a(6JwE@9FOS8V60p^PuX|D*V8d;`ZSc5 zSUNpbM;bWuLE z=$qM?JLhxE`20hRj94dG+S^){tl&U@_3`V7@DRmU@wUu~DFm^ixU5$vTBV zUsrXV;kA+1n*+NyqcA@UB}MtDC@(>MT@AuQ0)l5m_Lg*eE+90#26av4^^kjo zzQ6r4VW~zap?jspB=%uk<%FH??FdfGwN!p)FZ~}X{m^bj)cFz z?-L~r^#A-z-CiKgV|q|)tQ*hOgLWPh89(F`1-eYV{#Es`>$xRCcKVJ3Xfwe4L-JC@{eG@{5METae}Bf&9-r ze-@G7HPDj=#=v>9?Qa%+hb7C`S$;i%Pck^{J_-i(d@X{qJ$xe7_Xzka3BUWNKj8mo z?=9H#IJPy>`5X71p>t>E?z6+V!yNCRV<(2hi6LgTWm}fT%*+-u+hVYoEJll&!Iosp zOmUKT&b#DR`s+`|c*9IiKTkbfO$Dn~t*-S})mpFokJs^+|M}ZW12t%{e%X33)HM%_ zy@raKZdq-RS6GjpnrDzm)S zmV?(?I%}`B-)QqumqCdiKClDENA|+fWC1YXY7%!R3t3s>=V^xkZwCZ2_&Cbh-^(7p z9=7myvw?@Rr6^wx*2i?}r=+c%|5-r;(%H`HC|n)PM41itcSdxm7m{NGk&zOP{LEOC z<)@&wEECN&r_j+rGxA8yWbr2tn9jNs?1WBBD7 zL4$D#xG{ly1-?U|;r68=T%GO3`H6On_0^%Hu^6X|(~x~K5^2eiIFT3$W#Aj&=YgK? zPIPs4ptG|bogMcN93*#lbs#j@AFfWe@N{#8ua^s4ovZ~YAOJ`OhrBvC*sn8qZ)8Dl)_q zIcZ$6kS+8)H`SQo9IDn|gaB%QW?=`d;v!Dc=l(eXH`1`m? z`pkzw1@pam^M+13#f5obeZzy?h2~m%kzdGTYQ7>b{d8pn*U$Ik!eoc=(V6-J6z3)) zAE@ z0LI5ga3V1rRPe~R1ZoIcupBH8+m?JTyncCD?#)kih@#NlQi__g4B-p%*boiT4G)Tf zK}91gBNaAQCNMWKgo)817#}sj(IfkD#9$8&9oU8ad$wWsjvujY^LlLF_#HO>um;;U z|DZ!pUL+^RVE^s~MUS8jztLCmyY&EdC4h}cd3aX!e8vy>>uo(?CWO74xp}9R|y^&8OGah zzKS4%GL$39QqV|y`d{c)YN8}ns3zFYkjMuv5P+xog{DHor!%*(%6 zhO=jD-dg$pu`MYtwDL_Y z>;4Gw2Z9F57KK|^F5&vc3%E2lgSqKROpXj80cZ_9E;brLL4oja zcZ02sHH?oL=_uxECH-OJibBk@TIptdDaBTOPyOvu-)qzRTV5+5fs%)E&9k@9a6p1X;0Ag8L zG5C{dYimYtPX`7EdN4ZDkMXe~Oim1Aa&iQdlf#%8AH>*bKZg5SG0@$J?)F-=HC3Ro zrU+GK*(f=664~joIGGrRmc4*IFf+*XlAbt|+p~d8u^N_Y|-|IV;~i=**d)UE4Qc$JX`OwprH;fwr95x+>S| zaxkt13Dnnou6(CGEBP%|W<#zrIL4)xN8n^@0(WOi__*83KrPtc1!2eCWu-}Eh!+^R zU4{2T0$dU3>jXbfdw9B9>(N!6mjW6n_muLe&kB9jXKnp|@3odLyyncCt>sa;*qg!2 z%?8JPou!Tm(E&(J3PWys42tuTQB|6O#;QEDH5Q|{trEjMwU`)e!Z`sBI&pcX7gx^@ z;Kn?cU60_-)iL~hZ34espTMs-CMDqJ6qX8ne&^~qZe1G2<=H+-bFixhO*Q$FcXC`1 zy4qWG25#r)X7T;EzYY9209^Mix5IG2`_00$wJWf8)pD%<`isQ@a%+q3p4;A@E^OZT zEjF!RBj0_y`YZJJ>CUdVG&kb#!JV+THbS6}6Ov*Ak(&{VvVs#RFHA+rsbplQMj`VoKIzVrp90d- z*V9fwkoLA#bu#Gb=@NQv_a%wzmD2CAe%&ge=jWe%h!5U- z3qwPLI_VS^5;ZOw{5_IJzFF#%1x%LPLJ)R1r0d!M^KCXFe4=b)n%Dd zm$Rd-!YAZ2@|T*Y$V)$68N>ApgE&9giILtqG}q>%AUgpu;l8pQ-^pHoNxrR(1-|(7 zBYeH$Gkmvp1%4FJW_8qnX`Ime=Gu{Ta??S&A z7hY%l>Rdl&$J?bZv3sr~_-%$nTM;R3z=7Xw=5}kB^`Q;apiR^RaC-zVFYw|hi zx@YGmi7Wih{;=koFGcTCCvHJkv!oBRtgI9J1$l&d zFfZ~7;Bkg3e)L-dW`}S;AKbAN_1Afnb$oCZfrW`giJ_u7Iu3X!* zSU1+&#?n|Xo$T}^B*h+={~YDiPRX0!x~}&(8qD1`24v)ddsd!38BbJjYeT^GAfJH zQGYrQtqsNKK2wRo?mCPQHskDA8_rL40&HU^{G*q1ezh(M8ZKu&(SBTy#i=y|*viJ1{_?*=F?2`|%`kOC>{*(ihl}yXp!cYR^ zyvJv3KPn10Zs@Kw$j{4`yxAX9lfrSjG!xxzm6#qq1JZ}|B7dp*iM&R>yLMp+bCX>d z?yW~tZ2?YYB_J}?8_o`9aIiH~lTYG~4z^Ms@(THea-HR)GG}shzqBc38|4`lg&)?f zlGO*=glIrFJlIS4qNY4sXs?u){LQkF*I9Pffqkd1qgr?&Cp}im$ad7)!w}G5?MmVI z?OWGN`3w*3ma?&37{~)`pZ$BbNICcK)dvLPVj`qX)_=cBXufm%CT$gv5Em(Y9u?*z z{g1rF{y5s-D1mX_W8dUE>=VcRJ@wMDu{OnytsCT@!18fRk)y4N1jfyb4WzsTH%L$R zJvUeVts~#A{aT*!9j15az)qSCUVia8y!67e5*RPnD9Quq3guF8fGf&M3e;5)C7Cjh^rZ64KFIvpM(met7g!dS1 zHHBp#y@!uJcn2T6_a@$X>ot^?=mMJkeSOk)m!`EHC93>pkB0P9ePO{&z4jeyl0)g_CXI=}RA3F&4RToDay>xOi zQ>1N+@{&bP4fWJvX1qiG2mFUpzVZL4mT`Zi_(OpPv}-`n;O6Cv3w8}=rg3g!6e9z@ z=xINL=B5VFuED9?9Gpl=LPSIu{Cs`jOQC8J~d)hPb3W2?oFU+l7 zWhDSz6mm3)6SQS)8An#N1RrrpLN5PT-)Y5#4RoXss_rbww^p@)uScB*ljyBE(x1Di=o! zSeqNd=*T`C*thMWKm)DvuD#YOZ;z`ODoUtw*5;#CV72*ZpD%UIpDydppQRFb&HILj z_TaF=E*KoxA+*`Mdtm^pPDd%*QumZ+JUu6r?1CA~iW&wyLC`h?Mimq;Mq1haf)sIHJP+1Uv`~@P?PC3!I(oU}Iwr z(_;og4{e_6@~Go#z<_aW+x#uAm!cPy79UT01P8bwD%@8FH3ZJ6jFuIpp|&y?E%im{ zx(ghP4K`zXtQ~XH-MBd0zW^Lu8pW+E?B!0dzgVCVLYpptNqvq^{d!1UNbX-l>z12a z*MGknYgR2sQ=_h7Gj416YWXKJu;rPvWd?5i!CjvR>6eOdOE@xba(D)GXVlCl|^NzMq>JkA~_~80fCW%tR-yoFBxkD`U8QZ2~th zj|v@0hpsafC@)SIUh}0jdXq!4=U6@ZF5%7RE>SL%ZstudfFieprLuJAagZVQXasH)kt(pWiUfe!@P_cQ~jf&9t+E zrKQFAdd271xPA=?94ytcV>F^TyjJ$Mhei(C8-5BbvM`LY)&^sd3Ta*;;wbvf5E{>ug z?AW#eM+|m@?M#J+b!MRAK_!*)f=U+o!NJ~2n+!sO7I=Z>WxI8@R$yYdRrs3x&9X75 z+n7K|Wof3!7%H%&@wIEZ_Am$d5ry(Jh1NDui@qCs+Z2jjo-;LzQcFPH*6EiD1RR( zuwU?+?ZdVs=)+Zq4?4JIhTo8Oq>k} z)vtgn4G!+xE_EjO%zp;uCi{DHU6Gs#0C4Lg<%qqFvB;M3u~D6LXvCSb*6cG$@xhXY znxDu+wr=^`K3?;8gQon-M3%I+i$&wH{W;_ufO&(ii>pt&B1|we79z$v@iP(^I?5hZvyT- zvmM#LSPsh0O-pPM;|d0X5^ufv7rgQME0WiQW@ScU!6~U1{|QWsd`UiI8wj}X?<#q- z43uF4Fs)w$uDnnm97htsQo`CbE7gxB9u*n3C?};(p7xRlSESN_HqYT9Uc&3-C%)t5 z?ttOpLD_ahyEzl%qsUB40LK!g1*vGMFUD|R17;_?duM!Q|{Om=q(3x}FpKLo4AER00qG0@OAQqN1h? zg=HxTgdmU>5>2IFdF{HU?5Y==;694H~^+r@wxER(cEXYMwRXJK)8qm|-E_Mv2CP!q2 z0Re-{b7K;&oFB)fxe?6I3}J4n4^yKZ7#(OuUuPZKn#xgkIv-_)>BvcsM{+_aB13)P z@9hK^M@v}U1r4}FUaOct&b3x~dt3!kt%NepvZ$5T2c@fi_g-<%L{ND#H#sb4UQOgK?W*IrK>GBuOEjd+HZKRPFtNf2X-v$0%%~o z02+8YASl31+L|j02pFWLL?Saa200n=GEnAVIXgX0?(tc2JUwj$3aCWo(aYTqPWI-o z<_wC_K^^)te|34(@uffm^}PqR-Qzr8ie5IBMl#^yAfNRiSe6hIgw*5+SF)Gp0ug9Q5Gg>;SG_7{-lDW4Lu?0zX}w!p}FR@yktu2InN;_6(H3 zdwhrQ&(HK@a-MrfWgz%7LImi z!lMQUc4FI>^;q}qH+rB!M@Kup`0QgW|MC-jwfs{#cWXd{#)f)PYN@ah5TioDK{W^1 z%!_nld$T_r+`j``H~%2-6WCB6HPw~!4S}Y@yc9Ioagf+3%I&rJ5!}8yf!m@`jtLD( z2Pz3=Md=`D$-G!!f}-l<^5x6Y-$;X~Fkj?lCEf)MD$&l`WdB z8k`}eB0+kQcUiBHKo3ci=@Llu^L7%t5+o!&s1OWm_8(KxqEfPF=VlqalUBkz`=j@j3a2`>}0E# zPGEqSC?*6O2{^Ykm0@h48T04*aQ)(_l#S&RUO(4|@u60dk- z?VRk41>kDmc37Am7A09t)7Z#>#d0zY0ti&ZN=ph*TyzTjC+45Z5hHkPH_o1ZxAtpn z->SdTATBmS_&GepTlyaX0`^DpDg)!ZM|sG1$ou}j`W`8q9c`t*P@a&U4li-F!HdsHyle^3VDGLiGDaY%!TO%cPDDjX zCaTMG~uGtUL(+Csn_wg>wsfky%;?Eh@LLkD+>T+psGAZS3K;4iPf zgjZkTmW>xsRH(bEfq)|OVj2X)NDrpZ{>=Xg&&-ox66wx1ru-z>pgsu9y!Mxu7xQ6W z<72ujGfIjJrJVeyQ}!SCa}^#TfT#SYDaXh^?BkT>%!@W2)JJqw1U~)ihxlaK2NG5+ z|4jW@;&HK&i*k~3f$38DrvYuYHRVlaYP7T)pRp|L0}2R9+6MW%NgMH-(`8xcXsHlc zaelf-AQJ`Ie^SFF|cEPT}=nw{byU@|ziu&4Wlol5vGcz6W z@v#UAJ`PV$cRkQxDInlc?x_`j?RUyE1x!$`|5?ueCxZrys|++=6Z%K5$hHKZ;8J)7 z6vEXfM`q*~y$fWPiJ`#o=rja|B#1o$F5#DL2^LO&chG>w7LOQN%a#Z#xOPrHaPbJj z2QPkrk6->6pS=1BK6~vmeEG(g;Hm?H2V8j|0K&Vgup=2RBqE7&w?v;sj9mOqt>3 zpqfAb!w0#Ca67mskc_O;ssI2W07*naR7ScuSmjSzou(33E6++?tI$5E?0l|#t3E4v z@XV!)ECWFd0vaqQ0T0&4#lZsJ9`^DxCqTr3Ee)GxoQxK*AU``vwyRL#W5~}*lKUJS z@I4s_hj@#E%SY*BaPSx$osVJ%^5~o z@a9T|?ygQ*abjm<0as@`1o(L(z|T#}#K9#M0Mc!IkV}nq6-tE;6T@e8K?4ta0S$@@ zPw5O|X>gGPU@C7^aH-7IR_4jKy&W~8XgAgrpddF{+K|c>`zUQSs1F)|WWS)oM5U98 z0~H?fKY5&kd@5)h_)`HOxImg}K?CkTCiuX<#lbtb0oQOMOiz&Jqz(uqnw(_D{}$Q(@=7i|xVoAzI;cSu+A~ofBO^mX3xX4r)l{IF5Bml|HJ-`C>|5kj_IH9c zTF`*N3~8?9#WMjM^-)$@EI=jOkNuSY1J;E!XI`WU+ktdvyRdyocP(fT84-pL-hX>B zeD>)wbv6=Dh>sD#i9AEzX8SOG1sEbYL>bTeQFf9)S$Fxzcb~+y8bDxNUAE)L{lI|$-2#;q z=cBH+Qrs%`_jO==YydOoMlpY33YX_baczG5ZWzUt^COr)H-K{!+@jFB2pZI#J|(lN zS!uCIj15L;kf;2N{%-^g6vdW`H1~`Wt*7!xg^S7&2g>#~CUCGd{Vmwg!nmymL8pu%jjm}x1I~<-Zt9s< z1vF5UCaz#vYNY{Jy39^?W3Z=Q_*0n`CynfEOx4wvcxXs~fENTy$Y)eascdlI&%nC# z9-mPWqr&0o?xdHFpSPO;E~F9Zt*jOTs^_OI6fdaK^l049JoB0$1@j_!PZ>nu zMST!7;K~klUfPuz73HM@h>^$1^8^UUW277NBEPV25Nspu3COT)ckbL#XN8FHP}z3D ztrrY`{rG*I=e$Ttj1`_?e5~86Y$}` zkN-ga0|=z6W!rzOG`I(VK+u484Y);tt{1P)&tZP{EY3}iVQjD;eLY=hZD~Z+=?diM z=PtTl^!NAun}G&ez<}5PEa1Ss%JC?m!TV08lIX3Lx;fXLVW+0t@(Df0e;4 z3{6}|-^k^=E*6X7=9>p6&rI05q{z~Jx*|+S$zK96@Q_*lBSu!(Z(wpy(BN^vfqQ+U zR=Cv)E#oYQv6%zjc=`>z{p{O#_xX2a)xk$Ee}rfM>kD}9zr7?L7GC(*R|G)d3WP7- z_yPnJXw;Fm4Cum<+Z^nj{Xm-u_X7>I3btCQ*OpCPZf#usu2%6^r>Tu=-+dC-+B&Jr z=I85)$jA`!#hZUB3st8}(9&Fs-kw&Bj`ZN{^bjt{mV_Z$VQ_Vx;K3*^&kfw{_HKy4CT8g1sZ7U^0?PZy?Ex{OwNvO z-?Cn2G_+e3sOWP*!M3J?$AJ@n_S}*{(11Wec~QFTujT-Y00L*-IT+!H@Simr38@;D^8gl{PhSaC6bdf$mlX z&ZbcLqcX+8FK1=BY?}jQu4EvcIq2d*ivw=92?t(OI5@baqQrqAS0-?v##vA*CyFAW zp22Ev(w$xBiU0xwTux6gi@<`ijfP4CmvGa#rS_m}zD*mx6<*>wz+c~b{JuRqBt3#> zRIE5V%o#?OjerR0L>f`SW!(uFJQQe9paBi8UX@vYMbRT&IOD~ED-}G>c9T9-+Sqnf z&VpQ{2&O3MD1&#l z3)_h4Q3+Qo3RFt2UDe&kUy%Rz0}Ud>gBBEWPY0O+B=E%gQUPONocGiUhqtGTy4n)= z^>&k)eJT>`~FV8l42+Z?Rv9nERcO~b-Q-o)Y)S&o(t5B2l6*=7p7 zyN@g_=;b&!wZ|Lu#c*|C@zaC?Qx^TSuC!yJ>Vd!=RnYIx_Apgz>f{@_z)1y^y6h@O zfZ)fX*> z#`_f$=M|D_(0aM|McMN85r-49caK-@>-6+q2Ke^f@OnoI3Nsgc#WI?4323DX*@156 zW^`<2^?Gj)g+F~|1azY99kFE{!Ye|jhWbqn3li@VkyU>PSr*tj z?-;o>nw4mR$e;Aebr?)SUMt|y7mypVkGWyc>7NTr*(d=+g}-Q~zR5Y)rV_DDnazZg zq=drFn3$GCz|c-D&HUy;le+A*L;a=IZA1EEs{Q|m6eD{xy>lZ}rDwhUn!B!yp8auf zv~)bLfT-xsH_soRU^#823hh&9v%?i-Y)t=p6YOx~qsv;OP%^G)#999KEQ;sGFe+c) zl^Y^Y^IF(0^GR|6pzf2|eBJp5-4YNA;|*;K*J_ZO5%PMf0Znr6`7KtA4se^5ah@E4 ziS}XG&HE$k{;#tGv{%&`K(?rt?&}oiKPhT2PV^B?l3kPgJGEP02w%L97URrcqIcg%Bse8E`o0;>ehc8GmzXSm@ z=A9!>oVG(m`T*%d=rZ9y_8KQ8A-sSanr`fof?jz5lz}Sr+yF%u>coYj#fyizL=Hbu zTmtI$=8?%~=?>l`B|s9$3ZO8MPPLxlFhyhu;GwB(07A_lV!I4Ni~>@Os9Qk_kss1> zk**OjeVRfu6i>MkJJ!xg?o^Z3vKnm2(h^b4)k;y6Yye#1^D+r@r7nB6LQ{6f*4jqy z*)krM0&0mtdh(NIAbsg(<7z(rnA99PN({S|as19%rAWK-Oz?*!8scs6=eAAKq_aRaWrx*Ym31j@8hrb+qJ1gI%(Nk>lky0}1kN?d6?D z{DHzK(jdg1IYNqY>Rj!$uYfee< zHXIlL&hH{4vdhLcGc%AK)et-<7gs@XG10Cm<=)}Y(i(|!!V)yP>jNCx&1@`UywB0$ z=^9LWb~Y|>rx0WN7m>9uQvTV~<0Hq8R%yZ`H(T5vdj%?yF!-0g$yL2ipPE?S!poCV zHl7|_!()?3pM~kfQyf%3K0534eh1{bmrR)F*u=U1N|Q`bM(W-kzozqH^Fx{mcId8& z=~eotk~ydI)q?Is4n(Os<&xN!bT3~lJe4EB5cBRfEer?$^`Z3E-D3XvIei4NScTF1 z_Xxg`#T%Oln|Br#9lV(waccad<^lp5C3^rw4LYc4YU0g#@oK4!>j5IZ8&wb-VuBBo zLs49<1X7{V5K-AMd7rO8nir*hd7Ft>91QxZ;j16jVQ>VD=|AGY59x}Gsf`K3LlzGA zCH|#x1r;J9o1NB}X|C~giofiF7Vcmi0F13tySIW>2G5fZd)KNWZT#y44^;8V->q0$ zj8IX~Kv|WX&oZIV7-Pn0*n%jqqomD~`&8gVk$_IEU(k>7pXkyS{E*M*1UyWiwNgdTwD#XiQH%`w)KE^ek@45x4 zcY5c+hkQ_&|4M!}VIbl=Gr%-+I(tA1u{)=PG%^ainxSUcQYs{qX2HZB2zNZh?`+y8vtekMK|FBS z8fYN69J@NItQg<$gW2idQdHodag_O=43DTku&@-hA*D1B9L z+c?W#OKodJqwVm%HL6eYA{e4KeRg)?jEqF7EM1SnB5w;UU?VrW6E<|f;@sH@-J)4| zFx@cO_RNSbO4-X<=Z-OUncA5_%jH&aXoZ~7e-CGB8b|93O_2yGwz-#`96B<<=(g?1 zN1;pFVyE>CM%(SP^JQGNr;cgcMEW(x-a-;= zx+8;|dbo4NObg*0Dcj5yC5AhY5iZnctg4~3mge!>D3LH3ozx7vdcDli zzd11$(Lq&!f-FVO33lSfJY<1cEuz%%YgzKe9qvfp5AQpMdWy(Q3srO{dhrjRgKEjn zgDi*dAq%^8Mv={_8`8Ev2Rj{cJ@QCt#HBIgVz-d^zBZ^r2GuG=Rq{fJcdn|JWMVLd z%);0~Dxtwj+b%r&MEa*qy)k{&UW>R`04LXCY#Nl86@yyX$>q;W4qc}biDfr;v0+d{ z4c*o^>q;(=c6y$lN}8Mdq#Tc1QQ8_U(Mwbe-wD6K?3WHP-6?hkpH-ccH-*G_^vKZo z+LrkVK_Xh_8y%xIiSH)a$ozTX@NMJm-(ngg^O_-7d6;{&VDwu`A9Wi$mvSEqMep}M z_vUM!6R|Wqdman|I~TlCk7Zq*pLA8YC$32jip5d)=EU{!>4|eZI>wI@O?V+rO+luP zzgt3z7z=+WUxzK7Cz5TIR{ofHoNp666tIzA4tO{E<@LWu<#S*+Ad(Dkw>qij;0@@^z{b==w1w6*yN3bW4UP0B01$c`zEMw=a_ZS3Gs)N6I$2&w0P`lldlM z1q(-5r0|{J4%C6Y>#(TbrAFO+Lu`*(I(!-2)o# z0ZH)Jch^_yP2+G=kWkkSMP-qLELa^zcfdk|X zLSlB~!R4sd?=^nc&}+U^`MVSJe^1{A5}<@=i;D25`Gxf#U;JLAMo>GnUNntG-_6_?1l<-f<2wH_BW}r5cd*Jis@SB=^O1&16X0lywbI>%PV)dA9&#^z*q2s{uL~&A$j(0j@$VJhyYX}HxXDL(pQfc+ z0T$>}oVfYNif|Erwrp%GVHvgDCst`zzAg{%pByJJcJV)!<{h>gT{c?BSU)dA_=MfH z7bwU#C3N-1QxUD%q@!DH4siY#3TECS$YO1tx{_C5?dw(i<6>cHC3L)|5B-E(a$PMc zpG3Fcu(Y++G9NE3tBG|Dik4-h1;vHE6SAKjbvmg4#TeIf7xl6%)6x7yhx{6aP2J|HBlTpwY)SQVmtC3E zvYl@U%0}+f&E{vmBm#BX&)hUUnp@M#@#2osjIMJ9E>x7TyS-%B&P~7BFIHQTJQ^4I zPY|t5Y7}0DU!HI`FEo#2iDWfW!`0(e{SbolE;6g-w00IfoqSC~XM{Ns-=fHotu}U2gyt!w`I*pM9k+LC(0z^W z^WVC^LIjVNc-)--;Yi9ru|<$tB*}=;*vqc<8Zd8SFqVzaBslG!3XA4%P%KMaLVOfeD=pYfa0M;Ne5gIydjg?)d(4r55<> zs$m_+aw@0)Zd!=;o<@midVDcO31{CNI{P;0??`gQd@GRgpF?$WhxcTVtzt{{HLV4* zw%(t_m|NG*j)(|%$U(-W81;ZR9!&FyvJ@(ccvo;fGe#QvvF`Hr=-{CR6d3f{4pi#% zyXr`=AU|2>jEap;_T=R6K!6~y-{T~Ot-8+1-^nd=;(mkVwx-A9lE7GRHcCGDnRa)@ zm+y%;;6XNei`2QQWOLirl96VSwU=LFp#sa*J4=uhyApe~bigpg>jVGlJL6eG#I;x| z#zS#pLx+Wf6TTk;NQMaI}TxD)sUnicISJOEE41FW?f1R1UWbE!&~ z64(>bm!oD1d>-sH)77L?#^d?niTY2Ejq?`PAG$!SKX}RW$*UZ)o4``cXzynT4Ge5A#)aU)s=C=R8blDZ4U@Xf@+ z6A^t$+PRhoE=8Q&i}=}Rt#^AokkWf?RER~Jp@lEAe{_k^Q%mMh;48%<(rg%AI9u1@SOwFnO69vG& z@KJvqz=@s($tt0WEse@TAZ;K816ep9683HV-p?%j`1=D^nqe{-2oL?^BPZObD2W@R z*buiT_;?r&sbTv|jPMo1&9>iC6I1nO4r3TgU+4xF`3aqeRo)jCUI<65*sz2LY;Qyj zHPj@$a_U+Ag`b^gKRgKeknyj_o)N%1-|bNZwh6`wXiL+))5tHfIvSD;G`0#GWLyls zyB~{-kcxz6)M_Es?_06b1+)a*5WQVy05|{F3-I9V#l@c$qh^?y0HL2HBfRCiE%Io| zZLO9g;Srpjx3!3hlCJP_pWJJcyLzs8{VIgGonE1wx7o**t|H=k9_h_5=rzHibT$yh${5H3aCd85wkT$!9iV@>UCFTR$_4~B20 z(tlfHC{p&o(;ZPtOnr1|;`qfrixLJ|#ELGZJy?FoAv7_ah?7y}$g<3#^L(axcXd#- zmIqNKLb5UPZ`>2;D~q6@1e;^VXM)=g||DFRp^ zHj1^7+s{m2aCPaZ!jAD)za=LH|L&kk&Xt#TaV!{NJnF6U;nhcUXvGuvgN1uFT|e^R zb#;!su5Qla5`QBgY*aE7jJ1es(PwMY$R@T%xm0_nY(-Qq(@%c*y7rbu@^bj2K`> z&KqvB3|eaQ&B@5 zbvFCO%|fcx$Veizjho`%T9?@~$pQ6@B5)5W zt8*n1hKuO{+rIEobQ=lK6a75>FmA@9j4-&=*vYWJKm1Jf9I(;lNwmyjh`AhlJgscz z>x$YR8t~6vB=ofnkerGiVr^n3P9iS;1402q=?mx+W)XrBtbckRc)254OwEw^nayjGp%D=5BG@B8#&o@>Zt{(oAmUT6i&UV z?dct+efm)ro)nA-i%fXjSvb_h``!9W1gX~*$3RmK0{93h_AgRJjCA2)E>*vLLFBR# zz}sRBSbMi=7+zjS`n4O#i$zWo6J&8C$Eoc$qxWO?@+*;hE~!o5xekiuke;(=3)cQe zBjLXaQ9pC2Q-*p7gc^3ffcRo#3l$Qnt6O7xXr4d9&l8m|YZS$=Jka%wK)+20oy zbBo2hPSn3SO0wmsb$!}@2^mbLQ)VWl~5iP)oPW{dzybMX& zWZS)}5hVyiXr&yP#yW6Qm=8s~Uw#tncIoHuctzf<5{m5ZxP_ijda$atp-KLT_D@Q} zk8X=Wy>CoIL1WH2OK#h2WsftiPK4$eI(WZZ#A==PRYG4vxfnyy_(?)c(ed4~0RytE zGyF5FxeLiVs4+i#Di~NzCr=fg00DL;@x&pK8MQwj%|wcS*9UGc*G1|n#n#qh5dzMC za>paxi3e(-0>0K4p%yW$|N2ip+rJe?dYXC5dR=c(0ih7C@aK$?>-US4+Vl}OQVZ+L zWUYT?DXR`kSi3*>cv{DU@$im99v)okrPb{}jUoR&T#pX%-6g+`&kQWuWm)D;5! zu6nMOiR!LTj&+S>kGU^kG|OZ}fS5*A$gI{g$Tm?VLO1o)d!~mqo^9SzJ$@6seL6Wh zHTn7r;*Y4rv=R>!X$o$v{FrYuS54gtAO6EI%1z5YtG%<~ zDPcN&f|=}W8tWQEP{_fgMn?B2?r3?j&MTsYyghG-EXOagfX+?+dp<+m{Iunrp5Q5g zMrgn}erpouVY{rrlFToG#>1020{SG~pr-Xo{Wc(!Hqiflcm4Tb|LOXLj@)E0ZG2`n z@W|0x!b*mC&y3pC${d|Q#?HG{fU0L1Eq}NZ6YDfGJxX*y3W1W18}|#+uB=jwxTP&g z-Tb~(!f}yw6ytu--($tHIHBVq{lh%z*6aBc%3tPVK_RXei2yPv&Xx#cN29@Mo~mGA z?<51k;KQC^GrgjUiTig8%Yq64J+Qp{qo75Vh(^cXv!V z&i9c+J0n)Q=0AxzZoWxEOzvaQ4h9ewp{gphZ6a=4r8g+q>J$%N4+HDez2Rk^idl#x zjKoVuyojYvISi5)3FUEkV(r8m4tivdd(<*@1)|SOc%%dV4oe21MYNC2&g+FOWs-bL z$rd%$LWP8KLE>#f_Juut8IZ^tNKF^VRPw`|wEU52ty8ME%O}e4Bx$QORU3V5@oeV{ z{Y)%;G10YTc1}%DRS2k#v>pr85LyXJbW_a#p@q)s<^7rhWTL%0)F}XED0|+g}fRLyze%#!Mp&oaLnpm+D1MwK>&o^X!J`#A|U| zaSGS@KDA7O#8Yf&Pl%~_LMBKbNxF@JjZY^w;}^U^x^-`Hy#quXM-v~nyV!LRh!~#s z=Zt?mpQwvm8j$_GyHE)D>0GP5)#{Tkv(?SL{$)Fl+-YdRgcM$2Y*sHT^!5kMcNzq0 zsu4WLgwL#O8}UK{OXmAe+d!jwnjn9BSkKhR@a>mC@gg4VLVrxWy@*dN`n-C?R0l0- zQ#;87uxLg;C%O=(bKaGkOZe|oLRKN1V9sRN=kQfF>$1^aXKgsk;Y??b5{=XQyA-jV z*P1ZnYP67LNQ(FgM>@$LDQ%6A1vGB7Psk?m)xuldm2OwQgrmy#6K( z6A2e7pwYJ4yiD?S1c}fK@kk|+ioVlo5eW;QGG+cExNTE#$%a4*R&>Oe`xl9;3^Tqv zei07&+@vNMG*1)j|EBcX2I4+-yZh;uH$TqiWcWWj1~Dsh;nT5s$eD%mV_@}?5S@G_ zVjQp^GzfXgQ-qUo_ap1xC0|l+eFIP9W}*ef+rDtVAD#kdQtoMUMseaxIesR|hi^z7 zq(ZWe{$o0YxfLN`Y}fd$M>DRRU+pB}v5*IULsYfUdqB3woaq*0zgd>?`JhVLTXVjxPiLWxbO1in?k?#gZs>q@thKHS36 zH%c~2csdPi8gNIpJMNKH{vQhc|8V9y$S*DDA{>$Y2rwuH3nD8OQr{agyP}YQc`$Mk z8Y$V+RFjPZZ*&F0=Xtap*Bcs9h|7kHJ$M3;tOr4(fD^us_dO2mmIvK{iK(e5lGS!M zm^k!{u<)C}7q7aYT9)gs!S41iOJpTO5ju~%>#@DpKf5+z==@OR<_AIP3tVTCe@0Xu zvu;4PztWbE+wc$JUqGgi`OT!JPXgI(p&W$3Wk%$e+!x(5J*wRLx_NNRyY7d1br>=g ziQo)qkh{6TqJiS9kOl-l=%VL`vR~6PvoU=J_83k$M!YK&`zV>Zf|6jFp0b*Ep+*Shg|oVLCZ5FxqDKEEeD z)xO^)UQfoT)Eu2n*FI*k98B<9SZPIEBID-3Ub?urfCPVhkQCYTm6`sbSNt8+C+e5+ z-hD);-x~w~d%R=(In1Qm23a42@6X~HyjQNrAI6_w)@a||AE+FS+Jfx}EM0CkI4w)) zSh?AQyK&d{hb}Nxv)9%(Wpk&25$@)H>zGKUzcs zy@S-UGSQk04RPSgp5RC&ZT;LgNMw*n71c`nw(KY9AF!w$M<1l^80KdQFwle@;2YbH zx87y%w@y6oyBrpePp~DWxwYD*(=GTUEz1uOUTaAvr%EqBNc~0z3XKuft8eub^WAU~ zlk{Kkf;9_n5&XWp5o+eR`iy2)NbiwBT=wX&jvwXF8ValH5$-FXe%2@@CSngZ*-D0j zZj^j<*AellKBT(-rZ5zKTx96)A^Cn5i^v?(w<_G?Gr8gKJPX-Nl z@oZ}RSPem*z|h_u^Jc12TG~Hyr*_P<8&ct5!oHknGNEkPD_zCk$h8@&tXFDbTcp@F zAmnE{L2Wz;IpJVAB6i!r%J1?dBsv`y4QgHy+mn=#l>KyG89x|aR2?al;3v@2zlCYf z(qyhzkp?>?5m2#f=?B|niLh(!z*rxAro}Q`hp{CN2|}KlscB&)zv_Bn7k+zos4#p% z@^sQg8Kb&YkPj0WtLrQFPv&9dI2&tw7hH}pW@(UnK71$I$Z)^|7?6|=Nm^m?+s#Rm zso~eEWRh(~bTDp0oyDIm-wYaWIEi25BA!xnVW8;#9qz@F7iO4y2Elq+pwMQ1T`Lm%{qE?{fe`8G z)C0;P<}?;+RS05{;Z46XE*k8g;pCq%uKt9cD&ubb3Up7mlD7R}#2@7IqTBKQu7R=} zUMiXvdm75%Y2(w$yLeA(DMzOuWPuZep89 zKx?rGxfMe~c)V1#VsdeOG6N(RMw>FzD`QBx`P7Y!yLDQ$2x?K+g$Sw$(`}2Oc9-VO za6OMq#GyMH7JWIi@Cc0ipHZv(`(WDDn~$(}#e@M-y)5z0%}u=2D(}_UgkrLei<_bZ z32?qj&#C@h-cT)js@|_*8Z|*{j&cz|KA(MUE zH{VASD?y6fZ9*n2Q07JT|X%re$)6 z!Eo4dvwrBxA|T-f7o!aQ)Y9S{sP)}2IIHZPTFwhp{k&Ze$G5JJJQe_2Pv+J-SR;RU z9|1yzKo-r+yN@ZcEy6)$X;#ywmm9dBha<(7V@Vw<+1*t2z6HlkpbiWUQ}P~w9a)fV zgLlLzLiB8`-t+J{Tb7q#0iuHQT=B1|Sl<@hDZ7j03>b%K4=H&CrL>56Tb@~v0D=|j z;O4-qK#Jav+%h~D2miaKfRzRx9&Y=!FTuS6S2(OX2|QaMahZ@~FBND`igX}6x{f1P z50E*JUt}l`*7+K;_qge;tl`;2a2hT|ysH&gPmg`4fxM2Y#<-D>^Isriq{l>q8`3+; zw(&a_6rt$8TvSlZh{W}xMz4$_E}cyPdG;~SZO~QPsS{BF^fAeg??t%W9{hU6YULH> z<2_aaK?d;w>s|f%n`eh~c7b8QUPoTN^T^mnD8ciDp7CB)>wgy}^e$fO{m!-ghzNH9 zHEdgrEoP!QO_YXOJW#+duktBPffrZjntw;XOmqw?{x0AnSEp~b7OF5`s) zCQeNRRZH*`O3(&Mn0po>&c+OqFY8qNGs@yc-SO9kKTG-E4dZrgf+YWyOx_tS>j7-5 z)Bdhsb(U6w`;8bH)TRzd$?2$1IErLkTTs~dJJp=oF%MTw|1iXf+4*3%*(#d>*>DQ2 zZdn&KqgK1rConX3ZmsdElooc5zL7fSIrQXYNWTlNHxOPOh9uUKTnGA`1s?5nW1YG|uz3OZ_*(({wC-Lf=(Y+9G5BJk9_7M=TMpZOuPe;3 zZCO-YYcP0xyZnt0NmPx|>10csV=?WN45hFoPk4`s=p^5e7Op%N~)!+N0%3oWel5CQi1e0@zO zZ#?+Jqfea=C%=sx#2Okji}KL2nK0zL2)N#!6_DLb&1y6cFxN{NIdDle=~%Y{od6&~ z1=TVr?V-P{^ZGwRN*FnD2Px@hwO{`hz69!!u9x#v5X^|;8Zh|$H#?OERo$8(2$V_= zdb5&s;wKhAR*W&YuJI0C_|$LppGmi2t?5e2tb-)5BD!GQc`8g{On0 zu5qt0b^r*9%Xe(=3{Nx3U@GD~V7UNixh8%>1`{AN zkwuh1x0b3ayAu3u=fG)~b4Rd|cjYymmc%D_M3eFTbN>Vf z*>$>F-2{bhlZ9OBcQy{l-}rAvNUART2o1;BgyO!>rO#t|YWrJ&6d6V~O{Z4n-^(iI zl}0=H0$F&AL`FOg!-hbs}(~6PVZ=pFac+pL-=H~`9^a`Uw%3MnTQtk z3y8P|QgK}7p5S&-CNj913%(l}C0j_M{P0E2Q@>xhX;hQ(=u!!9B2rX z!x8eF$BasYCDZJL_NM(46;)Mg_*5*#|!WHGr3CO~QJTZKl)D zi^~U(;3%r1A^naiRbP=nx6AUyK!+uZ0Swg?0}TfA_F9KWB1mI8aZHrfM;Ahjw3iweii zf!DaoBtl^!0e&@wr6`cJ3TY(=G-PCypP8wDGki+Tgi>jHt*>OV9>BC)AB8{QL(_6a zJ2`iM+S-WAT&XoQTu4opFyp2;NlPo!n&G%%k)+ZP!=I*HUy?aHvZ%m3~!4mh9UoFyw6$r z2gaCN-^@4s#K%|nbI366ypZBu(TwQtJmg)_h=9qV{kN?ZoO{IBphZ_$#fm(5A~q6r zBdYil23lxIkr3kSMu=fAejG0UsYH`&WV67K=_}=TSdgL9Y2WldLAt~o7JH!%1?`_x ziMi7x9k`Ld#SKKcsT2D-toPim+dsUDO@_`u)77Rduan1e_25%JF0X3BSgKw1aB^cr zE|U|9tu-cVOdcfIpcPadM*VRSCW0-_L&Y{hB)2=YcPGp}g5|FQfN#+yJ}hGib#;n~ zIJJ@w_?LKZKx!qpd$X|pjU*gB=IW$H{1mWj7yFD!S2XMmdC)Kpbt(U_#7HYxQ1Jui zY71#0-9ZGqsw#ZS=YNNGx_k`;SHj9=^qubxxHtIfNuQ=YcXq>>1-nLiaSRhTM0l6K zTvd~9|G0yR=k2OT_FF@qHOl+^!Ob&EP%DOh?NKWpTzYe4@1iDFqsNbuaE9Nv?ZLGt z!6Q#(cS~K zO)jHn`lJSWbT;aSD8BkhSJ0it6wGcWM+YRQZ9>+szL|AJO!a%6nCGqdk4q@up=ELspdjwSO?bX& z;gxULv0F#>FS#eIol{Cgf0&{qeH+@Z<0?~#s*KzJD#OFim|#)8pBKgJeZ?-SRJkha zUoq%)&d5-;u{aG%5yQTm23(7uq&=?QE z3&>}Tl!x=JJv;%#rk(TH;GC3Y7mk^k&H?snWG0k4e3fq)6SlkC6{z0p7bB=?`f%6#I&7I_#qTwAz{Tb5i~ zz8AC|H%}t5PK~a$pAENYq}~(&$pZ1kwJWu>+TMvB60NdxGx2Z7d!5c+#SQ$ zZn<{N$p89c7(c{boX-nSrO|;1NH;eDlc5E)oOD8QvK|axi*0rxZ04*(4nddnoagJ= zOdsj4kq^{Ys+UDl?XmAxtCyRdg`?#iG#E$qUB5k>bh(VzGCzg}J)>tr4(SA%77OZ0{EP4weNYJaq5nQ3^s^13w`R?SwF@ zwfJc?O72os8MJ-M?8xTzgoTMjH#x2%wO;Q+LyJeNlceNe&`70+g+u7;pC=_IK`o_^ zgGY^fyiEH9uXrd|6FePM2@I*D5xXd7B9+$91(G!W$<72CXYP<|Ax#I1^ZHp*bbI5d zv&$b2z=DCiExxeCx&TGVvLG^-MP#o2Q_hF0A-`(vz{Mw(-XEiNG$Hu#u&7(!Zweit zB?7>XX!St(yjlyd;xv&~Y1y<&^+Hx#-XAFlrfZ^;Q_{wWs&T_2hk+Yj z(8wM+6RAbfvKXxoz^?>e$f^UQ9Td;plV<~N% z74?8IB#_=Yf}ZP4doqoj5D)9CG|Ba|+Nx_k_NUuFPapE^|_c4ZK#k!Lk-p|2<`ID{#LZ`PfL4yy-F>f?i`M}D=`A4&ATAo zsg{QQ-Bx8m{_W_u(DlQYMsp_KARyGR*EdC@mT3YRb_V z5EGONj=>HOn8etZ;v(z zjrw|-H@yPYh}Nt@Lum!cwbPigU#F3W9@}tH-SN$xok*+5?S8chcFly-rM2DkALg14 zTUF5QvtEK8#Z?{gO5uV#4m$$bY`?k#dq3X1&likH^v=#2j)p?5l>3%kg@0^RN;&>6*^DPzY3>wVi?%qi8N*!rKInt&w634EKSFu& zx(_n!6bGwbd5p+i50&g$-*a2Z8?J0AR@YN1{mUi0`1}#|V$|*_#j)XNQ&8M1F8N#~ z6Zo4&@9SQ1CuB_aE*56FTqzQh8U9?zuRWSDEZIQaY)2ItIr5H*1$%pX9ZhJHbfv2j zPCxT(c1|bs9|g>{qK_ES0I1~pb#vaKkLAFrv4aq!I}Oh^G4*>mB1tWas<8HPMD+Rk zy5+y)WDODw7si3WVbF2Q5+P@c=fzjhD;=|vH!|Q`vRx%`Do-Hxq5Oz)=Auk7Kdu|A`(Yyxox^R);c#;gah7(mD9x-dteojStZF>qTCH3L%eZIna6?d zW0PsVa0%2gl#E$gMuDkm1WHh`S|hFJ#6O$gHpNvtxdA9G3{PWA<$N9$Pn~ml5^aC!1V?K*g{G zbw@GTY8*!vSu zoIAaDcJ^BFglzav;|m?B8T2`v|9HZkq|0BC6%1m9g4#-cB%yese@>JAy;EjTpWvSs z_U3}2cw0Qo7%s7Sfr}w6+#ABJc-o1a`|luMk~4^l2j2)m}rC5gtBuB9D}c=gJ$XV;TM4E0?l@!gk7<%v*|J}`+J zps+y7e<~Tp+*6lgAWFDXoh4$hv#XBhDQRVZK+)A=T!BQLtpC2q02$^Gn>jN`_KniEp12P;EzWE5^VTjwrsnTCUFQo_$k;zc{ z6PnS-dhGL?vGIT%3z)|!=um~8d7)~s%l)Qc!u9J7VRMzVoui=lQ8H=)8ZboQ6q#yf z5=uA)3H`d6KsHNF+H%l`P&9P$h#gT2qYVk5T2=G0dI=5Sv>16J>EIBWOK(s~bd?A$ zPYK4`@DdC70u*aWj1O*MI&_&kDt#*t$55QTenT16J5jRRXzVfho{Z)&SAW7dF2(D0rB8n1pWET&+xVKLtMP*_n*je;swxJvciR<(aU|QOVh?#QNF&(a_0j-_ z?5|1nbK=baneqIP_B`>;frYX|vXjLSLv(~F42u2VMaLd~R6xfwH0X8@#rve&IQYv< z@ID*}fumqkQp=00C>j-#_$ymdGZmvqnV5(OKt1H5vaVSp$u~L+OL(7FtC0fHSKXirWCy$|JSE+>6_sJX(?=5z^W+aaC*PR@o>mze4#^K1U7rqWAFOZ81} zV=z}SXRf}?Rv;^Oa&Vo2-GnsKWT24lyNvkAPmC}KuLFx(rf=U{L*PT7T%He@&P81D z+P{m0?q4G@hi9oUlNcn`P6;D3RKj4AR2gOhb2q`Q{kGwmrXHYIujwf=Yg@O*EU8+3XNQCSAzC z=u0J=6{Do6lHbCWyqr_!cQ&G3|;oY&ts7uy-K+o5C9PjEtu!bHWu9)y|id@8l zJogo!n>CoIIM+Acm=BX1j@Qnv8T(yhj-qX_MyegmVqp1J%NsZ|GIy0%Jk{u z1znK0Ug+9*v+Z?2G`Q^fzYs}PRnz!|aTo}GHCJGuk_leFB*{X6ct)N@c@OHA9LJe_8 z^Q=VZ59>SMh>|9_r^#m6xk^Zt)Qh-c5PWFT1EKH?tXLhb0+7+|rwNRxyZ_(B{K$D2 z9U01;kdTXfpJcCLWSkG}<*tdd_j)}Dc`MaF+)N403KLl&7)h#3xw#b?i+_?d`$OH= zv4jk6TV;l~z&IRi!*erf^oG~cQ^XVI$>T$ED+&Az>}{wPflZ_TQ~jR(ZQ}J(LlJyL ztq8gmS}oH4$la|m5%CA@5PYe^b|iR*e_p=~WQAM@)9jZ;W2XPo7i-m8Sqd`7!A zV1u>Q2xG)7o0}A|_(r)&Nes!o{5yKJ#`4%3b5t{FNbS{c`^0E8%Oz7C)o>*-BsN6* zV$VEvC-L|Wkm2!uO+g$h|3nGB0?+!-bld6+@7a%J--xiMk4mMyIqe%v&r}Q@EkuPrBr== zJsGv>x#AL13r_a`OoRY-SZ>7)AukNCdu^9`NUkQO$Q7uglo3d) zZ4mY)c5Q3=UO`yW2UpzA^>u?SvXJ;OzFVw}^w;V_wYPdV`4SrYZ`fmRCFXQzh-8Is zP9BLO6s+*Q|H%0bJ2xCkRT~el4fG|_ytf;4F*Ee44+?!~dk|~e30(y;9bVn_$^RnF z)A215G1#`3v7z;+#pu`1F&0>Bv-(j?ebN|tz>e-puF~ZYzK4WGtd`s5oavO@^417kPl2X`VMpysT2R~uRqGOjhQ^O{4^AiM85F%G%BvLGJv0x+(Nf#7vK8HlgbaXj3c?MkK*=Vp^ zefBSvcOaDH!6ttr8tXoKBYA{(+)n<& z2~H(MNI23RAwKW47}F~t1;0i@y9fl7lD_A@GwYnoYYXR+3L;49cmiGK3jN!Vh8Bo< zFIwyKz8Y4T@FIGpT_P=ilEk_sTjRmm`ek7E8KN!&c?JI2psbSKDAHnrb!nCGQhqA% zQU(I{?r6q4P**|onpyL`w@i8Q=M;0vOO-_3dQs9NEfC_6%h2~HSuPzbR7|eAwpi_e z;*%c^$+{y^ow3yX!qvfCp962vb=foMwlHBn>aD0{;&m&y-b6~TLd*$BqzwVTl1MDi z{cVG?G#i?j!ez8!dJ4w)H;ucBuaq|9{qeh3Zzno2w}rxVumu*?aGZ@gerawa^E1zI ze*fe1vaFqnzr%|}Ui1|Uy8Pi&3^9L3)U&_0?a=a!Ef)E{P~pje7ARamMx_BLgcUTt zQLosDHq{sifcC$5u>99gSvZ=P>;=waZ=^(YtPh`&^Xd3B`l97nBw?>_Nymf-&DH4& z@5jwvujZ?DKv)Q~NH`Vg6o%xGZAJ`I)%FF0H*8jvYV9m1FXNlIp(sc=)9ay&Lm?Z6 zK2PhXi7inIw`Vc_F1LcGEA1?$%*#z4)am27eFuD{uG{bvN4WQ{rWU>Gh?LwSt}b{ zDLi_KL*a#_-`Thvj~EXyevRU^>|d2eiqz|2t413$$*f+=fIGT2*S9-(?m*#(y8Y6- z%j<6wHI^VfKcvXpoSDN`e^n2x`fo_reVKuF>YHDC7lxvY7-EwH=OioC2XA0A+FEnN z|Mki^YI@)svnotp&51iprL62Py354J^shIINcFmX`8C1_9~PtwCV)$Lbq95*Q(D2i zD_n*Co3bv1oy<)(jFim;g+aeGVM~_C5{Pme!jQl(qXLk-C<3aHf{n8kBj4&(s%YG9 z_K<>U-akmBOxHc>|gRfedc+VT^+jqjy!2G<{L`Inax?MH-<5x)LS1!-U8#IJXb*N zt2p7bw~IwNpUZ@?Xco*cc2?E36Dn#XsUH=KYS(40@F#YnLjcop=AvvAQ`)H&)dJCB zqs27>YvOl9hJG-6NS8RgeZiAMBGD0}GU?;fuQXN4Lv})jldE5DlxKx*10P*DebG{y zbOH$I1Np<1SJ_P+B86UFm|B7G)J?H@@^F-mpd6}QxLGR7PB+@1igb)m98Ofuec^nD z7y6LU|0*ESnpZ$@P>XnnZw30^?T0Nh>(Gf(aXz?StiaD--IwBnI;l8yLpQpCmO7*iet1MU=>#r-$&=#u*CM| z&N}3*8i$rgQMjB<6N`)f#s+il?+XoNK7P*U^NqABIo5*&Iz9dDh;f^SN^^@Ir9|G< z=r6_vbp1DDKjmBv(!Na|CLlx>(uaK}i(Cq*{;-%~Rbu%lMe5MIqRr9dTK^^;XIlAr zAid@Hrx@Pf&HTzR4y8*1(ZrhrO&u-DC4Df%wCU!Uztf0 z6i)OWZs^V?i`?2_hM)`{yDwe6Iok6H2@l;vpCgwuhTYfc1op9@DSPxzrh+eyHQ(Q5 z>p=is6%C_Kin#PnF__j_FkLpiW;qgn1_KM3U5h{UEw5`6mqNAA$Z} zc0wD_lH3JJ6Yv~edRSwYHs_6(%jRE1(i;&fAfedEd)Dvl(5k-MmQ?wi|A+Z zCrv*Yc_p%<8y-SujJ&7Wyd0_kX~^?Yzp6k4DE$GrD!rb8YS*6+nEalbYMNfH140PX z+cY=6VUc>cGqI`@!$QR?uO9=bY`F1Vpvc(NQrvK;KuFkY--jL+j6D?Bn`PSgJmJV^ z)EjeaQ=vtJ-_ZO6gv~u&0YSCZ#FCx;20vb@=q13%Y>yqxR z4~J@jVzYdni{qI5!oH_~Ll8A#t#dUzed6~XKSFn&Q<%*WAu3xo9=q|5RngZY>&M_h z{|1Y(^Gi5%d6oBhc?hHva~)G_Y$5Q0Z7?ZfeeT@bho|YG4#^4>#H%x4H|b*;ijr?) zpGbHZ(uxF#_zCZxx(I}!u$l&5;?d%y_3;Y+74YXiLOjq(c^3jhMbLP40Vzv+fv^Nu z@VjDgC2c(6EL&gf7_MAe)%E!KvttI`tuOeLYWn0z{tLsm zwn-FLW=h2=%6uG*zo<4;o23tmWuRCH$oxQ#Kqx%F8JP&?fE&{n2fSVlTyk;0s{uH) z)^nP>p0gJzJi-ChIaUmD?eF9FFSi|!Quwpk`0nAhW4hYWOqJ8nP~OfnCt!|fGX3(f zxYY69(iW7d()%6Svk&c(^W>cu#kZ+0e^LlVS-$%a{EQEv^RkrTy9&jagfPKI^QQFT zgI-J^c|Yg!7?Oyv7>rcHu%&HO)=V9(GTMVw!ZEY)yqD%THi>DJQ3-30Vv>HhXLsk{ z_0D_y`xx(SmHw?`iKp7#P_e4(*bVl3{BPH^SS5gB0mMooO;|3VH733eBGwZZSZ1`U z6~_jub*44Z22RmVOqtns3dapQUmfhjf3KCXOnKTNp8AxDZ&hFS4cTapEBRv(Yy9vC zQ#eINyyr@jt1$?XHJnnXsBA#7*emb^&FRyoLG0bLi5o7V9$YjQ%z zqPo$-aLTUWmqE+m#%Q*Xl?WjR)_&PQIx%ny;WQTKg2R6GEJD9ecP!qPlQT(TDT23U zgi3c1^Y0&=Lat_f4}gMl>=Lj zje2{wi~u@rSAhE^l(%Oazm=xrGJ474$2z zY_nu%pF^e>7adi6^U5HN5V-0m=gS}Q>f1WCr%=6qRu#;9e04T+Yd2vgPTMKFRd#8i zU-@*@W5*48b*lHj_Qoo|+|D}uV)po!p%>f(g(lIx$EP;pfwL^9-sy3dSJuC+Mi(gN& z-AR$ynEiB6mQcO-d&qcLo#qQPFzO!)MMLGnnf=VmTwHKw-houlNDHiy2&ECSxZQNW z)cq?lDl2Vh#l6t~M(fRXAGvloEIQdXX|nw`5Lk6=CPa;2dG55aWR>L|beKyt$%ce~ z7#q;Mw`CR7r#N2B34K2C6<+Ll#vXEUv(ChVqP@Fv9_+q31UA3T=+w1uXMSu&xf~C` z;m|BIQBV=@mUNHzz=y8Jqg{GS>m-&lFAO=nu?`cS*y@Z^=C<}gBXtQGTR7@5jzD0< z(<$OD86nPEWC*?UTGgD?z0O=^jHzGX=p|Yla|z~^n%D*kF1|EXi~w{N+sA*rz2!s(CxvEWScX;D;6=4DoXV;S z|1{z69*aIQr{c3J<{T7-sbV4&x24v`f3oU)$`HDTTrt^zBEAIt5Qg#eJf*)mpJijo zkuGiMx?KydVzE@#syIJ>bbi71$P2zo+m&#xo!smsbIGJs=J-D?0IL{6qg=CMu$gJG z<(dYYY}}E9vn?bZI1R?IaKy~tY}<-P5{1OakX2SCTdIYkctv`f$0tj5{44FLUr@*( zv8rI10Nq@C{k{aGZM=cy%saVIWMzc|;N;Ui3q32?F}32u>1RH05g~D^THC)LZe;_6&lr<*c$F%gTuElPxM8{&-x3>AR!R z64tnqLZPW7OByvL=DtMb^kKqC)H8a{;B+3FYCZpM8B=fz91apS7A@8-qf)ZCKG&|2 zOO$xUIr`2@Wwy}t$Na{hvg|f@xJ=*fIsj3p{8Jh%ZXGTZ0Y+y<*F`<~-Fz~+-cssq zXP+Qce7U+${}iA?#H8X$8$ilYmRm3oU7#VT;9CJ;z8gEQMdH-d z$Uz`?$qdt{SZFfW(PD>%U8fr9gePuYCQD*CTsC^;4JrqYL-9ID3lYY+GFlDoW>b(F;@bzOy zRVWp2A+}5&A|{3hMj%d;AW`J-F*2%g&hs`{2N#9;76@fC-)Y`FB6`;VyQ24A1%;g7o#n}VQ{gwkcUAlt0G z5U={D4XFKDqr=C3aBp->Z|IHqvE5+j%^{LzybTW_g$)~%wvD`>j+fS!8ION5)}1hE z5xRgh84li$`nnFbA+~h%i9aEAFLrE*IJ`f;xK0dq@!s;G^VE0+K4<3LAp+Dp9pN$?ZS>8~+;FFdRz2Kv5jNp!Q!yVVp!^D{?TV0o4j4Pvd|Lpk zEb0+uiNPj9W+go=ZzwkTEW8kzBeIRpi}Q2A3kk_)4E*3)lDi(-l>gD6)6{GUpVA^* z>og@uhxt2jXeDHb;p^4m)Hi7)qUs6g^L|p`cKVtS4%8a;7-|ZB4G@k288aMeDiZ81 zkPJcbh(LtTnvB$V-$ADcWoE4)AR?ShRdKvh#yA)!J3XV3nuYKPun?cM-RreJq9p7E zpyvhJ1XzGfbd#B*9i$A0@{Jr&N2*7n!d(7oS8v9Ra79qqi35viD0RMNG+nY^UW=pZvfJEytR!! zR^-0WtxrOvn)U0FVm2?Jw{X?Wh=w(pXwBpnap^b+#~5%1H9y*COD{W10)fZ-4L;jjSYR)|(eR zrWgtLtqB5b>KcoYR`hs9?LXOKkX^RK5R~g%H+h9il+KeKRWkb|2OF)W-i>CU2Cmjs z{p3);lk(EH$0Fah?jvJwiM;VQ`^d5eM9;ipm%tSUM_PB>Z>$n!px`*+AfnXsYQQ1( zyr6(9u?Z*E$0{kBTu(558A~Q$?x}B0Ula;^n9+Eh?92HZvXN69YM29y^Zoq3Y9l=9eQjR57m;VmrZ(mJi2}asMx>4q0(ok+UL0CiCe@1 zQ0Y&st+OeH0Uj$>?pWnZa4VoXR>j@>h8y& z(X0pQmAhoL9PAd+|KmfQ_KzboVMk>ze7!5C__Dtki`AC(#ph6%+y-3iq%LOE_@{l*lLh6d&`}y7O5=sH`7??^R#d?QPmFbS!Rs@@=z8 z%$4cfSIY!P3td$!A38bm)I9c`Z&Qcz2Z)t#LMLcuw{IMQ90~Pd=yQ~j^9VNHTA;my z3SttJ{6%t%Q{;x>@|NKcQJX*h!%l~h*SxSr{Ci+FowIv9S$00RImdT|DA8=r!ku&R}u=CAv zmERuI(t?V^`4W(H%bqkswpN*Xds_#7Z(B7oS^b*yf=IV`-`D}!!N2>Nt0bNcny2Pgc(6389WxoH zKKoajjHCn%^D;m6S)nbL$^?E$CmEKcGOCqnmVIFyKQ~nqQKyZ_zOOaq4IJWa{5~lK zc@e`R$GTSN_w0ME0N{eyHXxBpu8Gd-4qV@7g>V$3g7fuNs^zvo?FwusqqeUqBq%&S z4@mJ;l3#&E&|u_OLm{F3lAj0>_sxnbN-{dK!U#_Rk?=@z7c}VX8oA}EK06c*ui_yH zp5%v5eOiC-O)8rbh^fH_1m6nBoGYC3xNPvgaEGA;y&_=CBj8-c+)MG?XAdrb=Pdv9`ECw}oEd{AP&+37VPW%r&3v%C z8G)QMB>Y~#F~f;EjWf$0iCiOdiY?^uiFCF@$aCCdddEz^QaE1WK&PL^*{7&B<004e z+G@M)2Y;VmN$H!jAHrJE#VoApEH2Q29duwZ*`aws(n&j_31P=kuC-YH!X(07Dk4c_ z+I#U)J*NfGOal9iW!H(`E?3&Y~ICC?(Qg?|}it1)lbsPMZ6C75S@a1Rtf_2aKB;q6>_ z%j%aywPThM?lhacTb54d@ zZ5rssvJ5Gl71Q#*f6~%qG%X{tx{-bXe{u(T8+y7jV6sp_m+MLa|}tc?7)rG>Ss4Dlc&qED3>4SM|W`FE8)`wo)y zFMm~j=VGx*ceMu0%PGwqG|Uh56`vM?7qq4{2Y){ErH}cI+*nQu*TQ)7Sgv`=sJGFf zZ28X1ikKBXtQ(ml(erUujozLzEu1$tFiV#Xa2LE^P*uS)2;7$rC+Nq)q#Z04VMk2$ z0wTR5LP(_H!lEokd5@$KgTT3#eyZtp+a+mC^9EVbo)H#mGGs~-S!VF}2`4h`Td!Yg zA#T;RIxSc0r{BeVc8b?OH2YU@B#)x>YocrzVU$WwN=EqCR}fa#q#y*BBUqY+*R zd%2;|um@Gl`-*&Lro)iU+plFQDm_4>%R1|r0PTbz{i_yr)ZVBebZwaYg`04Fa_Lhw=3aj_-OtTxF7TCmG8d(g6MUCy zNd7dLh6*c%Bmel-zp^ zd*{5(=!5Y!k@$cv4UO_V`zJwO4JCcsl+@hRV=2(Jt03aE`)Awi4t_lG5D{zr@eaf4 z0G?SHTVC4lU2@?w9`$+*92ZmOH#_I0u)aug9X-OX72C?=FJqS6Ka4J0Jtk8Ea}@j> z%as%9&od+w9E-Mmw@1>glP?uH`l{H5|EBdR^Xrfl{$!`Il3QSA8Nk;w$oLkMY$UwE zp32wMOc`PADz;P!*$XfgCrn>+eGOF;V6bugCI4P7jS_%|@*BW*coM`d68hOzr5uHI z)kMO^r;|c~fM9Zn4eD;zo3jbEPx^_J$b(z72a%xJ8_G%9P*d;$EHOf0a_JOC3`ng6s&lPh?w{VnO2`8Pro&4nlN|@Q1Vlj2qcPLs&2?f zUWAKY+B*5Hif3@|P0q19(*C@&FVgpf@|uDiVjA|dkJbitWRMUoBkFZ(EDpC;x`gp9 z*KG067mG>qST}lun%?4e39ZtSt*&bR$$#^o#kOgB+tm%U-q3OU;QkHh5~$F3-$jVV zG`txvFRi`V-*^vP*mIM)>%~J=2w!3VKpqPA5C-4ImMpZ-%u$9MR;EIouGG(+rwQaY z_wC>#Jg4Fj(bh)x<0d=ls4ft1Bc|mk5NVBF?8|UP?G)rhAU7SQz;_9;I>ixCm@x%( zIxmzia00mkDoZ~4D!KO`qva1Asv8sOod#Qmd_wN)#@YHC@z-}Qe6$(cxJp&FKij8^ zOuWl`oOLnkvbr=k8ZuqEp|!Z<9SOHbOpL*X~EzI{QDz^H9&{SsHTN2IM# zdzi4eRr5VgVU;d{>WnSbW59n~8us(YH@rFaJf<`pq<{0MA}<>?VUSdYA3?mjn>ADQ zM%wZ5>}<0`-~GMMaA?FHZ_{7k{uIcZz>spk%Ix@`z!uhdQt48nU>4a))^!#u5ifx3 z8bht=_uu$cPPNCA#RY3fIe%Zi& zvT}6;@-GO1>;NXjHG$gpQS&iP6kcb*ef#YYO4!;qDva^+U8me)a^Hx3TPlyf5-93v zU`udtSR5h4-{5?}d`I8pI;r;I=2fBNbu^_V{e1hB$dv#Yn{a*ou|?=&|HiW?@+;u5 zf9Q2@;`hN1FO3HXxA4a&!FG-shQ_wlf{JSLsyctafDqg0s^F0Af(t;QqV1A_&(Ah7 z!fQWLy#jqIoS9%Id5vyWMP2?34nuk&2n|&z*rdA7Uu-1%(J!sV1`g2kd9Z8W(B1Nr zuA;eCnuEhlFJWIy0p^||Ei(rHvnhoQlrvlMDR}i23B@`9ODxUqdY9gV1$^f%zfg|+y6b4e0!C=VSp>g7iE{adI*>6r5!!5`#P;;hux=lCg2= zzix~+qSyW~lp+dLr3x<81_s*~t%TVjACK98+oFhVYGnIP>x=8cIy+xznZ^)}m+Jdj z+)z9LQQq){>s6`h14valJsTVfh(|TK=>lxbx7ne}fcy-Q!Q!wOpxczI%i3EZ7z|lp zD=YlW!^&Y{!#SNBGoupWr?quISCNa$j^M>*ji;F7Ak4cB7`u(@x7=6%E?hzuM?Jq3 z700aipJ28vP2pi@OEsA27xnJqQ>Bkj8sEgyg;_QBZ*cwkWT>C!7k|NGB{2%%U|dFt zYJ*2X#HhUC@BE_nG%n?*piQhTq_ZeuR@zOrZx``bLt&fA5BEEm8VjbU-YPvEWJNxiUE>h@|F?&S% z5B|CBNDFt{xO#Kzz?gGoXG_t2MK&1Dfy#?{UVa=H!;^e$*zbU{@Q_0AHJd@1;Xd+2 zCucJ%Mm1Llk3EL)v82GI`jlFIR{r4AyGU#n_*@(IczlL+SyPc;l*?bln10(VX50n@ z`ROs-I1cyRkW-^7)CGf$S_&kTEY?n)4tg%Sa3-DgnbN+s{)N?4u=Cx|S@!UXz(+Zr zpKlpT8J#4KsdSM!VR${nk|kD_~C|*cK{T(@c*8bhJI4SpTi3;@)TCuRCFp z|CPH_k-G3Q3bhF~WTDw1Pt|(R+20Hk{A!_0O>4GuW)%=u96pNS+b_J081#Oji(lXQ zp+fA^%;Y#$jd(%AN10g0@(4-lbkJ_fE~xheCuWzq_E zE=7WN2HZJW1YGczRe5kR!=Zau%TLL$|@6zoIe{4^)#bM5WCxwF;t>8TXm!T)S19?b0&hb*qr;oQ5WtMV&?uo1D9%QEQ@q$BYgz zSBhMi0IipTElNT;hK#EL9E>0^5is0ILAcL6&pmf1zcAFcyS75RWC<0uU9V#1DfH+jR>(Ib1;3)#D`?HjZ}cuBaS@i><>x3%J24+( z2p1B6+nv;}hg@b%AbqoENqDcVghd`xppi`zKXi--*q91v7xa8`pGNCN=Hss#QbQ|# z{K@nyabk;9K)_ZF6r1D=dv~1BjK0cT%4RX)nLvnO807C5GY$B*t=1Yp z`sZwJ^(UNP_*ZQfdYh(tF02K-aDG<1Cyd=wOQV-Hp5>BtJ~ja)Kz7_HbCL3F-4pc6(-z#gvoZQ6o9m(+u(&wa!Ocme5bFXP;uOH-4Bs{6?= z+9>rpZC7MOx;=g@c=MhYTR_`yPEO?i**Mv>hEWG zdAI2(f*Ur@nIX&#z8i|)TtdhDK5QXi<8RVMaOMTyp-4Wid#dJMCH-M$>>(M;OK~&g z%0^}d7oi?>OS{NpC0x6|@q1{|?*iN(71bFrBHB{@V^k7ZS3b!^sAp^>>fu`knA|}Q z>nQ&@(EwQ}&b}1c+`^1$ZaUOgokoXSO@M5LP3J$+#B48@nOmNKtnJKCO@qw*M8P zzpb?EyOTW29;D|SRUe&KR}A5hoY&k;N@J&a{HoQCJ&RdwmoI(qcMifN|72YfqJj@; zzg&oNCjVDZAZ)l8w?oUZz=bLrAwfuospEg7iy@ov(%C}qXDlzJk6FX2CAy?=5#vE5J_ zoUUnNBva7-M|6=JQ02?%)&R3);31me1m zz5?Gh@=)jN83z3hyWDz?OWM)-G)U&#Tzdv7Noz768KR>GyJ#N$kH%RXwTZP3hMxF0 z&Rm_DFXTpIf5>jtol_dAVo~L{5?)Wvf-cv)JV}?;#C=>a!KcRkDgNTp(rs@xrwWPD z30?SPdnKCv2|N;B=q0pbh=gj<66*-K+xm8(A^2iT8wr-g9fynhC`LF zVOmjd`<+iAcP~xv0sJN@V`5@=mkU%POkxh_mEBQylt2aXdN;}s`S2s*KvMfZwhGIY zaw1Ju>tT)(i-=zSb7nc$*w1D=GT~dazRkT@@HjTE)$QgaJ^Ag})=lf0p|OmcV&W{-XRgPNF5dWMowv&R7Dtd{HhV zh#TuF;B5boWTISzi7%6*IymodZdqJ)(g73&V_?Q3dY2>s01)ofov1`)2*O)BaQi zh{qA_NNmiQ`=p;gDn7#fp25#U>@p5Cn3^wCz!~aHQfSnK|IcrKh2J9>a}1@~ab^Mp zJQuN0;cy*;}lN009*wWz(+EP9L zS-pQRQc~j#ThUUU)=_&v5|C6VXItpCWUEqqLNagl={A*6OL4c@akhtp`((InHM`14d-&Evs{8?= zRe$)CMj9FWvum*b+p*&xy#Py~$-4yGVNHQVG-~M%md}{8{2^kc(s$DPp6XR0oy+dl zd;i2Pe00b+S?WH^1I_I>aaQuLZBx&C;_2wY1aeVHqkK_)NZB4W^Cc%6kF_})V~a;Zoo1o* zG}@t-k16Q`Y}+50{I{@)IMO*10e{iWmXHI@BuFX2e7CE00BozIDSz$O$e_`p{2;z# zZ){#P@L`B%He!50JMO)RT5)ZKzP(fM*(ucq?qn`+oNXep!`}OqVwqB^?7IJ;5l`<- z;e~SMxC9Zf)$>F-pTD+_xGHJevU@p>5}7o)HKBWhf1~G#zcq7dwwCR`-Ddj#s*2ik zQ;-QAmu{*}C4*u{@9xwWDSd@W`%yP)0tXa-dw16&`cz|>NUAjgGjcN-pnplH1gbTH z*rQ+M{Z|URpu4d(%>prrjlOS3^JbRFdi|c~u4^H9QY5kwK6ISRsOXwOUlXq0t7Zsw zBd)yJuhZOYa;}$t@5q2gczm$N^6O{8Ct;Zz5WA3)cBb3zuc|8oC@927(Hr2;k$qX z+uB<5+s>{Y!#ThzPqh3epvxt>dqG>+^9c1X)Y#8}D=HI#63Ei-_SH7yv92vqf2d`_7u#3e%FAN0N@zK0K}ku$FaWnG|J<} ztSIA3-_0|CK-E4fvhOq`qwpT!f0PUeeJge?ey z?El4YiFP6oJ3u&Nt(uZ@-$~yxA0A6T7`XEJYkQENd^D(UnXaN^B4nq556dlKKb}u! zL)-&!RxH7e(h!Ki@*J_6r`6#_evZ`ZtUXugDS-FsV>;`IcW(E=LFZIov(_V{kb52SvlzwI=z2cXg4-y=K{hyeU8JVe`U%=qIb$& zj(oHhJ3p5pq0Tw$KACcC@+c$g_tGhFb{7PwOi9!yIB6X}b;<{-D~v9OrLS^V#A=+! zon)g>&AN`O!i!$VfsgvN)EzC{a%UtB$D zYCATLKa&IB8D!fh=8|G47=*ItAv&Si3m#DbZ-9+=1gUg5hs`Ph#vjnh?T06HOhb1g zG5BXw3-e2KP#$$io7%Hohhy9{HM0^He_A-K>O|M;OKp7n)6MK5WVNXQZmvK3Mo>A~ zp1|p~bD&Bv72EInN*x3!$?%tF%mf^Mc+yTFL{8D5}pzK(D{{kX6GJ3{?lJSjI|o) zWH9*nCo!M)A_2qh*g?uqrWUgJL_HGgn3IeL$nlmUKTN(R(;I1Kk;U!8 zd>pD&-unlV8_4waCYo4g=Z*AyFQX_TU>QnENEp^-%(7 z_3hVANfn{zr37SX&eee!GuO!Lr~I#K4uCr z!t{>Inx=5M^l2}6{ZXax_p43oMZ&o{DE!gF5!%4-Lzjl)9T{&-xiAR=By;va?FQ`n zz2D2zT`m_HjM`m@_r`MI68Hd4531PXAM9*8!Rh?kR>J${1w|!wkjJN{H)iMBVJLnf zAZ&c*GkLAQL~?=r!9~t_{qEZL>hD&f!%#4HohTdmxkFHB)<@SmV&_bJFu7iD1S(9x z6P*;FV{_s@FEAnCmsu|{!B*=2K9ks-3rvH;vZw)eH7XVwbt|_o%F9v9$Ghig5fmXu z&LFUm=hzoeIDljZfI;CH+5j|Cc`_Wx4Ewq)D^;Z6Ps{mf3rGUnPt|^ID=1=nvBAiI zIi1A#YAk0FU7EEyaO!epW0n`YBZUUX`BxoHsjeRPpOvZMf*k=u%c zm+7^G;U5swlh=7(z^5lpsoOn1L!Q5S^oC&n>o%Iur~XH@1l`>)h55q797IYsi#%0rb|VDMEPoJn zJw}^l&ttp#dR|A8l@#faUQ&y6;hXp72)UhUWuD|3D*Za)3>~E+Ny_Dg?F9 zU$OLmyR}1B+;}Q!+IxeQ%7}2EluwHhgg*;1D8jSminWu*g&YI*qX#tba}r4Pm?nNisQ;KXCRC^|oP_vKAtLheOq z`laaLf9f_C^u9Ed)iHa#W2^8uQn1dRTtNdPQQN2p0IQ>sP!pNg%8ZN2aVe5-j>TH8 z{`?luD!N56-v9C%#yjYMhvXfqR{b$sk79pf4JeIdd~g<8Mw1Cjua z`+f~ZzQ7l@+RZ=>fd3ho$Gbja^8QgA`a`F5QgjeI#68iFzxna(U8 z1eyTBoa>v-e8TRN)xcvR(1o=+4u9sK zo`F^rp*1g%DXPci;Q`dYt^juaJj~epx*D@pkBsq5!GNr=ML)BmYQW9$qObhBpo}jU zpL&#rtu4CMT2lEb38u4}(4PlnV)BfWVc2jxmq?(Iw_f%GI8wIPd-968DD%u>+>u}; zz)Xcj8bnNMRn2h=h?(2@uQa=dqdU$BF!k$3%>rew62#(Jcm#yWGW zcLDQ!(*d(pxPN`xHUmR@KI*PQ!Qm^xWPt=ou9#bZw3jTOc??Zj+K#rCARq~UCp3e$ z)HM{PqyoE7i|#sRA8?!ljJX-*BSmu@G>1y!0h~6$v|at*lUU1deXn7@)kdNU6@ZkC zohMJQz%w*CZ!_V;@1)hEVPS*s3d&o1K~6v89{iYZrAi!1K!`Ys;#7KFYmV660Vha* zm8mutCPy@;31x@ZAu;tKD2A|qYx12?LR5cNm$KjZQU2wBdBi7-InQn!xQKg;e>32I z|Mtemw!UBWo6%0?|aHL&94j0-qm)p8Bm)>D|x5z2YnQ++X1ModfJV5YCGu6gIKA+ z{fV#nn&R!v*&$IDe$kJSZy^8oj3|HDTy8)FPC3i*k9&VE&Mmm8jrM!Lcc~kR{2^j` zJgP2lz*ChH8l>51zkzC%b_kp030Y2_L#GEnqc2nGcH0*+h*Roy^*WI`RF2fR{lm%_ zeITD|zef`IU~q&z85ZtZQs=VjovaHkB?kT5d#t!ELY5|<3^=_~%6K_p5)M2pg~t}= ztE#WLuW;se-klr&e>8n#bes*ebvUs#vDMhNn#Q)1CTXn3w%OQe)Y!JwOwic2&2Qd& zzx(T1Yktg+Shaa&dQ&m22oa>4IgoMt?AUUoQ@NHlK^A`}tb9tcE7o{X; z;){yma-pn2w#oV%uyd%rc|wH>zlsT@Hm85oUXSyPJd6hcG?Fx_&@MEOjLo*)&3xhW zCOOv(kQ4q+JH8A8?pOwe+G*AuL0vUYRr4p$etsPzWN5iq1j;h}Wvr&vhI%pmOfcNz z_HL(cFGLWO-k+pmf0B!e{>XJV-u5B_?^QWT8ufjtAa<^$IY5WIRhnRqh`Y48m}&^& zc>RDRH|Y`Mz}AQK+vi!ArK`GZDzmQt!H4hVd)wo*p37le-p@H9j`NOo@0Bd;O@sA) zVr*Dg4G$J{On8Jnba68BV5*SL#|`hxuE%c{Uw&n<(~E9;8)YLOA0;?rYuJ@IS9MV+ zN@hn83n-q&yyp-*AwyGZ6V>#O%M+7ev4VK)W#e7%#T^)9G$Jiy-IQyTc`OFkFyD(6 zdtASNW}K&0-!Mty`YJd5!Q5Pn9d5H_$0r z9g~-G_xpH_Xic)^wSe0m@eHb)pv9o)$l>0?Jx37Gk{}Q6M1$ac&9rtkZ^(2Q?y{T8 zmF*Pi#!1q&H4UOB^P4FvC_V1@0%{U%6=FE!g*f)}=k!RP%ZCeEn&s8#p8>PeO0ry= zT3fEZA6#Z`%OU?P!hX~nyFJT#b(#Z?w}TKEQau@6vVxW)p816C+O6dkVxmOOa_xtz z%G>`CNx^#V_ymI~(ls=-0BF*h`(TWJdRV|Tfbf8?_r{=rLrY8FmK(Ii z*?oU}x&7?_90%Zh!bBy$?cadbx?0gY%w3t=(g_CCcUJ|#G?_5OK8k3T9Y~!+UO5f@ zJFgH6R(hY<+;z!&ruEr25()i$YMI`t`8cWJ23Z=eM^AS?{3Upwp7w|SyhWNu@_IbS zb9&k$vN?*wDQTnvHJLBWBv99 zP%BDMbMi6zU|#ljm67>WC4BW>DXT|koz$&8747`~`^^WdPx(I8E-mV%r>X756YsWR z0AZncS0d1tP)D|pZn8Z-DhN3Li@LClAB7l2=g4|Y%3lu>z>ml_uLF)DD^mV_-@I4Q zK@WF+pJ7!lD`95A{zDE+SqB)MwDuL-JcN>#8pitCU5YT95~Gg z%Tw|O+zLD1U!wl~Xc@=zar(7ZKaw-Kh#o=;4PW~4C{Ya+A_4|AkV;xwplfb6}s^_QQJX$jftY z*wVOeN)HQxz2JQZPrm+%b0U4B`0cf^cMtzh8;{rfO>zO7-R-1?2L8^c{^<~8uwQV? z((N!(*-L~dw4YPpz1l%d=M&P~c8kdSs36L$8rIcCF5VDt&-HlC^~yxg1}n3YcVCTy z^2m+nW2+Z#pZi(@_HO)6_E%1gQj`25__+ZtRz)5&>uP9*5)whq$F0O-JcbfOM*I%r zOzTkllwJL}xM6+uUsMzf`y_?^4m-`$7W!_&kqxwHWSmc9HIQc^muBIceTk2o!^gX? z+l~k5MAM|hp$(V2XXTHMZ&!vy!cPlW|F92=2R0uOcPJf-=x7nAnlg?q>4vS0iphpE zh6PhimRETU^2)%)5AUJto#Nrr7a#7S3u=+!FpuuG5)=H5Sks>$T`ZB@62X^(Dorh~ zQZP@3()uARh#Z$i1r+!O3Vh;Ps`1XuYCWo?VQ_7`VI9!lqU(9)2WnJ2j07yR1|aFC z<8fbpiUU{c&c9vbOQ48K2e%wZM!H76$mVNQZB4)oIf z3*7Z|o9+TEs$9-l6?nvWR4G5;%5LRu3lj(q<7<0Q3x!VVl4Tx*|2>3E-bp&u3>*iG z_ZYbGqhh+fhjPG48HyPm06c}xrIZ8WwI>V&y}uqYX&qwO*yZ3&Uyy*hy>WXc;%H$% z?bDPH4aPqIz>()hp!SeQIDODM6X}ErT387x|Lh;>4}#r$Z=axF>vEG441Yd0+4;<# z-jwu*J)j{FU7!98967Lev~|Bhek)F`3k00@_OT10!dQv+8v8Bw_7zFN^44a?YU{H0 zu{-p3iqR_O<|G)Y9oa&o9hCo}lQ0ouW>-xn4-D=V@VmNy2pQp8q($~_D){{HzTDaR z=;E!twCn89f<&j%?o~zsE_2!YVoAyhf`VT;r3~Nb z&%kAHsWK#orLUWhDW;*b!|n%BzYoddqKr4yd)F8!7c2!C%dZ_xLE5%zO*?! z4+01-irSzHRrQr|eQjw^1y{Iu-@_)f|f_ltRNM_w0Y#y93%Z&E5|DDb;BzBOOx z3&oo+zaerpTrC#7ey2jved1Wry*#n1;5}VmDP%Zry;7I9IGqHilcwtzv+3AFhP&${ zT{Pf8!N(23S6%Z(pc_?Tw2% z_|Rg1l@}5{BiwaF?F3mi0RJ&xSkaM!_faNGXGJE@3#7^w&ue&_bl&Yb5?_0{eh&ij zsd&BtLsKk`^a>IfVkJvB^7cEcb4Jp?#|xv)w(tAO2G9~swBMNDwcwe4|BZW)p{X64 z<6(8u7gbIu7lt~iz-`*ugPEe@DaNR}dlA(heKXgz-dk>ViC6?WzoDNQ?&?^S5+Ir= zb0lTUh55Q1FL#KB`93?wd=K{LGbFU;FE{eMa7DBoy4?r-gxc9R4=>YHIJ+ zf@^G>kNGktt$lZ{O=E0)JWv$sC&rK}%$Vh6!sgn~x*jx^$baYltFVn3$s*M0s~n=3 z~JP9Tx97TnZw}Bt?9@ez$wLQ_4r@~ym-T)pxyV2s5evOZ0;vK5P3 zO67pw1_tLlj4^Q!npY4V%?sZflXNp-ni@F+scJGt*cm6hJ>meT`P-xX2n4k#%~FW1 z=hPl#EN7&i9cFrHzo}sg3t1J9#80G8rV?{i3*-nZu)C76UEs1MBI_QNHIt%e3yD&2 z5A!>zw2q3F;Enc*!;6|35!RVJ3*#aKzr}$4qxshLljC;Q=%_|sqTQsWzj2Ps-AEEw z){ybw^nKXxP)nO=!Yna+s+s?-~CBDO7@$>MSZ~ zn|H1u(Q^pqS3Ys`FknYn3Yss-XcysRXNC~sLH3lay?BuBK3o2)gdcu}S3T#UWS@jr z&h8-+jw_QaNt_?H6xsO z(xNHeS2SewUED%Cvakee1a`wpk?f!K2i64)9ecb;77hOPj_gvrIT+%eU-<`|-+V^+ zw(jpD_GB$?pKk}9+NVi&)iZ@vYcUJX;7)j!tsr*p!fIItt)jxWpMP?s@vG%aJTxj5l>TbP)$<_XW!#;TZ6moBEMt$6nO6W+BUTIi1T^K zMICu$JB~9Q?^o$}?jK+_?X*7j^hurOX+Ojt8?G4y;P9~hXX3dWVNn4^RLM-}4ogJ0 z0l@vbWo$7PL_Hxmc?+04cH6mIuA3n*VC7%cn^{th9*M2-K~W@mg&094?N59}+j@U|K!6Aw?g1N5BYWvo`&|%)nT)=P_*r>za z;>_U}Z66fAy@uxd&-eI!6S7r}+nW(^FR1yvWqIoPyqGi9>pv8Joql>`@c|e;?;P@Y z0LvhQKCeYS;Lb2G^be6_91S{6T(F~gVOd-01E2^DsJamfTg1$dP(q%J!Z%|lt{j{E z(RcE|9x)Fvo0!BQyKQKaq%1~)Q4Db-As8c|=N%QuRCGaJ|C4-=3fG-c0n=+Lv0z_s zL$4h>?pQVJM)nl4P=33P)`g}0rj@G=S)UGW;XiNZ9%_XBCr>hc@tSd_kOzKZ9{nM( zo&nMG^G~96%1jgS7||Nc@*SDZGmD0FG4@aZ{Z{8bUM_W}{>Z>DCLYcvjF2I@3qG#g z2l-9RYQT%8V%ajf7#wLYMP0gCte^yRH@!)WAY9Hj-{ExIv@Z;73wnWpai)zt=0){%s5)chLGdB!=qcD1 zlsp1B_|^zt6{Dm~#W^u|3eidN==%qs=n_*?&|`mx0I6t)Bb*ttlCY!a_jrF7(?wf! za}}{=q@agl$vhzLWNE2tj}p%)f&)0Ckm?iCa+LaHR*6RMV5f#^fq4L&X%QUgK??#{Y zpfqcU7xRj|SJXH>dJ3+92jg~&xnIJ5+YqD>0@zf=?Y_W+0ZAkTAQ?en?S%_kQo$m1 z$qWRFqL0js%;}u{I_!ThoUd_8AdKdd|4AFqdPRw*S zXI=`?^xoC#h}hQ9wL3@kG@612J~Ya%U!YhnQ^UnLDKnnbsdsH1VDG??SS2HBe>-ag z^(_SMfj3*tW&fEvgLL=_Xig<6ERzu%Z;+DfnB*dSJ!De>ueCjUDD*bm>20Zl*Y%3& zZ1a&|WBHc-q4PZ{zsuWjxVx)ntLxoi>+03p@#YCq-<9{v#qIS^>E0ZhR=mB?T5n-^ zlm}_!fR3`o)m_Z$4!#IyWF79KYPg+3=!7hs$jot9*Cre@^LzjnCCY!3`>i$&^9pI7 z`?}M>EoQZ$FiL6kh~xDe2JfGvooBQyQMB;n%k9A#-~NH^E_Wm7Kz;(9loq03Eu$A4 zL(l89AfQ$}!o&>;l<3{fmPf9Dr)U5V=Qw;sdF1D>`C`sg1SsVioTUI_sOsz2`;Q0e3B4oc5WHKGe+F@RDj57p)l5c3Qg4Wh*v9aLETsA ztS#dEFZVDgs!(MxfU#(kPDrE%J1AZ%^jfvx1OSa2T%gPe=7L0TqOWb4dO&dFlc-?p zA=64JbLqAmDEbshcsl!56;8D}o8wLq{p7$4UrC7@l=P||&Q!5+6zUYr(B#5zZ*9MMfowWAB-h zQ&J;D)~Q6alSYB^JFo9z~g6<=B1ZZ`~q0W1uwScXl3fKBZDz7}$^VE@lmmhD^r+smg( zqfds9{m=KwJg_A+0J~ATgY!V7T6wjbK=he+=Z6yXFap7w$mdmC(=9SQrq8RM(GXhq zqu|Hs$Yx)S|21WYXdr>$)~W(a%k9oI%~3PqMYsn!%?>VR(R*m!uUueEV+a}55KM$f zL4@}PeETlIh=n%L3X7~(Mz`q58fAD2S>3wKW>v*#&O6AzL@P(J|NO?fk441;6Z~8I zr0(XuEn~rf8=VB4;mC)(Ax7Eb_fEMD?upGW1~zAY+Mun0t9qQghZ}P}z0eb<1Sg%e zwN;iH5&5!Tlz0aHwYRNwF%MT{N`pdISO8zK?;+Z?3tGPmtAzC!k>Lcado_(s^9kk# znn1Dh2rZWF!W@4a$NGK{1}MiBRIA=K;T3f78O_hA=b#3`?ZZ0JO?m~Kr6~U%T*nz! zmW*hDSUPHRnOL>f1CfEIH5j9c`h5l|7%16*&-fU0SkZOnjq~3NEBKTGp!Ynz$^h+& zUXyVPNWvp8UuITy;cwKF2vL}SUc!0zU4}KVLNMpPiUI@1P1V_Wtw(46WxDR6AjN_1mTki*v~7%r@dW4bUgkUV z$E$J9Wth|=jXC?8L0EG;BO5oqEO|dxNPBb`@^g`Xt8uBAs4*uGlYUASlN=x~vHb?S zPs`*dRT*5{6)Hk2^Ker1_ik&f_flkaXXEUf?S`+SNzS|C=}5lJgY+)lQj|0BhnjR@ z6jR(J;BGJurJE=a%fG;|irsq{TC~+Vs~06Le2+I0`#5o(Vm8i+c}q<{JTiQ3At3I+ zpNH*hF2dI=u9YkDCaG6x^!hgXa}@2F!oO0>E@D_}Lt0Un_s_Q^&_;TAL9VlW?EFB! zP4Mzku#}5PDjvYtfWWY5zZip&3DvBR9loKQ6yVEKQo6z_s2*Sa*LnWmL4Fx42K|_c z2f7pC$H&FhoooNE3Cpc5M{G;Qp7>;1w4JAGXkI_t9(bi3{ty>Sw1Jsxm})~IIENtE zj|+ITTPa(4vZN&O#7xY%y*<{!5m-w0S<(VAGmCzrN+?0}jflf*No!?dt z(Iun-B(@%$H?R0#Ze{Fiyr{e@7-M%ijZA}+pY?}P9B9|B+F=~fWY(^fI|&7A__i`9 zbo8D0Bjr$KhKK}Rb|4gQGWh%L+`Jcu_2cSNL~gaiEIiQ;S@PumYJH&126SxusQ|xo z{F~xQ>(v%8O9utF8>Vbd0OLv0T=%f| zd`9i)tlR$Rfl8RWm1*@R_^HMAJ09S%k>LRGFlW9-b>y2+g?;oV+k94v+7Ep)XVn4G zt|4&VpOlU&+^k1wchSbKf6@-h$bAC)i2I7Bc78bMUuE*Wnx$&I+V}T!sUTqKhXu(* zE#qgjC(Cmat;C0W!{uJ|Tlqc5Yww}>NBk8&ry^I)JDekt7T%Fb{cYW+9Mdbfcz1zs zJGXiRMi#6I9a)3_Sp=i-f`Z`m@|^O8H$`pL(s_DK=gs_n0$$1y_yEKsK3ZXDW_z`p50;prW&N+W{1Kk=xfD0itlLgb$Ts%%)Gw1@Pf5xR&3pI#rTUi zy}RQHE4nmUw)wii;BkA8cm2Y^vh^#?uR}Awy>kVqMR@#~BMQxx&swb)dc~;>F5(|| zkD{P0!cSXhl#gwjr$=z?1PbRC2E)MfTu+`vifVC(Z~z9gv8Skeym&c zz6*t9E}&avFx8{WOsb*3+6_hUR*`^&CQ4;>)ph9uE%H9*esyZ}0nhUBapiIz&3Qm2^6$7Q~l>DRhNhU87J!0}Vdf3u|;b9t?fU!v_W%im!m1Y zV&ioUP7Tk+$aY_g6E*ATX2+>oQ=Q3-@2kd~5%#3cb5T=ZRpdhOvy?s=)Z-!ehr<21 z(l|&~H!U!_iPF81hFt@fHs{#o^JBnNy-Qo2MNucN-ql@*0e8Sh&TVc&1-Q1Btl)r% z=_bB)USTXy5O~o)5s0*(-N>qrJ%rF3d{dZhIdWo>Zi`7?lc6XYvj4P@@m@+qClE)t zUU=NCXdIY}4VIu98!5DFG7@%Nf!3l&T)7O7uwFOu+N4bW$TkjL+f^!J?TTk4(JoAM zUDl!54$J?b`*u^PqL&-PO@0VbnKpG_i16h%RQ$YK0~#k3%vZ{dpbb&yHG{odpSW47 z?Rt@3K3>)EzrwRBe4NYRwFjK~A#BtcHyqzx}5^773l zj%AR0zm zx1@#v3Q7u2BMn+wB2(d}=R?+6 zW}{7!N63nwvc+aNBTDzFLt4y6m|G>Fmbw}<{Qw3rh2C`OSlAmPFjnVvzzoAr=2rzO{0C<7VYF4x$*R67RTY_%W-Rcwv_}ILn6~W}W+|d@9YKzd7uGVt@AjSpCO^9>W+D-3 z?9%9K1TvbK_LTt)+?sR%iYSM|6kOBa`Z+Ylj7}yN_S{VMfe>U{5H}HSJx=mw+=i>OzZmZ^mco0D3 zW4q;gBJUG|rTfaI^Lgd6_A@8VY45!yq=SCFPd_^jiHDoyVMxlvYRgSBY+Y15g*0gw zD&ZGqQ1+ejo@H3H$Peb7$gtAkO&mHWj|jXsUxUHIeZS5v<-zO9ssj5O7Tw-}MNGzo?eJ~cjf#U%>l2&d=j^$o?VYG- zUg1s7;o}pQW_r%UD5(=|f4-8iiUPulV3R^I;La__RD$F{w)g%$778eKA*$Z&9S3*; z4z8#d$y>!eVMrQ!fM_OfW~2g;vq?Ki?elJ;U1K9n)sne~z`U*!xcTyja;uY(Y zr5(r=wR1u$a9Q`mw$yZqHgd6PM`q0E_ECB^Og0B0eQ&6Sby15ob*OQ~v)|qklFIH9 z6;|DW8l;GcW@}b(H);1t3VJihBg+^`K>D^JvEeDQ{$xf9%GdfUunm=9U%MtODwLRu zP4%LP@2Dc*rYyY+{VScgr~m|$TrCyya_yA}o_W-8XJ+U|+gbLM(-oAWf%B=f1zmyC zau_t>e>z&`Y+j0c&`CNU6Rsul-0e!y z`l$2S}UY7 z-=~eJe;%Tzs~X3&(Bo$Sam)v7k8#T%wX+H>(t=;`dsMFcrUvmVZQYE>w?awt{XsHH z225*ww1iZWz`I8H-^F2+Ow`Eboa$IX=%iQyN299|otM!O%A_Hix6;7a3FA^A+X*-pUaPzo{}?aG>hmN_qa}3reH<%kr0eL99!b_{;rbVS&N? z0DrkR-(^_4++YTr9eA5xsfg1qzc5Gd$_*L(jcvqplYN?t4J<*0V#MHG;!|-~j=$2! zUZ8&Yy;EF4t@UO!pGuABD@iQMXHmL=B^s1q<{SY+k}v)EG8T==AMTa@zJ-r^Ch{t6 znr%I4hJQl4G2jg@=xmi~FY0pgmcpw^UNN86DLD63Zus}OtN3SMa9`4#cX=HJ%SX!c z%8{0FKiz-M;kwa`q`B4meXyvs+=_htuw?(s8HWX~^p}bJhT{qE3FjQY<#FCC1^rX_ zJ_(m-g^lJYVUP)iI3(Vup;h^QcHm$3+|^H4UDcw>v5@F`g$9u5yj+j62gsy~2^wbh z?-pBwAAKiDBo%UiO6DmOw=t_C&r0S*`7i8dzl>D1IT5@XS>wZTDJyB9Q)3!xk4jCl zGkVVk;Y-5cSXVYSb6v% z=51;i%EA3HOA>31*D`7q0Jb+O8_HQKl6^Z=s-5DBqK zi|;#p!GC(ymn`c+qL8SjWbP-VXX_sQ+8Ny0NQV7AB%fD6y2SU?ud6$h&53&-8C*h&u#XzykW#7;>>sk#_ z_+!&t>;BN(A`ZWA;(B^q-vd$1J+`S=EldODemY@I|C>3Nyc*Xjrw-+8dMRmD z@1!z5&1*Ei)ByAH>}l2I<3Sl?LkR? z14t^gr{H?PWyg9?Od|*>tn@A$jTberj@hbeAV+zx(g9wK4@ep%TFtR)(m&Ns&YP%c z#TPGoF&>?m`q^8D-SGW`ulkIv}yxh^1;cT+{J_l zi1Q@$ob7dNy+0rK(T#V~nrkOv0aWQl3ew$4_n$G!zQkbLacj`zHwbH7DJ`FbO&DjF zg;}(tB5}A;>~YOyh=5X29?}GPQbr2888t(yxMYv&V=*l9N$J5u>H?3cMKylBLY2*( zRX6NH8x1+$f)Iy#RN{rtUDJ1PXeaDmLY;zc-oXlirEkTzQzWwslniM_>xAqi)JdF*d^~slc z=QJ>u{;G zdBvWODifAjd4hI-dzH0>hv6pj32TPdcri8-hn;E5#kWtb3^5qA+%4&LeNwcYnmYzGGZpS!i%`oUCReYXvudt9C zY5!kFp{<1h_etiBl%J&o^-K6E8~bt)f&pB~UC#fq@+ECuKsN=?vOiOjo)%xeO(d!4 zrbf)p!lWQX$>_)ueTz0#)<+NRUxVMX45j3u#O6CDAN^L`N7^WjKNhH*oP-xKnIdXl z3?S#pS-^!shY57;+gylr*uf&PmLSLIKaV_U+fW?59(0og_|GddOLS^{lgjX29 zGuw(9*#Xr(gd6ATVYa`OEryrzzqPPZ@)L}5k+N9mbnQ?ZU`2VruySi??o58LY-PCA`1+WpIYqIb`@RBu2@lRss_d-GA+XN^a- z=9&vU3wa&2gT1VJ)z9#+@6&9%OF~oWpT!%uYf;67Xm)oIc?jFq^|-ljd;ueJSWvv$ z2ARVrvuDf!&_VD5kf>p7T(j|YANI&UTMA065YA({tp3o;*m+`niMmnFPK$i2R5vfB z26GswW7jG+5aQs2wMLsSVp1@A`pYO0fyA>iMX`j0?{4S0s zB2O2K*At&FsD?h(NShja zyUg2AiTV0m#cQ3RZi9C6W}wT`2JVX3A~yb zBR-m3q&Q#mQ7$T}XEIto2x`6pQ;Y@OoNr!^q`C_ByK_-vNU*aQLpI7A2l}WEo4en1;%42sC)WUMU;`G^+rg=%m0+ zLY5aEEVzn}p-M@8_=3xBK^=u+0Ghr&O0%U|B`v8Mv{X7VGnQRu$sbq|xfd^O6cp_Y zHQaT%2F^hnN&IzIyh~W%$(A?|F*xGSs$5Z2f)C{YteSLY8<#4p7fnHua-+M|NqwXX z`$+_DJ(8a*KaxR)X^au~$^55kpnvIM8>z^BuV39sN&ry>r1V%f`sw9E^|@i>~vheNM29e3-;aB^3mh~5G8Bdc~Vi`%)SJY zMgmEG7-=yAk!0Na!yBH53$8wh{JgNI)#|e=mReY}2W6)mz?){?XDq!sT zzSVJs_=qwwfB5N)&`LygBES`SvA`}LFx90|C@-Of|5ZT<$7bJqIFpriJ#2efF=oom ztbd6C4BSx^TMFDO5ppEltWGN=<=p8r`J-l*G$Xenpm*E0?tkLOzt0P(c1}|JFWCTUf`Bq0j_=H{`^;B?$Pl zW@py>Tej{Rw^#K;y{yk#ERk}!7xV(k#VjtSlr+r5v}g|&$MvzkW`}3bIWxPEsAxGU zDxl$ll`1X~{BwdDln1zO5SJQ@1D;*nhtd;bLc{!Jgut5>L!s>3@QV$k|I-5e5F)$p zvzJ&9%Ms5t&nt5%b6?_igKz_TKU9OL=gH@3lROlN2R<=Vi#EtNQ^MbrOnj+MXy_SI z3rGs%cDgDh7SO<-7ja%RL0v{}#5;d-G2?|Jv1B(JYOyrXE>W+S#~E zZ$an!W(7`|r^6bTURA0>rZ>Bh%}{$#6;WfkUET&--+$VVys|XCxiF+E3O2g#B$Bn8 z(QQ`l_o2n74Z}LtwsVI5qh42ofV<;P$GZcuhvPIrY9^D&NfR@^&;u=p3-W+{lSgDU z0B_c{)wqwp-(8#L3#tkb6}T+QD(Iv&WQE5OUBH|=IYbB%VF37+JoM@4HKLm|=#_k} zdn;U^+wkhT6X338so%Dj4~2@lwe=yi)N*)l2_OKKHN&ynT68+3mBJ#t6u){JeN_WKc`z6cPbIk`7Sojhzf(a6}0otJW-QQ~hTKJWG(RP1G=y*Z+q-<+$ z!2S?!a;jn!jT3FjO}4lY(DEi=D*%rG`)I=SB0VXqt3rNmf6f|L7M<-@G9uj;s%F-S5x z_UYoD;8+wi8I2iewnG92(@+&@P~g^pqa`ZM3nD8e?wOCA5&a4k=>&K0RzYGI$7VfO zKmTF?wNUK3ZhA>8nZ{G**&ziJ8l?dr(Du+Yd6*Zk5Z`8gH3?Pr#B~^4ey=tPP?;lK zBn>Fn^?`>76t!YI{b_;?QyJv2jOac}*RjS-sVJNeIQbF*#9>~E_PEhU-%QYzQ=`99VOcGbFk8;GocKh;3!YLWKD0j!{gVD{G?LmOPLMJC z#u1P1pfVMY`3G5HkrUxs!8{QHq-1c*!e%??XYf4}IH(+iRHntS^{0y$V9WchC zwZ@vtq~96e)0>guGwYE9IIW8iTttQye1RMfrsmaz!3{Y_S@sf-9#|{j`YEU!JiPH` z-c2jNxq^s`*rH5RMZpsPM+bxQrdsIm2SFn!ozzI8P6ubEZ>%TMmX&g#{oY`viDF$b3SlEigdPHtZe>uu6$Xl{NerbIBnoTBwT*pCFR`iR)eE=yYh;E+qIwCx z-XOfmtHm47o5xpLMk*WQa#4NEy!y7U|7-A>@vth}rK5Z#ms$BVG-p^RzEBMz0)4I0 z=oHHh;vUuw!41w0@;-v<|Ercxx*Lot*+?wH`R*7%OK`RJi&Ro-)DZLB5Nfq*afhyJ+GBWN~I#zyig zA1R(`9lSQBrFp6SaXj+J0v*w@*A5W|ZC(#&?f z4?C;tJsRD(j9X0vtj79!VefNZ1n8U|8wb``zx>|--A|8qoV9@fqgNQtC6v)Cr(i$_ zBq=x#VOQjN%>8*kLK6gUrkA!bo%Yq~!u&0s)m zW=|VdV{29cTD)b1@?oLai)(-Yz+(@FbWlEYhl_7tL?CvBy^3i`Wdvm5ZJ#QhJg4k^UauuCET+e5s9BU?nmA4mKm_hkU;x; zD{nRS{#{XVI{t6AF&-5@pw+ablFJuxXd>7>BjDfKJ%7+OHkoA8g+W3}fpqt_iTnbXY@0R-G(oC0A=6|KySUIIznWV{gVZ@N3Bsm+Y zoMtL1R&QI`wOEjuuEVC6B1R5y1$B!w1=*8Vt{kycZ!Gx2mVAb)$#n!#_<=vw4yL7>3E&slk- z+`=Bcf+O@p6B%5x{zXA1eW~(N2j4+;b4Jg?5`SZyqsz_{{aE95wvn&ZUL>(^(VSS zax5^@w)aX>Nc!up8<3=;4`js^CjAGSpn4EQ!zrkbAX`L<10*c(eX@e3X$!UPMC8EI z0435?unOoPbj2dW5ZQtA#VLoaO`1{V!n_#4*L~ckp|`)v4@U5e4cDcO)7uw-!nwr_>)8z%2sWU{SkDL-~$Ux#?K%N?^_!}yk_}k>;b(NC8QUJi{^Uy&I z5~VxJ|8LZmU`3)9>(c9Uytg z0opSbac%rGJ^EHOZ+NupN8oOsEpv4)2anbnH0o_1f#NRn2CYOT?a6?B9Qp*0CW!>< zh3#|Cb{rXj6kb%?UfHK~{ON&qsA%v11O|cbD-Jq}1jFo&mc}-(<-e9k5D2VR7j8&m%eQ~SFVL;fltx}P9XalqOy3Ba)_I+K&?u=e~j&%ym!nwz+5s{9DoCH7XK z;GzWkuK9N)cQ}l;=w*=4Br@(7yZE$7*la63Bj^g&Olu#Wtr;I^lB`y3o54RBNRHHh zT?vvG_?TO5VB@3tnay#a=NXZm2zC)OO052?azMtsfNUbF2^`%`wl$RV>3GmaOx&@DftPM&q?QU6SKVN ziz&v7U9g4(&R0(sewShar>Dc{V@eQC|+r1`FzzP(*0F!1CXsogQ$_kE|DNOWMDKJl_xukUOZE~D#^pq1>5c(f)e`jAPsSpk37Hm#{Cvr9Y zHyf%Uho%YZ2#Wt#Ec>ga@8=<*AOeY1AhZ{;wnBqxMgPtkC*uo3x~mzhV!Wsb8(nX3 zd7_~_@=ue>o&n|nkiK5r%eX1JVE&<)q8DbXMPM(a5bDK~*TCvJj#duK4%lE!DFAjB zlm^k;0IzeXh~k;LicDtwVt?Y9S^p3K<3_MwAdKup%=v^0-rIQkTwfv(_#kY)KU`i{ z)qElvz1}E&9)TG@We~x*o`DU@ekm+;bB6;1NiK~;X+Gpc`RV3~FnG?if4eK)#LMqn zb$A2FpmqaB8sN6}y)ec6($KLE;wB|Uur0&$OZEb<81uJh7n8yQn~_Z#@0v;ww(_gO z!gnR3&k;PWA-_gmV=#Y=FTnU^y#>c3b1D-SviqGJ={fS=$FW|mXQK^F#2#{F4;XAl z!=tpuz>!x&F@BA>!|eU~qY_PZ*B-Guxv+Cl6dDRC&@XPsP-$_u)$7<-U+|S#k<|MX zK~%z~@uLo$9xrNhx3arm^mVS8VPwFt6)T|E5I+d^#1(;LR9OI3$))N%ymXb`=|W07 zAIX$bFfrE=2{uEl>`P~S$vDuJo5~J_Xh{^B;HsalB@iwZzuTz_n=IHQ#o_)KU_>Vh z;e{IWb50}s;@$Q3(C>v2@(X%C@UqwvvV{UWs-+2r6kZ&pTnahDM`KQk7E)U^79`*Mkc zG3SSq1i^14++nk;5|H-X9iK&VTFBnkXA=p4R|&A$I{>jV^`|x$IQz992@1Xm|&Nz^T?HTF3%x6^6P8TPST;4oYHG%cS)qsKW{}oE zgS9w45a@}pk)CD_$a$#_pQfH?agUk@#y9GLbzP^{C-R={+Lz^IDC<`AJ$3%(B+JTB z)?qJ{Wn{Qjz4r3teKNGy##U+aJ{j6;L#D|xGTf@(Px6!(22u`dpn(DyNYJ3e4rnl; z@-~oL6r{I-{F;LFHrRfv!lMNv9$E}oG3#M9>9Ay+!Gd857X3I(x={fh7^a3WJJFAs zu|5a@VW@izK;YR2a{EGKO&O}o3Q&@l37&V592Y6JDg^uA5{DyRzv_%j7tVfcpn(J< z)CRZ&2eih$Ot%+m%RcLCHGk^38az>h2LCBN4L(KC;M@4>KR&N~cJXh&jPHH>5BSzM zevPkx<-a~OXdn&St&CcAo*E>u7nk*I7pe_q#qf>G8Lak>Dr55r%1Tz5+yui||Bbh#T(tJHy}S zf;j(x-V)9Z2Zfix@ef|#V3@N%S|fa?ecY;??6(Zn#y~ZW3nl*_Hk7hahg->XCwba_Ty;7k&gJm;bwqg3Rm4B=LPnw=xD`hM4r0ZYg8sIQ zwQT})Ij1{1-LQq*sW9Ss5aBv;>jLxEwk+7T1t>1t#bWCM&pl8Rw*}BeUAX;^@*D*o zETyy~wnW(4k#4QKbgCUewuo;_t>kKY1=L6|CIBk zVXrp!C19{(ZWW#d1PK(dpdHHsG$3#wNqQd;G|&PE(u+ZQ9BePE#{w|e2pTM#?STdZ zXj`5{-HOiUNw5wWl&{RKfdclx0fGbq93VijGLIq~t-aCbTm2Q2pnU5*)U*Zw(CD|C z)+onnf|_zy%+ONKiW#JA6=kiMk+ouZ3gUgN%Y+<~)rdUnoS*`$0fozY44C>cXzIt1 zsSm@ZUW}M}F>2~rqcKwt?9sTX8>9(AU6?R+VMOwzO7Y4Ap!1E30X+Yv97&rS2jVAl0ue!2_B$xaw1I@SS%;hwea3w<3;=xnYPhbC5) z=8MA;GgIOb9~CaPDbU-%^O}n|+dvxg>QHSUKa04!ZnYt94;0ug?OB5a+WOS|spD!n zYy=H{fNy{Ld-&$3zJqTNG*EqZ@%#Vz62ATXZ^aiBw8pgB7?lRAy>KfdR$Yg^xV`#h znzr7}t_c*V^VA@Mwof~~)*9dH`ah1iR#s9b47Kg6%WC=l$q&DY7k=}jHPFE6{6X=F zMSejbDcVQ4Vb_#IqOCR&eJvT{Kr7|ovOt=@A|N7zqs7Y-IGOjh|>=~m>yXtfpJhYJQ)7ybxLg0ap zH1-5okl+XMnUm~~oRk0&@;WW<780XwAST>HfF6N-yw>vmwAb3Y)qH4qd{)<58S(mQWUanO+Yes5Iv>Ricb!F}M&fN03E&_CO_gyr;2={RZpg0}s1M^?JJ5?KfNMw|M##ewdGHetQ{>@KJm`vt zV;M$m!~@30D_|Vw{{8g>vv}yDJTQxOD|=wMNa6|M3jMhp$n^2>xittOjgmiQ0S2{pz$vN1G54M5Fl8xbl4^4t$8Ada}TuJ6xM-*o$$EM58py7o(2kN&?Y<$ z=FOd$Gk0TbVGym$Q{eUkdKvJn0>#VVNx*=>f%GO=2MiRjKmr9aELfRGz919wRyNX; zZ~e8vfCV`#8!3Cm0+JdS$Xv02l(7k=uUMd^v=s{^sq>UN2q2h{Wt~U1@KR8~gM6z2 z1y(%@t$Gw$^(eN^qQt5bRBF{>bDBY!RiSe049cz3sI*R@$~uK=>lA91CopB|#FVMS z1|qcEK!i5vO>HokT47WH2Nr?{rWPy;YR00?>p<~5XoA(G(2A)ElDLJz9`OtW8awhV z1a-KT5%lMox2~_H-u@)~L?$1{Gq3?PShcic9Wc;>27M~fKz>PK_n-lRgLUx0h{uaY zDByt}4=waMAb2o?<@sqW8Tzp>+Xu^RuK*Af4}@XpCkDj!g^8hVjP$jGz(Ge-4H~LS zQC^gTyo_XVz5zeU7j^T<414c z)gQdN;j@cB`0mU2&NqLD=fC!gC*IJjjZwAHs*P`D#H#DC7uVLMzSh>e)9XJ5XrMOM zcgp8h<+QTeN-pZMYCaezXz;sV{|MZkKu-fFhl9A`egegz@+zNhFZG3a-vap6HL3f32ad&EM@c`~I|swUmRs(4Gvnyzl1PUK=t^-PY6gWheJ(pOf9n zT3cStw~RYF9D*Cay5VsScm13Y5#omU$Q#H=x+9)@e$jvjg3=?WzdZ|_E8??bW969V zK}|C}(?IzWfN}_3lQ>bFr;77hoEXg$vU&10KZU4MKG|sI$>J)KpK@dwo=nd2Yo8($ zCzLni5rG2L0d=dER{Xaj)t3=Af)G0e3;r_8$+x!aUIvP{fCLPz<_;_iu%HXZ#Q{uP z$1uGzZlf{Gtc*ct9mU+zAgq=SSk3KNSpyE_p@{3C0oz*#VC=^g&_Dq&6wsg*%jPyL znh6?oz+?jr#uoKCL8^7ZE~Qu(ASv0pfQ@89 zij`zWs*TdECXh0%^ELp%h#c!2a)k$i0R$29t$G0@5KJKDFV8+f1xq@R3YTV3Bxo8X zOH+bMmnKoQIEK;rPK?cW2;gAa)DE5SJfO$Hx|e|(Ea3J8NphQl*s8$o3O0IZYQ|uVQIJ~`?0XtW&|n=n;3pXg9?apQ$x^=_k+Lz4@~T7Yd~v#rP!uWn3IOI#27?J+yl2L@JkA=moNRvg9chp zfRFlG?OmXbYr&IufBr7kK!cyYjW>V%CSLpDYk28~Hm){+)kf@Y;#<|Ju7A7uvj7ct>XE>5T0?z1{&teDm77{N+WXb*YxC5y zVEoc~f(B<1cGnfjvA0l|c~5-9yR#uxe1nBrPKKLHkyzoM*rD9#QQ zRFr*B00#sO2q+{)-$Zn{hX73id@sSr<1DUSIR>W-hjtAb(D2swZ@X))@w*d)*6SibP{&Jk;}LdZ@(qz33WPbTsn$X+8o5&3HIZYOztXNMjyBgk?jc zD9iHpi1`ZGuwK_Aely&}1w`u_ty1k!%RPBCVDV7*oFSCX0$iepsunQCHYy%Oie&+ zWH{~x-huB854gEFedM5l+RK1(wIROURs`mM)F6Snel>5}`2Jt)2T6hl1P%86Y@hHn z*z?mp0yKF2hp*%1@4t*ceCH4N&9{DofB(BLANcHFe;!}|%Fi|c2U{7gY9p3$ zwXv$bZ>QH=)v2z3ySUa+-VFfoG-cIBJLB8&_cZxi@wHX^T3I+=I1FzO2iyyCM^an> z3UVHxwkjFzEjbwIF2=}UIVOfHF)>nwvB3%q_LQKjH5ZMwX(%s_MNVco5@Y=l9^#4H zzL&Q(w6(_CcAx=`L9O9>{>(u*Upk8Gu4i!5+Yte`T@W7PftW~NB*zCJGc^Qx+4oVD zABob!7{MobEh~yaNkKFUaw3qO9*We&K*UA+AtKZZK>=>?y>SWdZf9}D=@=Z&9^AGs zG`zL^Yx}p|wbs~uTBBMkqd(@gG`bl+ZGU!qpH`0B$=zPQns3Gr9)Az#&K!c%rDM46 zb{02pTtc9~8zMrzkq~=ZJZD9Dk*F$5KvP{hI$Luw&{K@Dp-Rk**TOK<2$P`|i}N(j zy0Eg)jfac9c(k-myjG}3#%5LD!c-&IxJ)m7Cs&2ZoSRP_~m0F2kugLu2c?j@(x z?7{1)i*HM=q-dk+>koZNi$29opX9!j>~8ibk}Lc$6mJQ7D} zB;gPqNq~rq#39%r7^wjyQv=R*>0}Q^oc1zpXZp$Qepp=^(+EW`Bq`dV8>VYs7|A|p z$$rFA!|1o7=t?KhnHJEV7I7ghp)D<;H7&a+XiY0PpH^^=<7`^NnY4lym(yt#r_!_m zB7LENj03|l4#+&1%0M7PfeeIE<6yjD;Eg6=CIO`sJ-~!NpBB5vDIJ?nqBxyIiA!nP zaH0(;;(#bk>nKm_s7Py9sZ47i1EDIdqS97SWhtmMvLCE+&W3V+^6!7(|~jh<;-L1I7RbjR6cf^kdlQhu`Q&!01QF=tVr)12NeRIoS;* zNuR*%hL-Gx?qVdnkxX_WmF$A)VmV7-GJ9swz8U=986(aTn2WfS91nY5D19UT%)BN0 zNOj|i*^4Vy|JA?mbNV}y`}g5S{n39b`MKc#J$^gn`LSP1{-#lbfEfiW&1M*oX%NlP zG#E7n#+n7$jRR&lWDEoqS1dxo6-<Gh-fHGGj<5qgRasP4q#G4It|8!*G8mdOFVH z{OKkfZ>U90MKKBw?!k_&8}Qm2WEwD$%~EC}kSL$ZG~fmO8#A29!SZ{fFR~ z26z9_i8dh9;5Xm-4IcdVgZTM3e~t&f{s8X1^mf8Sg~v#wryUDqP$Hwa%eA3pD0CVTP+598sQ%}fuN5JgH!Mip1?r&QRm#b(-k<@ zkdNx}oyb41&M_U399)m`;;pEy+Kq<8 z2hh}zkCRPBICY}Lxt~+Vi*cf{5RFF;qVCXMRF&^Qalt0+-?IkWw=Bc@wF~j;(&zB< zf+s<9^3)T58W%N??d|+q#We5=UVdCt&G~Gf=f^_g-&>xpA&^Ub?{kyQ6qxQYe%vh2 zp1HldR-q_=qx1Y9tvld6XBW=ZptrLgzW(Eg_*)=E&O;U2kyN^1={-m%$sicOWor;u z?4dExamGk$06gqCyOyr!@wWA@D4YG6|3uS&q;D|c99%a0K#ZDG14x^Lu+2eO<`6W? zkAxLQ+>Rh(#}Q162#$;r8W9mr3y7s-5UemnD+I$DcCH_Bo>_XPGks7$x%?JvOqp@@ zVZ`i5+U$pA4!|^rkTiYJO&??{fS4Ud$c`dt#}TmO@Y`_=+X?s_1Ps}u4B7%11Ga#E zTR@*JqSqGDV~gmvB{bUtI7<*rOchN~oHjuejUk1ibcT$9K&Am11Y{IsOoEJ2K+6*}RHjwOARv=~QJq$i z9R<~C1vO~}hte`?(=raHWz^Z3r3)vl7@AF5k`TdZGmI89j5B5!XU#CqIfT$^hR|k) zaKQ|s%k(2aOIgf82ri;I2-zHf;?NJ(?1yId!!Y|Cl4c)LE~eQBi^DeiK%`B27Dl;b zlF2&CWwRGVF3;FIzfK>nSOd6{<=>KA|NiIy4Y`pY`)}$ybw2oK9uc+tCyx{ek z0kc)+`-p2L=n zOOU^R18S@GqPeLAZH@qHz)+(=rwFhOz+mN?^J$7zifeq^xjS;p?AbLgS+sQPb zdtkWW>? zb4AZw`}tbu&xn7Z8PUL5h|vpBg^NfkJ+SnCq?2R_4B@inyJoJ~!+3Y%!xfv1mm5qy z2Sd1Q58;yS!-&H$(zYMA?T2Xxpx9A_M?{c05FC*m0wXdARt}9wPMyezfapj9YB~(d z4q(I{cG|sUXZoOirXJ6zVU`)!5Jqgm2iqQo<&G<92cX+QXm$vS9foX29Yi|{!Hzj3 z>^OMhb{s^^jw9+4u@eZ}354tf0(JstZ52&v1IJt%(*_#TNr$89B!~u%`g9V+k#rJu zE{D@8)TT`wN}H&0sY;uubg4*Zj03NEz?LBtr!5p+#cLk0GBXgyMjVVr9q5jkK!yTu zDv+@-77gWNA`(W8g|Q}rggV;)AT2u7r$scRMI22FXuP_yVrJvSvvv&qb_ikHkElz` z9!A0*hF}jvw0)3lA7tAH#r8q9eb8(lbbAPfOVSc(qA~4jB zzOFN9JKKm8jn$~FDnMc0PVC&a4zI0Vl67eU347iUxL&4#SCmgx=EeORk>|(bH4Mf? z8)R9cK+y)YMB$!W?!otO{yx6@#qZ)a_bUot{M?lWkHrO%Hs z49Gy3i9q!VKyMpsSG|NS8<%14uC*x4+l+AdVj`#;FtK&iGo-975aKT2M;& za{5GtbH47-L8pE}-e&CCwHBK_QO6J*Q5^Gt>V!umL`OuZ=_o8a=(Kgo_Jg24 zh}_0Rza1MF84ttG*wVCbf*o|)Htisiv?Rg~L${+)UC88+?HFV`4#|UP$H5R>Lm_S_ z5VI4A+6j<>&}l0;YikZ?Yz-|AI!@aePT4wmnr$5?T~62rj@t&BYy*vU67_ZphtuX5 z1ED%?qAG2nGHs#4r95q+%%wDKp(Jf#tZ^{bL?}#~V6f-|N@>XggDqVcm)c2`jKM&u z&CpS1>nOK1RM;9SZ4Fhn>QHSfsIisIJ_xpqT3g0p2g!*@sJA6F*dmVFB2L-~wA)ei z+hGhkgfL`>Fl+}Au!9KNL4@oe!d3u+<%ekbAv+91v4){q!_ZuGYuJfgq3D&AH4M|m zqG%QeAJVi5r{%*4$0f@L;(7_Hw|~3z?+at}-x>bjoT>8kZ`2LmIdkCsy>H6wQ$VIb zHfa9>T8_Y$B#>FaM;XkfX~0Jv@WuhG&eIMm^o1{cm9 z%h@#G4Fk%*RZRn4)U*6-nhC5;O0$^;G&k(ii?kskTcW_eqQI6Y{P3$k#2sJ%Ic~q@ zC-~Y|euyuB;k$T#{_=4f{P7~583YrheBIf~PbRAQbG)FZJZ~ao6WKF4=Iw*;e>!=- z@5$Qa>rIvKUGyRJxbXK*`DdQ`3l=SW7VFk5!rq;0QChSE^|kqEK3;*=Gl$XH)`0Hz zMs&4j41@D6wK#RW0!Ql#QCYSJ`3E*($JSL?x8@ZrUG&^_F%9NE`!_6j;Yp|cH7gfp z41=9y7;JIIK;u1rv=l8Tt3czsaIOyR=j+ja{s>yn9>&>IH8|N+j)uBIR9Egtap89C z-@6`LH?P2&)h}bol6g6q1|%xI(FROFdj)5%Wv|%19;N|}kv9O?nE7Lr_lk4xc`CDO zb4_`{O?hu0vsL!aW3KZ*Sv~LAS(!bHth|5EdgsqgT@4vmr8wVm2wm-s80tHP@bGyg z!W~c&-7w^SnA#9*V;Cc;04`g>t6Z@|xIwOSkgK_HqaGPim+c@fIU+xV5j%vm9fEC# zVcHQW^d{ah2FNVX#t|G*LB;{qAtEC()N~w{9d_EfWQUx#sgKJuFuv#-8e66vHntEf zI|S1XBV|XCw4*RwbUOykAr94wjYF|wAY_L)Br6WlibJsCh+7FnECE4FK)}Us2^e+| zF>HzOaST}^h(VVDOG3XTq1Tde(Nb{6)*a*Eh@C~ zW^1mIprXR2JrOdHp)hJDC|8XHTGnvXme6F2IN=~TM#3pOffhS~GfqTD0XmLDn057Wi6{ID%Q(pea>{9s(N{K$q^ zFkLeJc=r;(CG!Ss4(Q+Fw-apK*P7lmY6>uOfKQo8z*5@$kZpj-3q z5eO{efKuK(7;hS+)DTqB=WK>Zra^z#8IWmk@>oqykp^$3X+WZ%7wdf9YY6b?CdzxS znNFE+(`y>AIbx>4?Vr3O^XWzID+)jR#?Nry?e{qwBHsDUU*a3LJ%C%k`eSE9#09Uc zn$$EPBVZ!KfR4|WQNXv8s~Go+Z(cZ0CAf1v@9l#x=Q>WR$M?s#L3zF%zTSlS2cN?~ zKlq$u7<9k#L3F+R!7+vj&BGIq{V!g6;c2X1vCt9!g$K8yrgA?TkCfol@hY4>U5oQ) z>TtfL4rfmtLUU6k8jlp?P~`y>7i`DgUF)!U!*Z;8^(DOW(wysJ8oc!4(^$G_9@eaU z8Cy2KioHA6p)hY7s>=7FzP1o28fhs4MHbYfv#k-G7mhh}v^ApjY&}jlA3{@OIqGT) zP+qzR2M=t)_U&u%+G|U(Y}o?LU-0Y=)8K|_Fm4YEW(s)IxzGL`^h~njWSZse-;9dV zJ*clOaQ=+Yv)J2t0>cAm5e>9MjCMm4`;kY+K#}sBQWh46k9~tF$OdQ9n(NZU}Tiwi0&MxI%FC|M--^(1S~u1 zv~|f2JAyxB8chE;$y`UqLk1dS+73J8v+Rh|k7-98^B`r%z)0G0B&`_q3D8_aL9ybH zt&DjvY9J(#uo8}m5VI0sM6CpPBCg30wgiM+vms+RkdYvv%~EmHPNBhN)I2b+ng=zu z2{I0djB#LPH4b>wz-t(=a=x7cQIIo96xbQaJQ&45kz*j}D7Hr_u{D(18puS*W+Y@x z1l5g5P;l5*P-iPRVk@Y(Wi;3_8f_WJ9793ENlU_j6-B@bBSf2QS|LQNAZH>3Ay^qi zD+tL7Lbifg41@quRsg0IfaPLa0i<0`PjN=9(KyN!d9R1hPn&<);2 zb3p&+VBCbHh{=(FWHw|Vsc@)3QX9kTW)iPk*NTDHEkbv=VrsaQRFKw1q~ti%LFxHim*->ctBbK^-74(ewh@K@XT?D^Xom=xnOGd;4Z=T(=r4mM_M_1ux*aIimuQ2|-G;y@mF^Vb4}) zy2re4$!GHRo!an@ZK|?2lEB-q_xx-`8u0VW^4@-DTIT0*y1&76>a%gPbi?Z9*u7;v z3is_mO-UY(9V*9}V|C~}a~uO5XA$geN8Hx~IW!18HVjh;A}vR7NsZyM7RMDm;qba4 zz{?dwzzsZeV1;qzUCd=Ggv(?&<;W#73}VC~0^5whGNUj}dMhs?Y-a7%xSSi$5Db!ji9I{fVvdBCbH4Z51U~I&}*eHX1+r%gt(}0-=(@w1v z@~tEatRxC8V+=)>4x*T&#L`e|X()3kw=`5(szarvqRLWHZK*h9DX6s+9JUnHSu*Nf z8Yv>fjA6ixV$h6W$c(^ehB0i0;Wxtwm|=v>Fv2cTGmMxShL8$FN`)Y&LQqm6XsHnN z6n(uTgrrL<6@uwvr9!Yd(y0(e2_l`!kP*owl!LhRE@LDaL{^L-M)WX7v?xZ@7%r*t zw-7X*8%%!=a{CQ$%5Df`GYQx+G7A`9(_pM|@VZH2|5{B0c74V?xMJ$AX&@mbC!i+6 z5d1?3_4l}@!AZw7I9y(WV#hSth;=L9-lhRB@_B*J=lMF*&GYR{Wg2|_lizl}qA+Gd z#5;ZoC)(h)`|#th{TO$DQD0SpBUL3hTwa9g z;yje)?M43X?T%2|v}OfXEqw)x=Fh|P&ptWMG$2!8FFGB(n-sg=yL}Ui_U}SfabCtSXgGv(CmPV+avWW)r_p=i4Ej3Gp{M;U zy4qTB;mk>#IoXJ&hFa8Cm!h=jAolOsfi0WXVfD)8SKkzq_{&u^dWCqd*G*QB7rT_t zMKpV_p|W>uQCpb*5^Q&htw+y!DyT=F@Eb&g7VPP9~f4YdOb{o${-fzJe{U zt-`+Tn^1CK4{FN_alEby=T9`C`&=`IE}loY{~`o`AJni9$#@W!7)Dyo{3q?QMy7$_ z@VX)5N)B8$L|oE^cPTMkHg1sX99%MDAV!S1gKflN8wps3fTSTpGh`@98F5oZz#eNH z1k<`>D8wxVnjt|qB$$TaTu<#?x=N;xT*u_C$HqwQv2jwGcA@c3h2`86-B$u8p(l{i z1&5?Az|aNgx&X~Z)desVT>wMY1u!IC1R?4o1YJTxmk`q>M05!OO~#W@G zRP<;Xx-|_KH4UAbh7L`~1zkt0OJmAFwV6VNl|s2?qRcW;YMCgpOcYxtiYya_E(Mke zB7Ynt{%1uI%JFlW+LzgLXBf0sE&zHXDT>m$~a+) zIBAM#HbtB=MVvN8w78r#MVvQ9w3;H?Oc9-?h@oTx2|Wfuk3rO9ko6c8JqA^eLDOT< zT?{>j6o;wDKv)bd2FoD|TN@>$?o;)IhBlqx1xEFn+Tq%;W47b z@OEOR_vyWEnx+9W3s}mV29zh$VAMFsmcB3qBA1VqDpdx?2 zV-^(c+lhlaw_?}kb=b6a1=cKIjHL@-#DeFZ!JH=_ozyfS^MDxzeEPS)JcP#|`3s(T z{O@@FnJ34Y2HQ8R#r_?eQG8%Gs!Q_GP+f+TWEh-0iuN-n(cN|iy&dP#f3X$)7u(R& zaUPv*XVKcyjOM1Js6SkT%CchQAJ~WO+cx91wX4S%1|M@Z!6M;yO35g&|r04XsHONt^*|7oE&JX*rxvMzv! znFAxb07hCD@a`pn5&fOdB|U*`T-FoFik1KwPz?4wv2;XBAgv`}Yl4HNi7+)0DNTf- zNf43>f|i~!4#+&Pbp&l4VM{|Ir8xDdK3$)7NPya8?X#5ipKHpl^QP1`8*`>V*6+mW z=)DQBv<&PX={}P#hI7w!-y-xZXqpH@b&#NF5@bz+MDwJ|NT@R6s*I>ABcjR(sWO79 zf`F>Pud48=Dh5>*1FDLCRYR|;p-0tl($I0pOrpwS#z6{YRtlw73MEzw#a0SM4jJ=g9L{tGWHG#OAfS@KI zstHJH0LsCBD{j@om_r93FtR- ztZ6xl+2oD57yh}O!Zcv!z-aoqAz>65uN&D=@VcSkN=gGQC&-|Kq69LGHw3%}!9-;; z4n_|mG*_3r@!en1gnC+zsyeMb+>4^I4 zS(lB6rC!tEk>*Aa%mi^v1JCCdX+y+cdOyGTmAmovTkm&1zxb6e-Zkb8JrnEM(l^31 z@b>E!)qI%=>};vmDB#PJiFp2;w_U#P>E!t~y?MSJ`WgcDNru6u+sHH+jVxeh!3Tc+ z3_kF)r>~j?E57rF->?Q7SHJ2ArDY4}W8w32@Z8gnJ5d5;0PuzYYgj_!_DTxe~dI(!85=q6WOV?Pc=(Le(Z)_jbAM5{GQ-16t zssJx^FWI2`?xW(oxy`DO}?$<2X@%!A1c13G79g*OsLO@xejFxEuSQEFyjCPJmDf*5NesHip7 zaV7#82**IMQDj=u|2&;l?AP9)70urhKflvfUiU3&=ptz`t08J5~a~MhjNsg3~ zfazi>31o=FRx;4v!`T>7;+TEjUT?Tb)Xt_zzR}j~nhx3Kb2201CJJku7~UY5ET7Fd zpkoSNPi7c356DDd<^iSCGZ1*wASDY>6Hy33KSG0j7`WJuj+SPeI(h_0D$7xNa6k5L z+j7G+*x!bUj0a{Guyi8Rz%dU_9(5uOShN8xQJ^m={QAyc?LP&J zHsHmvSG4nGW*YFvu6Ldn)!sZmZf~A92`0PFE8_XGw@q(5xt94hy?NFK`-CEy1@u(} z+T?IFy5Lzbv)}_idkXLW>63W>{g31Q_dSO9|K#s@-#w3vF%5qA;Lq{!pMH<09(x2Y z&UqS(7d-Do9IRWp%!wq}wtfw^uU`Xti%NS6Y+UmyXt@AIB~XL`83yy7c>+&A_6Qz* z_|N$3L%*N4X)y1ZC-KtrbFpOMe5_phiX*;gIl`W;n{aUVc9iDrLv?8(>JL@mM8jd6 zInju=GtIczb{4&zZ5Zh3z(7wY`g=Oj-E{#S?dNgs+-aORaSU~JwJ0qw#l8dkv3c88 ztXjJUFE3d%?rk>{f|H3z62Oz4&-EM=u`JC+0B5Viu4gF|=-C8&HnE?r&8d!MYlrpA zr`g89&eL48Jf&>z`E;srb0SD|t&r8wtEY%|kf)HtAa$&AR55&D@ow)|VIsq^E_hOwr>cyl7# zc{UC{W%HJqOJ>2fS%; zM%U1o)KQ-_a3pDb<#jp(m;7CdDS>z<^eMdSen&1NF|Xs1qV|} zOqaZr0iOJnfdY=glmVhBWuQ2vqr{~&rGqF-X(&%=sBo!DX{b(Vs7Yx!l+sX}(r`GX zp&_NB#gNghis)5E^r<5HH3@^7gdt7BuqMH;iU_D8B8q^xEI^P2h_V1l79hJQvH*rE zC!om*=!B90ZzN<)gg8tk4pWZ9lH-nvOGa)sXi3?4uD|%pCJ5gN$80%@8_fP3344 zbp^`v4`ToJt#7Jnz{I#Wok+yL8OPb!yoLdlS){>L)8P9LWtJ$o(FVV}>v#C=cYX`@ z`Nf}p$l#ATb$1?-i6Qq&$sa8GYiH<9gt|g-lo7*?K4q5 zo2l0f@Ctdp%-5ai82I+QdDcFQE+E68>y;1U;>#bzXmr8TxM~(WFxD)1-;e)__xs*{OCUffcCvbwpR zVpY!|JotJ2ocNS<0W!CiZjfm#>$t9ljryXJg2gvN|mFif}6Pea>2?Pr_O*Kr=h zeVqvVdXWeYL5>EX31Jvw6e&4|loEHsYbip&8%|AO)O^^q;=K8!x1aA$=>F*qFnb&P z=A{BiRL&NLDu6+vb<`Xg6}s8X1SXENrK~*)NF*R5WWU zPHHMnXey5AI*LjLuFD!RZ>HBQp2I7hWez6G$95t97M!7h@tL_=sI@>XPX*vw5AG`h50zRb33-K zTZ>go7vtp@=3(wrPdFw53%6&fcS!zGhysaMGJWmbn$YSUYutRHrcZ_k@&?NNlm#@jw|)iCH> z_`%WW0*Wkn;0e6{emAn<-bauz3;q}X^n-`+Pj~-ejA=ko7Qg<*Pw}VU{RXtO;OR#n z!Q7`F$BT2HcA^N#9H31O3CdGs!Th<;IMD^(WeBXyFGuj22K04=QN!SAXF0;Fix)c4 z3tQH$#;&a!oaln$yuGL_DZt_CG90a|!O3IwICJVa+RnG&V*7b?ceOhvK_8g~{oUy4 z>q2KwCt5q&aQgfiG&Ubc&5=43Rg_^@-T|!Nz7@;Xt{JoRVJdM*=b5l&X)f1HRfmaK zmgXvoS$&qWF|pJu(AjZHvx$8=mTTXv-bC&2eNo;!7QXDQ>lNY5G+_71QZ|NMQ+6Fo zr}|xTJZg~(pdbF6=FI#%#yf1}KVB1Hg^h$KNt0+WO$iB5W>O>egovVfQ@ASw$8 zOCo}j2)`s@SduU#$rzAi^h+}OBpJQ3j2>A=w=APemT^&*(c#iA%eWxRXp?2M$})~? zDoT=uLvhkTkxOCHK&})d4KVVP26!@Jp9KH(O@jkT17p!~Fqwf2ggiqVL%yM*z|c_W zQeIsHiejR2wR43>CG8iaJBZ5kp12p`yW1anw-JWT0om@GG4v16Eh;<#c@L;_cALKwx;aAgcS zu2_UIj?47*gp`J~p}SluC1l@=jy?=EcLv>vNp zU5Z5u=i#|IPvG%K|1u`}fHw%Tq0cXV7xU&X!xK->A0v#fw<$1H`%HMx zX3B&*rTj7m%6mmU-!Fe1<@s}y<-Kk4Won0_49GB`&nQxaLC3-m;=+Ot;{5!7=awQo ziuc|7H@xr159575BD3I6j#=>DyMBlFe&^TY?&GKT{|LW%@BuvZhX=<*2{032x+xP< zEak6%^luO0=_ek>^UpnwmtUHLeWz#C`-njt>4{k$A$zD`d<>PQ&DH@Me z;pC}0w46JJ){bU$bf3Y+{#Nu1b)aXs6TSY6=o;=s=THY)``ggcbq2>;PoTEB0VVZS zSXEJqMR^A>Z~Im}zGn3p@tliD^a|WuuE|!1iAqXy6}{eid>fSaj*S=QEYIppB=)_1 zOjVw!9o7#^S^w9Pdhd6tv3bvXug~_o%;Xq*uKASjYtfPyv1;v7Y~H#Sd-iWdQRzO^ z94^MurfQrz+km#tW_0(T!=S$dfp9k>i2=kV9|YA8Q4c~iLXeVS2+0VIW)ymRK8otJP3@0D=Xpbc+F<=;jEfjdg_hT3uwApj zE7oVToQv5oQGdCJJ0=QKaui9&G>Ac$V~)5ap-G}skmH-JZ z49GwjH4Vr-IACZF2MrAj-bi330y7eL6QR^lQD&$pH&j$`1_GG~hg=ikFqsFsf-?%4 zF(L+?`4$}mVc7W%1O%ka?-7y&5E(NefvB87Oimyn$054Eqt`%CW!^-H!Ek?n_8ibN zVREo%g{8SXU(*qHZ>74H6o#n=U~1Q&l3)9k2X{S$@7?)ZeEXZf#5Zoe-}(IF zvXxsff8k0zGxz0pq-nqley>r$mw7=?dEN}*+n6oWVDyuUnNKOMyY=JFR}t2@Uq!eY zU2xAMc;Aoy;+h421Tzc%@!JpLAHVhUai+mNKl&cXIN-(owd8p*MR~rhCm;J?JU8c2 zyfptAEL-v-)~;TREt^+i_wEhI&)UFg zfi`seI?&_qLQkL@7yVu67`}+s!49<*?qCe0HU$hqiVE|#-ho~ArR1YDZj37#+q6nv=2&JNqIQFMv7*56D zOT{plj5-V?qv*fEq;oKs#Z1U%FuWCxg^Vb|E)gS&s1ZfXh#+A^Ah<|I1d zs74qQq3B^SWIYTXNsoXKv%t<#O4qP9R6Pt$4?{Fvbx>Pxur2NoAh-u7ef605agE_>mn-oE^%d z(#x&VtF9s$Rs!G9|0FSvuQmUh4d1V9L7RG~Z1(rb_rNp_X$*B9yl6Zc2%%g-L1E8y zQeL8hPhx)r|PFaykF z($GI}JBBg?Kz2+Gnz@}MQ!~AWb?8# z6BYKZE74}3;B8KX_4S!V9A9`izF>2FVT+6yXDKiZhvUjJ;z7tYs1-$G^`Rm>sY@)vsia|BVl(((QY0y8tM z3EZcl-e^WoaCu+tC$v$~G#rK^VBzM2=*9!$U+MI+nFtMf976G)IuWO^rSw0oaoHXg zf7~EPc*s2c-XF%QNb##}d779D>W`Tc4`+_~I((E?YqmQ?vfS(_`tP4tev^}Ug=37` zre1i-zA$f|^T5h=irtBWq@U>q__ZDPJUSos zLgK#jn|bxB0=4!F8Vac8R1yA+Ei5@FAA7@l`907$;hc*xlIE|(RwB*$UUid(ZesS! zwe7#6KnWNH`x>>UsC&GW!#=h&AhB^>;ofO#K>iN3LeOGyZj<`82HHD?SBCX}3p z(K|r^Zc!BG05`^1Xp9*&38$({ptz;u%(KinsUVUbp(O5$8BH5{1b~)c6dX&Eb0~}BPr4q*6kk4eBibdaWLR>6a7_m+)eOCLudl8cS z(hQcMKTCYxLivt@hsmXmBTL%AHXvdqYpm!&QrsTRV=VKn1}>$mUS3%?tF3j+=1@b) zf$d-{U7)J#3XMfGmJH)4RL^kJA>NwnBVX*pv@=I-21prTn!km@NTsxJKqY8N)1iPS zddS-?dV8c1gICd{!4+uv_DF{u5&Lqp%*A(-nL>$`ZR0u#(9bQqF7x&FSOJ5Pd+!0# zw0&1*i~A1P()%TEKBKO*Ifc8OC|iN7-VyAyIWe!bepKWvC>ZbC~!EXhSO?iBkt_XYjPtG@lR)Vpd<2*nL!HobGT5$Yp&i4D3J zBQtg#<~&Q-d}Q5le+clNs=nEx>$>mfF6mVfSckd<9e+-A<1%&+Ubw+7bF$XC`6iTL zzOCebcJvQTuRD;U<t@*{SqZFH%fB0qe@U`M=t8Y38T5 zey1sE`oasD4Y{^U4f79FzYHd?V;e22oYQNTo3N>_o%(9vq9e7e5E)An{MPxx-+fp) ze}!T$q{*gf|48Xp(TRox{KnsOqP;0FdsN5j#E)Q{=n4-TJ z9~5uG%#Q*m(5pm`BL9Z`m6-`kyrd`coz6nZeqj&|4HS(gHSSS2mdz~)?mHM|r)N+K zO&@qGDdh!{MXQT&5Pc5};4)_O#Djz@3CVCBQYw1j4RXk|M@VHL8>1whN=bdCH~)Z~ zXVw>#S7UBq$9Dbg&yp4*^vVUx%17Ksm$VR}=fD=ti#C`YN|d3YBAHc^Z=|WVtx?We zHfyEzecp}--<}8Gk>`k);x!+Vu>)}30kzWsHNb)V$$>n~fm|A&;dTK40-hJ612j=! zl}JqUuTc43spCm#JSA$2Yekxu9dUV(Nz=&AGXKJSSP6*n*RFaaE$^Ep#bnaSzvLS~ zJvE!KR?9%Ja}vsdx0Ty>E0nj~kvS3E_IouhWb{Y4k_~1d)NOPxYAc!I7i?QYv9CBa zR*5xSdaxKM{k>fzL~OSoghy0hj*9V+b6RaG=tucO1+T2K9Ae)q`Ddk`gv!(~{Fjo+ z(Br|u4x)w$kXA-v8R{(8?dVpw4y2xcZTfYLEB^^E(_W&ykpUFLf4f1Ki%0nS9x*w0 zd46ugBlPKgu=#?z@!Yv1vh;8G`IqJGZFeAb-fioLE%BEV@pIFcXVcpOIq`%K{(o?8 zrxJn)U#`wMx4Xs8nf)JXOydc+h$+xL{2RLNgmQlJj<74;_Po$ppM~U!=5ph9-4n7u zjme#jWr+Xrr(m!oe?_?;7&J`g@{@1O3z`2YSsnK{aC_A_wp zN84`v+E5m{GU^Z6F=dqWnvwwAmYSiBr!VSS4H#+7;bo3h1NC!q(?1uX?~F^`x=yKA z<<;)q&k!C-%C(W5B#A{vk8q7ii2?60TwU|Y{Mv=~)9EGNCr0-U^@H%dWHU-8% zcuo8fPTzMR@;>$%9(tiLcW(69&MwyL@_f5^vKDc|{7~QBg37GIS0?5TyrLpZ-=LO@--8>x3FYOs{4;gTe7;t|x z++ODQ*U>_1>KscH@2($x0T2lSP#Ff{Y#8iN5<){rBOyf~G5rYO6KDECup%?_NIy>j zw-5B5X*NG2U*$@s)mY`S!ETmu)}Wggh|B#eH;oK)M1nTa-#1|zTnSDdx$*u+jz1)F z@TA~t4|On>EdEN^$mF2#Qx)>9B(!W%i+Vquds+h>z7d|*$@+e(bVJxl0rhQIncKsg z1uXz`cCPqZ0I{i6>-~@=iIFAXf5EG$ zLyTx|jDVMTv>bRad5A_N1mV$w1uWBl0K@it@uYka?;LOs=E0Md>P>G5Z_{3dD!yVE zOsLzDgPb##+!E?O%7X(j$GDg<=&S}YWX>hE{ilI+9)lQ`*uA2vXMT9W)MLAYg>nOL zq`7LsS(QUtvoV*7kUFR+9^T_hWi-5_BuVm7{n+jl&PA9pL2rYxA(;ON8A8fJ-zggE zmDh0Nmn;IKtRl#8=x#QYMow}M-$-*Dgrgbb?GqzA-;eU@#UX-|f-yDA&PE+=MZ*OA zL11e2ro<&xVe2H4Zn!EN{pSH$ClzRxD4Z_vDzcCY6qv;id7RArg~jCE+4uB={eW%0 z(;`nf?8Bqu5ZCQqcMwtD{Z{GOCf&Wu8@tRrcz` z$wrhM|HmFWQ{#9HQ-k1#1CfUo0X%PRRi9e#t8^c3apMrt+_thN{!sss0*%ROJ8X0(3F{ z0t@?)lN@|e^E>A~LiA+zP9g4XWTiVOf^Y9#Wv>fmu;4N{+o_~|s=81YO)DpDD<`*= zD)9294kW$)H=acyyCtY)tl^y(Z_pB+e&3{{RR(*=@>`{4#+ctBN zT8?_Z-I7#WS@?8u_;fYe%M@5K7B3T6L1qqC;si=FYC>_ z5mI}ul>@Ss2-wZ~XS%@0X1d+A%@HS<_xKO-KHVQD=84#Zkku8`Qho6cTPC`+G-QH0*JHM@>@2fjFN31+zgS^WSz}RIQ5;)S92=RW zSaLS&=eL$rCRXv|K{TFq2jF+x#BHeBf& zC=Bd5EVKJY!wSg8^N)lA195;9519IWCh?;2D>4zf=+8ePJ`Vlkf%;PX_#;I4pY}$H zVE!4%`pAW9r0N6e>@naZwA3-=F)O5B4Z+y@62D~j2BMf#T`W6^4QTd4@LpNfj&jcidCvk^ zCp^JrRua;xJcJa63niDOo-^xkLu{T5$x=?t^Nt`22f8mGJ&;T{-^^~>A$CLayhNHV zo=|R{00@c;24b@AlxJWyy!>Rmz7%W-Kf`EY*vUoQt{eY19z4r+dBWc8cq(l>alF~8 zG`)X*zsh^Nhan#IA>dF`6^ew|ByZfhpnDN{KA3CWZOnTX7JJBY5&Zek!`OE49C==t z_lTDFJYRi#`XP`c?|!OQaGd=4*V7BX`$MK)=<@H<8C z(f`KI-UKksgP3lnzU2hj$+pNer2%ZstgQKex4l`^`n z@NJ~hz5dm?vtVe0fE~PeWiF>}HkA{brW`kixl>NNBfna&Oa!v*B?6wEwv`aN5xVEo zLwMfaOR6I3iILy5NxbWyF-<;-g)kpX?JP{H{|F1ElIb{0cottRcv(@lveuAl7&b)_5Y;eKoehtzzZq zkTcq;YHFEsa+xfpZ{#xJO2y=o&E&ld+@bvzs8<@~KQsWH|F|NoOl_n;tYCEik?vsz zKXB1VH4rfP*x{P{U=sRZs{3GaXS6AY1_DAwFx6?Hdt9&dX=6YH!6VeCk?gi|$qx*p zDERZV%~Tl}glXu6=@EcbfAZwW8J5Ut`eC)#!!-5!jIY(0UsH1{!kZ=tD?svfL>;gn zd(6Ob3Pm6mUo_NLrcYf)st{D5kmUOF7ZkM3B-aQsZ&#y2ZB`24ZBxsWGdcodMUr4O zM?%13kwim5xHyBKWCise=e@6e9 z2`vfL=&``5s6YkeXc{7LIuSUD2%JU)P9Xwk5S69wlqFk~C0W=dg6vX3f-ExAOfs&0 zK3)BS%;D3Za934qxHLAs#88M}aHe1|RPdD~buiPlH0eWuU}ENXF_)rE*yq~suRdH# z_)vj{zq^T!2B`WLFbP5f!6J&7(c@)ViQMEL$2#r~&>ppXY>U(K#L~~`m)A{&r z`s*`v$rcgf(RT`+p!GL9n{`!*Q-7acmi?v<1#8|J>x%C$QG93+wVlj~x^~NS zYq2(L*>f6KY_T#_O}4gvqo<#m*`u6@5a5y6qlU>dg)$K(xuXl~XzSMeb(n6jn!2s> zTk<`9s;KOdsz*X*VjlZ?cV5-$wNPXHy&Z|@)Nr#^An?2=;k;)mu*rI^hlhZDt|yw` zdo>+?Hn9F-Yvw)OAZPc3lF01|#`&DfBk<Zj;xVlzkSG5T=ZxsFV*ziRQ{b3^jayBK5!9H60>zdFJTyzMyIQb>X$uEBAS) zH_~e-B+|5hiq?05i&*R?%VpGL(pmuz(2gcDhcju+e7oq(q19fG`m zztaHhAorWy+hfG8ia~!57jD-l&gUH^uWm=>uyyX*9W^IhqS<(cH{y8V+IM9RHBxim zSUhmQ_I@iDyX1_sSQc=s(wt_;m?i?c8R*7}8yWUdQhJh<@>1|M1pj*#W|2qrI)f}x zNHnCV0BPXsY2WkQ5AV(rY)&BQRyjh~5#aN^tqDi06tnbN2ePYkFNk&&^aZ_qX)CKkTW!1L!?)#Ec;c=$O33y$6M_v4*D<;}D09z%x zpCJ`04aUO|kRyO=E!7~}w~>}MKSp|zUV5^odP5R=eYX{u zvbGGfpTD)!Rs0Prc>v6IVji1R9hn&M!aANdDn^3V!tdA4_@6DN<w$!`7AwD zyn~{TZeyO18+(Kuc9z$@pfX1f6YxMY*M_px9k&=6t%+`HRoDCVMNN1x4bnVtT2czC zgqD8wziqG$y4=P%JChdgmnL}LTUADRx4Kn+DsIgVyB!eyuvPz^HY^Q(7IrEccDi}R z^tVGa8GaU5`!iwhQi@tAJ${{gIJWip^Lap_3d+IL2}?-h$Glc+N;L=MYD)=6a z8S+GP*W=e82Q#`{OY2MeGrGMAXnj7>(fU}>(FTg36Nt8~aS?T$eOq(8uF0u*kBGs!8H`2j%xERJWGi z=6Qo0Vc%nJqb)I25q(j~Hd$RUMCIVCx!y$yS#tnX%L3&giOCYo1*>%t#v`)0(D)d0 z4^!O28w>IPvi`$v@}ZtVE_BWaZYv&t?pQ*qLb87PA>|>?2=ig#k7@H6HKlIs5jvi@ ztK@nMGu;)1F4}UZ74cuSX>4^po1mWak)HG6p7T&otw>L;EUgGnt>yfd@P$Z(6=Ud- zs|MAgd8z7BJ&EdXVK{Lgt0?q-920Ir0GA|y&&a0K6bwoX+8gtMsMkD6Xb`-I_RvPF z_}@If9$5Y6NVK_<5;xM*0f`=Y=G3U3oE|BzBVpPpF$@Hl4`0lWGaH*~RzCiw9^Po# z^lH2xoW8~juG=4yJ1L*cAJxx?bX2xeslFO)e3>g z^#ygX?ug?tJsx}^dfsh?M?p8c>j`-RUm{{#ImW!hXxYgn)OHx$0=d3gSFul++4z%( zbso$tEQSuPI;4{BGrnfTiyF4%B%YjsjLwO^!{a1+H21Aegr2&GXsqBlM1q``W!@*4vB#!c;Cp{)p@yN8wM$~d^6Oj&bCvjB|2FO7>e>G zms}N>)W|f{s};)jZr7TNO&EbY44k{4vOO z;@*|s{zPlYjRzNvxp41Vy;}}y&9U5Qw#4`w7uEYzU++!NjFzyszoT1R?EQD1wPSWM zB6ocqMnT!vTW&wV!Lie}7UmrxBNZ&yz{IGpo>YaFM1;%0Tx81f_@al_;Jy*%ORh?E z$@OR8*nBx^uK%`>sfck>(qBGOMoM1JLSBw2V3UD{wE&QBNbI<{Lg`V)sD_kGyD6F@vggqYlHt~m*f4JAfrb4lwGkabCU=F>Jk zC9aem=Gx4RP4vY@rEq({uy4QceV_1szc6~AFuF=apKye8EYuTF$UoF43^%{3uPJb| z6TxZ6SU(Q+G0m3#pf|iy7f)&|7sfj2=t;BC9?zDdXe<{liAmy%nZ{pn31F|d0yro; zTmk;f|7OrjoZiIF_=5B~jNSqlp_r9BGLCsqRVY?O$qUuujX1Owl5&@q#3`1Guxg65 z@`zya2xrQ{QD_4Y)lpk*5#0Bp2W*9z$V+mj=3___iylfYhZwi1ulsDQlyHOE2xmb? z3edH1%O>H@q=e6p4hhE9hxn{-yak9;bzKWrjt+?L@PAG(fbD1x9U;m&U!E_#Ks5tF z9n3rT^xHQs(YH@7XvBowe$ucrDx~grKF6ShRt{`*ml|wuckKZ~GAt~Y8Y0jJW{e)* zIVLMRFa+iFrq7W*R4_bhTk_H?PiFYH&AhgDK3JR}%bpb$Biev~o&(L)=uqd8pmij#bb0$e9<|(A4L#8()uDdKj$KR&MHksKd;z+Dn230E$L0u0RHVh z_4(;FHRs5RJ^1U#$XK<6|0fQ7Y6X5$bdTt5DreyGsfz$sj^{(iC~sY>y(o&J%I)lM z7Zkx3rs}#cuch4Y(RJx0F#UcK>3x4EDDotggYfi?g&Mlt(RN*if0rP{csU3PK&89= zPGDSYZ}zeAcAEC_g!A+E69HtA2L_=Kag5>d?uq5eZ-Rc`@GOy3{v$@MA{w!m@_VG5 zT|!C;g=f-hXTVh)+h$0;T_i!Vn`!|$#z2M(j(r4fr>BPCh4-VAXq6EuLSOx(pi^y2 zPvRB`8<;U4xc+PzWccRu;=<104oD<7H(ZW*_q?YdtSxA1@`WGo`KWeLEUc1bac1B; zEq(>9)0$N8*8;Ztf#Ra zXsXqW+F>f%l{7Wv!xr;lE%~tP{9t^HTuG#X;$0Ep(Bt2@|LO#Z_at-h{t4R7(%|L` zkoQP{gRR#ITK|U0-Sk#IY|RCn9gA_P=kLzc-8Zxo%$RwIKep3}t-ExXo6HL-{}y49 z5*d;fk(EZ4l|qh?Mvjm|MwdoLmjc~OgYKn3zS5x8I4yjlNT5ecqSH0u*m~3_Ve5u)CJO-gWsuT37#^H38y`c5nq0p& zww~-lwFIOpj(OM%=uUoqjz>!)vHN!=mzHr}BWn=q+qrW6u2zCi%#VzBr4LUf9-#G8 zkKl=VdMb=c;Az;9s3n@=R^if=x%;6y7!$PN8#Zj%&4BEE0gBwLK|kAPi`M)nH zJ&#ZwM!r?aOvt~`!$Zq=Wak~lh`I>5Xx}o)>Hj%TE{pLnt+Mu(f1$7)4n+I5BL6|P zLzy}yzeSE@8DRm2pbn)=l+JQ&wQ6ks<-7J1I{t1FMCkXq6PmeROFn(q`Q5blZ!V|# z(xh&^<**VWSv+1$?PS>odafMoAbMoZ)z%WlR~=dg=zZ^Q#85y6(R~T0en_eCv(EQ< zT%Xm!l@5bZj}A=5zo_n>Qiom0*0fqATAkCeka%dy^{Kj)qHJOuvZ z*|;e@IN$Kgi?6aiTaN^NXZAmdJf1*4e%oz4(V^*iyrJ`r^Dn){JL1@Vp$<12Io1J$LX;SAb%AZ;856&wb>G8cmOec>c{c%pJ9Xc5q0 zfa&31d6VCz08x{JD@dtD=HBMV3#RN!(hNHdpnC%3XsEFwB&fT-+A&ZEei4L+n;n#q zq7pjpW|9uLy@d(Bg?Xo-zQqL1Fe%`K=9i@^*+r~CBIXv7rEJm^#r-H}weWsdMB{49 zlvL0gYP(8lCswivma~D?tbr9g(OMJ;o(++ zu1Ydfg`J6a$4&RooO`cdV?R1xjtwVr|laD7vs- zMHu%6KPMUmJG%Y^hW-Sa{siI!RbLrHNEuB?8C572L&yV-c~|ASJP{rKF%AZ3g}PgU zVI^vi{MKVhk1sp95dS1B9)X1a3Ail-CH;{*b`_5Xb%y z&;AhKUXX5fnq=0MrKlinpO%TyRN7iidJuhD=tx=%gKs`_9-VIyjZ1tSSQ&qRTW4E%T@H>;_r?mRIns!D=Nju;ts<4Z>v2<|*Ue$4x+v4ByHh|GEw)~+f zCofU^?E6R%$L@MCJIA)K+uNx^#W%3%KcPoGJj7)kte13^T(?hbQik-m4_r0qCtkuZ z`ZSl{YJpVH#|ZR00m`BnwgGK4DLvU+IBtM;1Z|62ek2x&zdS!C6zH0bDoeOcf}*$m zn0e90RWF#(JL;CxIh~OHF1O5~Oiogtbyn4CS8w+FCa-IBkl&iU$nuoXu^++E)>#sY z;HS%1@k6u&GldwgwS$C$GKT2Ol2=^6YaL@>766dV3%aTg?6P`Y8*Pd^jzF-GgI@NpIzeQ0hT2uP&jVLp&9}KUS zRINZIRhV*=4uqR4(M``E_mpFI_8zIDf4%`*Ka~M|w7^7cd}wLCFnu-EAXi0DG&1|Y z0NNZq6UhApkSH=T*7^9lwS_!}u1iZRxb)pS4&u=-Q4*z@#n(2nJ+cQmp^2;M;LcT^ z)y)6R6L-o?B`5A}7nKCP@lQXms@7yW+*KEiYMYxj`%N|{-37%D9CL|{Paj3yH^NrM zKPdJwt_a;~yK#T5EFTgsR8io$tS$s>GmD2>YVQuIX1JI#O{<#NzP`v)erI=V!?vdAyy3to{o07{&_pow5ps#l6gm5W$Z`r4F#xqDNYjmiVjAS;P-dH`cd}Kt!YHvE8E;?33W=H`A>n<7^T3Mu)BmvBt)+u6+hHA(_ zgsNQ-qd-k>T>HRSyTDk)+fhu}PE6TBOgT&0Q4EmOLZ-RuTf)c5Zo|t7)Bj=1ReEPu zUv^h-M~-Sm#HB~ii+;i4P8p*gH`s&}$r{%W9WpoC<*INyoP}6o(EF|hu$962%iu%w zpo%5b<`TGx=1f_+AdQwAOWBT-+MrO%g(L~YOHC$0!9@*ihD>V)fdd%IEP95_)WV4$ ze2zXW5%QwP$?VPr9Bvp(lH~S|_^aBpvGLu%=*xT~PJ<(pXjNcWXru8}gc@i|=8m#z zOLkV|OKMM-vDxw1>yR{M<{(~_BX*jcrN(J)%&S^hq}3JBIhME4P#YPk6i|U=l3F*G z$5%TI2=5z^0g%u+Iv78Em?C^wpE>v=bFdh5uv=P);dzLr2mtpdfJA_45KrGtvc8~Z zVO=fuA}J8jGvQ8L2UrWBqL88bFoK@SYWF14*Xeoblp{blBsVhwZ}#;n5)u1-HPWPnUF zr07c+byxw<7zji1U#b2oK=%Pt5(ZZps2K*E;`eY~oGBsQ4!jZ(i6mJ}K&!=>8;>E+ z%91)A0SNm|78YFbjyYB)8EV1yCUB{v);1=wu3LW_R=*$o-gyFinr!Jj)j6u|=t8MI z+4!bItJi7y_Qlv(Zf-TSq`JrrS~8+v^{jLtfoy z#y@?=bK9Q25Rm7g1<-1}Tnm7PdS5@^&E4JvJ)(-;cZ)|5JUz)R$xu4|;9X|o+ZHo; zbsnYkp2hz}E~DDoEXuPqc%|y;W$Pt8<;T5?$7FkJr~kM!75$|7-j;BLYIC`nH2SgvL*d?H+^NI4etSBefl?|09J z?5agQaOziXPYSET%P$p_@7^Wtni6YxC>8IgOlw=*X|J!Z0QMI!}X8^T!Fil=+UEYCJ!3sM;xSe2?ouJhxwHeo~6NyDv37t(s{4q9m{87X+&W1mZ z9Y2B{KZb3g5qDDGp|1lB1W+uE#h9Reb6d?6X`9?c4Aa}bo{iad&Rcmw_o-oy{UWycs ztX>_VH}3>(KbhD}zkPR@r0+4#E~|x~()+5!N!bAjK+Ljh@XC@hK|O95CL4jCAgR(5 z%(j)oU`3J$X6ZGm9xLNfQ?rhCDxGF=QwhCKPSlw$k+st$@yPV3zy^&7R*oHNTVJjm z>RLnkHzJQbj1$-j4b$9I<6;+z#}0YJePh@PRg=^UM!>pOsjNJTDrKs}W7b$CJXoJ7 zRH9>TWMpGNyG@`%?W7r-*@BTnUZKJf`gS0NEeY0vN;?UbsxOdG7j8&se$WBh$pP(D zf#6D{GYm0y>1e#!yd%g*SPBwhak2^$DNOlUfs;(M&Kj>yG+yNrMRG*-`$S3CPMB-i z)PvuhA;=m)y2ogO*c}u{ax5`a;A@jza@((^fvAiRTV7jf9cKvj4(NyI%hKbVx(0%u z*519NhP^1NtJHbirN?i+3J~ploQd?J?!~!@v!I&t`~A*xD+y%uaSt+qdVH($xzS9C zrN=Ny9x0l18T;r9gPxjI$R!m?Uj?#Q6+IxiCz&E2bt^^B8x_4{gr1&j%R3K=>MU%R zQ4JC@$g|rIpNjEGz|mBSAzo*Z5FyCV zFGBjgQcRVNehmy3FS$g0=r|!n)_U2u?T$MA`AGBgeDJ;NO~zkD^0>mWq#AqQ^#tg; z`E|Pem2*ApeYf{(vAe0f5EAFJ?e3RWPlQr$W4RlG{y|m3qPNCAiwx`TF%7sVy&bQ8 zHtT;&nu~1H*fPhJe{J)Wd+>*)cenPmr|{usr@T$CBQYsrDf%Cwre=75^$+<&vB;(* zNvkPkke4+fnixSe3cKR(1PLBIu)nsZT7^8AG`txcM$I^8Mx?+PCb$@Yk6~a~_q_zW z7D%$SGQlfC81%@)@EhoNE%Xs6RJXpH4rt0)BdnRZ7e44*XfYPiTo<~2Z%w&;dYnVt z+n zjN$v>>fw!gt~n=fq6euMkHZxYW9JB_HtE4qm#V3vPf(k0jWd!752*s_>Lf8%j{HQo z`j`Vlj!W65H`a**V@DU!YgmztHbgV&%fPEZCOU3LI&R83gpQxIble62vl$TnC}*OZ z2kT!)Nx(lrWUdk#W^QVTM?Tq2FWC)}>^9G&lPpR7PKaZaey0XaT{b7qTOB=#UQwP` z0p3KBqNOgC4F;_bEc2(f;CG@oKnNl6;2kI!qzg=ZjV;KEJwoOU%m(6!D5BC9vsfc1 z{3}CM<1oTM8I#t^*1|$UV1H~Rz=0N0ST?M{t_*~Z$Anu(#8F0cuZ`7N0j1UM^U>}T z(gdccu@D;DM>`TNlX}FKB{OS%nI9o?u*UM_S4{$EAjG)sk{Mm54FyPk68WZLI$9W! z&N%Ppu^RvePx=Y2jD?^RGIA3*CtPTTBO7e}%Bi`C7gg#$4tX1n9H@<68e_(bB*tvkM%4i+3C6%Z2u;ur zS?b1Z^}_mi3fI>NprGC4=?E0=MsD>&jMmROhw~^PWgQzC4~FhAb|ku=iaTN{F=c{bLaM&Bo_ibLzyb zv+|%jcCqIVNp>iT>aOvP1@-{vB`Ai8-26QBG!ut@<1>QZkp8}QJR4ngw}&+t-h3kU zvqHS>*i+>5;j6Ez$~`zM`rg$|ywm+k2>Er2Fc>J{P2)7mD>1 zr~{{!gAyxKZ7a#Q$ANwRqV`x7b#v5Ol6&K94XrXvz?HGLEn^lk-<+s<$VU?C-}Qc^ zFOtVjj&1#ky~Bhy%#1e7gjSy%%9tG5pByU9FR9X(4ZZdxd4k7231p(cW5f9Iqj>OR zc;aC^@!12>JTOam>@LganV`<2bGQ{bM!Jv0kYs~3Ehb01=6Gl zGGHQ%d!F79Hz-!j)FKwK>4DU;WB1! z24*vCTz16d9+6EQNR?OW(y*}n3&arKj{I>t?HR(^)iMG2`K7Z!U*dCZ8Hn>C*KC{QqE!bjeh;?bkJlgoO{E!&pGMwBrs#63I64Nw$?!HKh8yp->wNt?p1H)_lqh1Kl@S5uP~_Bf zl0tX`P*DLe3(2xrCQrdcm<&IdCZ=gN~GN*@hmCOIS?n{a=IfOmu#e>Q26nya&; zs*T(wox1N1%p&vHvLx|{z;3@b3jSP-&0JMv4BZZ|;uRsGi;28BHMS*B3<0QU8C?7v zL0$fP9tYXhL9JLA7Lsl9aru>L%%!Qi&TpPPoSe(#GfzUNtJS^Of!uG8H2b8M=qjJ+s+Z`hl^6>PM%CvR%V5%%ZHNOZ^j(3plO>9(B^{k% z@)-~-c@Phcl>!JCLbw8VUD$((z=%N!MoDsCM|PQttD{7)Rlsr8%SDhqbxJ&j;8{E{ zF)}@vs5e?T9~S12BAX-^GeXrJR1G44|3IQC-24!F&mSX_4e8~2poAcmLXeu_!EDk- zIAF#?BcKHOH)3JcgSTTcNRaS2MN4+d4-(Dbd|9B{YwUc#q+a=(mO15;!Z?g^xEbWiYdvO(vhOl?c3pQ#ANaLXYL1N?gV7+1!THP3?EWoG1w^E_)tzI$e_@r z-(Im_m>{g>4L=iIE9E#MmOtLKG1QIg`D5strMrr*T>lif&B@)I^VJ**x887e{jXi( zfcdBs?vGX^Fv8RZy`@5fx~ijhvoYl3n1vzTlHk+MBv?;|p}k<+tjFjXWDP#<0BvlB zxw-j5>(3=)WAV+rJzhyOYT;X0Ibjy=_D4ucu=Fkul+DmmQVfKL1bW=$$PH(G=H(ZF zH?$Ll%b<-+j7j(-%TQ1cOd4k#y!;PMXC2g5-+g;DSa1uj1&RhpA$WpQyyYpb!QF~` zaHmj;YYP-9P~6=eTHK*P3lw)KH}9SKO>$1oOlI=u%HH3-_WDQ^6I5PXTZg`%6vF)$ zW#@VT<}>iYtsP3*_E{BVi)DT(hW^rS1Xa8!Sickhu4zfb(KGUBL_zhd_;dX<7;~7S zOzOXg`$z+b$U^a*C#Hc~mgYin?N_SOKNVW~#<4{oQimtTWDOL_wzreEy9+@_%YnIS zNJ1~of(Vjew+DgK3m1iX2(z2o-9x=0nvnMVzkq_@>h5~T=V&GB84I%`0;b?x6nXfxeKjbjk!I>an>otzdh&I>OQu{DD{yJ zejpSkRA$$gUFBw4W990{4rovb0}h?0xu!3k$;8;8$IBR>^8=Pg z_o+#gO9rxVOp8T#<&7_EZyKkymZ*&4Wm_Pno%jD4q6}_Jcj7_s&16iXllmNJelMD4Bq4r&RJL=Ly`Ro(%H*3}rmRRL{7cX@MtCq=!*9h`EH@Ubs1M%88VXe>i2nK=p304= zm@Yy%iP+M&HqM}D5};Ni-j>H3{HK_Zd14H&IO7rePPwG#Dqx(FQa(+UCiH;|5G)VWts)o_AQ*y?Dk~Vmnra~!^1&82 z=Pa1u>6t9yO(>=|hbtE~R0o%y8=L4qj41n1xhj?1?ya=$!gX{8wu6ArCokqgS*f_k z53pk`Ygp+jhoe}f(FhJRehzW}7MFMjL8Zu%KsqUDv?p-1>eLTtW6POs=^t`_n?Q)O zvR`R(6EHZ5Yd+cLIb7homH}PMP-K{vMkM6C(~D z+EddFVhz?Y19N~uqNfPiQ^f3G+GbRQTh0w))-vn{3EF=G?F52;1%d==wgW-&y=W(x z=DEc|eGUu0f}{R|lm3D|{(@G~0mRn6#CyKPR6fL1cw{Rgyy#67(K&`dpBl5x0i*6X znn{!)1*t+uoF@0pI^7#eROMA+;EeN+1a{A!*-(!`>s` zuA22z-rg!SXNd9ol?XOTCVss$kJm8nz8vQo^oJtG(;If>*GTwUXMWv&NFTD2QLI9qduAX;z^kJQ%ZQh@q@Fwcdxq?`&qE^ z>19O!_+k0k<})i#+&tT`tjRjw?*2Xv2i#4CWpwnlmbQN6pFgjE(w)WrToQ$zY#|TmaSt(V%4!K?4qW2$lttu~ReD1N* zMh%WnpGxD`$n%;X@DMlQQ71ki;-G!_<59Lu-;-$@DqW*g^q8VVlK^x5dSu0QtZO4I zTju=lD?+Z(9-2Ed7YT(YMJK<#Hs_WxFaUK<)wii+`jCSDb431j6{jm?3PlYOsQ=c( zc{US#yVzd)JL@Z+z>=4`4@GcbTZ=fRVA}W~%B)@QC zX>p%%6@S>*>i5w;&{tfarFSnGN|9bo`uvxl-oc?abouoWw{*;>y1AO2TexJ?$$QC` zox3qLr0on~p8ofps1SOizhu_*YPs^4pqXzQv04q|7!~yd))mhAQNpvEUFygmW8=9M zPyCf94#gWh`_051k7SG+9Ryv{0l3xdFU&N(s1nmCSZcokGOJ46&L8#Dh=>a8Er3@S zb+#t@vK3QEqWL6YbSfJK#(nml&34}H*bJ5)ibTgPplYLRYSpPFk9?+V{7c>Y*kM+U zl@$3Lk-qGO-W)4ZzCl^b6fJxF(h{TJiu&>$yxVD+qQ-o0o$I4n_2m=q0NLxdskj{G zIqWe|j@U>a4pQ~7Ws(JSbU{&iMt@AnYxjjHP$Ew4l%>qj4%*NT^U#iKh*Enun?42b zjXXN4?>R}_3D5k3!T0v z_D&Mr3}%c9UZhy^`E&J;y!7<%=~SpzEP}jcsemgiOx7Td*@7fZSF06{ZSPP~l!3(; zsp5KVgfr=#FG%>&LG1E%RHFS#55aI zN(q7@ZRvl-opfiL>o&kT`@a>LX+MC>)1W3{%Hxw^mkaN;QX6i-)12v0Rem$2>En&S zwg=PQYMaRHre7w&JAmaoS`nocYK88}v}+^ek0pJ;U!-Zj&A+RQTT}@Jw>(rR#Up(+ z+YKS)U$H+ct=gxUT{wwL}Q%c&@ zeL3PIEkG^7JzCRL+p~Dg{H=?61i?0(lPy98|NH~VIv@1`4FSTovSifCy((PXm+cvq zJl`uxmXZ#?B#=@*vLBimG&tfB7@Tb9ZO_OG(Iq+=s6)Aj$OWY8P?7p%}g=)dQ#s;zR@HQ*-78&?QWpqZsROj%h<{IJfblK?CX@+0GmyRh}(+lilw ztE*(%|DEK>LbklZgI6=hhPwFhpaSQIP^A*&Fx?&|4T=1x5t>*_aA8@b7uyS2`RsOd zhn6V}gD(k!vQ010OJAV#aZK#t|Ehl@R%H_OnoNrmuPg;i=QT#`c#W4|YOZsvIoV)L zQHY*2Yo3Zc%2U;U^={yvQN;DQH*e4%S7HS{=@ z$qYt8LXSiZj1vXDZVDNKUW);&L`KB`C?}p)aBCvh9%x!`Cfr+k$bv9kp%aObKJWrW zQ3J#;*6J7HYSdml)!qL;FF>zQ&D+u0=c<|7n_}?GUN*h$seLxC(7&w>-Cvhad<(~ElO9BZpz=A~p%*FoABl7fmwc~mC z5+d@m;9DnILj&sYrm*RcRoPcQ(e<Y zJ5C)h{-_LhJ)Yk)U>xMEfeZW~2(voG{H;#szk3Ho2qs^n59Atmd)scTFT7zGovnje zVlJAI*`qs_nTrcbqwSOxCy zCwF>b#DJ)KFl03c^^y6vko0f|4bga{ei4h6MPg;0}BeR>wmW%lImT#ETjEe->vltEh?ogq^}w{^ki zCFo9d%5Cg=+5k(?W~`H-4|0 zZ1{_9C~50Asw31(PFkqosjdEkr!cKBNTw59p0;C5ilw_C&fT z_jMzJ?1mMey420xk7B9sN%>eBdE3ZA|FxpK^FykSl!Q|*tiHeK?WVrR_ty_LH7R)i zo1UH4jZVnF%&oiE|Kc%e=(IBM{l6w@oC?p$0Xur=R2PGj1OL00pZjfZWDYZrzq}{r zuHMtHJn1(vv12q8b9rtlZVe15KZ#C~Q?nLNq@rSOX~ox{Q0F=jN1p$a{*jna;AV|q z6-RL3T3s-<-y=2{^%pIUF;BSQ)C6^8Y?8_-jaIbM<13A}oim~@9m1a~Tz^2v1dB@W z%A+D`lZ^7`D>dAlX;nn4>h;qgKwm60vX0|m2~lJT0kDMlv4n_wH296aC|y05WjSvY zpQGqvk4?ReR!;l{J+grwA)x(W`s?MzKG((gwIHgtCt%rXw>Ag_md>#Z81$34i=R?1Tx+v=3SNJ*==bn#4DNS4+z^L=ET6WdqHoC8f+(;14!@g|YbM1MBL|*^` zjDWKbV3EB%3gFp_!zp>!0to|1q;H_Bj->i^S!3C_N_*M?sVv<6|%21|j0%G=6 z;@6M3b38j4f|&{TUV-!;sK-|^m$}`SqgW+IZ$aKu=KXEaq$gyN9jc(%-U4qt%ylay z{6r|41;>*w0Uq!73B0G@9qs^_8$7-~U;{YZI})zO zXC%Y1k8|p5bFpvy+#=DHo%zMwX!`@)Bb9_*uKPVr`(Cdi)(=W~P-&Z(#Gl8akTD98`pKrraXI9f%Brf0vb|^TU8ajOu@)?77g27Mla;20 zXx`{JiNxJqc2u*+A|XN0l4fEC!o(ibAbRm-fQyd@?(6$C#aipX|3b5}xPScok1mBQ zLH)|s*-qZUkYHJYE31gX*ha#wvyDJXDqUqduBR{vm}Jy_u*f{f83`5?iy!%FuBM&@ z`i1fqDJngHp`MIu9hSq8!mnQd|GgR*9#K_rUlybnYb5r!m{&5B7gjmq2tzscUt|KN z7QNLMtx?;HHm+ks&Vnd~8IO|okn>hC>_EjTV!wX>&qQ`)mN(X#Gg(w5 zy7J$J^0B=_z*~ky9V&!Nkcijk7pvg8Zhp0D#T;>LwuUCuLPOw@#ZtMc3Rf4M8s`4K zO+)UK_m{@2@yS`*lh^qQ^%o0=ZEmQT0ThwjTi2b8=+_?ew|XqQQu~yZ`PdJCJ<4cl zVNd-agFWl%#`+MAG3cqkTi#W1HUj83Ebj^%#DJ&Zd2!Ka^oGTJLv#2nskJO;6QZCL zqR@sHLEHq;t3N|WzRN?V&eg+q0QINzN7ELGRO*sZig|LFQ-yi^T0I@RI zPO#^m^{D`Mq7+&;k`m5X)`DYzUBq5OPtqj%97{n=N4vLyi$t6#fjRYG7{2m{|9_$B zE$TjrAm7QEaySBd&hBHU>@zRy4_vWN9fsznnh-}ns@L2*zFQs|zw(3SG-Lc2YMrE& z*w_JRZ@Lvv?cL?kPrF3^GofTs-H>i5Ex;%g|#S*nJcJlI#b^ zrDDdPnRTFHUw;dmEzB7s7f9 z92n&|`o8(bH}8QPB_l=#wAJ_$K}KWQHzRjFd<4faEd)M>8OKBYE91A0GVA=`eE(`o z>z3Z3lqf{iNXTGVuUTdKomo%CSaj@ntRPH`Q8HerFKJ~xnqp3rsh$gHoR`QvpoAES zu$d8_P88nHo}M*{YaJ9y)1@pZV5e*0oJ-Ekt)B$f#LXWaL2`yCU?wJ18hdY{G93+5 zijy%wOY1MJFJ6(louwRO<@T=Iku9#w^q*S~9U)T9T`v#J+1dM9`1mNr#PkQnv0l8e zbWSTMk7ecH);82lcw1_pfK6b>hY_0wo@axuh0ixyBc4Kqjh$*r>9op2DOFrY*qM=L z{dzbS)?UCmkDZL{d@#+>_z_o0Nz}CHV#Gy<(*blPx@7KW**6|VZ9Agx?x`sm?pRTY ze|!FR94`1qUyol;<^M@Hhgm`9%p|_zO*&Ckv#)MUURYu|igX5k``@DC^KEDFAg9c& zO2EBbzQ`;umwQ-a%4g+Rm!RuxhZWv8s6A>!EpCiVY?-G$O~TI0lxommC<>)HPij{q zHD@O9&&x>)$$-kBK0c(8M8QooETu3HCt5l@@l(Cao$@h%<|}LTd$fr8G*n{w|2cFm zD<(YaSW{-8fz4lHom1Ip?;6N|b;14>PxrBs?!WM0?2qd&(yGP_J%h+1Qu~JK{wn-l z;-IM4VXJ7xRf*7tW@UzC+{*pWXsAlRGG;5g7<8nV0l0p6yC!YwzxJ}e`iEB*_PZ77 zl8bd+dnIAQZ}UHDr#9}|K*!S6j53KCm!9+!GBLZO_?E9;F?ZE5SanF1(J;#P?P6(6 zO%(?Vrv!~e^qI-~8SCP#v*Oq@ zIz#EaJ-zzMo`MKNP2r(#4f3Jxq7=mD=THRfhX?Qv6wpAAv`>Un4i)qQ(Myw^{Vr6C zQp0V@c9d9mlrVOb=y!(9yO;z`n6CW-7ZKlA4l!#T*d$Gk+$BzLYYw>=f1hprIkPCW z!CW;tg49mEZ(1R+s9uQ!HBmpTn$Vy6xcxYh%Ta0Hz+vrSpE>DEKl4p#R`?KLBG0yj z(g2GOe=d48vZe?mzM2p>%4RKKa{e|U<`rsZB*|QWr7vK{IacFPiJ1_)OFART8AaWj zaIYE=3AOr}$8LQi)=$U#8qLPhiYVJ>LiGHGFYnNCSgzv&z6je;14bPAH_F|t-IjN* zvkhUWBdP_VSfep6H@@N@4e>$?Lfl4UW$t{1R#sHGs;SU6NX&(5>VbY1>|_?}K7DYe z3u^6Z?nZ$bR}6yC7|<(tDuU}l3Fbh7EM6eO#~j4w05rGUa#y5|gvIj#%~vfg%yClz z$PAdzVY{6zp zWZ^Hnc>V-LKoBnZ1rneU+LGI7jxm01zD-M$|9jxd(yZC$A2=#%t1FYtc!OyB#psL-Fu0|XMCc)coG5T^EIL8Zy~(#5jBh^2F7Y~X&D-HMl3m#@IFhDThcfj63y^rWh`He=z-tD z%Tsu9s8|%5v@EMiWgD=ROnl*tv*#70u&{;9it=uFLX&TWWJ7o&q9k-0yl6v9kNB!U zHeqDfyVli%=`Gcb=THceQL7K8&999|ry_nJ+IlZk7os3U`0r}6dXvZWp0@LTqchay zaYyvVipG_P<5VA@^8pr#{wgZqShSjD0CMYRUxNNhR6PREHMk=XR438&Bh3;(P>!F{`O5x7V`ljcgqTu0n%$HPnkdt!Q4^zsQrhGC);0`vD{kYC;ewRJW|9YkH7jA#aa4#=g-Zd=0*~*+ zgilUowpDQWds1gA>%Zg$vW1EZTtR@|DNTdO?rZAUH?&MIEs=R0d^V_WYxejC)I*)PS7lrxRxD#H`FSErjsk_(?F%AVjxK?P^S= zEIrdc3$NUzMBJv_o00Of+uX|5w_FC#qoacNHaLV55@jn(@QF#Ha&IrKhB{x6eY}5O1*Nx8CkdrMq?wbc4wq%6i3fJ>{UYqzg;r-?3LT>~^KVM!a>e;2zgNJSAk1~?Z4d~J@*h)II zs7Sv<=QjRLsU{g0@shM36IcQk{ApMJ#rnyl0SCEcU3rMUZodlE>@A$rbFS<&J>SN<{L+V3Dj>z*g|0HYq1kHF_is?QP9!dSP_}dg0<+&?!#V_dM!DVn<7oGh%QN%(QCX31C_e5T z@obT7T$q>iz@LDVQXNh97>4#K_BVE42TK12<0n1s3jRHoFtpd^8YCt=R|*{wVc=2CKQC8vkr(`VWEThQ5!wEvZm$>?Nn_LqU%5L0_Wgbx~a z-P^L{$^v+WeA~}xlWGQ}xxnByi<+~dU|nwa>ZJIdH<{jIA|i+>yS_aHI+n)m*1&aXo{W^S^> zHXRqo0&@?{glsxnvYGal(4Ag}w%Sk*S)bKGK$fq8hzP9yyxz$Xru;Anz}*r#gSJeG zFN+eDAP@}k8a)|K5_U&Mnw#S)?9-Xi1j+?*8}lEd*;L$D)^nU>g4CXfwr-A@>P~)Z z^!FU7^usSXESf(?7YdNd1+&KX_+ZJM;YRL|#t*WAlA;7@h|Refd(|YvmwZSr&Y0N+ z1%8ln)|=yan&VuW;{b3U&VmF#f`0NqiqXs;OGy{BIH^f zQixJCtjMx^^Gp+(vGHUBvXH)GG6#G8W9!evUJ1r^ zjqDjrq(0-L?rk@RQQLbB7YbIw%5w&K@vT6Y=4Kf{Bmg2(YE7M7U}KFQN29Ns{LzC! z%vUs7H#sz{=*ajSzb-lTQ|S27;qYi{izbkOFwFCR)l;*&EoeF;U5A&42Ob#6*Mu({ z94s(6qy!cfP5Alqh4Yn%F`TE51przjc;v=JDICp1WXANZeYm z2^u>SV|dW=v)wQ&*)*f}L=5jFGhykXlxrLUO}9H8Hf&SndvhTpL}YFyukzy1Dv zhAOf4QD4=O(gGmT2ci}$n)d9JjlppkzoC6qq&n!QmNiY5zSBApJRU9{WE7>^R(9YiP(udr({?0q!Ipo@W z8DCwj408)$z;Z$$%y+L7UTAsZ$0G2+uPsm)0#Ap7tZYqBX>CyakLdgitdeswe((y5 zmRu!^3=f<|j)!Zf!j2NBl!<{9X&3c=8Omicx6j2=q&P~Fk=L53dKAZ!47FU+>Wep8 z6v3J{y!eW`y!b^DRB&QV7f6`l4EVmt94OxhijM?S5L!TK`)wg1wYF$GGiV&e=)8)O z$q`3dSWa5!Wnm)VA8@*U+b|LKT3PaXS-N@{HN@ipX$=aq2KlPNg+FAN;b)m?AYa&G znE$H9R%bqflhez0XM_oxVaYvavcVq6trxKuF{~FcsPr(Y^q`gCaO3GHsRwYll=60@ z;8A2uAGYcup5Zip)CMkR6uO3t9PvKh#&oK=*-hE==bD!PpbnM%FPxbuEBRUM^^8>< z`3Z^ot0Irl68)};ssX@KO(eTNAYrV!kHM0J-WnH-*hCdk@bSrDth2K&9BAY7=Fr|r zfZoO#bLX+VPwpFiwH!K2FRp@DRkGz-ecOMa9M<<>@COKx)_}YD-meg<&UqA(zcJh# zpPi`-Q^ar+-ogL2(H>s0z`yyYA?~5ywesMJ-2Xg1NKYO%- zlauOhf%p`!@tRsgmx^$#NOAp1Zy$e@O=FL;;zmYyX+(5P9sdxZ$wF1P*BTF{I9 za87TzZ@hAoGrQJx+QMW>YZUO8mA{4~I!p~I%H->@0P*=tJ+<{UU-}~|K-~AV)RGpL zFuXV(ztFDxHF>Av7rZnp6lUoc*7MEtl@f_HO|l^D3+_1h_O6LhjTYxY4e8$ujQDJK znj82F?{e+s1j#^2Pxf8&#T9)(N>$G3Dt5ruSK?D&ZF2cqA5Bg*jn-pG3A*vnA-1ni zbvZq?A+6iRJJEAaMXgR~oZlVoGNJwDasudlS&;GCOnh%>Rgq*loUS#T?!K9>wG1;W zneuf$DOnWl7zd5@4^@zHc5hWCyq?&*=v&-(;Apa8-jEedPFK*sMm0>bAT^^mlHW)u z2(+_=-F#Pv!&&2oo}ABuwjIR&JPeeePb7)&&D|OWtU;(Z3|sH=D^O-{*=MSVoBkkw zs*Q>9ZY2fm=6A+1IrG*OH`fJzjuaCf9tR&P3r&j$%SNJAqH=|asF3KD@@#r>L(KY` zu-00lkwNj#*>uUcdMm5lfA#?Hd`vhl(U|ZnrD(tlFD(;YcAWuM&#GU={#b`N0j>K># zCm#7=l(MG7u32{b$w)q^-VCQQsTMF3M$}@>YLg`FcyYxKvV7*ERdRzQ&f3!dI)ifi zaPPS33`Q?zYEdSHmQiVuClpFk$;kyI4f+7p^QmgNvJzE1P;#LFbKs3_)J(OdaH1!z zSI|`ShlHihQsMdU(^dSR7eG$UpB>1;kOJ=aRO~(2{+$>;O^&zq4mvzTO;jLrG-S4z zR9M5*XU?=h?<=(1V>BIcSCEQeIp}93;sw0b$DjS)ppuUCsywX(I3;8AYTc`AJ*ZFL zs!yLEJaQa74jNwuv4w*k6-g8sQ#WvXzsE7Y>tbwV6YSp89QY#|X0|W%5YMb8O&%Y_ z1C;Mh4-+&)3Yz@_V^=bdTS9IpR$GqPud$&4M+w(?!wKqTx3@RKG%#ar}TUrP5Y`tf6$7IO z9;1f>mDwMa*)jA?i7gOp;S&?!#>U>o^+c3csd#ZIW{Z51U3oKggVZfCcSC{H*qh~p zD=VltkCf_Ldc-Pc@yB~bUc`SQ$fW^Npyp*kThezRx3>1%=*Ml~>Ue9~c~1BZ4?RJC z+ccyguvsyB%D5L^(qkB=hB*moex4I13=ew-v&lYYovz`^C>c7V?@iMK5=CE}8Yw;XtHZa1(4kZZo8_n6Q*V97l(KfJkK5mhfaDfJn3L^7Fmp zb04?+B*>E8)7^{PI_N*MxDYlv&rP92y=|?{!EcT77JQO{&O!Z-%$&^X~V-0wip95Sg}6%#ds9*WZj$K!WYuss zdfzQvA~sI4U*nk8te+E7pzazlFLr?9JNC#Y`4rUXWGRKKfBI_wd{?1}B$X*g|F028e4Dx6mYa+UWqbD-b1{X1riLX50^uw>AK=_a!|;t(i+IYqwNT=Sw2fq$SZMm z&(Po(@KC_Kr>ADfFAGHvgIf{2I#NJdnDi6ccKMCOSEsrTtkC)9=z?4WaU_)tB* zQ*P%#WdLxs1BkvXphb>4gn$|r&}4Uhdf0aO9ryqlrQ#VGfQ$_BjC^X0eB)6?$R)P$ z#F=A@-N{dqoVngE8Y^!EeJ@wtdN1@>4fIxN8DCX83v%m?;6gb#$(Fpt#%-cU`1_8{ z>Q&B$;DF+U6Nz6fvE#(n;LjNZ?X|GTUWRdyvJGy)V-y<5 zk_fl36FW^G=6D*3eg(#@o;wFpHDih|uD%BGl5sT<=%r{_SexVa?HC{Yb=byov{Glm zR~35unv{s_TK4SzUzE!h(!*s3ndCFsLAZSV_rYcR*xOW#Dh7iJJ_LAMmyxAy9AC8MjzP5MP8l^uP=Y}NDuDd7a>20IXoh)-{_4rKVf zufHdDX%R}WG+OQ zFzAA|IS&xv8&(5hF)j%`y-1Dr+3J*a3;vqWo z4NM9yFA3GNjoaVmjq-kt@7DQ^R#e;|S@cKT-U$4XSKUInGsG?zEAAa7J3j-3G&zKY zz|)-Wl9Uc;PUp!Y3<<(abLL|g!A`%d$apu2u(YD@n8UPX_ybe7k&2}oP5v)Ej;Cee zY^&kI=kT$u)DK{B<~7@*S2p*^RjZLtkVGE0k!pguV(K%wV>FZ>YnS}jSMZECUbZh} zaC@I)oI*uZ`uBy3w{g9?k2=J9>e;L4HfPGXJ>-+~dUy8S-EBb;#-}V=x8gRsmcBl& z%uM*tQ6bti{Ce8UgL?g$9rvQC{Q)y@NTD*QZw7ZrnHPW1l{c0J9a+l-u+YA|xEv^A zc0RitEMoTaX>EaQbLl3n*5#oU`%8uLGnP;MRc3GYbV!e#nC&nmb0bkdgWCU|aAl8t zofoSN{Dm>fDww8d!L{|0Xh@49u@Fozhprg}1+cz!R9WR1Ayi`F;G|d3;OZq;bO!gQ zPy<8FE^^GcT8NK>Nm#@eW-OzM%q$~{l*!=lxKymU!p603bu1%#q0vWLxbj4r&RpSj zk^UN&mGU+F!>s?E@P@LuAE!zj)vuw}W3!nGLj3%TiKDF?K0f98wBbx@2+ z2K=zHt^Z~6aTc&pgl7zzq2*Jm_n^(r&;vIi5bQ@~C68`mK|XXDP!+n20cNN1GKO?L zd60nkqlxEz$HBS(^zlu>&`=w* zP@OP${hA_=iBwf{&)@y$sU}`O-3Ic{uk)ZWws(d81dIO%J}wGhYKa>8iq?0ev&p4K zBnA}u9aQ-SG)Wd0K9~Dh%7wbaiqIxuvOO}jNVFR6l76aOD5`4y-q!5Bt-`bjA&}~2 z64pI354o91FhNq-Q{%vYI*37o?@e!wpDb82b`oHuh;Bt$Gai<}KpfrQNKmWJ$!ZCb zPhAsy*$~Pv|HZU7D}dHRl?{}81V4ch7>Ji^8|%gweRs6{Wg>+d+U%`VZ&rDm`~qSK z;n_aUuT*a*G?@%KxU{FSMkWan&c;}si4@ww2&uEP{!Fi}MQ&{cjgQA8-oHoZ{)nYm zOzYJ~YEn(uQxG@C%UowB5XT%&LW8Bv*()DEj)Bwb#)(?j#7l+%has+dcdTp{|hna`PHLIwBK_kC|{scU(2`!9Q$BL~~2-&c?(ROtZTggh2yH>dcL zQuBA^pXc=7@QMI6>}lI?ZvA~8W|~^8g9T)6g_?da8%k|$wJ{B1$^@XvJpY@z`N;Dq zsE)~TKR2)g!aah{qn#-kVfH^<`_bS6k)}b}YRD+q3;fDb^jELhQ@6eeY)o9q6~tqY z8bKj*AueIJ#6~4>(oWAGqjsN#apaz1iKH^uE+%xyk>w=l9V zQ+%h(6RUVXE&VFG^ViGxmsDVfWLGJC%S)MZX*N$d!6i$WJ^srV(`X+J2{MgiC{wZO z{wTy(s}}|bffx{LWrt3(`l^)f75HvdU`!?}qrsI=(%ltI?Y`wUt`f3IiIfC0JJIjS z@_Kjrw{Pkf*d_PfzU`p!08T?fKK*;4dYk#zH)M>Q()(}srTZ^*`FDO*^0xnH6i;kl z?)J5cQuM)@#U%jv;=-d0)dHDR$;Qn@du0=@IaB)unp|SP{3zNlNJ3=JOtyEB6h6bb z`Hme}^r@7SOi`3rmAoX)T##V~S2uOs{-ger&=V4$K2IG$bQY)ZZyDny!1h6&##`-kQp7|!G? zEkoUMj3FG#@QECEtJxAqmifDn5GG6X2yS@t7I9vNS}+L?IV}BIxR)B1E)a5rIedog z>ewE%n-gMG%_Mt{dh&nbI=$20B`)Y^f_>eX(%!p4!dDh=+0SZrUO!2v-G4|sO__L^ zewOwSz|0*Wt#cnxc7CU|b5r;Zmb-yNlu!LWU+79&pdWJE4kd4AgwVr^7cdo57cd1; zJ9yDl)pS*i)JoYy5nf3I43fEw)UA>lo)?!sIcArB^vV`W)iyFsl3uIsD>M6zZkPU! ztN7~V{NyFj_zW)^!9L+bp|C!?e%`5^)by@bxYLN9uR}#|lU|fEj%hGhdJ$51y-M?< zj2iuhCFi6o>%kSvCanucXhxA4_><)thf+A=A2_)aA=M*wuCvi((YYDvDnF1D?A2qe z)Z?$w6uqk2UaSuLI0I=H}!5>uO?NfPsYA$ydp z!>U67RC+C{vrwddhVDesZzne{=kc&P=%P199r?-BAHBNsAFD~=PLqE->eKf)f`Vnd zUwVwIfQxEqD6{TDtFo#B=I>8_kJBoMa_kL!p&6#+ng0E93`S5o1`O`*sS1G60E~Y3 zC`P+jg0|x^ga|%FqGw{Ol#PeLBhlCzw<1XzbA^ExDt#fXMsJo$o)GVTf2u9X7+gKa z9W3#4bEu)@V|Z2ejWd;lAX7}&^=?@#z~|p_n$3$KB8xd#h7}C4^)JoNRl9k2`z_OU z2j_>99y;Q#P+dkpY=M7&6eJ%mY|eHy^ZVIuB*UVDE=g>$u?tn08S{51x?DH$ngKTxWJmwr)C65dF;C4L{O@)^9B(b8IR-3uF?i8S5XU8TKJe#>2QyBYb|vawoHuvfcn}gc&o0Hp_rP~G z)e9}{@ct8``BQHI$)2#STbbE%FC05mNZLqR4`FHwL%)m+qn9dV2CWq`x5|4)hB1p{ zX|;k=KFHD&9nW*VJ$C2Od<%_l)dKz3BgKt0C!v)56-qLSl?IUI+S(wRqq7KGry?k9 z8a_(+eyi?j!W`ZXJ5`2~hh$>mC(RNHXe_77p&f#qFgSe|#xi-|5+E z);KoHD?NDcC6^HMxEdc}CL1ijj?HP&z87H?(k-^vcMHNEUM z{||HpFyg(E)7AwIg`1tyqVlSoa2Pf)bqZYgO74c>GDy z>ty{#N;R~nCq9(|87fMZ@zoV46H`_$gy+?!I{GC2?PA{*cR>)gyv51{yn>A+%^apq z{FS|ju7oJtK+ov)r1}Sky;|PP{>w+^NJWX6pQ@@n?+V(vnS3MsUD_is{^L50Kx|11 zv|j>E*iC}GbZ=3sR&}c)h21uYE#GhpT}kVQIJQ>?mMd9V_S0)~u_-Br8JP@yf0pTW z{`?10=U!y+^9iKFlGBh!F!nDz>22VeA$Y*Wja}L-{iTlqfJ$ar>W8VUN)(ajN}+IF{2LuXUQF9uK~%l_>WEsq?g?Y6RagDy zbFBG=&0-tr-j>qIttZa)p|+%sxHaqO`lD@uyrH=pnS`Ogfxxc2GndnDV`BOh2noI? zEdlncgotg^_7iiDEjI{NzAjYeNV4}Syae5fSnD^s6}gr^h85`XT%t>Z6-;RRaxg#O zskGoD)!*%O!$?~uIuhOLA%MQosmbmBC{Nnhd@ zE)hc8pw&atznqesba7p}lFx5n5gv$VhFG6LP)*z2XaC8gRo>Wq%~r7$T~Ne^N0wV_ zFyctm@@(x7caDqQ;LmkN%Y?)tGcT$y6+C5cxV5Sm3P&6jE7l^tnh0`Dh+6|pJRbrN z@Nd0;18?D;xVFT%GhS#TY38r#s94JNol7VV&Cp(jqH#Z=>)c{;QEMr>1O}?S4nPOT z2BNM2bdm@R`~Y;^ksEAg_9<$#4s(qcFYhyNW!_)YQ|DS2*CD6bdSPFoe&EMC_)#0d!AN~f zi$AP`nfe~gbT%Z#$0flxIP-TWzzGuj0< zNg9bChJBw4j5igwf3W`ZPzMu1=HuDLNYK>4gqmvhgatfu1w2Ff{3BjqR_FvHRHGHK z#3KR9J^3JtJk3LxNj0Xo#7pF<83?N}!eiiUP}PcAgN!|sVAh?}7|8Dpbhz;AdZ_ri z38uOge9@bK1xr`BSfliQvqm}lQ}&Zh0p?Q<8u`=?VO^ysteF&hK+OHNC68JAXgx@Q z-@mOVK$I6XZr2d{5~QT1MOawy12sofnV9%|pzju&P`8v?n^m$htqWW*k!v8(4)BC0 ze3aDrq75}m{?q|=(34X}lcM|kU@pa&iwa9rLyXix>S#XZnlqf2_AL|XyYSQE_1a7L zHbh~ZLetRoe>U}(li6!%Q9aKp{Dk5+^`(I;zbAnLZ)0BBJGyFSA5pg*p$vY1KPfcA zm2B_?)BbCweXZlf=yhjb6bycZ;50c$Y02^5cnN2S9gbN1R?u+6wP)GR9Wcd6c*f-9#&UY zhG#={OX{aJMZw?a%m*WCR@A&vM^5>Qi&no#g%D>E5b&`utAbL-BYVpl^=V26Y^2## zbH-5%*KM}IHTqLSvsQKaOExlfycG06!z7@-GIp<+Lv3akxFK`OhPQCs;?p-&K)s>H zQ4Mj|VLkDb-L$Kl{_SDo;k4y+(ZbK(WcgTjgsx-4#pIUo-yDqTms~A#?JtgTHDNrclU1l|?(lErR z;oWkW9A#G9f$yZ0nHi@mUBB5B+qsPLSD=yO*-#Z7<#)W zG=q*laEc3)h{hf|p^nVgJTF;(wpzW&naEY&48Un_9NE$ZH6PX@D(aB}{){zQ+vO-x zvmwf}P6!K149)?XE!fYHvd%wp!$cuH$-0^YPena6 zJgQpsYW0T_0yjb;26mD@K)!dA|5+L8^g{mNbM`%7?7bDK8jtidSw^PX`o?elYfhJ&`;I z3*(K*S`(4Wc2P87J+l*L#EaM|EmXvP#)~q{q;faD6>Oy^jQd?GZao{Yh7h&=Oq2xx z5?y@Ajmj(6d!f2(!~ARHLwWT;Y0Lia>)?4-ziuSzm5w`sn4?|y-nz*uIR)r`42YVR zrcR$$piv|f1DYg3R`wvXrL2eS2clJ;YZ}^9%ogNB=5|VwLi$R|#Y#9R>FnEUFU!ogT66BaX5XuB zRJTlRwegRTtO~8!ymo7hYX!3AD9Xz}ri0Dz#XY8Dm03AdYmi`BOS@npotrXf0m@C0 z6|r%RWax<&8Krz8V%#L!FBw5Hb4S;Ucp+0F`Q1rfL zlSutF(tUT>%*)}1TcaIfQvM?LTQke^Z2Dcww1uexpPw?8VYLe>iuP_OZ zUectC+-{xP&on`;OzkotODiMqXgs5h*WtQd_Fwek5&ctIPVw}NU$6#cY0#8fGc-ET zSSnx)ZXG{gZr~jh9iFDZQ{(XO2YOE_fIxd@y;GYk{qL{3ie+Vj>(`NzwUd3!QE}o= zoW!akcb8&ZtRgxhVhYqeFgCiuz}4UJs3ErIh+iW&ln_2N6$Wxx?T@@KOAgQxybQC;4JIX~jEUf}W~}QXT}HNF^x`@D9g25H|0JIfg`18Wa>(;?_$_gPaFC4&3JIu>B`;#ia|JyI>oGrV32z z0*ou0f5J@qov0q!n)itO|Kd}=4i_1niMMCi4g^jC1r%O*)L)Aj^5nS4Vuj8*XE#~m zM21O_tZ;o^e-K^XeK+mn&-Fst@VwvirOoy26j*mnMr;E3_|I7xn#2e4iH8yEH(&;(RBxnjcU7kUrj?)zlkL!lD!*Vw!G#3% z)To}n+*%%UMRxfZ#z{?_H3E@bN3hBeEq$TdVu`gsQae!F-UF;_F-6|B(*n%?`dsld?L*`=O;9OaXe-P<<39~`+-A>nO{Py}kE&vKk?IrGH+=unp zC*uBv$bL;_t~sYnMJi<_5L)IY+_mMBuOSgK3Rh@^xH3U2TspEB5O1G` z@LXH8>?NSBBHX7XbcU_5RS#wSx~x8+d0Y=w->xqj0y!mr9%?L2v~JjfR1E#1AFelW zHq@&a5`iNjB#RA-*eIgK8)c0QdEl)hSQtxP+5f#1gs)^{bkJhMy~EmU58Ux+wgEz$ zCtQ2M@H?f`h_pL=&2~UqHo%83s6(8@2^pb|ML19NA0o#}>0r?bikpNZsSqQBZEeTM zPYTj{U&alKWHDu2r0Nd9!U^!F_UUlINX51tkhBZTc}!EB`|n#b7R7Ol5HK7JJcMx9 zgMoB*+~BFP0+}dKj1H9aGk{?EPG0Di+3h%`)$J(daGph@xg^O_Pl`iDN6_2d#q9*2 zTvQ0j+s$Q)Z`sMHE|TevyVT2OZq#h-XBuei>{qa$d!pAJZX&A%s6AZz4t_Av8?KLg zGSVAPe!sR*#adf5PMaGwxh_44AtP^^1v>sw>hF6&aMV zSf99|FEPF^&XTyGxS*osI+PqG5Uza$Osuh_Z(()&?LQ#a8^kY{-c8L%kX`^m=0Vci z511l0%Rsck=3HEX7<}v|;_8+P4KzhF=$rNA3xgd6cB5{J`*U_?;R3 zI}$iqkPO_`H3JX2qZRSup3%j7X2pE*fTun6Xw{8vQWY1N>>mb$YkbbvGafDsk2;Lp z_JFutm3zL&&0(y|^PP+BO4*I&ro=8mTxhsSxRjjkpWZaX|o4MsJ&HP30#mCtWNNN84 zF?}T!BV|BWyy0rA~SdpGO1f|CbZw&S4RNHJvaTpJ7 zi2I|Mdj2IBdwUdq6jsOU>-={m^;j+b*k7xJP#Z2bZj=oh1j$}(Lr;hxf*17Mqc`e{ zda*yNynz_*`K~{)UKK5gQzpzb8UjdM24Zko_3-uTnYo;_E#_$llhq@+)|de)iifFV z`CxN^KHi6BJ_s6>d*jwxs8E}MPSC-P%jNE!gXiN*OZ`B%`h#mS4P@~^DVvIpJZ^a+ z)|M+rzpJr?2Vu5m z1oxAYKJ$HGqv!dhDv>&j&XqwA!ws1UOtih=fpI)YFBlNk9ee`7tIA=LG2$T~(}v0+FRy{1ppMy8I`1~jW?3nafwm8gU<=V0;*QP{f+%^kUw zEgVgC&6dpuCaji9x2r_`2F@MVQy(98CW+h$VQ8oqnWOdLAIRn|(2{7Mta# zmSFWg+yMbXuBz3^U>6+8G8$g45~D8QpomSfYr6KBxe8a<6M~-FSYT~gdT*fxVcjn~ zC3z&dQqB)%I@~A&*;csGUc+=VwbU7iwTu~?dU|Ao+j-pOmf2$TF+M&6wav^{L9=D|n{&FiJ-0DGwq3Z0pj0eT+b3O=_F1Ofn4v5fVi75!TC) z81h`|2t97}xmA0VdLV$;ST8}@#r-bXdTMqfdcX1K8vnWlo&@9ZY)t>N_{$J<)AP0) zpCWcmatZ?!zMJ@H4SIE(~Wa7k_BLV7y z9c1Jza!K)i`v^6^-1;P1cXS0_7h*B?vZ_B3==dJ^g84%6sw|U-}n{z6=1eH5tq?bxV`VMHy$q>olic8ApFs zB2xTm?=>vazt#@&a5K4ePLw;i#?b~jbl%no>4jMWl*24oxlub_M^+vu94@w7o!a6q zI-Y1c9_9t(|FUNbb0K<6S830CgtOU`h@ zbo6{4%-La%gQTl$K#YG+#Cs^&cJZYsv>AZT_Rvn%SwwZ#_5Q-0+03ZUhcmQ`oz<9!Q!pD5c8WN?F$Fz)>!nWD7k8 zP@X-B@r+OPpYi{fYP5tASOHQEFF%8{{8RCagv%cCXvV;ZnA8tZQKVLODl&}*2(+@Fa%G_KXOtlZ7{T~|z0|Rxq7!Pz1`6 zfqKUPFi0^-c}amK1?ojI6snanF}G!E`yb6%AlrjRfA|1)G^#jzo zA1H#ye_Vj?!CIp=Q3|0lm`tSF8bFqhVBLyB#oC_fio`AKiotYMw$lek60jRZoXi11A12~tHSJ3Gp~U;8ujDdjrqGyYw}c)}66!|! zpw=lc>Yh}aEk6@fL)_us_*Y=6p*Kg-O@@h^Wzo@xii`W>N% zCZiEgSD9&XY()pD7vW0*Q2x4?A8NA|Nb!XY>@jIg#%>-Ta*7?FbhmzH^Q>$HaHJCM z9A!I-c%Ly-z8sSK{hL^U4N+$zE_U7vY>6q=*LoV55C0Ffw4S?3ro;B`imH^sfT_n0 zWU9q5&%C0ECp+JX^9boJCzmOKH6GkAcvK98&p`3<*J9zg$JW@)sJHfC&o)=XqiL5u zI`k$?``^gw`F1o^iN2s?(SEase?oI*)Hjw1F$%IzA#X4sIKIoY`dgtMMqfmzOux1@ zB?eRSD3*mTh5rT4WyA=OBOH$b*ztmX(F9L<&@|W}#7gDJ$9d-hk}zZ76CWz1>y8kK z8^DAxt(77|4EW<11NN+<`Ldl6kbShb7FrqivHGy4`CL)9RG5n;v$YI`N(d{fpOa5>&Cxd{5`Cw8^lqAN9&&sPTYoOkKz@bs@;XGPTZOc=C_3=c^e1^ z8JNKGbCk%qU41D)BOM0`BaI(lTgo(GMN_`UPSCa41j`>e*%2;O0`^NItulxKOxAQe zh*p${Kq0)PSS`p|zW{LuHD(XhNDxkU50$fOn83^^jV1nv8nx^Xi7%wr$*8+G_>2UM zTFh$2TKRfEBz|ZFa;LyIFe7DZqrw*Ye&B<3>5tTyyTIzqYUPVXG6h}gbPs7oItiF0 z_W1HY3AnMf!@BOxYh~D_*}@PTT(}&{Qm6tQG2B}#3RM~-VYh9GIefraXNu7fgr{2P zi1dxMNWU?fF!p2pNa_^5p=7liWv|05@fL}37CZ=}A_PX}F%Pl@Tf@JO;t}iRc2Qf} zkwX=Chz&>wIR}Yl7-zM*7H5cwcYvkWfBMyQa{H*~$}`iqmN+u?`ni3=(mEg@rU7|;ZJA36+x4J)J+-iZ;` z#l>Xi%J=rFvJrFKO;s*VLCC2bz1@@A#LjvjZhF-qBrVc-64{m4A$?`K>L0YS1&IWD_XWof2?3l+RTa zkjr1G#-)nEFkDP>^68*b1~~OA^$*ezivqg?QyT-H*r8zY3cJs~#caU+cO?Y#Mvy`V zd?(@#$Qo60cJq9YQl8~s#$o5fUK-@0yn4H1!F15qsUzZfop!ya9d?n|_78CGcc=Yw zSds==xS9N(9Y!%(2xG5v-Dy(y28^uI z!r$tsz&?niQKsU-Y-dHoJaGq4_ zzA@jgn2c>!>d+`#qS}hkHxfy!e6MVpxrM(#+kjw%S0S0%nlZkT#?~5##FeL+n=3L7 z@O))ri)`ZL*yY5+e5nKyqiprU!!mBGaUcw@hVE~FQ(@?c!*$x8%m7~8g2_Wm5)gP{rhJRybsUdh#!`3mfy7>!V& z7}^Zxa?JvLe-8+JW;8;eo^4?cq7SpsT!vd25olYCfbCdWGI4OKR^B-`TFbjOjF4{g z$XjlapOhDjJLRYa1#j8${;Wka{i@V3hzx2N9v4vt@RA|{iRa4r!D_OHyk&nJ)QT4J z4J1-b5M)YBppgiS3l0$OImU&&cR8ecLcAk0g?sHZD z(IYk!ZeKe@IEjUOc(A9yDVE4W6Z~16(Ig)Be)f=H6u7e2W&}5Y)B;arb?s}EJnVb~ zl-p~jOWAQD{W7#Wq&1Y#pHvwyB^N6hYvh$E(n5~pB8a-@fMkbi&@GD)jt@6Dy>L(MSz4F4Ei!TRuM%ezYq%pzpMWWpJ>p(tyC%S zcSl7Kfx>W*k-3ruIKI*jBpv5~p*JwYbu@Y{Kup{mxPgCx;WvPhX#^grE1>oSJE}}N5mD~A^~es`?IHDe#_eqZl_RoWwqkrk;ZW4*FXPBU;P1;U zXHYhwja*!8(R9B@e_pF^7{%V7d#{o@_8wYsloEy3H1l=4muP_r^Z6Y8};RR z!yE0P^9IxJe*IhX+v|h#8!{E-<+lC7c|-VOo586gq}B9W3=gJWDqIvy#(+_Tfd>Qj z-5Q9@p!^wx`Jw(DhhXd{He?iO>tof%wrm6f}Z7ULX3*kZ_i>*`*U4-YknEOPDG6Flxn5-le+7%E4%`E6femoL? zBNz9Xoys2=L)rKZIl-a_=3BJedZ71~*QIMznom~@{2uKCaLs*u;oPIGNye?Yu&%jx z#B!K?sQv3h#WH!c5^Ownmda^7X3m<_W5yap*@<$srEKj1w&jR@4hlHT!QUzDh;y^XB;@eb!KBbJxT)MAy(++E%Wb z`O6$2DPyC&3&}SNEC8)nl}<;6e{GyMxYHYOwlIkW?(mDXe{}86tj>jku|yCkq#pk8 zq<1Wb?d?%o`pF+WB!4bCBTe{QZW~|jSmc{0$uQ%8hfhx`a=M3k%HgqTHUeoY!!}6< zWm}AzF4#XkpK^>)Hy#ko9|)i7TdpahTIX^f6FsvQt9LAhN!mR3i#1mgJ(rE%_&WZn zdGf(>veVJ&xz88$f)wrytavMq%yMr!+jk4tizA1SJ8N`>BE1NG7k?K39r8Bks+J}{eN!H zPPdis&QF7GA$!KR$zP{m3Efh@LJ}vgG3|fcb)0LEXo!|@|2$$#QCC#0MW11r)n$d= z5{(kGrf{*6GNsV)8ZZY&rzj9}q;RS;oB!16ar+URp@HIBf;&HAUFI<|b(&nT#w69L z849vmWr7ynWpXod9lN0Xxjg%0Q2A)mQF;B3c5aVWi&nZNd|abn=0|vp##XZh9GUEH zEl9NI(@DQb@qDD0)^3eVT=t(Dld(Xi-5Qf2%0)&ing;!$LR#p!B*3unOcL-(9k$Y^ z+7lnw%gDWF$vLWb%|-0WoZdXn5q6Hk)1(iqB(*lDL!s0 zJ#JdGK^WRD=|rMAw&1Q55pgLIalg=~L!_AFAzO6a!Dt0|!FcSDf@ZuVZk= zbs1cCzB)>WkKG}_cY^Qf`XGVuNM7le6A5M#=tzquU;1=MX2yncJ(Ildxz!=EFu=@qLvB}r0m#rH2gsVgCr|p$*&QbJ zVtp8GSR=?1M<2YyKA%Ku8vBb$tn7RDjnlQ~(PA=v(v)t-NEy-b4N86mB-f|M_J@`r_a`+n4WrFE4m>7 zM;JA#`{zn@Wjx-`V5;Aa_@NrO13Bn~4<0r3olzmL zqGM-gW;WlWBP`%PWS|3foNp1~!C!@@t@w5d6hc-U9Gb<1qf}*NO<92XlBe4J%jJ!V zQ91^GYlRwq<_wU7T3*NG^<9p~kGNz`LYu-nQ74{RSW!8GsX?}@K58|&uD zZogmqgIY)4i@;qj*@h}5>6F9Mo$1BVz}Ym8NOp$I%`vx7^2#C4G1qpD`N+Y54_$c5 zCw#Icx@Ty7$LE<-!u&N3`P?wJ?#qf78Mn!Y{BO1X(f9pgDjHsslxUocebo21ADeRt zh`03NQV*J@f>M{2CDoy&KW2c~!sWm(AYKQe;;|pM9^kJ+UJp z5MK284IO`_a6C<`t?h)~y;4+gwd$>H^hbid{E5h4#oJQ*+l}LqBA(ifvH$vu@wYZ1 zdCNTVkgojt@BGnm;JliUqj;nlr9-ze8O1!bwujYk}P{RH9<6i~qHo{u!RHBjF zOrq(ve(vJmk=EqQ1$7W_iV$3TmcpV-Zy_}4A@@Brfd(Tu8Jd?P!Sy2b(`w+I59S~1+Ej6S-aMoxNrdG@qtenn zBf##Xm|cZcoZ)z>vlgnu68^mOty8}ZUqq!N{E8BJq+2f!cPlc0)(d2 zNOLxVej$08np||t4qWdf49cR|_;9(Cu9IVtaX= z6MM5pne^B1t24!4v^||RDg(x#+;K97EVW|}7(=EPaa7pqft$tlD6p03^mLMeE;)W7 zZv(8Vh^i(Xu*;11k#E{PuP5(Q@Cm*d zSC;iA8q2OxGKTVdfVKgH1mOEm~Y11w?5Ttf-4 zFq3FUTcXrV%r?av z*Bc~M(!D+8nfwdWRoYMhn9NO>ixkz27N=K>FC@c)vQGHp*y#*aWa}wb>#z&SPCspE zo&GJu_8|(=^p;1_lD#xkB}_OgtGT5)T$O}gVU}Y`q>yuWL>>7g2wO7#zB1I zWqc;UkTZM1418SbkJ|Kex!R^uQbqXv{ra27%&U+c8P@xs4c8W(xp~&2&vJ3!W?HU3 z|MB~}xA5j=i`+qeIM^P+C1R4^n-s%)3r;5HCgVJ>H=n;4(4c!~Jcg{v{N8~cURDg% zmJ3st2~JfI#Yqt9LIuN7_{^1i@CzYOE)AbxQrlAV%iRCC0P=v#!oZIA7`y$`5+>_w z=u!w?)9*~{V=ffgFy854Yz$u3BU*SH1pA6(y?sFqT*D9IE?C3IJT1l+0znv%*lUu4 zOn31va$NZlW=$ynzS6oqOM{0^LTsuL@3^GP9wOEL$hR2wt!M|hG)dMPzH4eX>`Mi^ zHictM|NVmE(E73BJT)U_jXOPuJJmYXV?;o!XM4gKP52|{9`63f{gIE^72z${!#1PR z5S~5SA)scD*3;Cdmgp@D6oe4kSyRTK+xA!=9N)rq9~=$QC)(z79~@)coF`h$UDQK- z_g&PoQc>LiBg3kI<7@C}d&j*Ir3=Lpxyr{RsjyGB^kMeDxdr9iZCws=?rdBRM|U~n zhs`;YdLi^-(@K~(EehrxDU;^Hc~I^=s8AkMrg;1yKPi8KckkC!#BB@fPp;ixn_%IM zyrxVe!mJinzF!$1=Iclx4om2m6oi-8@cx2XHgRdwA8Zsew6vo#@OK|OqK@e7^%WSL z83Rk);75_S_2dU@nF}ES6{UrG3Nl_rgi3Hvg~ zyjjCz5a1jK;1?sGYS}dUUTZ>gYC>{q!jJ}V2-UU%KAZ+XP$y~-s%j7>;$H(;te}Pi zc)tov&hrVXw^0n#WB9FlX@uKo1c&cyC`?dH7cqZ)pg}|fVfKcZjiK~-^M$vw_Mq?& z33nzUBD`I7<_1206qVw*Li5fwxxI7pxVqLAt|(i3qmR3eLcjio!slWwaAd>ZM++|C zbF}#U4UPxRk~rf~cxG0D6foDy%4TxnrCM2-TAdaO7*{2oTAGdgx5XYkiEi#^je8O) z?SVlb22jZ(NoJSU5Tm;>x3Z%gd&T$2wXJ>Nj{9y(bak7BoBJAs>dXAN2lnN~N0lSE zyd{$y9IJz^Xb0sS*b!<>trj0yeB{h$=gEyH;L9w4DLOaW5R8)5rDsz0Pw7$peqNbg zUVr?Cf}sbY7Au|dFVDk>lzYf};Lg84UgK~+@Al31UkyMTS8krVMZMQQVR4qq%cx0|8P_0j4JCe`Hl&hZ#|m6CE`4>U?jD#Zkug5o3@B{)D78oB7wC@X9ToTiKua2!kK+46(I`$4Vods&9{A@MimcN_gwFMvRWc zi5my2;RZg54gMz6P?PX)R)6T7mV}dn0WDk1u8B zIg7sf+1QW(w9NP<-%(3>z~)de^)4-h;Lz)j!0K(bJ=Z^(LxK4mR@PQvz|k;RoM}ac zP~+SMRgA0nGFcOHUcBUS^lj00`e1m<+mH2G1<<1cIM2a{-xI)N?FUKXZfTI;ZC;=d z+9hA2`g39C4JpSNrD)Wo&envFl>ozkpjtA;Xfl?YL=h;$s~}F=-VSu#^_C zl@{Rqh_Wk-v~x`PrN^;XOK-qNP(y3LPEcc1@#ROlEN@i5$WTz94_90!s@E9Rka>sN ziV+PmH%lhdu0$!Cmr?{hEZ`qzorr{5hhBTleN5|(2Xm%L@glU4!ywi#!CNaVG%Gu} zwS_V!xf7CAY&l2|bUFR<2D2pD^GR+128EKV-TFj35uApPv+)k9r8IvMl%OX{ zrPC=&MZy^}PTVmaR-~`PKtPh6Qt?c>;`iEk6-%a^0R#G&GbPeUCDIWkQf3r)`j{l} z3=?*xT$&00e6Tuc`QKBN6U|u3b)C}q1y$KW@Q#1tc|lK;zCLU>f1K_mO#XQjariYrZ97?a zj`*cdJBDhv1vO)7QZc%STzj^7dd)N~73)I#@AQ=>V6N%)2Ti1;YS`3RxSj&kP9^4W zreBW0pLG3&LkFHY1;r!#8}uE2>g01VnRy&<-5PGiwP4FXC$I)5EJYO6o|z4rgH=oy_^Plk1(&+;KT+f*x(xQLGA+JTMio52`m==k)RH z(o46r3DH#ln(-#`33Qs^gvxPOe!H_eja%B-!GB0XIHWlKWT<Os@v0 z{uYAxdSW+~GC2ENlf>a0g1HW-&6^5VPC)(w(cPcmdyjxJu7c6iRF3_$Jd*y!>R3=M zRMBZ-p%=e;p&U;~zMVjWn3a>0W-jqKhdHzmO2Z%A{TA&D{ZYTX4NdapSG>{sbDlt!R65J2HesW8==0Xo&D)+N!qcRL!RgJO?yFJx=Yxw%eqjDh{F}(( z0p$%=MbUy}AxvZ;%z0fhG%);r zBwtfOgHf}am9213ny!L-u#uq%N|k8t zCs~n*2~S+(D@5;Yl-qth;&28|d{r~L+%8X%z?M(AC&LP$2{gC$Ye|y?g>4CLxRPMz zjCbl$z+uGjMpR|mSo^sMfnu!)0ef}&ZR$t_E=PI`y@~&Tj z>yrx}FO}js){f_4PCYt0{{52KW5`hSpsya&ZQIXff);JUV|krvPN?5z z1JS7_(W#E8^-?YyIOh$l^NRKqrC$^oTxz$Ov$41n__O=xy&sy~$Hz^$aDuA*80WB4 zNEnNVIdU5g+(p~VvF$VcKU;G|Ng#@z^H1GLPTy``xbgjjC zCo}7BICZ0%#91UV8**67-}3T*oL!NH0A^|eICRlai%*IR0^6G4Iyc&y|LtBOWWyR# z?P%-|x0^-XAR`ir{=uZAM=Kk^!amU@6A}_WZiUmPkh|!H&gMWPEUX0d#6pNeW>-ZM+oL=($0j6}dj5v^)NEFV{0h`i(r$Mq(3z)UUX) zRu)rFF8}M6C6tVcOceR?PHnXM>NG?F4B3ClfV$V`06=YYB$J!H{@<_ACknV-d%ijT z?!S2Jjk~<~j*9V^992y`yZOTQLS-u^KEEPi;?@?k@JAAQQW%7rQySq`zut z*!v*`cULrsJff||`hBrT0-g34yH#o1ie7Uv7_jg4lIrIAC* zJB})S-q!S+b~DX(Tdp?a3)e-lg2rFlN?lq9Mf2k!Ue!!@mppKz^RFc-5m#yEOB^Vp z%oPO}L$w8GKtoHjAZ$aS_YOjcXn3K56rs#`mX?+kwn=(PdgJu9iOTIWE_@-D-14lp ziF%28V{}&vyuVF2ij(3qRT)70GxB4lN$K(oTsbNhk@Du;##{+1=53L+Zm8dRGgZui zDONHtaMSyPE>uGvy)^MqS?$V@Dd-0_y%xTrdcjyjKVJMdT-AKuTnR;t@hilik^R#? zL8W@+Mh&l-gIdqByVxbRQZqgQq5q(oc5e4G7 zy=ru!KfvgtR|?bZq;clT^^|euQZ_u42uq2JvC<%XT5FhOpHRblt=gjG+V?-z`)C(a z7o(+XaAVB4NV_G0L0;2FbnsvJaN#lpu?O6C%YMiauUZKNF9)TgQ)QwecPocM%h&>r zAn$l^MOf3(p1C+O(Viqcj3qhUG98#6;Y+??o;l3 zN-bz-BjgiPDCg^r+)X*MBjW%NX}nTIuLd8D-?Sz~^k14urRhqWv1k~SNKRwtZVKlVd= z)+Z0~nAKVIR-zDFt(QF3Hz1ni1Mi+Om9&<*aB7QDOLg&nXXrJXLEaySK`q zZOHVGu;s#@(l5|8TOnJahkw)SP})1t>?_oo*`}mhUUXE1akCOgUe@5l3XDgO9740V z{}CXzuo{g-N9hkD`d{rLp? zOI3^Eu#OUfd%L=Nyb0Cxx}ZU-N+v!Q_Yp6$=he4=Crkv;Bntw8TKRC;CGF^#RLb#K zL64#@CmTNBCvpLaQ~A!M{_58Eh+^2=u)cTm>OCUW!`;@+m9q~F2DP4?c$VoDOrFfllnLi`=JNtK^s2U>fJbF`L5J2mJmyeg+G&Kd z1jgcJT6K{GyO>Wf6czhvnmm?#8b3DQBnGDa7u*BJ7sU*@8VE8MNd=>aUNI|ob2jgr z5f^_XmT}+=ZZvy;){QL`MB|1eb%+u=MTBb3N zjof0sm&P%i4;F?U!=&Ohf`iJWNl+zKeqVSnzW>64|4I5CS;4zhDL7U{mVGE(ykNwV z**l)XBeQp_TAc5G3`@MjtKJ>_wAp+WK=rBPv&bd_KhEV=JW*0$QHfGiYG ziPHXfvz`-+y4R^_@f}KrfmM}g9(elIzCfnw`jtSE>53K1FB6|-+3MKI_CMXQlQkoy zVW6?I5E|>Swp6O2c+0RI7U0++i3;T8BkxRszAAW!VLFXaAF5;giOL?f>w-(ep-))) zj9A;OOh9=IQa8WRH@nd{e=xk7IQKs_KS*n3d~*p~dg{lNd&=V0{QEojLkDxgWnsW- z9XYouk6bcdxEfJgGF4SL8euh(K^9@wZ)H|TRx=+za$n2WistQphK6fd6qRQK?+R~J zvm>#Y?by_;<*cdoh3*Mg$1mu04z7CIm6GNfHKy;PCQ)g&gZYo7sPR5EV}mO2Wi9w4 zc1=)!yaH#QGjvx*sT%EIn_9;-?L~95|LTtj2S>@GF|3=7io>AHC z#J$5_xo`|I{Lxn#gRyF4&~ukT;-er+2sR47=QDEjF@g=z^vTw#vXHUR7waQ#<$@$} ziHSx39{>$O^1du2xMuO=nk8_A{F?ad4=;Sk0)r3EeQ+c+I0y{bSO%3|2Jijr8NBWM5gXc)&|+#AB5-|EGm-RQudUTemm zh_fgBK0|{`9qssdZ~&i8PU4HDMK);RL#-B#W;0p@0Z+U>bcDj_ipJ2BNU~l96ciBF z!yp!CfkA&TfNqZ)?KT@)^m;r}C~$9O1z${09|;Ml80JBNwEb;_22`ZKP9a{cc$6Q9 zhXuUl0YSC)Rbc_&F8_>b=OJGw4Gq43?i}Q#+yASD26SJg1wUVw-@|%d^Y`+f)oEM# z&-Tg}*YWAyTe$h?KJKUoD z0}JDYIqHQe>V+oehaw)tc07bF(Plh^jT5ZLLttVdtXHuX3*mLF#)4p?L9EKGM1xp~ zhM47O2;5RMgoS7bv$60&H|?od1e37{CJsa~9y^6-1mmKyXarN1RCmcbys4E;{!8(QOoiZKaFxo?5JdtS)h0!8v4u&At6b#`cjlmGA3Iy@^4Lk}2 zafCmJM|F7Y52BVve-KUnAe#LFw1}Sg18DaL(BTiD%O600Ab`gwv1!v`)279?NMX~0Q`)pp)j?_1;3O)m2DPZI8XRHMLM_tRw2;%|q}3AvX=CePXe zaxV+WJ})5sEQi#7h84V#Vhq7-nEk_O3p${8nV>MMu%cSS%-S4AW=7FHeE97*FRD%( z63F-Gg)Frv6~5KB@pIs9b7u=W2D>mYIfU`WNz835U`?|Dg+&d$(+G>-1|i~Ne^B_+ zK?HLVgsH$U#Sz;{GVz@h;=47_ww+XE-*OVsQUZ};9N|I?;e3=GFOUhtpANyB3cy2i zkJ3Np^i5AtfW>En(QSrKFhFI|VAG&r_ji7C5tGZ)7@i$P?^r+D`#V9`!mo>3>Gkt_ zCS7;ZGT)!K(r}>Ga@Ek_&cKm#;^%k1vlEwS3AjkVG*CNt>FfBHCL%{OJ~3x zqZxNCR@}GRaNq90Lx;dLI2>rO+tFaN;i1Wl`#K%&DwVjiv4LBQi?}&8h0lhE@kvh) zu0DBEH8kMUJsuAX%!fS;4g!M!u33Y)W)sn}HE`s*q&*7GUic6noIiv2WuXBZ$Kbn{ zL60Sz`F3S213uN_kN)wekUpC5FMs`SM?!-mfkDR_{+fpdZ9FuX$6r!UgN6zG#l2zt z`R%?+Xz*z>{^ZI-{PBg`_}1C$#|r6cMf97llNRZG`EpkmJ{}rkj}UyZyo@_r+jyYW z;jzVn7N@fk8ql`_(HOep3D!NckHUjQ61}lF`@^X}6he>Ji%tp|OeQp`)p)qRjyv=7 zxH&$4tZ=6Sihn+Dt6kgM=xI<-L0Hc|@}iH21-z{m7VvfT7MSwSsOP+BA07;R|J;Wl z-(&4LeDB=x-Ujs^^KI`ZzczYZ?|qT($M1K&Eid+^?dx2d^!?KFsdt%Qzx4Nd7eET%S>u%O<+no)@@`ol*sLF=YxJZ&%qD&c{Z{ymDgPlev|+d${xAQWbZ zcme#X!nZOt7oVcb10hP&bh+UaxuR~omWUg!Dx48FI3eOjHFPc2*1zsLc5lLNIO=4l zU?}W{jef>*As1{SYsdv+kuZl`FooPOhTJfO+|Y$Q(26u657dko>QIF$zZ~ zbhbktRJgGntZggk!KTDU(1Vqb7jvP&LHFw^)@?h8i7*K<@=34y$5Gtann3iht2T+sG zk0zfVjWUmYen>s?`N1{#{9wF(G}Pgt*N>C=@X&j*2ColNkGwuS_WIE1^`Xh@L$lY1 zRhXBdE7Rxkg7k|9JYEcXycqI$G3N1t3UMmX7ez}xFP0@% zd|r@M(VEW-vM#aV^FnIV=f$SaQ`3ge18&{t!J5RX&w~}>J!;wO!IIa5MXv`7UJqtG z9!yG1cswBE#O*#}%*K5M4M(c zxGl39Z`-z6jgu(MY8;?mgBCTTw5Y*I!U}09!9xeNT?e8OX&uyq!ocWQm_UzYnD9>Y zo2MWV^7TFw{%Q}*%RPi&?jiJY7h&>Z2chR>1fG`Q-z&hglY_I6f-N0`DHen};KHWU zf<==CQ_2ktuPmT@dK|4om7WH?Sd<3>**trfZ z&tr0X9SeFD)@(*>yY0{fJut)qu%sfeWfO1|QgD_saFw%g@8saw$-}doXUp{ZKsg6@ zImh;+ed#^UVj4m*4M#o+doBT6HV#WV3Uev~VgDv+McIb5@^uF@d-BAAq{MJV{;2%sMVFgz+}Nas~z|40v-xZG&tRO?DnG3caB95V06a(Q9`uslhxSZ&)TG67@;qmr1?kz9l*7P*44-fx$XwYw}t3Z|(kF;EG zamzyk3JWSKfx&-=2HCgX(}2Q*dV>P#e*95=uML;!tABSXLT1T%>iyuqcR{Km^XAQ_XV5Oj_26Mmx z&g2(h^b0VE^nL+439Vm%hH*mUcS0?qzisL#K;^Gc`UTWO;TLd#eurzI-*2+z6R;^- z^}8^~x=#Bs6{wi3+6BAPHJf+QuD2Zv_%Y@uK4#SK!-#0u?*kc<81(xvAkpvlL5luO zB)xtgx_v&hd%S29J@I(aD$(NcqFJKJ<3&ww4;p12yFDO}s%UU~Kpqm;={#_GP@5YM zT=jeCa)UIu+<4@2^6=>q9;y3p-( zp~vaMfYXIZw;R(QH)cF;%o4W?bE0{-3k#w}w+q~o+l6J(irWRUDq3^9P~pUy`_Q`E z2`T9|T3(e{aXYc%I%?VF#FA*y<;1kpiAjkGrxW9xAYfb&FeV5Xl^78OaKnOtlMD$0 zh6G0qb_@xJ1_e86Io!{NA;E?rhYiCLBMuwLC}YLAgR@}5Q88vWW7ulKpoJLgGGsA= z44MrX7LAw{$*izdu^Op2z=dQ6KJ%sR}Qv~R_NNsCumG-*MW%(`Qi%{s`f zSoGjltp+eQ16FMYR%cS(yJj~r>kbn(1T!`S3$y98;+^1E`v|<;WBf1o;D51;z>8h@ zpYK#W+ku}c!~d)d-+mEZ9vBoeuxFDnCnL~BeC&VBt9BFS^eT*Rt)YKu4jq%DXzcGf zD72_(JZ(sD(*9HcOAFm<%km;wTDa2kqrNUY85=^++!Th^7BQ*Z#Jo|%{&3pzIG_r7 zpo<1!Oh#Z%$6?JSVK1cNC}tR;ltndsJMC*Lq+rb_VaX+6$;M$y$6!oFU`T|Ziv^&G z_}J$t{7!6n9awkS*yk@<4OlR0*&lP0s!fb-tzu|(5xw)%=$INq>*ydJ_jludXB%$I z0t31>>HU!3hib1++Fu$D)LO1LG&tMVj`O{}xI8k7t2Bu~*>PVG z*#Gz+dAyb6*yl%!&yQB05A+XUtJ{MX!HE`|4NV3E8r5nvY;EEG@-iOJ&EVnK2=4Uv z;LFZ7eBRuMYY!jb>YZChLW9Fc63n1M503-}mH>EI@Tom~Bs8G=d*-7{IP=kEeDKjF zd~o?9-oJDa?_E5PpItbIch8+Y@@N7D3p9oS4SYzmB~T9o_E^F{y^A0I<4^FtzyBfr z{qMf_`k_G!^)#5lUs6v478>;9&vH0TI~&>4zgFct+p*Etl6VK5rSAPtb{_oK({Mwi`=c9RLs zYBe5hY~bF)0&Y!A;PZij-)U&Ti!UF!(<8q-})a7!4w7cAF z;9x44n@`Z>bU~`o>4MZ_rwil}5sqpQTp$l$;ep_S+gs7(IKEoqS+y!MWWRqfIN|Ca|md+JJ98DU_cNs$O>dClBtk(VA$cn zh{J(V(U`*lGVX9-(&50Y;K00SL2zJEv?Mq{mPIRq15&Gk1Dtd{U*_-QEkB;L<)1a{ zaA3yaz_i4a!+|Ngotd=TK_*1wc00!Gb_~l5+3k=UwA(Rgw;eHHx8aZ#1NKAxb}LR~ zv!c&tLBGs^%>ptg8nT%&e87ZZn+YStS}|-fqR(VNpHW}8exn}!MjbO?)M3D&!=OQn zA%hmfq7j3Z4I(^d(147KW(;baWLmF=+*Flyw9ky3L5l{zSh5(fY&BrnW@J`uCQxlpUnacceX$4c^IdqJ?HqbqhKKBz825e&%w7?$ z-2$9DdDx2?SaT_uQc>t)L8yWrY`E;~!=^P#jBKo+XMP$_#)k2zulo-sG>``d^!jms z51x#Vpl5ytL+i_!P;Ft(sKp9>+u{+R40@rV9sr3jjHwt*nFP#P3IHewNLNMM2<>Oi zBw$L%*?SGiDD;U4w6PF0kpNU79~6EMHoZ=)yX;tTSg>R@V&0@r3ExjPvYUoFz)tt+>E6q?NsE2HT3D*N{XJ+I8%F2sB>GksFtW9V3C%WUjT$Uk4eZ}Q3b5DR4s3d;NONM#=X!1Q{x?&9 zp;)b;tX4Skb+kVfuiIV$3at11q<9Fxe+H~*mlW>nZUNkyTfnP1 zu;xB$)$KsNR@@HAExR4ymfQ}IMYjVBZU^Sw0%jQ}X5CKAh^F06Ow%{EuVKpN1UKoT zZ+wLV6HWo+P64AXCx%3WE+@DFmlH=gofr`HJDrdkbUHu=oDTGhxK^im<*Vs{+T zYIZME9)z-q%oQ3Lf(m3eHnfur859L>-~nyogpSgdHZ+R$dTpA8!%w1pb(%-udPj|MVCakPKzE!gI--lpH7W_(V$L^ zA zoQZl%=vc2q>Up?mF)&n{zTN#-QZSula`kEKP(sk0} zm6q>!wWD#c4{eiU=vkb_@a8He)Z6R^F0;_Uf$e|?s)!%jcnJDr1P1CQkcq>TO;knO z2<@k*P=!K*co^zv5UNN3%8-v8bJOQye~hgNHZ0l9m^bU$4{(Zpp_E(f54gd#CG;)N zqkDcD?b8!z9Uo!e4mI@m;9gfdZarzi&8A2A?BRWUeD~IoqLyDjZ>9HvmgOM;-;Y}P zzSZ`ZzMqE!wOZ+Yf3K+-XJ}@F!9iRepTNiS3;1kxolU1mvm)G~F$(MsG*GHd-RH!x zpp~B2VHk*G3*jBOev<>gg&hX-HJ_gtS+N z56|MqXWl>3qk*PXAQUB8ZZ@7%?i#wJ|o=wwrB z-k6@oo#kab*xJNnjRvhIBiijYbU2;prf*C9e)I=}7zl+}?}9;ErgdH~`e+}U4IMN^ zqgsuojSW0pT*RHpN!%D5#I?>&Txo7TRxnm8qU7sdRftvFE-k=l`837gN&Cu=D=$u^ zudAI`J?rG3ankunw@HJ6?_W5NA6&R_K)UU}Lxbb9C%n!*k%k3)xt^b|{P$b_^QPBd zv^3*hcPAbX4dBV-7`hf_FtE0aQN;%6-=JCgX2NR3vcrNErwyx48`fNQ_HP!22ybG| z<-pst>aydl6R(-Bn^1VNNsnxJ94u6zV!0M2ZSxS?w?bNISC$3Pew@lHK;spl^*N#Q zIiaQH*X0qQtwG}vz^Um=5jsbAb=z(Sdqk5S(4Iqg`L zSaI5MTFXv5$dc3cS{9u)EIRE67Mym>bAlanf*mt5(}Eop4onL*IP91{!IZ;}$tors zc91a#b>9}dcRL&yayT$Z-)z^RpY3Bm(v6$Cbq_jh?B7i)be~vltmti_0=Nn)jOD0c z<^?phys)On3Ll9YELM<*CwO47Lhe3|S0$nWu4()#sXG=cPIB99fz%zd1#)-I7I62> z7TlM3V7A~GlbMZ^)nGD1>XFF|^4MfXqsfdWiDr`-q{U=LtI3QfqBfHmZALS?O=gT( z%owwnF>WzqLNsYHgG^b>m=?`i%s9$~Im@AWiwV^%SWKuzzCSyj*@QXKtl0!^#%uza zHk&YIHeuXk!m!DNp<|2~G#wf+8A19b`b_jK|Dj%!5mG%SBe-s(0a9H?18V6u>LJ%- z)Z++)4m}cGIt|)2suOi+R5(JdLZ@1VF0~5XY886aN~Tw>M4wuTe$jwhi9v}WwGy0k zJ?+=8Rvgn;WgXvdM750rY6V7X7*i`CHBMhRYZRC`pu~hmiAkcRV58zNWKd(80tUUN zf&vAj_5juPRHMG**ek)lTY`P3$k=uYuLX0sG=b#!U1dtec1GSuJoYu z=g>Jfjkc+A_H9t(&;T0xdT_tH1Gn3s;ER?feE#SmuHC=Oy4+v7dE>}^K5Ymfzi;x_ z(vU#DTq`W#>!tVoz2+92>FmOVfgxO;n5u*ZYa6(!P_nTM?wYN5U>DdJ22CDc<#7ZW z*e4LIOrH}7qRa0`x1XkZ@nPIc1GqRb>ab(fV#c6Bhklh3-5cxZSYANO^b{VC4B=j1 zH*U4J;q#`)xW;-Le0eN1pz}Ny7&t1u4CpZhejOAToVofD&Ro5M53YQK_b*?@&&6H_ zKRx#$ethNw{P6wvj)Vr(vw*^aAG5IFr})7?{J8Q+f*2V5+uwW#^1%;}&6pq!4R~m3aDqnV8D+7pO1CJq`;uZ zZbz5Ngm$eKE!*38yt;}9v$ME8HijGh{rIH49UsZ2S)}5q-fO9+7?bWJFT|w9^_wiq zk1Guc+6k=aJ#(?5Bq!3G&YQmnJM%vEnskC6{E^6 zOzG5^HR{+OsEal;mK;_r3$~gC9&P(WMCbh`mg%~s>=rCbQ18Gs!G?8##vig_(`mz& z%YIuLtA7K~WwS?-D83hJ$SgjfVqF-)j1=EX7<&x9A#yk&*9(ToPsL!%kwK^6CnW{`WLyGAqa z7)@2(Hkwe)Eu#t5$oFN(H5hS6#Ae>2*|(~=XE5Tv%mafF5A+6xdPp`%Jfa?xGL3oz zn)C)V>kVi#Q1^Hv`i({m7>yV-8Zl%vFvCUzMvMlG8VwjT8Zd4&V8Up?q|tyW(X`P3 zZpLVU)U43}GFJz_ue@c)Gw3lRnl|V$B^o#AF`};+*6SfPq}M}gP_M^;UU#5huS1_+ zhhB*uy$({{dL2lYOs8H4u0y9qHJv&wI(3@5Jy9ufj8cIoRkSG;Anl?Kr2?Hw1-g_9 zbSo9;Q7X_Y>QgE}`Z>im`bB+;ZE(GcZE!t`ZPa5xu?4w7#TKN76k8ZlY+_isbzp?P zcxJXSqO2HIZevt+h=&a08YRetMpZ$9f=(^cU`nsSv_Z?fV<{KFl=3i_@~}`_%)wm9 zR^+oVGZ~n2X&5p|cyl?p(d=Hasp?08^noK?%$HD!S%p(Kq zN{je6U6vQN)m}?KLwX*x{GhiRO(R2Sr$3mM7csQ8&TiU_$$&+>6)V(@&hNoi&<{l< z2xT+`RXhSUg#t3FSOi2F4MP#3xmttleQb&pubT~8vg~wV(Qd=M#f%xF9+O%P##9On zZ*5{=Z56%Ci|pRDPfwv`VhoKVLueT2$Nk=J-0keZt+rO&Y;HVqKj}Iy-nfo)pM82{ z{o4!;weoxZUP~*^c6Z~#&@euloWduIi}-AP122+h0=4=)07`K`+V$@?uqe9>ICc0Ob&^AAV z=7}*p9PG!Pt`64Q;M0c>aplhKBcTDECk<{`8N(oqPbn|r(-BJD$g0SgU2zFG+l zu3llG!Ot#TWW5Z2a`r3>48HfXcUfrgM}PE3AiQS*g$0$~1wUY87|I(p}{AQ@yC~choQm8ALGY2Z{p|o@8fK93odr`;Oa1i z1~V))Xb?k#7NY^}Rtvfub~eCaugA?EL-_yLdynTvvOLc-58Zw0s;;WclHF4xwFs>v zsI>wKfDjbWngF2*NdVMZgv>}$S>4su)q3Wzv$lt|nYpd)WzE+1xYqlR>|xjJyY_wX z$9QxCB*%!tBZlY~?b{ z*(?mP7={A@^f{gAwAn7?X+R^ZnE}>pz1|ROWV~Kvo&LC|8LHgYY<%i^{V^{xE`CNe zf+-eU?d-(0t~%91G47w74pb??>f(x_Kk{XIGFeNm4k`>l+>713b8 zX2F=V?rmU?&B2*T!B@;9QmbHoeFdrQP4Tjjd%TarlS34rJwfUDQ}MgV-^Po;&%X{u zdgNUu&z^|u;!VD05|sI0$yhSS)1 z`3&b_{qtv7|NQBxtbP6z%~<{XDUQLhpT_g2SkbZk{3%qHo->j2Q`8iy&z~OMr}ERs zIEzLzsQTGcxvb90Ht!!I|Mc-Oa!(&)L88sFa;8-!^W-s_k$&m{w_#XM{a)?$JpD&!a2$A?INR*-rGe(c6X4{k)%ztyMu&AYKN&+*pTWeXS*&+;43a&b3vz)>h%x@T{%EyS577+A91S zfwfhTPy>Q%s~~b8|Jn+OuL0h*73c}AE<+MtTR|ftYb#KhTU!B%s;sXfs!iqLR zV4t(<|L}L%`}^Nv=l8!AZuT30^J}d9`b*HgzVze}+1+i#>19wU3s-uECNSBO-e^>f z_&3#8#RK&m`mxZ>zaG<>MWk9re2tz4bj{ocXIJPpM{k4WZ@$9n-+Y6$-~I;cfBV-$ zK%j^q;X1-uwbwnG|Ld^TI>J z8fFNB7ZYwL42~I$Ofw9@f_}5<#66YQr3wXVU%elCgI_MI`{?^}pJr_%u|TeqW0UPI zhZFbwK_MD+XBN<3u3&h11!J3AFz)ROcQGqt=a{hPtFP;&a=!TnzTf-?eo;@ho{%W} z>#sm^Uw?^(FPPlrInvLbAa%Hp#O}6G;=)TccuNKGLd+LqbI=ci%YmUO8+y$~Vf@Q+ zv1JGXa~BML{yPl5{GDipaPZ={M1 zYeFoLq5;b(GTGrrKl>CP{_GQc@Y9d*-cLTnyFY#(zx>gApkVOxcYb-QXz+jSz6Z&_ z?Y>tpyC^*koF%+7TfjS0S-fqPqCpVf8+PL_`lj*S&Pjadk>OkMG@!@9O~V-OSuJRD zI?)>nVknV-A)m)&tqS}48fJF3;W|8km!iRo7YMz4iSU$P8M1<>JP%wCk zz~LdhJ3DZ#uVbcGgSAkADV4%lB!WS&7d5w`d^CEw*Besr%>+(`E+jdDrWY z%VpI#)%VpgHS6n-dEPO}{Z%7ahy~qUxZd538$I1ZP`KUQjayxvxY^l(8}04KM27Pk z%<`NUY4z8u-WM9*>hfuQ{k=YISsL~F_Jix!prYQxv+jxhSgnq|715y2Y|^|9T(E?L zm`TLoUdSL&E+Dd0)r5l$;c<{V*cBde{QW9EJv;{2y%rQD-T?IAdmVCzdm!|-sIxEL z3;1qOINV23WAVu$B$X$JXbQa-A0MFl0>PEs6Ay_vc^=OK8A$%tMvGwWr~jvKsYhgjQryR)Oq#XDR`a60=+yH zvXA$X;bcw&(ue!FFbDfcD{%I<5y^vnki;p(IrDq4*Od8#JxF3Afg6*!)tTGh1&K5v zyuS;T(Ect+P$RIv3&QyDnVnrsY1nsmA+hc3q7l}eT@Z_cG_=h-dob_p!nCssqmGH4 zT{L5SXBQH~&MuCzy#vD~GrqMAGSL9z);5Sq!@RW(GP$)4i-vV;8@8=&*cGO>wlTf6 zjhU@&%x-NXva^l3ooz%FVmsR)^E=y!Yb18IkyJ?SY$L6a+1W-jvOC*Q$!u@oG}7B! zIE~cy7F3ekTS#ne3gTOvh;3~mq!HZO1PLhkw>II^;oaH<@kq2;e>wZlwvl&$ew}l3 z11b~@W>!~Dva%w=T^aKFie=2M)N!mV!>Qp~S%!Oc8R6AsL^PtS%aFv_Us*b0ZemiVFJjK(6}F`206*I#0V2@8MoYtVCmo(C#i$8D^mx-7g3 zzC`tl&$0OVb1}1$e{zV0gFW#_o!ndpzgUr46@gMwcsV%JDa^#@VV{e@5)7QUZ~YeL zEHI*b+`AH*_3{$GD1YU`%yS@3I?y!lcH1}t}z`|>4npFhXKvnNPD zJ`hT0Y;zrv-7cH>T0mk3R`(e_XzKm7FeZG3d&IzG5^<(O!|yagZp^kb2`fMNl?2wLH& z#G-fUNHCyqa9lK~;D^oX0;Lq<4o)8Z7M#g!UWmtmR z-W(glJ&OhHE{X;r3?~v8&*v~%t-`*x3I`S8{XKY}Jcj@IGXy`UaPT?8U%W(wu>btI zaIFj;9>TY~3(v*|oXg9YDwko&W-&28kI`Td{Vo@}?RK=AOf8EBQY?_|X~tu-ZK`p4 z8OH5d0zo6Awb|Iz_3Aifzt!=oM($^AZMfRefook|LMXV=+k;zuy|~raC)&HcJ-E}; zjoV#aLO4)AdzOLR>Ud7uPoD3+>(`-jQRBPO{cg6d(K)#8{cBf`A;&1&)2^r4G1X_= zsIUL~mCsz?4%)3p-UiHV;7ljQZy`P2qRUH&Z>$NAgUs$WvU_w(hhmGZ$p&c`0g2YXmN*hA%T|A^}21Js_>S$cYiQ+aZT zr3+A_fI)aJ3L38oMG?W_0V)cMhX<&$k3~+%D58rLUz)djC>*}xNW|fHQOu|we@^N% zJL`F8_IIF?W|%11J5FkE2Nxx|SD$&6GqBBCIWx;P-U!8Dl!l|)(x8+`BU83@19S^> zJ9Q#ETR4p{JvB8#J6j+@jlj+ph;wTT4vpEZEs&WeOmA&LGPSh{iG6De#JaU5jB6U) z()gCG-asGU+=3pyJDvt7q>k9w#MmWa*w_RaTi=91V|;xRl8NzlBxZ^FL53HRn^-6eiw1Ky1d_%!?*8z6y=4Foqf5Zc&4cw+;RjSWOMH!#1s zfw)Fua|4p(<_1(!n;SSU>gSL3H`bBVk=R&=B)+kZ7~S*N>x9beznP^P$m~)Lj-?u$ zOEtKbY6vb>1)-%X!b?>lv{P)K)4_ETZ>oVU-D=dG_#D~v?U_jNKO4R%+y$lxNUC3fKJ`Zashza+b3r%Py6sYS}gOwTc8UN22 zd%F2sf_^Yh0CO({ig}R)ik=co7Qq8%R~^d6vipdvg9n5TfXSDC9o z5ew+nnLF46U%Dt3@E-9?6)czF(>x1~i3MH{3{J-hV^+Nm_N6c&*URN*tttXYL;ti^ z-Jku__T{!lVu4&I$H?}Y#fDqVY2f$cQ8b3GbOwFJ5{8zR#Xn!u?k+5ck41tVX7qKw z{6f^v^|FM}S6?CYWjz$3p2hg35DN-lu$;{cp2aW&*1vQhq&@-e@nC?7RY^C z7Y)jF(O~+OXz+va5WYX`!T0)S@ZBy8zSB02KfgEBl4$V%;Qxh+-Vo6*tAYXhw+se6 zuvyXJa-lCQMT0yn)heb|SH(+)Yi~~^HuODxir}+n2)%eAJPYVuAO(Za;UNOtZ)*$g z)m1nsIur^pr&1W7o5QfrhrZcabXhETG(P?Z6AfsPon`+Kc70X+`X&$6!` z|1$gf^SpcQ8pwMZjf`*oJvwW-(Y@ENYjmFXu3p9a3i`30b{`rYkLx&Ab(?lF8QaT?_lb~m)=CXUfH-u_uC72Lya-m7L2*DbO`$+zs#e8RwQ_{LT0t|opPi-KHKr>S%v36v ztyJI;MtKE+Dp^FZx`>cQxVnf&aJ##*2-jj+;9M+&I22|V%Q%f0Zm%ph#Zg%VaW9tO zSuDe=;H#8zM0F89jk>@wGRnEgJHp;45V1x=P?0$c7R&G#a&TwTm`%h*7=rLD z@Va4e&SGSGN`xS&<8IV%CJr=PuZjR?2>{%#?thkOAjN@Ztvdc|7HeHJ5Qz|@=t`&2 zUnpX@wj}nRvXyB>V%Pu+<(ZH6%+va%)(O|@j@Ac2(FS@PxZrcR@ z{NC_|L<0&4dSgUgZYCOZx?JcFg)o{(z?jd$!hhQQ$IqlRyF2h4?2814fhYBZO-$M( zc>EajFrZ-I-`<92Z4J()CCrpcux7I`F-Jlugdw*Zy;D=@Fq`pkbo7L1KqE;Vr|e4) z1KH{guV%}t(RG@^*UC2aSZZHyjGngKY@GV_>hak>YkYd+RxaP@?!wL99^CHl!`;CF z+#4Fiy`dr88ypmQRUY*B*M)=bddPzO9NV+bdC~3aIoN;q+SL>2uU~(E&RRb08OUv_ zAus#yUA+SGzJ`9R`fG0GKFMRtRzG(69ha^C+U2qcQJA8L?h+nuQ?Y2>+aRA4zljvM z=@l1WUlpP^^Bj<7hS-VqXSlYW=JqPLrM5QlI#BR9FR85!NYWHcR5sU<7HlB1xq;mF z)-m$iTR0b6o5;67VQUj-QQY1_ac2vq-EDyo8YniLf!x2iyNyd>XB$Nwg`I8a$?t5V zIa|o>oMd5V3j%((HaE0qu`WDa>Fs(NoVbyQq+m=8rb8wTYuM6N_nb%<--fMb$f?HN zMf-JQ@m1Wij9;GPySYMSeHCZHd{9TMtstZkTw8%8u(kq8vlwm0ZR=ySX$(rFQAnfD zzPbYQ>Z-uBx(XHJ>MF>DWMvf-8sjUgAcmDyj5T3&WfjL@4lRX|(Vl8 zOUsyEUWR*RStR}rt}G*@5nfq_B(ky$2`AF{UMz{NEJI~}Wf^*!ZeL!)d=p~JOOViO zO)|H<1PMKXk65aK;lv@%lrPob(Ps2HtIyee31|BWXa0%w1Yj$@17s^i0tyA1SYTf) zL&dgOhM-)6tqJyW31muRx?I9cxdbmKe#<5J%O&B>Opj(x1~-D+h^thBQ^QdzK{8t^ zLBjW2GTnfwQVGrAxFpVE0TNfK2o-m^2my-~XdHxGm%+%CUBuvb8OHEvaNtstAhsepsD@wvq!}E~gv(j4nh>3XE0q*8{-MRP z$S=S=1B?ZtcL2Qvn1^6d5e^o455D;P2ridjzCh{o=O{jZiULD5C>AgjVRu{nAjO!Z zf;Ychgg3V!UdmXp!4~GMw-@71=aE>@XEKQp1a;hv`pv|FX6scE;4INV-B%*hS9J-S!^yLc}u2jW8e)HxQth;-dJ~)Jf*?pfrgZKFhBwjp2 z>cumpUpzxb%VbDylqS4?a6ukU?Pm~Q#2TOB^rF^{j0sPJPL~t?p&&*QaZKbEV67}-im_sx zePF^HX23mQ37rE`e&?tp&%wT^l^ftboWWRK7VcK=d>%8Y6s#Gxs8K>^5$?ul`< z4G+Ij(Lfqoveg@W7g?6aQd?<+Hf!}pVk^t)@!3CXta{^CE;Ib#USA&`4h-PY(2%(2 zOvFmshKKNIa8QVA_j-E%V4eoQym}RS^w;0YJyZ8-_AJ!((uh~vUtPTd3D>`S^{U|g zD|I13-dD9f>)EKsXI~vB`%)}WTmAKOxo2X$E~K;kqR$KaTo{fdh4hRFGvxnHh8!~Y z4u9wQ`$(kWb>UX$(yDiHJ@2v{*JZUyUg!GiF_IKcG%}m(LNLf~Za}iIxq;KjZmeVB zby;7-!bRCwM~-Z6oDeAr+nZ=aD`G~g`{cGZA)wHrry=zFHN2jiVW4+Gw>ZLJHwp z6@>PQgtpviL~B(vB37$H(rCLlX0?Kdj&QXCNvK)@@l`8uS1WK;DsXBzIK!{a^mDeK zv;JhdvUq|izGGGvVOJ2MK(PQ@u>k7@;OFcbQ^f+@g*-fkJiLWGd>Z~j9)y$UdgL~? za(}k`JdY#cai=w=3VEp53wfN1GDeP-dH&@SF;C739G-R`(-+Vm2{@tHmIbpP_*VjxOXtZ7${<1wy0BGc8z|Wob87U4l zYt?aIGf(2y^fd0dJ$Mufqbr_3|3VHU<+Aw4Z(d&)iDIUA_ux16v~imY#| z*0jw%eIh(Mm?4=tBPiC;LxgU#bfx99oaYZ?r7jxK1BT%!lL0@*T}?!TFaQ4NJE@La zewW&Y2E})|eP~b!2nrc3$%6UQdJD1_K`2te~gCfFc@L7R#7gUcxM6)R^dI zmnCypUS}VH{e1+<-W~$Gy9jJ=iZ*wO@|KElW;2+I$1xcWiIQsIyvRQC__F=Q)hi&sRM20){{Eb` z+~_&z*EKqZ-oStN$`ueH8fdK?w`|Y42l`{`&#QjVWnX{&T<$iEVPKLW3ezyM{35Ff z%}0f|Aj9W^rK0$4j50AIg#&sWP(08X)J>PyR*`s3;;Soo9au*BqKNC|HLI*FA+@%G z)Y>Z2XOLN2#hI+GAajYNS66TmGHWYM$C_PVgUUt34~i!0G1Pu$eGO-kUSGp8_`O

T%bMy>11@X*c4?b(u4dx;SYWGwrWc&l{0n?BqVT~V844j34VYj@hz5@jg;+xI zK$P@RN;A=`fMt7ftQ_(90GWe5kt~Nay=7FC?f3pIH4;M)Fbv%_z!1`1B8>vl-AIFU z4$V-agmkMkNQdMA(jeU>AT25RpZohfziX{?t$8)Cu6^xu@BP`w!RHFKk?l`+hobUT zF(0X&T9E#TS5n)bRV)lOH~VavxxKUPC=k95#KedxEPqmrgM9Ex5KV>`lHI`DBut98 z?eBf~R-JXZPIDu7H~}T%v2yMXw5|hlq(yuXYiR}CAz5wTzh7ToiVkq4Tg6CY5R-{x zk@U->qcfL<%Y_YQ1U4tNr-5U2B@z|jJ1h|ts;2@W3Y@X~d(;(Z(g>d2*b~NqufgM} zYH5v+KO%9`!YeT`A71}W9-e>QEy*phvG@?cMnaX#LOyte>eE(olI-2FDZ&jUCAu48 z=w1tE3~kT^09-YZXBbwPYjl@e0q`-rSisb}eaTET+cK^2dI4$X;_`Yu>o?i`j4We27MAq#1g7|4?jBkV)$Hp+^7H7-~euJPfZn;@6ZPf7ciD z<5$fU#;Q6Ayq&9`^;AnIsBXX+`ozMFf;Yc@viUCO;fKTdb%&*$V5kK0Xg^_+)vVzh zxCxmFC^l|tr>k6+_NMbYA>|rYu7JK^(I_|ou}AG&C=(1PnnGGLbsyBqgAK-7a~C-Q z*@D}j8>aTe+qmODtf`^acf;F>!&E2}PV0@EBTkHQJNrp4d?Oip<_}u4zB|=oZtA!} z(`0OitMi?j6>Tqrrp8AGaZeTB} z^_8vf^m)}jOA0U7@A4`L<-q#gR_CCP=cj)zN<8K`Y^yjtq1U6Z_+jWBdBTu6ztI3n zaZvvSbvE<3Z69+QS5}x2eD!KqHdv!kVpc~8qb-~}D@-BR%z0& z$`ptFwN8FMY}oBMkRVZxHqo+^_D>g1+iPN1=lkDI*c)uXy>{y+pWA zhv~@s?$*jPGrXJL?se&5kJk6wpp4A;n6ukD%7{2Wh4T2#muwxiQISXL+nMuw=9)1q zHfe7xS8Sp3y%=2zlxcn5V0k>&uU1mN@;ua!n$CQhPbH4pVCm))c=? z29}Z15$KvY!sl0Cr6HEZBdPIV*N_AW$R&^#QI9AY_4iu4T$6s7|7Y?i3;gn=uldH* z+iCpB!i?9&$1BDoerhkh5`;D8xbs*ygNNl|Kn668Wczi>Wbl4cyGLB$U#q?OtM%td z(ZCS3IKcbBrrrqDbwzT+K?ZK-YMt%VQebahU!WSr#$FiKp+{Eho7nK8Sx86$Y0le$ z+t{?Rwiq7b`NkU8mV23q%N+G$J%>MOm2FjoYhUw&GjktL3T3y?aIR4^tnyX+cl{!+ z)(Gjn1JZDVfjw+7d;l@|lq6qR)tP&(8pFoqDbX?EMII6U_L-sRwcl0BfbP;TIliyv zC1Y4{%Vf}8Jixfr?X-JFjLx*fV^b=}`{>q6NUZwtz!uivC(W!4-KHGd8WVe}@sQY&H_se;zV2>x=zn7! z4Zup44!em|-h74@34ag23!wtu^ym9?e96OBT2}1o18zLLs|EjP)s@JQ9)3h{q{v!> zr{BCi^%T2~8~I;)9xNZJ=do;g7#4}JyeR2BxC(tkyes`rD2)n8!7J0t!~608C#kXZms}@ROO6HP%Z9W6dRfO%ED0!SCyUJSmttTyUvt(f>-z!(W-%( zK`)-iJ=NL{IB%Tx2QBk(2>N zOGYs#E=&zg@fVL(gSzx8!8C_B)#xaVx#g4zs;F>6tSTs}0iR0>PvnTBNe_NT*MT-{ehynZekG`g7$py%>=R8u@sBbHZFOi=7cqtPV-dLEfIg9RZr@UMF{V) zSEuNt%zwp-oSL~QoU~Au+?6gCfEMUF82Mu_r^iQpTok*$TFvGKv}&g`*)x z#;qh$yP3Csf}@cNLKi~%Mr4_vB(tbaUFs?(#PmG|h9h1Lt77vbD|J9sM)j{ohw0Y` zGN!|1+wdh>w{SLOTwyN^U99bM8Z=yeb8MCy>P$k^cn%UKm4@vSbbpwHx`y12bo}zTuQ&02#+YVjy41o} z&APwzU67vTfbzrXWZeX#D~D4LA+M;YqTl|`V-zxK_^{u2TA72p1^l_=y~)*7^Mb7o zG1K(vNKt%moCIHoiF#+-i))^38GoLb`}+JDly_^FgWM{iJ?4@F!=3L%0~ zDLRH<@={Cq4`(292jwxSIQAsf63H*aQ-tD2{ZwXmA@-+$1+w<4%~kM@%`feI_I1FX zUU6W+@ZnEfuvZAQ+b6cl$RsbE3SICzY|$cGzm7J=dQf6&&Y|VH$SoLznG40GJGWj- zS+=xP5u{+B{YTMte;Pk!3;D~2-tf7{VHGgdE7LetANs%YK^@h-fUY*Oo?*NJtqE%h zy8TDUovw@tGeIVX*D2b{%ZqO~vRMu|Bhzl8<7U=nXAYPg;m@i7KRI zn-F!8S=z&<1>$dNn4RFjGX@<0_a&fVx~o=zkDtbK<>e5i{R)_NGupNbnM;F4~&-hVIF z`FKeEC4AB<^E9{%1TnKneFhi5i2+A5akM9 zl#0gV;Q>m}<fUO-=4_)aOBZ|+Z@l6fTiQm$64 zb8P1ijK*0(vQ6Gk2E6S}F?*Id%4^R0Bh(@C>peR2)jfJ*%5YEaa8IelsEx&>Ie5oj zD1JkYTs{*D5HKKC8rCwL${Q-wED%n`+Mk@v8InsL%WuO%6(p1|^E68)D<@M`&R}{g?7H_ zRvbT9Gt`N(`Xmy|mKsH$6TTZhm>Dqk6Hi{8n8MWkf<8@T^E`P3xvMxYVU*U$cA>+P z3i*8_@wpqU(L4jL4uRlm;M z*nu-}3$WGGVk0;Z|RRjwdsFi$R9B$)SkM7>-JN^DJACzn*r4Cw`vU8@G3ve#B z$msD?d`4N?byYF0QXu1;6$j`DYUY;+ry^Bau3bDG+~`v7dd_qXEGEeqv)SOJP^_bF zEgr9|j9Dgv#xfs7#2apa0FAAEC+4Tt|=Q06o?0j|kVQT%KT>`8j^etk|HD;KoXl0qT^ecb4tFf%Snka?_{KLvE=4=rHl!yxB@ z;UI4RrxxJI1;3jpAI#=u(@;cXZK@5q5vB08!;JpNyM27umOxsJx4}w{f9D;S;`qKD zuc?^jYC4ZYnpTN+`OhhTDZ*RRWuu3ff0{IAjoJ%C&g=uJuTjoaKK9tccN)J@fjTC3 zqS$yaz^Mq&GiyOFG;KO;@>u&7Wa!6}a5WhZ0IJ_u5#jsN?dd9Naz#0wJu%2P?TIQU zN%(LwNZ?|$w7SVKsm4981n)0jzux%AOWe6;EEeak!t@F0$W)BRwWv4H?UtfSufVW} z-+PT5W{Nkj^1cc7;jADi?DE0r8J}n?B?gUS+JUFofIc}4Rgj(CBRa}c4`}*KuJ@16 z%c)A&ud2>>>O}BedE)C&w-d*qp6@eH(5oUxh&7^e97V|alSg>0=`#%m*D)6aOJ9`M zIn0wGG6n6GJ^AC2FB0BCmZnbAkj;W)4i&0fCeD%Wd1|qo78M}YeU;LQm@#WyyAR5R zsyI^yI4G-bD!!WNNVR z6?M12=_}Y!V{um~uRr-rw65Hjr0|RbAoAPF9{CQ6`zcc&WNjE$5_vgqrLFv~mK|b& zP_&3sj2x9~>n}F{-NsQ~&!J!Fnc;xWwn8;&AM)EWwFW&qPEst|O0YHYANbulUxpT z^2D# zuPk;g&jNa=oKXGuu*ybErxIL&)MV(kx%r5y1mKMbCVURQu|RpT1RXerQ#%Q0%b4)q z{S_EBoUykvJ01uqMfE5zb_70FJ_<;5f`Avhy5pmKfxlMZ<0#{_Uh^)RdP>5wGQPfL z^b~q%EV#6uqxp->^k6l&rAtZF-XcHA0oSG21_(oN?^V8B0ewd&Xa2K3g;!n$In}xm z!Z>EYf3Md!q-+1}X^SKb?SNcbP?TZOU0*G&ADI?=jS-)O4e5@UL7nHI3s!mfMP|aD zAR>+v*Qd2L!v6HE(#ZGer`^r8^ux5LA7lbg)}OMbRvYGdgsh9^)OOt^8^OB;Cfz>z!h2+m5Qvvj}DQKi6Vr~M^~&kg~ukKOoo_=iu& zu7=XdPl_@?)S%EV9rl=r7~q?Hw{>k*tjV_gI(EnPsRV6oz_JX zYGu%XXMa%=yX%QbVw-I9|oMAH4oM9STN+l+;dW{VflsQQe^z?0g$o(h6+;Q&y zX1E_)D<@ zeIbW}+a+itIE)MFN_B$SHcNwDF5fi{r74JUPBSs{=CjPR;$`~9D8l-{vH6sx%9y1s z*dw0A8H^TTq9o*^zcOB`+lY}Um7}h@K>^G_oYaGZYDF696DDGopS!;!*7>?Uc52yK z6JsnG$$R_mC0H{84waQB;;}i}Kdsn$^xjrLSMZs3!nKSj&rh~{cM|Zi6vCNXJ?lBq zBhklHCTc9Rg(dO8Pu%#!dPW_SA-OwByXM{iZOfDvpc<*AUIr@Z(EjGf#@3BK-oJmY z7Af2#BEkUqrSJk9lGSti3-}uHMXhuo4!7dvDCNn&QSUyXIliVAp1$x2Bm~`wt7bOM zyue(`6y*K}poba5W*#?cA+bFWGZ5LG`PC}wtKjdMw4TslgE*`@-6r8b<;b?+w$(jp z=axyy*^}zra&0rorq@;FGyC+K*GA{4agJrrs5D z>@{Nty4T8@|R0X@wp9SODE}TbUmOm3i;< zxE5&$E^Z#c8S&=K#L*0?Kqxbkte z@aewI>10Ez`RQ500ev33o58A6V?u7iW5%tMgRY=CHbZJFK?VYBBd4$ng+O`VeDW4{H6Q^rR4-<;eR7r~LVC zGH^^P@^LtdR&Wh6)Qla!-L`Af_2cE#q5i!Q%j+-s>uh;#Y^i-zEIFWmJ=?gy~zkG5mVucJInLEnZ4Lic}<^pw45fje#&B2=X(>Av{^6T6!Lv%lD?T-)BG~9? zw}dbo!Vxmt2gadeNO;#M_?_)lb0Q0Mlx{CM0lY>f@28FkLQh+o?XJ-cn^R9C`G9Ds zNz`HHnH4*xtO#ZiIvZlg{b+*-vmpQUmtAnjc~9(J(UyIX-+k&)`5o)A88af*N&!Y3 zYi{X6u;uBQpA4hTA(iX#g#rrWut|HU7{Z!FsKf^rGt_kC(&<G8_Gt>>zK3U?M&7uVG4CJhBzUB@E`QZo*4_|6U zl-TGys>0rWgQX2KX0FZ4X*9pUugx|WL6}w(nh>xpIw#1J>R5dWLg57@L>G5LhI$D; z-fgSv(kQIBemX=+@@-M4|6`Jv*r|al?{SR|gX(t!)=6oB1mYwrq`3^cg$@fPU4Lr{ zw56xwN5#QUv1-p5+(LW<(0I~#@=!t|2{oTPu_W*>-YI_`T4W8X#bN2WNtm?LuV&gb z2pKyW8uT(DTF=;5@8Y)xVS`^Y_JwD10JUM}9NGuWt*DP2@{_@)tGD;&Px#%<-mH52 zox#d<=qlhfQSuQL89quWoPCpq0aAQ+wJi}0BSuP(J+K6CJ#plU1|yu8lC*Ms<#Peo zCmUNR85SCFSEV}!JLJ14&EDUC6VeoDA;!;BIf%JLR9v$I(MTf;*}rb1cy~tVQ4h59 zHB6b+yu?VKJ%+FPIXuzeV!onTm@h1=m#KMi?s`oTF03Of`@(qU5u+DOOUV{tC)?H^ zP7o&_I7^O4o2ljt;|psmDr$Zq;yZHlX~5nZ6Qwrn_imw+1a-r>Pl;rU$p*YV-9VM> zH@7bsAj)U!TL*Kp+uk+KUamZRNtv!4FkKnX&vQM&Q5@FAEa6=owP)NMN8RW(LyC?(Y=i-><^`UvdceB(^CcY#qcK1JC+Hb99E`uoBRx2t8z7N1?ss+fB!sf}|on@So zH1=81qiSPcU>_){8=PbzNZu8(^6d$a@{bCg{fufmbCOINO23el*7X{ zDs7JITq1L2h&phCMx0AwVC?YIoTLnSSv5ykfkZ9IB7S!$wy^EsnGJo?&@3YkCTsyc zP3D

|AoBJ3G+BkK2I*t5?CYj1gsFwm5@FNd9yw{|-|T&sWINd6+DBpbDfP{e)V zNvt-e7!f0bCQB4gOG>nAd8MB=VBW*@$Z(!V{M`JihB*g>$C@ngw2K6Bme;W(-K;i@dyjADwm zn(b=yo!{%l06IVuU-Sk@8KshOqB2J3YLa_(7?SqoXayoDQz+^fHxdVNdYE}qu#p(S zz%~;(`@(gvVe_trZic|cX-|g9^#LC%yD>rG&p9sET{(6+j~O09x9yd|wk@A*9$GH9 z^ze1Bq}x2H-qI}(BwPtCqiE-&$KYieTJnwOKzaMDY*4st^k~$3%ZAO#ZDv|soDP_y5n{nb1$+ zX!4}&M1dY#QNNwtwg$IkI)tt+ua*D5Yr7==cHN`6+Yh7j2~x|pS1~0~3kDeyF8b)f z3^ji{LXiNo`AoMz83hlY0dqRhTmP*C%eA;hhATtt-GVf!Nz=WoyMr75F-rY z9V`5Fa_sevpt9@lF6Vm<=Keh-4Y7U^vA!T{5wY^fB(~ZlHUeVhNeonC+#{rmj`|KO zebM_F*&z7cW{HNNh)btT0HhQx7r>6tbHIx%_{$E8`q`@m9@V;jbNAPG07(Qa;3n#0 z3R#a4x(W)G_+_5=o#Xr6Jv|L1M@m{bU9M?7i8fLykFG;X8i@A8_aqDZCNiBvQazI{ z(XWyjg{NVMlrztU(y5=_DZCE+y*=F<`&UWrHmI3>E0_)$w93R9XiB60dr+T?)yd*D6(kKrU~jL2p);c6bQxgKB&@^1q|ec7#?kwhqxTKRTq;c(#lZ%4 zNnHlFO(r=+meD~)g5lQyEvGXrub3^3@5N`7(zvazRx)bsS>8HSQGMi1q7EQC zX!6K8tp^-J&uF19kEV9p0rOu0`-t-?ZFKR$Qw(siAci4swh%Z9tZQ1D9Oe&Cwf(M% z*yIk7bS!)k7GoF}U|DKHLodwA~RT2C$qlhub7_2;L&Km7=NO?ck zGkzvr`h@Ywa+QALd|Gz1d`Wt!{(wDPD$ER7{=qAOUj+oNmv)B+2r}B)P3~V7ii1cT z#Ze3Qfzh#%895mt0z#D+NszER=eGe5p{ulyyKmstxDR7FVzt}n+gwZ0XB3{b2*^nHeB#sV+WV1%&UZ%a0fMvS5E{85LF|B>JKP@l! zu3cYonmawdJP5y@_sC@InJH)MWUE{j@XkAzpz}8C2;)`2h+?OX11waLA zlO<+T-MAwDrfr^6|9tcJphpwP&+L}qbCfj6fDL3wVwOq(LDh_&HevH*G6i`a!5A~86F*PcCLlpDFT;BPWoEO{+I zFmO|l789N52E!M%%GascAAPr4@3(%r0jA}p{o}iR7LJPHfc9iBl)=ES{Lx=WXK_BA z+IbXKQoKNjU{}e;=OLaI$kZR)o}X#YXCU&?^P zdv4U*jp;~QUVd0%VeY@4fZotjq{ABZK` zY4Ex#$ZcJ&FwC*$TX?9W$hRQxy!zWewF^JyD%)@D{{jCL;J9d;Ch;A5eX^tmZ?*lY z&BSAz&EYv5!R7A9Fz}DAU+VTC4)Y)mw!P$~*x(_Hy!&3F6W*c|RjW_JfP>npX=`Ag zl;g!D(t3Kgwu~ytae!=Xem(6F9jgmf_Gz-$VP3IdT??~TiFtlm$3v;l@1Q^BpvLdX zW%b2UyTCUQ^B(NgHYp&^WZOswW^?nl2j^W}ZNd{1Ns;vUOdYkw6u_~+g2~8FtNH;e zHh#tpy7(h{ci&Rx9nB=!?rxnXslFL^-kvhJpm;;2kNb9;|HlGo61w0Mtgr5|)2bo1 zh@a98xV^j0euC)e!HBUo100dK;M&9)I4o> zGHK`gj?z{!OeQ5X1b#xdCAQk8v9X?{EO>J$pe-pI#rg{io^^Amm!s*rD&d~A{g6Dz zlWtQ^LHrr#`R&QGVFu~L1I2;UWOe}~LhYJZAG9bo!+X>D@Zc1Qw5Yrc8pPDOxrW<< zz|WDQ3upR-dDkLm>(lltv9ZNqylk7B$66QZ(VC7!=W1v6a;5XwPR;h-y6^w8iYI{w zO^q7D2j3vlY`3io=9jDSl)9}S&uJa24sP{Y-w8XFY$$BKvcv@_U>_;Ko(+j4aP|DO zuh=WL`uHzh@aD0QU#lB;9F|_OVsKyU{6b3ICiUW7);{BVQ9$f>u&lZot$L z(rL@x>b1OSJ&2q=SQ$+g7g}iZLV>Y!{NB`Q%~c&-6a%9r*y4sv-Irm)iT3864PhWOV<5D3zXttv6PRsH94)ImhNYQ&iDs!0 zRAmeco0qs{OktYL@7++y3c@91<7OnkOC&!DC~CTnfaU)X@-}#){$=C+Ln){O+ilh6 z;rulg#?|H0%vSl5%eB|m#(JnSl;>V=!7ubAH*yuLjO8cL@ zMy(LyesiNIVdqznO*8RQo}`a|IuF_FetI0wxiJe~La8RiKfn2TPD)*OxVfE0f`7d6 zkVp_XHJ8MN%CZ)@eMes%mVH_xNz@gyYdzFjdq+AtE(Rx69;rV)#j;I||DcO=@mkv= zWD7C3rD?XS-%1-o928mIc$pK?dHZa2G&ZIw!s`)E9kMfnHEBwV2j5XNJ|}4JTKvHO zV(D^s#tbf~Jabk5GRdv7o>chu)-Avu`x=RqnT)c)?imgZ@4nEX!F?{2_1pQBQ(;3X zM7rv|&&KqXP~gQnnpAT@*;nlfx;I5O-hp+R-JzD<(ZVk4MOnDQRa?CWbEn-bF@W~G zTf2#$9!&7Z-txB!{0hJMzXX7_V9nmZxaWDR&0(5eq6EI9w|7%})czZY;oFn0oW%DM zAU}M7;%h5CIm^PWvjv9?V}cq(k`=lmRQVI&&djXBTYv8%U^q$;l>5+$&-8DP+N*5# z#_9!vD&e3Ge{(vq4Dv30DWo1yC)jDk7k63pBfTN82P~De5s2)ZlDT<$!RwiS|}a z?VRN=Z7C7Dw`oiqye~+y$Z}x=BzAjy+lMx_E!$83=eAKW9Qhn_ZNj5`++r-k>tn)` ztu(zQYSLVN*0qoB_vLJGUoK0jZ90;m3@-;_qCuhDG#yFYq{=)%yCvSfgarqz?X&3^ zYivlqBor$m(9>>XzqQI~IrNJ81Fw)_r}P$sm705qO<)VKy*27T3jc@c?H&={Ke?9j zTalsj{4+{2LAW>+Wu4$h_VbiH1auJIjTp=x0sfS4A}vsxCrkxg5M67gt%P>kGZY-W z-!*|+2DUAg9Y={aNWM2RfvzJs>o2o1x1FhlUk~N16G#0-XR~(+?OdS(aPD45B9t5Kp$zP`l5YKOk3@{&Vqdp zSfx6>N%NLlz5D)C@ncdKNuJ|gvc2B_ewmQl>u_*$Jw2HJbc(A8FK3KKQ^ddpymeVa z>i$ldSm*B`Y&MZ1ToCeqe|s)?yYy*}XQ>T@@9#gsClYf!sjW@yFwf8NjaePm6gJG# zPDJTC6en;mnZp>T{SbZZskTPm{@j%ykKJeJL%QpSVg5i~k8ELEs99I#b-PPfNX)|y zVk65%69P^^Bnmf-;nd%adKyGA;A=`=r0Me2Wc!fnU`*zN~R6UztM z&G7Ac$?&hc<*#i#W8+?Wu}G~UG3C4G7A`S?G6s;_$?c8RTffWsnPc$WaOb!JV>`F! z!QlBI+#oswx*0La^gD9eKF>QQ+4XnaR>NP~)5n-Ql&?hJM%S0#Fg`3e%1ffks%IlK zZgQhbQ7frCFtn19^+433y2~5Mnn6wQ9k+Tb;wB%L*@Z%%>}>Er*56J`WLi!tv7Jca zIOf^vX8bck3EQUF52_%b7~pxIYJ_9NH>3m8q>Rg3>7pxMMgqY*gun5^uG*{J33`8g z05EfOGctOvKjd#sTBTaD!M7+W$YJ(Zbpon2x7qvCA+1( zBc6gNa-Np@F|Z+1?TQXh!B(1f0LLk2IC;^e;2!#AO?K7Fr#9mBanBduOQXGL zNWTmM{wfGckY;c6r}_Pwa%+KFi3A52(Gzd0p7cJKi&*x^>Vw))EvcyZs`Fp{;RLRf zu}`$qx!1MO1G68~cge*%iA5+7ynueB_6yOo?0?kDC57zjr!W4THhtb~OIULS5k|Pl zG@)S-FDNpk5?f;A;BJLIQ)-9qxYLs29D4;XvyQ7v6Bty2873RQ5*?5Ovql;1wVoc6 zb_AwR>ZdN(t%e_H{@?^X?Xd#}J{{x4D`HR~Gg)NkvAK{HX)Gr#({@E62^zbFPe9Nl zJ$vxAys82`EhCI$TrGa>H3Rj8x6Ii(Xv6Enmf}F}8d{WcCE%tdM`&cU&_BwpRQY_L zbr5eLFB9<8_!iGDoc;WT#z$!0)GoI`Kx@RW?Cs#;l*;Lb98Ar4D~9-mAt5n_-n1*u zDPZB-0+x?CX{m)D({{eUByw${->|FFX-mLKi~D9S^WwY|J1v=n2S58rNH4r-B`Tt0 z24FGWwdlCzn;%pqky|tq^(L}>2C%{UncG)KVUb%wx9`_ARQh=^kHWVV64_m#I2%8t z24TWD=OP;)*cQ2y?9@<0Qddcyh$W%)`nk(69R}_Zd14&PCR_=my+Uv=T_zunjt<|5 zjG-SE+fzsuB|aB-(@SWet7M(}^b>vPLXi<~_`{%zwoIZ&8}-h6(Vs`R?xGCqzKsV- z`?#1e;snNzDh#>fOm8X+Cmaj-B@>XSfwj*G@}e^+L;NZ5u=!MO#4M2SJ*`AcPCEO% z_dd&nkGf!DMw z5;no6-{Vv@)w|d1d)`*Y`kTMyA+%$~c*&1t#*d~61^6&Cw#w9SMLq`6ItP_cMvMY5 zgc1_0w)XZu>^i-=|EfQWi?+Ds-u6Cccrhp^>{(#D={{&P5`F5=<+rg@|09`zYaX?e zrT7JmJ3b$@>IE$Ha|)A~otmveyn=peMa&m7S(PRF$6XZ>$j%OZcJ+Bt-gmYOnUtrC zr}3<__VlmI8FVUpv^l#?*}Hzu1}{L>GJ(J$X7FD&Ot=iugDIUqwT72L#k`nHSLsHI zVqy259tJ=-=}QZs%s_DBy_P)}4d}7=Ir05;mhAmiKThCz@pH|S#fay2LhED5{h=50 zE=@&qyS*~Z;VC+}TaoA^Gn^GiLWkcA_+ZhoZ6M66L$b>7`M=SX!F|enVME=(^UO7l z9xr>d`WHs9w@xrnTu(O)6kjCW-0URB7GAtk$`&$QdGJb?&EtLh(#629YPy6Np6eTr z6N{Fk+qs?A$Bw<&n~V^2BfHeXoD#00zBEkUzT#qi}3GPzvyrIn1}31)lCIVk*xz44#87}hG=FOI#j6B*B42}96k65!b9^F(&u zKqmUyIVFblmO!W&O-6YHWSD3i)7GwUjr-~SThjJwQPTB?<3HvqfiF)3Hq{D8#_Y>u zrmU&h;x?_Ra`MT9zRO{zdmim{y9gUvFFGq1FC7ABmAz#Qg zi^n#st}6mjSDvR*ClVrqs_8|w%8fC&!!%wf=~O z@hrZ7{hIj=F!xTCSvFLe*Gs0EAdv#pQB0r+NpQrA^|w8PtbvSP)ziBzGw+b(xX-r$ z@2HIeS1yHa%lYu^~pTVayvg8BiG}Mk(;F%A1FduX2 z_r`8gzsIEMm3UOOv?i?5G)Uf?nLEK=%oxRB-Cc8kWclcGBqwW}%4CD1W34z*ut;f9 zs2}nBT|JqnyT1zKYYm@`668!Y(g@&MUx&tIP5(4gJ>e;LPR?OwL~J4tbNtHV(HutD>R-5mbPi^wVMhfltFhdW%PkKPrn%n2tIZZ6pim zz?9t+^I#<)0FkK<(}%(q-oeBVYeZ;jTC?$LL~>wnBx)AS&2iuh2<_>q4_FUQ_GV^0 zKDSg_3UJKAOyCDOL3XCM)dlm8;n&#Al5!&Xo~{GbpFxBgWWMbJp@8uqGIyl17*?*X zQbGu?-Lv)qBO0{=u@12>YU-8^TDkAG5Jf9WexI}*o7^Pw=lvOzBdVsqu*4d^o_8=H zF?|)v!om6~EvK6~mbII8l2y5tg_(FRsmdRNWXvBULO!x%HB>#aVf9&efH00{N0?RE zvRUF^ed_+RebdSri|QH0F|zuq>;^I82C-$%`N~8Vq!$5c`wuot&Q0LG>#r286ze-5 zvVA2Ql1wENk-41==U?uE)_?wZitxZM_?Oa`@|KdWT5ku$aR?TFq+`j-igA8t3`a)N ztAh3Ag7s<_WJ-G{pKE0N5Lwr|U=ztByIspe%*jYlIdID&&H)WQ<|d;fLo%ASR!M{q@*2C(`MtolT5#yLP;Ra@o3zJde|(k~eo$t!F-S z@3-E*^^P@$hddZQ`{6$poqpwP%C6nq(dohvFY_Vz6*N)k=fh5OuswDb5`W&dzF=uf zF@!y$KmomIff~4jtCj$$fbwPJ68D6`or8Y+^t?Kg!DuB?7|v^|mhzEm6rdX~+G6@ABX!Q{k{==hWTaMaH9dOO51J*KXS$`2nGRfJc9tFxxl8Koo|ugxzF_?QT>QCesiXTle?jH+kYW z=693qBi-~ssWlEVd=Yug*Us)O=H6`-UEcN6IH@Z%SGEVPR0bbLrt$s(PcA|E24Jo!`EiEd6reS02Wkco2Xz1t#|m zWoIjXg7de5(>FxRrAaI2GiHe9ffsyqEMHVOKuzQgb5O&pzdZ-2JM?%=-t@kLvp=Lf zY=-gY{hg7z4(pOgs=o7w!0k(;&8NIIv~nzsXH`NslD@6l_Chrze-i)~gD)WZ1Pe+S zsA$7*Ap5F>p-?v|Q#jd$*`l0)hQw`e5WAp9o0I?GN#fn3U5+#F^n$3-5MPfh%@9Ar zAo8nTuS)XWkhT;m#+w82aXL#yq8;%Q9r4E;@zGZ2%FU%Hy90t4U!(N)81Gaa%&RnH`If{0#~kf*3sg7euP7YEXeW~HL;E5$|D{nT{eV_XF;8&h|$f>6Dle(?D0y~G#^g5tt5MCD8*$sz%UpIuV_Sp z1sxDDFPtweSSTwrrs}YfXpBlNHgt&SKde>51Vl*Ru5IJX>Ms<;9JDd%f@g)&4>R(V z-~om4#Mg-=cWtMXY$ZVcG|+$%XjEVHpM8;Xk)=Jsxfco|BqCYzSsV)%9uFtO8%m;k zev7K|^Wmr}?sZ_xoG{qwmW3maeuHV7!Y+z%K~nl=T)Y%szYyB}J)~Jbs8=;K?F;sQ z#L~`9at+FIq>JJKoi|>7)I#+t=<{`sHU~XamnC$AC6sOh}wwq+Of!w@>QL+@wk@9n42Te34O@!$= z^WhTWLKpWSpr1aTT#~;_%4`9qZs5nufZmB2KGlJ0WaI73K^obfV!6uBHD4dB6U`2JDndaL3kOR3 zDpB;P>f81uO;g$|&NY5pOSF@y^*gqOEmQQoB-+*V-2eFVKvAoWfpzR(o9;=dsV7rM zG?R^SOy!dW6!w^9lTVZr&2mO^0LXNdbZT^R>*q@(wo4>6OC-!`zXChe!$PBqmdBBw z^#!K(oz3KUjWvwxHO2Wg`I)qkQkfjnn2J-rbgy|$;fGe^OZ~!^s>UDD9I3{~in4~6 zM^|4$`3~!9M!`j|a18iF;8#~lj7K<8*2cnafe9W90!ZS|O=(TZ9XKP=;l#+5r>~yM ze>zJ9ZPxj*W*oY|JGH!iskSQgi`UObiWq$!Zze8{8HHac!VAQY;lT1U-3p z_u-cb{G;=8R>@{i=bwCMg5ZsSZsbvQf|HR+QTyHYSF2y|DW~1;QKjaz2+b+5cI3}h z@@fH6r&#Cg68yUqww-8g05jPj5M_dxNJNxA!L|~D{ez4OjkL+9RV?o_eYk`%8eH&k z&Q;0ysdUD4oSi#jn|95r88=H;K2y@m;(I0@D!=pc%y~heC=LN%Rh0hs8EgE1JgIu$ zuEtXNidoXrRL_j7V5Sx6Un;Ryl2)AO?3FIo;@YB@^S7ps`g}61wkAY+4)bp5XD?No zP*;!KvV+A@?bm-jnX5AoX0r|Cs^!67^N$@fVht%l!MeJ7YRMutqtX*-Gp|~3MkynE zFAQuSg_n&(n`YpfZp0F8b0XMHk8)9xyzTTWfki)tHI#!v z2Rz%wM$3eqqusSW*;H;wjEQAIgH?mQBNFL2`l?B5(e$}E+lK1cKGCchhc5FVKsscS zL0iX}U5E};Q4+Yy!6vgYQ{za5G+6i*S)+s@U&xTrm^x!vl{4(a3a>W^&?OwB$6}5A zpYwEbLoK)UB!0#ZVB_@Ha?!EBb?5UEpZqHcX|dLidMAEYjmq^UqLwV!N6rOH(c%%X zROFarYt|fO1YQUj{)mUSSLq6wmEW-|SHh|R|5;Q1_ZsK$X!1 zSRl!s6C|1y$VULLcd$-J3%c%*etqs4M94A~wJZ1J3vDe4a_qQLqkn3am#ioqzN&iSdm&~0KjbGTFzjys{ANO?1$9eb{ zatik^8q}A$`o(*~02@|9eM2^1f6+HEyM*gMniM&+W;sHX=*2=^@kTY-&NZxHd$%T* zz5>D#SV2r>SkJd5xSbF&6HBv8_?O9+?H-$|>#C6Au+k4c=7o#7fkL z??cl$s=zz9lC(@LTLUuhW!NQS<+Q5htP?B0Q)1VDZzMBWVx%r!VvLk)jb;}bPGd5` ziN|%qP##NTYJjX?4XI3k8IsInsq;uqr9;z@PW|xEGRSV#M}Qn-whXW;m^nkdW6B)N ziJ`@a^n)?7GSZo|U0tR|T}EFz*jEQ$2(6Y^Jq;xuUU39LOLZOvSr=QJ2_W|vM4y#q zyI*7587gJr^fQ=x-}z7ShpA5bTuRAWro>mNo(W2Hy z>v~u+4cUt?<^N*=47C|NW*CB$x;+@+TrSBSd9$et9`2Pv?eN8r9Gq6GVb&1ynMgMI z2hI=ZwH>b&WeD|#2RjUQITQ&Tc&?Kfs{k%s!}^}-8TT3ZHq1h$$r_bo7tjbeyV>@| zsM9BakVW?=OXU(M;$=9nFiH}7|IyKopk4A-Xv{p=^X3rxeXr0X(mr`wKmGYb8deaU zzZw7N8)F{AKOWrT!5MB{mu4)JxmhozUqjH%44EEc6IgYB>+%3*-7IZGzZ!TZ-Y_T$ z*cF4fuve$k>~xCp&>->-89GHsioA##jOehIqh;E=n4kf^#^c+?&n=FA(Bk|RFavsn zdEGmY-DAUe)gD0-D}pznIA9;kd*!jj#(=FYZv(#8u^~5Q*J|TlIV7O7m+;eBkL}~U z_Un^Mzrz0Kn-|LG1|Ra9iqY8hjvo$uH~rf_sd$fvBU6h#Y?hs))`z}+`WZ8ct23!w zL=f2uI)=&qDu0`H?Xh$B0x1%bvuLWaX^U!Lk$O<$LSW}ou(>nN^2twaOA8Q{g(d#X z4E;t$`H0Boigta>Q9OPO5k!PPQ?5`HM?7JN?PI&OR8HkT!P?WP9Q_q?SrttcGXo!C zR)_6AKkT~%7e5*pMv9apCfReJ)Q!86kJh_OSrzVAJ6^O-ePF{p7FzW87&J~-i)LWK zzz@d3`e+1Wga~zRtJaav@3E%MQS|LAr+YFG)gQ_MoElq#K~06yJ0GBN2aNw}kD;16 z$gBb?=D9-(HVazpX66zf$982TH1q2bnqUS4z)>deH8Ts*F}N67RO4A^+Qz9x?Sf7A z-R*>$WFFnPQG*-uQPA{Jn9mSmLVyXh{*imdIIPe#VXiVI_tpDJJ{HMO}sQ7{c z%TV+fwSpw*sVnqP0SyEV=}}Gm?YiirJi#!MZ7cLQON{Bo!M<)B+V+0MpuQY}ENl2s z>ZEmImvh@L>ajc-`9gtY)f8>qBn4u7_i&~(FmoDM)tD{Km?_Oz%a|ceya6{ov`TZ# znLT|DQ1xv-prYWJ6+f`4B`fHcB#}6Aq}#N~z6?{DIG!fyI!4rG;%u z9MBosfq;B-grCTqQHa?6deWYkeveTcZU{;YK>RPwQA$cR7s-_p30iz#gr7-+8JI6$ zFPGR-+P~P8uln;5Z2IE%{^4ybrpS5!nq89{Qnd;Uc5Sn1cK~i~#g!>l<3_K_4!9QGW_9##>fW_#S(p z37Yky;P$d&GuNiH7$tNnc#<%%El9Z`=*DbQxn+!&zen(9CcNDySodE3eYcgfb0wUj z^{GK;t3gAXWJ8NwNKH#LKHZ#@ZH9ywFh255gqfT=*pB=pF~-T~ zp{_(v;lWpEFW|FB@h&tagYU5pT*gJ*;=j38{S6ba(Bf&4$fozb7XnZ5&_A~9dY=OP z^Ts~!r|~`#3TUqTee(uBuXNBp(?}vAR*QPq%hGxTP3YvA+krxVlu;s@k6c|z$YQJ< zw+8^cv2n)Dqc9)n$$u8H*;5rvsSCzEJ7FYiS#x3kK2S5KXn?9ef!Wxyr%aSrr=DC>D9P_|GJw=@-s*n9(;IDP zJl2r&jmDqQ8w7?w@--@MmvJ>Z>)li57VQ^Vr(F_DKHiU`{uT~nq|?T#C=KAD4B^BK zB`FN0{T|Sph#@Gol~oWjDP7aHGN#@j;0R?Ht|1FYY4lHE^s9>07Kw1AjRSE)2QZ_k z(8C>#ggPQMXh2Ovc&bhRbuu>JOgTWxVifrNK#FZKv4QW9^#wfk|1VF0hKgTI+dz^ zVW7m|z;F|s1@uChY=$^6h$tkKp+|!oR1QJBAH$Svh|#oZX$kWaC$l89uJ8X!F~hm% zQAj@Yde5S#7><1)p`1*vsn;s*+4MSzy0NZVbn7iwW2I_`X*%TmE>W%@4(BowsfkEE zZC(>9)rl76*@*`H&Wc*m;;5K0jg%p9ts~Q*FH@)=-Y->b7^)RkrX3oZW!LG(jvq5W ztj)aVSr{O)a(Ftil71u^KZ;{6TZB}B@}npc)EKFnbm0J>WP&ZFDP5x-O77(RPa{&Q zG163`3JwJ)uR$tx9tlNV?wA?CjE^}BoD@kb4*Cu_ZmFSb)?b0#%fXZ8?;kDpH{sEI zBEGS_k65>8p2I0~417YlU%=lm?7~}Anhs|-$^KDaQeO)lscp65M*I2E;RyXDOx)za z1h$%zpL|hZv&IQn6O4XFk`3Y2%C5~`{T0m;zPjHb%oVc7t%z5in3FAG;jI2M43e#F z+X9zuqX)1vYS2ymFlxVQ9#$6ON3$Q?5SiA$XzEh`!IUyRMh#oo$1I#a9d)lzOsx7w zi_06IVER5WkxUR-p+`SYZshZ=wOE`VJ3?Ju9m{BW2xayz+vR#O7KqNs&sVnLp`y#-0u2?N}E3b1=%!-`Ry<&C*Y{IY1wwjfNGrwt3gg8Lh=cLUv)-U7Gu8 zu3vdy^qn#6^Xc{g*gn`FAQ~IsO%?fwX+L^;Nt1cy{W4gVS{qChj=n;j*|Q| zp(coSP>GM;)~SD-e^pXI!##;7^Yp087{du`T7rzbL8nesC{_sH&Vqw>%vottGx1-j zaJYtbzBqj-`3_uLw|+61M6z-G&09Jtjm~2H`q8xcSDmlhZeCt14;l>}eFbkJ5GF{;hG4SCItHMoBEJyGNBM^R`$$?)6jqg3e|p5<0{|5myD zWL8Pjt-qYlv?3cPqh=x|)W=D6iGu+v&5krch=!7gl>$m3yKN8dCx*ygk`{gn3;J2) zwf(G5_~>%gUAdS$R36u7B*`>x+yHq9grx-5!8i=m_f)8=9$>1{AHCioz)GlM)u9Mt zW(Eu>A+{^_7?Fou=9~_-?%ofa-wrAc0 z`H*UPzfes!tiP5HSzd1CUk5=X=Nx#hd1_q5rk9M;pn5|Ek>l^@>9ts{WLfMR$(Vwa z7mKJ2*o`F!+@?DZ&e27fRL7Q;EY^e@M26;IP-O(_GBVOEmjNXhgUf&rpQ^-^%#^~I zC{^X~Uk&s3)j^%Ap>P5Tp^d7cVtr7>8@|YV0Q)Bgw ziz{yGEEbSqZh_jMB-UC_=zb>V>TVC+xF#@Sd6bx$C+X~t!OT>+3V6|&a~acv4tde` zs1NJ2!$W4+mWM)eN2bIeRD-HLeW|!k!Ine(*Pe@gwg-&E0D@836O{?*ZhWJAcB% zUaCS}1R?Xk_BPyiN$CVPPB$f*vv>T|h6CgyF9Ze;eLl9MeB3(FlQ6rJvTyA6KhvXF zkox+reeZEuAn54{;L6`_#m4+?JCKlb>ZEZf+@J)$`J+A_ln*7}C>DQ&jz+Hx+YG;v zr+jtUAWAj}0!Ae%5iqk6)z90h;^yHg)uz*HvA1t%2X2npBj0y95))0CU+bsSqLrx= zMUF}dU`S#ykgz{#D8k$yRT*7MZMMv1OzSqS|J1o?-|Q&sCe>>JM{H!EAilUP6fms_ zB`u`oR|LeKzPS9sy*)1}Ip!srci=Uhw;x9`KoFr&vb`sX8%mN3+`{ZZvtl6_Jrj>~ zi{&ZDgw)MqZP&(n^y_Ox+asWIW}72Mb0?Q%`UB}J2EF}o9OS1GHTIF^^T(J=SA@5y zS*Y*T^i)J##2JxD!jCir{_Br~k#0!1V63-bZN%Ms7v62ANUq7JDtZ;|i>~APv=49h zE?!6*0>l}`iP8mgoLC4DyAJ7hbG3vAV#9+Qw2#~=0hKUOK)_R|szjsIz!9zqG(4UW zpfHu1eH=i7Z;s6I;a|Q8oCBoIQED&)=%#Q9Vi0t}Vkk%zrU$1r<`Zk1JY0}(^??oc zlsi9J_h3me%iqwY9hMbs$8kPvMNT((Zw#)xN`dFvxs$_>;U}Sg@d&0acecoDzHlbU z=eo%)I#Tj$5W~qQY&g0F*fQ2U3%4{J+$OR^-YE$Z-FnFp-FR7XC|jPQB)(1^O`G1j zJ#`5a=9A7XWXzcY3nGl91I6zdiFDbpXOD_xsS6?q)RePxp-i5I35pVB&-jZ7=?>g* zOBktLaj;r0U>V4B(^v@Lz<+DlEYE*_$$*P0F@#*i{=%;|kLNAI)xQVj1oA%hc=mST$(3-|Bhbv0cYvR zNm*E6=VeLTdLvx_l(yQf;f)f7hk^`-T62=Q_M7OqeDrLh>afr(%9Bb!>|bf%Lg3&- zCV5k_8VPda!UIbd0(%V!?G&ZDlNlFfm>_v05gQ(R_Ovm7${>idDv@D!V9FLYLQ;E_ zk44g7rB$`?YyNlcc@zYF0?3qtV!MU*Pv5Rrxm$*`Hmcqfp6*%HhRjcAoU$s0)ba}W z<9PsztF_WCmu6yKc{7Nls)|9CIZ{O#xNaZQASuX8G$tXvIPwrs#XYu%92-idfQZtj zQku7Yp?&8u*WY~+S8}{vSZFgmQTzrIjcBiyzI(2p-ryx=MtoOuX_RX0_$wCy4;fPL zo=6lrUVVPhqMz`B+8{9LMe2_uw*99|(KxWEFV-NT=xR77+g3Cm+h#D~17lI-qY8sL z3Sa8na9XEJMk>QGav~mT%Ra(i;mn!Ue~ys+L(+jhG)P;YL9KA3PY%&%|43CCt0)>;3CcQ-}4fE|kE_m3#sSN}v>65Ni)KUiF7o0@}5^P^g@G#}Q zpY!Tcu{%OT0?n;j{+-UHoemiTY9D_26^v^GmXlQ>XZ4bhz(4x8FL{Dj%jx_H*8%VO z{Q@dn-g4{fwE27Eeeqz&BvSKll$=HAiijb{TpoSmW8E*rryiNn#WqRqD+vZWYe8& z&J&(&Wy%QAfY;;0bw{`DB%`i@Z01ffB;_Y;T6`I0C~MHfp;&Bls2-wVGtFHBag%`B z!|(qboZ(z}>6&IUJ^oG}4G0TRNS<`4oT&lTYoKa(jF z#EgWMM560b8jDNKqacwy27MRC5|6Agjito}swVOgdKdR?cHv>QBuv{)$F2Jbv5?Nt zs(DQ1$gImtvy{`~MHeGDU@>9?+jJ;93 zX0PUysD!ve=I^*+G!(J3vt>N3Ns_95j+B>&aTV6gy084%o<@K8Wr#4Ny6X>TImyJe zNS|`1{Ea1*+H9#QRIIvo^+?aoGn=I&hovJM4?VkqFS~&!yJ49WCSCW-U+Zrz^c?9- z#c^LI@hqKm_>`S#t$THfcdt!yhND;rQ15C9pR;U`KTfm_)wr(|{>SS5Z!d;U`V>_{TDYn_kbL|80c1000^YSU)51|aUyX|W7ggaN@NTNV(r-@(+;-qJp0Eg6 zI1CNrx*detOk(%F=7(`bFyq>dgR+Z6`!Ei~8Fn#Kq>KO00MHk(1{0mYHBvRCJDr>f z22GH|+C1ld0|$C>Q#ZA&rvPGRp;$AXwvQeIDqLua+&j{6csP8>(FQ2g<=v=(!SD3+ zi(@J`XAfSZAJJ9~Ey6(sDiw3z`oFyjcyzJ8*sZ@GHhp9&O2L+3znz~EJtw5m-}b1aR^9~sh#~vT5E8p^DXwqc zyIqD-6TxnpWzJ}gW~P(Uaut*n98t#C{_9r*xJ-^basgx-NF_okIxF2UBeznoCOf*M zO6d!|Ks5U253MH6;8#y#z07cA+(k@9vJm!d@4rQyas<9k9!;5Eulj!RVMUEVv1COJ z4!VOA+Q9b557H;lg>%u73w4HU7aisZIo24Bpu>>}n&M!_J2_~u_DD#xr$*w`5%y7> zu`sQ@vS8Bl{+fGnFtkw!_&cgeQ0}+l?!eYeYk3%!>>i!HZxE$G8Q~1cWNV$OP^B`U zMU6`wf^#i_6#t4D>6(0+RTCM=S|N1*Tf<)iScJcg7$U3rQXRk7tfg%WHHws~dr%&% zFaB6ZPkx@QirM&iMK>R$M1zVbd$T6n)Z^#vnW!@eylG$favXVb9C>pZ_!x+|L3Z3A z%71Q|TAb#VQgh#;vvtldVAg8rS0;n!oz93eVaypdjyaEYArR!mU})Jg zy`dxmNL8D-UqyiC*^?#(3+7dYbeVobP#6)UK3A`&-Pi3au3$pZ_4s-WyKy>ZjSf## zLxBe3xwG|9Sqr}1{I+BVz!x}XEq)@SbuDoHO6{-*ullACPskfQ~wkejsHqhm`0nffz|a$x|%>; z_2fJnf7v2n_|ig`3KgE(MF4D1WgK_)q=tfMY@A0J56dRsr`Pi34DX@>{TA2V2L*wV zfdEdIW`TOvmSJKCBf^!$^*G-VSPW?>E*nvG*7fq{)g>5m7f#39BUKNxIwO@XiuLqs zYx180qdJZWq>2g*LOPTy00tfsQjyYOM8i9i@INGCO$L*WZaZC%uRRLN{BrqsztK6! zop1x>3|mUCG?On&^m0|`7QU{T)*BShoZgQsr2n8Ut{BMn(@p4?iE^$}6{E9~cca63 z8E-n*#6IM4%hgv#>cDfN`44hI9<-%=c^2|*Ds)i|7FGhv$QrXoSg}S#Mmw@1MyawQ z0yBRD=b=Ar2}VLujCfJ?Xkl$=VPjBSXkmv+hcYJv*(-_W%m5telOURj_X8I%GV+zF z6)odA3$W^-vbrI@FrP#|ldRVVS?i@r&yEtppb|ontvj}7f}3!pSu;PQU?i5VxN%bC zyu8@F0OrKP>|Pv{!@;Vx{PuuTxP<_x8|Q}k$)Lh`gWwm1ZiWSk7%mnCZ|*Nxxk-E9 zutw3_PGib7fN}{68I_Y@TLQi4KfkbQsWQ)gQ#-Wr*tWw-xerhy`;Z!2L#zR+8T|dTa1e z!pFzNrddV-59%IIJy-LLia9I}o?JhR!Mh!}jUy6hAmN2%j-{f`^`t3p8sBV%B(Kvp*RW-P#NZ@H6G}_b}k|_j4okcRzdx zfI ziUnz;#SVIsQJrwhSP@SXhB^Xtk2SUJHMBxuqTzpm2J(CNoZ9|?KYm%U$p!;O z14Zf?Nov$8prei-K16KKOC0B^LPJ`aNzimyh+G6g_nx~~uhN#VM$F-2z#vD#I4fSJ zk+0DRc$SbDfwCc96%X^xrm}`MDw`D+;i5dIMf~q5GeUraoVL87y!&(S?4^hQ+~PM{ zJrvFX6*lK94luu|U!N<{m4`UZ7#?Mda!83eNe#^c$kkW>fOQ^!Fd4;N7F0eMya*sC z>|b0k!_ie0JG%79jMNa*MiUvsK=#EL&F1GqqbF!!7Iz~qz0Lhu0xFzwwNRukL}}R@ z)YbnmrJ17Rs%EZV{1tDL%4{R=RBV1b3t0Xn+(Mw)AEOS7f4|1s76vp^aJsh!>UxW(|${ zZ4Hf8r3%;$)QaqyeeVRN-9x(vn@TF%6+r-c41d(Nm* zG`(oUnp9quE#hbnwJxW$eNc^-mSkb7PD*8E$RWBqcb-gaK&fUIzfajiAD*9V)~Z3h zIF3qLo-uBpj3kzuN{Dd?iZR{Kj8p3C+|~!aY$V=nB%bVvRz3O_J^D5s%N>cTC8 zjyz%%xM`piAd^vBwL`8d^oKwM!e$(T{`y(4jHDAG`*7j^rZ(Y&@(uU74YrHsfFUs6 z0*F6nF%@DNA^s@g6^x%F#E)KzDi&V>G14QZ81I;bOZiP}fw9K7^*hvMdzB6csccaq z%FGjGqiuuqO+J4?P7ZFV z;{az^Kwm3l_VsaHPX6`|K|^=jbYE9jcV8`1*pDCmupLIsupP}Iv>l9j=O>ACp{xhdA?e^S3cHg||+;8gVAbfc- z2z?iaX6oomMn#J|X2+Xpu-&L&{r|B5%Bz_}6j#H;g3sDYNIteHMAPPB=p6EUDz7!! zBT7zUOjuTW-&v?-ZS)abTahcE`@0!rB6o5_GbxWegk6xOR$!MX2X4umfhB6O>kyf!!Q}Z$e4VQJGW4I$ab{(6%s$unLc-`|EI&pIXXs|iS#2e~A z-@P1jj=UBT522@n({glH4SvMc4dwiKEDqx*Z%kp&^a(=N=~GEOw7CKu>I&<3VkCU8 z8{bbOy*9h26*lN4R?)H_-Vtai#T+?YroSCu$=cZj{K(mp@QXsq7{|Dhj)>zERJPSKVAkRn0WGU>#x^I??V z;c^dbyd=k=5+PAw^vEWp^;1&xQph4frzSxkAw_q>pzfybQeNI%`PWd@u>23J6MlwO zmC|mb#R=C|blm?DNLHt{LZul-!svFd;9#)|nq6ZI)PD78y90^C#7>EHIPCnHHH)@_3 zM41)LK|b!uAFI|+F-(q$kc)ArLwH0aHyFqY>u(R4EOppzLAB+tB>X;lFkTe+y6Wkk zF~L~~5<{~WNj4Vq2-=39uS$g^y;X)r)MT6g!RnM>ML_cN4V&((>FTbldoa~ALj7qd ztOZ#^H4H=wrLOQx8ED{obK9_nf@El{k;9fZr*X?(wtYNAq@My7%pPvS5lfpg1msnw zEL6q%>LJaxrH*V-tRF7Tx=16j5K+X}l5^eJNF?J~BPIr^P^<=)Gj(Aq>3-%d3t>x~ zb98LV1LiNOMuYQ@t)q_7O|x;ie`q7a*uUIU@h{Ee-i=(|!QSJftZ||IE=vpo|I( zDqq6;f`Iei&w(7P=s!bt1374YGC)?jepj-q_K1Gy8EQ}k8Oo}@g#b+Zt&<=w%zwsW zk69?mHeO`X+}fL8!LE@AZ@Gu}3-RkV!{+bzIzW=U1N@|=DR!yWT*XC(NDLUtYz_KC z$JrZUd}lx7KWEJi6w`y8J)K$>F{NMAOfZVjXLO~`K9y2`ggMsB@z3EkeqE}+rISh( zIPFc3JU`*ja1c^cX6HIb+iRMF-dyI76(aeuS2vc{(d~qP@zXHwm1Jc%=&ze+rPo*T zpWA`s*?fDGW8XZxytwl1HlvSn+QDIe&pkVx5Do3N!&Y)c$8zGjuibCyJlnl6w{12< zFi9T4C1dYTEzeLQ4#JUaq?im`)4ye}n*WwOg=Ol9NTddA_>%P7h=lC$6^v2{?pnd! zN>K!~HMK?FMD-;&?BC9suz?<|50!!^cndjGOC7O(*nCUVv}kKF>1BxORlEy%i0sms z4M)NrJkbn=s?eYo<*JEx%W}o0SB8n`KsLFw3fErf9q9WnT6Guqy~QhpPNP8@y@F)D zv{&svLA2FJAwy98G;q&3y-QuZMpwM$yL5}8WT~N~cA!)*?QZ1~fU>>Qn#U8eYeyt@IB)Td(HPUQMRZsGp9302kB9xAhHXqD`sm~8mpk^LnFYo`;ePtF4o zqHP=)>4!}~RGtMm^CtPNuer12$pp53gMW}@0ctZwrQ6S{6VEzJ52)1z76J+*;{NBC zu3)|zO|#&zRGdzesm?&OhfGw0O(Y>6tNg@%;LheuBxigWX~o_o#a#$$INTJmEeAO& zKLQ5>iwFB(etcRdb&Ih<)s$QP?~1POLO07AO7?~2A-ax3ZQCvLvmNa~PB>qU{2zO; zuj(FnD#k=~oQH69_h7QM3s@C5Ze9qj{Z86tz$O)zf7Nh4vIscCb- zGeszcY4~u^I{!t&QNReQzDOV^Odv0uBPo=UU|gF&);Itv#E|VJm(^9zE=H~~ztm0l zQmXhKC|=?AeoK$0%6$BVSp4$%7{*&hX8tQ@a9t6lE#c506z}6bi=Ya*q9SYS^oz@~ z$e8)p>pvIu0ZMhJbG;r`Sg?>&%RBX{B4qofoSzv;hlh7435}x}-I8mNs2n0;*dkX3 z1sDx1iPHr#PE_eC%I`65Ay5zP@kP*J&!{7DO{o5)o7jPi3d2AyHZ(%M-@grIF>3wW z%oH*s&!46Y>z{tpoL*4v{>O-}ZuLu=H9W|kk6URd{6spUbq@7uI`;d2U6!lJ*Q;KbR9aQPd> z3va^uW$a?FaQ`ciOxTl!wf8_!-~R-?WA8swr{ks^$EO=T$HT++yaOiyRK(@$r68Q0I!D19AQ z=DuEoiZDibpE!MjS2%sN5B;GI5518EI6g)ra}V@S&liMZZze0Ko+kfz-%O5BpJ+Hf zVf=YMh5cLiz234jg@SixL@@UpEb}$k-^u)$IPS?llud2~-nI^0p0*B}pA24+{CE5b z`W;xtD0K6}f|N}lzU+3?qvJREA9Wvi{sul|{WT)d1>ebsGRj`Bb*>G4Q~OCTk1j@p z);6v!{(kSt?m}jxtsi%ZvbokgV-zNTrzDRe8wvq4IXYaaZ+__@@_1nzsqKU9SnI~* z^L*GPc~pLzXoZdV!qqV(5~pZqr*CVw2c!7q^*8<*M>@O1gsHu7OjaY>I+Z-P>|Q0h ztQt8=2|JdU{Xl|i0pX+wX7N|$(5~|<4;}D^eYj-~c3tg$g9CAx`7L{F4gyDCBSi`6 z3wuiu;`?dWyw5hTYe75w#_U???<3oR^5zxO_s6+muN@&o%f>n9AR3fh9!5q=t+(L9 z!=&$W<$5tW9jbCIwtL@Jg98V2Obc+- zWkX@yrFLhq2UiY%Q-tJ)o+sbe3)kDqXq!t1!iJDW!;dJmv}It`rh*yLzzj@WOLYqP za4e^xnNiDen-`jo`)6(K>i7>&Qnle`wdHWPOREmKKX>y6$2tG?G2DB#td7%5X#O%; z&aH0*<+1$$soAa7>=5v5*6g$XkTQhkLT%ySW2OHx$vJVz!7M~Kf_t1$S$ph@d+glV z_}gNfAcgpU+$ny};Ct8*?VXhfx2>;qEF^M`;-V1GkN6PN5+V)~;|5(&F$6;t#WFuc z>AA=8lq|oh!4MgU-3BsdTQR|YP)CkehnU6_^WuLGC#i#?B*0T_AdFF9({6Jx1}QMY zy9i^LQo~3B0@VsIP3?ckE{H`Vk`en>{^nS9Hl*M!*ogUd1Pg3|8+P|)DK7NCKz^5|__nA_WXKet2afs8OjyGk5 zIr^Q7xPz2KT)e#->iQ{2Wn>`4M=1De)(F^MS2u_VI7%2hPKH$|>+r#ygs6gnE-&(!poltOmyiN7nVk;64E-sE+Hy$u81czPESP}%U&J$panCj@IE2ql zTWJoL>~9FMe!MPxu=tUt|9IIE z_>!R}xfq-ExfrZ_y%?^0y&TU+q!`JMARp_C zpcw3vB_9nMCm(-K5RJMm@I)aLc}8RPe$ml?yK~`xnz`*bSR-^gabeqUIx-r>XX}Zk z=(!@n=)Duf=zpX2f129pxJmQ4D*3T9yj0&8VPoh+vC{VeT^I09rT;lL-f{g~#ql<$ zVDB%V$S6yFK(wCGCtQ2q1G2r(J?`em6kW&rp^D@9G{ydGhR9eRn}2M#;S-Ul{|8l2 zcfl)?sMiD4=Iu;G$I%I<)8!(?USEaC$h(Sv;A_DXL{;Sjn%wscR`}@{(errW@%oAi zrLOOvA`XqCdp) z(i?GZ>z+5i`_@i4V0^<9{Lp^AXXgMO)!P|TZ0`xnaPUX1-+ZGr>^%9_QzVJu?Cz5TUn%#HF`aCDd;ThD$ zNB3XxL`*DbPEqx;5tKNY~aS#ye(d4mPJ5%e);>TsEyd6o1vjWa~ zTJq%drXi0b8E&=;Lq3(;MDTTz9AQH5=9jW;)y!}BHscjviu7GQ;p<=z^@o^ z-FA@Zyt`$OBemA(hPKQ?#qK~JY`h31!^bG)<><%vvSKIu=%v^AzWICAdsap~mCyH6 zxaM`clmF4ja{qPbnY`~c?{e4Soe zwJ`#{*sGOTV{B8Y*xiVTddNTgG6ZJ6%)kwmqyaVs%$9hVZ8U2Kn6TGjyEk5V=-S2Xg5k9?xNVDe zyROA^r^AJ!fkmoBrb(5@CWFb?2rCV>amO*!HU-neWAd z(1!Rqf*>k{!x)GN%mfgF#Z?i(u28gOGKFF~*{{Y2UH=2p)CCw`uF}7Zjn6v}$@VV< z8kRtRMF^4MCmL)68`~0-jr{%ih(B^?meS}?$e(aF=xbL_aLW1Ed<~Ca=jM%8!scEMOB+nC3d=_x|BU;z5 zJPsteB2wH$uqG<@%3_x~>A}@O_*K|EVO;1zX0@C_)l4UOksw(K zAy=pBkaj$LEcBvobWZWbDUx< zo{nNPzJh%Ctyu;1@m$exJ8Ic*TV~mKns(Iq+Dh1X6qnI>RQsdh@qDG>af`3v^1Z#` za=5+mv&5tEbN|tCcM;QZ_ZHLXgOFnXtzKjh-Y6g%)&E6+^=*x?b7HZ@hqS*5E%-3;uWW@Bew$gEDX=M6{n*eSq@Mm#+R_Px*+@bH-JFORc z+hxKx@(+_7fjkECsJ*KrqrHd`OO(2|J4Gzfmjl$GYLO3^AAWc6bsxv5`nTYtj=v#u zPPHSi1^Zo(c>13gmL1?P@O*vm#P+_YT$^{x6_)zko(JH^l@_b3i$gYWtz!N-DdE?U zA9DdXY?lFeY!`k+bLZYrb7vidDzjU0qlROcI4pi_d)oeu2B@Abo5ht*D&*9x2Y zqOm#68T(^*<{ctlSSw>}BMHTbj^>^e{#fgA)38ELlOtrT55IR|=I|amvsd?POf!0; zz4VB=(qYPH1X|*V|BR0E!(DE8=`6$S_T(e0<^Hj@$M8|kJ6-3;1{Jf61=TZ*4#GZpnOd}JBCp*$wWhw8XcdVGqDV!i^*|rQmCUg0+AQh-Zc$f1 zHQWdrEImuLAx6Z}NNLeX>57h#YkzUhT7Fe?EvDnxlo5tBFZ<@cs(}jUcgq!vG-Yar z#6)N)f&`Em@PEeJs#S?M>B|I{VIMXj-Nd9%OY|V6O%GW(u%+Wo`!>Qgqu^?Q*SwYC zH|FJ40ooAv?-JYkN)!aDHRkX|Vl*0!;-z9oVmQg;tW2?tjgWJUh|H5M6LyouV|rdl zuH_dXx_tjYuEjkc4fSG;qP7C=z(azqdnu?sVtznTj2 z^oKQ^=f^E&N2rAcel$p^LUw1rv_ZcKLw7-QN8m!6AmoY@Zrdn0=0>6!FgwIqV5}$F ziru8yc*6GL$xAK+dKj}kpARsFb5}g*wX@YzNoHJoK*Y>MvRN020GY~J+VusI#L|a` zP}mU?BcjQ^JvG&OUKRq$=e@+B!94i-f7@t^gLI1Y_>+>obI*ytSZ!5;GV{$p)@PH*U638r zTDW3`*ZfL-;vHN=*Y(_nXNFNV?#QGN^p;P1wSIl6^l_ zQK9A51d27y*}U6D@V1;PF;{rZQTbc}4_JGNI;UC1KcW?rL|p|?M0;Sum@tbxmyGf1 zJ8{Zv0zz-xew6qQx6<#per0Um44kUvEB1cR>5)mUvs9mfj_X5A z$9L4r-Svu{k)?$G=xTB=Twz#p7_h zP2|(cFMo}hVnb+SF^SmM`NF~Z*l6yU#-LXy@AijcOGV5sUN_^@@Y>ZTe^lPujZpNX z|5Mdf#x?nV{f)s!gP?Q?NJt4H&Dg}CK~SUz0us_C%>Wex$pO+sK)SmJC|x2*j2P10 zIpUeWe>~5#^SSqCFYfC)JMlf&IoCN(n0oi$b5j+AKPG17S!eNE$2+M?gSR=y!q4n! z$CX-^5*ewl=fIoZDfqp*OP1^e0#its-ysy-sh-2FPq=JCAJidBWAa5(nQS|Ugl|}Y z_43dvuqVNHpQoH&y9N2W0jndsUPLdOeCsVC$DN0AqZf1*$ZkL?Dm@E>SL(pBbYQgx z*InG+5i0pj-&W?kzcaeI_V7LC-n)Xl(jl;^aGSnx8{#E<09l5_H2JLuy|D&xqV6M)+@3aj4DoH4RQFxR`%rCOHR(8tbFVZYJ*lHl$hJMj#@ZG>de1*?|n9#ic zb+CXcx*bLeCX3e4PJl;tSeN!cN(g37?(BSM*Y*xxC7F?9b4~R(-KAbxAtTiTiH3=A z@o(|&-y)^A3GGEP?oj?@3h!glu}PU=_=)OoA#hlc{2c-lWf8Nr<8l5;927A0MG z&@No+bORS#d@1{>RG;2}6fF=!TA;MCmZ=$vRjH^`Fh%S8e3zZ%SM@ueI6dc*32DfL zug` z<-4WJEqa%n7`0@U>d|g%lJnD)a$%#*tU2`@++6c66WdQx2SR7UOERWLj&QkDrb@$~ zHWC)S<1$jIXj`tg!EqfT%I)KF5+64SE#|&vVr=i1OuRAs#2j$DcE)n}6F78SVJPx* zC)2y!Ti;B!9y~gH^9;}SPuX9|<(viO=O>bPKAib{`bE|-Mj<_Ie%)u>kC_Kjs!D9~X5G@IA?i9z502mwwBPX7G5}-j!LMW#C8hl%F=RDwMJbz)aEqV|* zSATgX?8-v8iPx94#A5qBg##<6ut?V!N2f3<(O5;^czC<tEM&6PqJIbbVaDQM-q2?M@O!n>>?*Xqvc z9t62Ce+?65e9zuYRK|G;*cH0EI%+!v#!oDSw?n8|lQEa7Xeg+E+uJz!&H z<@n<>t1^R!9W)=__a%tkmEbme)^RMcAE5ht_5|hNfAp(-w{Ea&X?ZrPUs_2hPt0Fy z7;)a1)pFp|?SHD-?Y~G7bFs#F3tuJH{d=rM*m(Bj<3jW4v+jWPSLGLsh=fh&AZ4eZ z!sR4hCn*S1$*HxQ~N&_3Ew$1{V@r&Jq>&dutXaS}yAp@CAr2_ZHvB zY4}6=z4O`gIEAZZM9+T9#Va4+>g$#m#-OWLKD#tQ^uy{`OVWG8oIyg{7ueawU$Ylx zW|w%SuHLI78XpXf^U}a|2zMBCru~eH#eX6FO1$uaHx;fk==^vu_-cn{ucrks?=w4l zbrUHfc5ykj*XA53I7r~YUZ1>DEZ({0mUeqY>H2Xq&+C?bk-CfilJ29iW^QA|Wr)?B zQo5hAZu%+8A#iWd>H=|*H+6o}X|nw)fuK#aX-TTcv-vh^TksLRK`vA--(I z*W(|3aDEx|pIU%NvmYPrL`riR$ReHLB^F{EXTAo1K3W&oR#${ePWpXRrQwHu5eDlJ z;od-N%!Pz%O6$3dERdrl(yl$1URwIq?&bb|gkjG$)^x$VGm?*;({|ta@~X9CYaa5) zXHpXy#^Aa21qt0sO6@H+2OR4@xYKP-#e2qzfhW*e+}8ACd+DYQB%*=5dE52U(@0ORXJ?sPvuVbV@4$@z+<58@6 zsJ@(CO>DTZRYiF&UGt!Px?1<=e$7Nv1Wk2{iD7hE_KHbpV&YKX*to$;N!j*K5ppS) z3ZO^X=~6S)j+rS+zmS`WIr`}5lT|iOn!H#3CQ)*o9Sbb_27o)vY^eClz&e&9$@d^C zk5X+YHE*f4)XqW^`e@P#4XokUz?mDR+zkz-b@c*Nli^;on7ev>>l@g1uOt#q5wCd6 z;V7PQ5w&xeCXlh6b^TK5sp%B`+9MklT#yYk#V!g$)nW6J7~#Uq)~*)%cu*2e)x*cOz6#iV(X_fSN{ExSmQrP#A;v{=ioc}7H}NpW~`mfsO{F)Sr1 zu-UFW43!h!rTl{#quA!dbgLC+YJ4&a98JFm(QqQ|UPGdW`xBLfWLl`gLt zp8ksL>EVa+6YlUmd;vYejj)F1N<^&YiDaZ=r{M#BZNJ zC7A0XfRn=M{B~~>r~mVFbom+BTPf($^8K^-tE@#jg;MtvR(RQs)TvFx@U z8^i!h8rAlf90ye!`d>Ut3_83~2Q+TJYHID!8&nd~8=Ow~fR|x9D-NG-AM>cTmPzQx zKeJapn|odJJL|QlVX>Hqn)JD+lYX(LwkpKm&tGHm(YtJGTb(34e!<>3QqpugzN1*H z&aFs!4QrHLoNXv7eXsk+J8+#2LTp(K5%10@)-$mm=Too&9Q{d?OSt(rpScC%-w|we zIa8um_WwiHJ=MTU*Zd>(kN(@DA{SByt)Uqo%V1C(EiOmzr>4R7&33c1e;nT{f~E|4#GdHU5#W>0woQ; z(1eX2S~}zVjV+wnQ1u;M4P|3 zU(d(CZ});5KuQw~9?$>zi|4cHt`HT|8+#T;|49k5OwwroY&y?aBXdU(aki~q~709 z^qq&Qs7d3OAR({0kdy`&Xd}D4-&RTryv?}0!e;UM3@TNYhhIBArc*nW@T8$SziUmr6d{Ot+Cle>nraoBjz-spV%qiA;IBjVWD%_x_mHI z=^CJb25=i-VsI%Ff{i2|x=CEi8K}vCxIzmz9_0%I(6CYp3^%zq@FlVNd^V%i+1q8} z*6oFgW9z-d9P2-;{GdBTNM7RB*EQA)NBX31fQ7_SB&|CgzNGK{fPIBUDud)9e@Ir% zz9ba0x)00B^NaxwG&Gl5Imac*BaFe2h1>psW+Xt?sNW+yQ;|HzctPSkr|gNSSsgdy z+Soy+hPJd!}LQ-2&WAaqJkTa^I~q|;|HAG}PJ2TEe3 z>y+E{NmATtwa5p8=4IJDP~C6tl9oCG?Uwz%t$GBOGZzVTr5~gq9(@40l`h;66xLkS z9VI1Pw1*Qj6*@YS0Yl?VwBp@m4SN=OX_yukz(fZtRFbn#X$ZeHlQ`4&M7Lo#O2at9 zwjI0Mq$Yd2bt^-F1x%$$H$~@+3>IleI|Eequ~F9QOFLe-$i1(fQ$MofYPfargj@(x z>dPf)@eD{mAo^aP(F8FYwPn11Dt3$D3Y+6;2gJX`$M2HaQDf=e5j&e4s)f{7OVv$H z*3+}`}YWatQN&hf%pI-)JW6_+u@YAkLhu2@$(wbyDJjn$y#|vma{=eiElTmlvBvyL)=N z9Sz@-bth;Y^tF~&sv=&cG{2Q-k5Y=_$?scLz{38{&(Y1A2>zYpam&aLT9HbZwHxuY z=iB-=h%xOn%2p)+;9G2tR!_HH4u=|$SI1f&-I_-#Ly86>LpwRkNIX!)45cZ}^o-~H z6Y8_{uhUKKNeQ%+Jb(M=l1OR*2Os|) z*Z1$<4?44`f;S9M00Y`um&}6J38`$dnJV(;J zaZHY&Yyi#4$t=-Eai{3s{(d(?M};(L;ve3A;TR_8sB3KVBIV>!uVLADZ5BpWe}%ar zQQ9WG(ypGS^`g^|DFWTz2JsJTL!*^0u4YVIGlE!OJB3wJm*NIC0ZfI?%e+|t7AtF! z*qCSEJk)j+r=Fsu?lON+?@eai<62B;C~@SYnM3q za^aDbko&~B9p3V1@^TgzdvLuLDejbkHQldW8rON>k2z79lk_Qhmj6}MO`cfhl!0_A z{;SA`t-?gc;CfPD$X!F`E~{+BEr+}2lRz*jZ4{Bfdkj&EDN>Br19Yd>N4@^{?>!+( zhJ-B3K=>q(Nkf}rK-`w2AEG%GZw?18%r{41eDM=sG04#Cy|vhPVeQy)trQm}X?{ft zis6Pv;eY}fSZJ^&5-iB9VOa$?dM9Dv8Z}WywLwqa-Jan+;c%j0dGdg#`leMyE9X+h zL}?+rI<_n&Ks=S&xrh++aP-bPPsdDD-AgnxBun>C!ASTBC!{CQ`A=jxTP=(u!SVzv z!UB-N5mZDwz%UpG!~l>)8slxSOGNV*2-D?p0v3eZ32K?VX$yjgeAR5)1H_(CcpIBM zPtZO*bQ8>yt200_p16qk7WmH%XYV}nu_;*`NM1P4;%t549U9KHqqt2*)+$D1!ODe2 zfA%qsTz-a>K>tRy-djCAt4|Fye3ZZaYxAo%`_SE$8c9KbbzM;jHhg~5AUY=;mFPQy z1fB$t;2#30A6AuMLhhsCI}{;c6FZkRl)|GSu0k0ZlOZI4IFE#?^fot=Jx9A+mAIDF zqwM3Ksk+h_ZeomyX@*_pFj0X>Tl0dgb2+3tF5TeN>bK_>6!#CgjQHce4=fX9g09*) zF0oiT7-)zc!^OWYnM zAtSwB=xA+yPff_!&~WLdt-LuLTDpw2YIJ=WRSfcA&00sYkI{BzLburat=fQh=lVVP zQk9~pdMAI{pfGp)=cv3;9hrVVJ5>1So8^_*NE$;E!zmx+DaA%ZV`~?=;$N`due_0A zOn z0QP%ih)0+@5|v8&8LhDIHKTc&hT~IFr=LCR$^zAwoQk{q);?;8iFI2UINssUthg&7 zDJuw?w;Yz25FUd-IAnhzgKr3gC>7t~ns&?%ZZ@-nI%NZUy_oq#OX^t`cZh z2@DXmlbM|s71%h!qf#5;Ymi3^2rXF#f{@o(B$1a#tSOV`3_fS9Snw!NV)I*X%*l&Z zq9eP!_~1ZGd^xa*>N1gEChCD<`gkI6yKqPRFT@kQ8t z_%AZhDX$vlgAh1oZPhJ+#yfzjk%TJhuYg$&Sz;q2&dt*M>S=2KOQ=5}eyQ|YepUku zmt!rN0~#SJr|B8$bg3y)bZfPP1EDTosD+!0h!Vh-pBNYWvehj< z92p8TTIUyF=gRz9dsPPiz_>?RT;Kz^>$59GEXM--j?8@hbDEZ9&Ua*Y`4-=#py2em zfkGM_HjKD_PJteeI}Sb}Wav0BnL`jUX^bs^dW0DwUqJnJP=bh<3klExtQIZKLl z38@rI(*lfp){PjjVN^@Z z2gXSRA2s#+@l3VjzCJ^Ew1m6xi2LqjU9f-_y=t#VgI%thqcYkyJx^cB`Lt5w}HDF7hfVU9S9Zi}2)ChJOPPE#SFi0F$5E zGkyKCi*gY!(_)Z)QwCDGnSaeebRis zc;7PC#MS||PetX%;g_<$zK>54TRxTxyBK(a_Gf|6-_(gXg7T;=(K&#-zrfriy3t@% z@HGLDsg9F8mq=wk`pc`g`W!l0qk4aziZB!~ouy*lqLIAXEDqmfXzgHFY%9!aYI`s_h+9_@? z(=3&4jqbT?Og^ssoC{IFk5Ji}zy@)gBSZjKA5*1O4lK=rkQIIScB#ku#aY&`0L;G$ zcXEm$BLbf^asfaa`&(Pv3B}FO)s4;QSBhiVnGMF14fR=?>B#Ayq9U88^rfz6o|f(v zl4eb}HJ_KLS?a|~N=hwhW14lv63T26bIcJRwJ_8<2!yxG+2KTm+mgfO$g2ze2{71~ z$Xmz19nQJ-Y{A$~i$zuTC&?(isfHIBr7bxZX6X|U60>GI1goJ)Gbagk>Vc@$$x;u8 zmZv*1Lcc@dKBfu5W4>>vm?%0))Nn9Jd;F}BEe60bQp_~|%B;qavZNK{WQ^+x<~=)7 zOMg>2c}%Nfet2IAJzxi7pSr8u{23DwqR z{~j9&0>og5;yb6?k75L@xki1_8*J&nT}8AgE6;JVqB;@JupjEtPLfr?CNS_1jL7)g zdgz#AY^O7oHQEFfTaFbU{c38mG%wxlk=)S#FKCrN3(-o4iZo=?r$iym932B}-Lgw$ zTkvFm7Duk}hi9dzgt)nN1K3BvyIoiuqQ;_RGky#S^q%G{E1(>MZEv_({eO=B1csKT^~C^dk0tO*FQP zAWLX{fAbo^?~-kfg#_crgs?m1Df_K_extA-31>(nSvwjnFWH}q59pslc3qJ`7;uL1 z@iB;n7YIfr?5(@T<;S{>j9t7++k0ZBTZD*+#sQzRub`P5sir>lucO)h%Z_j4+gSgC zH!eC}x%yD>p(D21tL^q(TcfH$CoeV~ww2Soc(d8nvl|h=YA+qqH^K%9I9$}FvbB-w zGFpt7VJE3+@UI_ZI6HRo68z0Ksy{fXfsL&u%5H+qJ9OA^ULR~3wUphPWN4TG&F4#* zHYjks|Ld~YJUInk1C}{9cW;1J3Iu;Kw1iHY)V6o0TsPjzppoLW{xXN zj(U0~QHt;E)6YwI1Ov!QxtW_u3L^^OeRubm~?G`tm9uLxL|mdgESH|&xEvkTbC z&;Kml?yl~cu)xKak;w`+pM&;h!G!qHh|Ce2AL|K&IVK6kz4p668srfppzhKnXbY5m ziuquFy6Y~>aei%`jGI3qMaAt!9)F^+&;xlEFtK2s78^__SEDAhTatf5IHwVXh|FVg zC|bO!Z3y?|A{5-(;_N{o5IGrba@>>R&{sQtO(i;(qsMxP z$>+VBjFqX`lkt9Yj(%_V>Mvwk%HY|dV4A@7+q=f*jyanoY0x~!uvu~FaZ+1Okz#Lj zO-pjrTQ{Rqp^UrRndMO5rw5z#JHvdqVzIFVJZ$q6^W?N?rdNhdQs!AeEJ#sx;d?Z_ zv6iTMHZfI<09J_j`pT<98nq#$H7c%reHS_VDU)MF(MYOCy~owXgfhhOPBG~4ej`=A zr+oI*^W5U*cSmF{I!C zH%pqx>acx|OHiF8nvt{Z%3ef(t8I)Xn`ExU5RzV5SBpb7V}V#tj|f=bw^tbZz%d|o z%p6ESPzwAb!a0SgRLh&1ZXNByVGgJS)I6?MMvHwTbS&8S<_s8HpZa3U^5VXy=MXiN zjJI_02%1{s#@MrtzfHn2gDDQnt#dtBE67zKCm3Wz%&eT_Y7?0Pdgyje^G4!pHVl>$G%0r5hKGtYAfT z7(4#S7jLY%c)FGPE4{T3EfBwKhcMKI?S(R5PtNL-($L6^J@}OCSY6<|lwG74T3pVy&ZCG5B&oGsE=6mG*T3pBbdmb3uCs-4AjHpdv*mmpl9tC+^XPRa z?|m2^%=?w)D{Rw{wZZtb_hECq$3{5=7;LMTbKLXLYH|Fp=d#ulbY~HdJ0Qk!CtQ4-?hHJ{28=(#mg(HFT)(M} zE#H(;D@Bg{{u!VfIZ}2Mrbf(Mue66>O>jiIX)y6zypgL4mTM)_6agR=T7!96UTfdP z0LBW1D+evGFO|H;dz&V`l5*JZWjhIHr+&&l3S9C;;HnfBjwL#Dw=9&jgp|nKQyT{U zsNW^mN)?=Rxse=GwDqFoCiXL&^C#DGs*qhe) zq_sFLIMQwKuCm+GyJXu^wiw)2P zAESkTJw=Rp8kpr4lTb#D9k%L;_Ndk!8rc7cFnYPeMj_DIxofYu!ex{WL5BwHu<({P zQq_8z)#$B2dorvu8?)HLzBPW!a|%_!jy>(Q^O@?D@(eO6(O<5L86yOK?cP<*)GU%K zgk1ZLZ?(-HiPfyul}A74^KTfV)U_0kWX!NWCH^K2)rBVWyI%IM-Il7|v336r5}(G> z$k@7^{j9kNW5(Gp;~vDs>S=AsPVigrlmLNdpy_qbDH}LwTGXe9M9ol8K9A#h)jlc_ zWl1z@xp)HiyyG=QkdnSbtYsIxuCmaVvSIfOy62#$7ctS3x!=f%y3j4j8r`B%-Fp(K zOX!9B4Y7hwZ8QVw*k%V8+3XVn&WS*}?0(zFJ!%thS&pHsGR{M{qENNH$EGDvXgZ+b zzrpOtHySp>A+$dGu$GQ&;__eKYF*wV%uKK~-`1>84+xQfjas9qPI3*wmoH)k>Z^XUHY_d}t={ExU$-7I zMgEhNolcUEjW6@Skb`@sT4spI`3dI?oN_NsGebao1kh)a2z3Og@*S2dM+f(><7SCS zvBljfqT4L%Q9k>G=TVzmzhts>>!Oh8^BBbt+l)O|pUYN%Ukbj_ie&jB>ik zQ!gCKRB56iYs4sDqAFm^KxZ(R0JF|GcFv&F&MAsqHd6*(LKT+QX#pFL4AUixTZ|5= zdWt%~yN1{YA*o{jS#r7$1>Ly9dhl0~2BWu^AT_0*UcV#=%U)(m<9IlVq@{hsx=3L2M71ODq9Bcc zwSs-@OL-1Qnh3*nVB>E_2P;ru>R4+F^$z)NeZZa(xaT2@^gG?&aeX$C5$W~L!{>cg z8I$YduC9$EWShz^Tp!kOh<#$Rn5~LMe?p-f%@gXs$^qY$$v52=O^2}lbrE5Ugmd~0 zr4twSdg^INJ{IyP5Wy~)dw&SgApm3;y+~Emp?XHOwn%LJvwc@3;@`_20sZSopB4`<7GkY(f4D`Eq2w}5 zZPi()IIYa^jCe@41{y{G^sfjx;w1b4J}Chh{@GE*Q!jjNz!c7f?siJ-aCraw;^l3_nK9Qt(3mQf8v^Uq9AF+Anb(+t~wL`Xd$=_A1 zJeGlndE${*jL)uuqOrM+Qf@J`*je2gabpbEydan+Y|q`kw**jSf^(h zaqJlB?>s()SIt|^tcCiPqs~S~ehc1m#(%E(5xChZ9{-8s-fXFFhGr$Zo%2OF`*jyg zGmH>f31ZJk7B06&$M=d!#;Q7*Y2psEgJ2H|;FOWU^q(&d^Pj{iptW zhFBq67%q6zE*}rlmW5S?yUHD?;xG9(|JgVO#Q7edx+_8B^*0Yd@D#uPzWl`yfF>?& zCDeu%9SUNXy#9yT!ItGYqDC|A!rtE6^0M}v$)(Zt>G~?yX>GHoVOh0+=T~EghTP}& z*eZkBwNR;{>g9^>Hd>+Jv&2e;b;hp_$xn~f4ONN?JAXW?T6r$I9}1{stAD>AAXd=d zU4ZT1T>9szSjUjlWeEKU4k9L@q=n5Bk+b{bbvPe!!Oc$U#yiXs(a4jiX6H+SA~ny65@_> z*3R4l{^QI3i6ZZD%3PCnJt%MY+ec;jt$WJ}lmbC}4J2%?$176zoblDCyor&Pb)%ZM z_8&i)jT=G8o(&ID`CJs<@D<(654rETd2c#wNiZ~fk*T0&j-LC!$mB0Z37($=QM05J zLy=s9Clxf=RKy;oI>OG_As=jdKYzCms<((bX3r>caVhrfU~lc@XGF#8seN0})r);s z$JO%MOT#6oE<5y(my7)Wp3>IRjKmO}uueM~$VSzQq-Hv5zgsHs;8k~B!NcG8&ql`b zADSgtUIo3FEKZso+&5e?n|@5U?KRzEY8qCo{D0OLJih|6hEPRh(g`UpWuehJI?)~? zc_OA}tGhlymzMt5{b5SV@!Gx|p9E_hH{+Ga>kq_FoJ0Q4AtOvS04Goq4t-yC3V;8Q z0%z<e@wZ5S|JCII?<;1#Fr$yKz`&)qAC5B!lBb9ML^002O3ZJ_#6Qp}5-^N{}mEj}ay literal 381303 zcmYhhV{|1^*DV~|?AW$#+v(W0ZKKn%ZQFK7opX{-M}1=3=FM}T`+o2DqiT%Ou2Flg zIoGVUSFEbC3^D>f0vH$=vYf1>Iv5xfCKwpF4;;kTnb<~ZPB1W1FgZyvO&{>H{`<_e zUjrBUB+4cTZ#m4)cdea(*K-z9oF6N=g!)R^EJ99)K%hHU7z1$$vRw~9TdQ>dDp0qAe0I_ z6cMjrhB>nx#Xy*k_JMsJVddTYm{JnpQ+F;>GVQjD!>IYDJ; zLKz&gf{gdO5i_CJ-8wWpMBFKw2q{=+P)|x8?4_3N<&I$=ExsQ4gkz-R+bgL1&#bt| zg`5&rBpbF?W!Q@Fe^MGRXtQUgFXYws+Ud%eJTt^MFq}0(I_9$O4ibU97Y`d;D4Jx^ zvla>syea-W$&A-u)3wdJ&4>FOGz^WKSEj*xec&$0{O_!b!${iM@8fX2n$F*-TYp#e4ryt@2*zrnn_!H69%qgD;eduw7>3@J4(#8Jz?zXbWvw!bn|28*v`gDx}@>VY? zo(kk`zvzCrbniNMzv4)NO;}fi5ma$-KmcC%-^hO7nRj1}Am-=td0(DG1Kc1kWd0Za zt-81&Gv4Tp59~`vN9Fd=X=SFcX^ucLzdvgt8v8bZ6H^|Aj?SgcW%j2ifHV7yyK&~V zDd0z>L6=Hzu#z&zrN?^L*;;GT$4zd3n(mf&MPqU2X^xn8c;S1X^YyM-%`}ua8 z?Cugrpn0*e(rxt*k`FlMn*z8kEamjpZvQ>K5aqd}UNP!3cBKv=N5X!*~F|)w;o7kzcZ^)8SxPk~w==3RaDf;jqiv@v|Zh`+r zw|n(0-4B4sXTag{w!3uXDvOtI@IQ2fw6s!^3~5Omji=; zt6tOqg3wF!0dGJkGA)R;-hF62!vz^&2kc1dSw59ES(PmMPCrpU@ugUy8`37v0As zT%BUQKSxPESZC1J6LFX!0Qw=$2@BkLb?!q0|8#Fh@(1->2||gbi#mgs*Z=)TVs*OU z?yjN-C2RE#0K?T}s(AKk*$$&?`J?a&!+ktiQ-XQ30MiHkRac&7u|nB;Hx zg`?#uVcrRNdj1HyecDelWE#TXtj-*)gG2(1P{NKLOaObqbe7@l!Nyy8>%m+ip1;S0 zF1dHmxCUEwSHB0}EWM%tTjrpUev%I4!vcS&Xm>bd{PkVJp8W9JkAjD}`-jFZ{oMaR zh=?1y@Ua=`|Al3SBveMF`%x0LvS%1Hg8H^{c9S8BCVKpF`_baMZo@s} z^5Eu$XZQcjdM4KtO>23ha_~xZGeDt71A~Weul#$jCH+FWhfOy9?8@;4Lm2Mkao9SR zMjrE0M>1i~Z3_y#$dJstwA;p+AnHIpr=#g~hThBSTc;BJSVu_uyfk;w-F4v2Yy9A$ z)A0W$&O1SfnQ1-~u49KmNjE5K0vDQ$pUHE8XjaA?Ef->0zhfb!4z?qQdHuf@KbesO zQ8SvwPcpJrI1GHYBcG(dfVyDuLIj9MyAM%Ak?eR(9kpI{@g5v87d1BDF8h7yCUBIm zs1W`IrKl0=BdW{Y`u@#1O27EO99)C@dOZWPUbEkL4Hv`rM&ov`-4joJ=8dNNodkg; zr(@$zN0)W4%c%U&1ju3~iTT-$F`QsGd)9uYJPTrpKHcw&8{1?6y4*L=@fg;a zTs`eN(jHxKjB_gH1>m{SPM|Hehx{)EUZ^4WFeCz)exWn7>jZFPXm&ihLZbO1MYImR z*y;19M!YfE2i1;n1X0F-zvi8R8_N11x&yA^VbhcMs!+-QQzwqEdFioPj7zuIZZPV! zn~l=4=czYB<$BDS6*!nGcs#lSFJ(_kmE4Pe7$wnaTiggXBBoAXD}0LQ%0A|e>usjtmUnG>U&-0KfgcX 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 lP=Fz9q9JW6CkI6byhZ|k{ywIa Date: Sat, 17 Aug 2024 09:49:42 -0700 Subject: [PATCH 02/63] [Bug] Lock Capsule no longer treats common items as free (#3591) * Fixed null check to actually check for null and not 0 * Add test and `startingModifier()` override helper function * Add tsdoc --- src/modifier/modifier-type.ts | 2 +- src/phases.ts | 2 +- src/test/items/lock_capsule.test.ts | 47 +++++++++++++++++++++++ src/test/utils/helpers/overridesHelper.ts | 11 ++++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/test/items/lock_capsule.test.ts diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index a791f543d9c..365fc433d2f 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2209,7 +2209,7 @@ export function getDefaultModifierTypeForTier(tier: ModifierTier): ModifierType } export class ModifierTypeOption { - public type: ModifierType | null; + public type: ModifierType; public upgradeCount: integer; public cost: integer; diff --git a/src/phases.ts b/src/phases.ts index cafaa4bd02b..6a9e25b8b5e 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -5580,7 +5580,7 @@ export class SelectModifierPhase extends BattlePhase { } else if (lockRarities) { const tierValues = [50, 125, 300, 750, 2000]; for (const opt of typeOptions) { - baseValue += opt.type?.tier ? tierValues[opt.type.tier] : 0; + baseValue += tierValues[opt.type.tier ?? 0]; } } else { baseValue = 250; diff --git a/src/test/items/lock_capsule.test.ts b/src/test/items/lock_capsule.test.ts new file mode 100644 index 00000000000..32103a6d780 --- /dev/null +++ b/src/test/items/lock_capsule.test.ts @@ -0,0 +1,47 @@ +import GameManager from "#test/utils/gameManager"; +import Phase from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { Abilities } from "#app/enums/abilities.js"; +import { Moves } from "#app/enums/moves.js"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { SelectModifierPhase } from "#app/phases.js"; +import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; + +describe("Items - Lock Capsule", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phase.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .startingLevel(200) + .moveset([Moves.SURF]) + .enemyAbility(Abilities.BALL_FETCH) + .startingModifier([{name: "LOCK_CAPSULE"}]); + }); + + it("doesn't set the cost of common tier items to 0", async() => { + await game.startBattle(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + await game.phaseInterceptor.to(SelectModifierPhase, false); + + const rewards = game.scene.getCurrentPhase() as SelectModifierPhase; + const potion = new ModifierTypeOption(modifierTypes.POTION(), 0, 40); // Common tier item + const rerollCost = rewards.getRerollCost([potion, potion, potion], true); + + expect(rerollCost).toBe(150); + }, 20000); +}); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index dbcb02825f2..d5eaee003db 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -84,6 +84,17 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override the player's starting modifiers + * @param modifiers the modifiers to set + * @returns this + */ + startingModifier(modifiers: ModifierOverride[]): this { + vi.spyOn(Overrides, "STARTING_MODIFIER_OVERRIDE", "get").mockReturnValue(modifiers); + this.log(`Player starting modifiers set to: ${modifiers}`); + return this; + } + /** * Override the player (pokemon) {@linkcode Abilities | ability} * @param ability the (pokemon) {@linkcode Abilities | ability} to set From 54460405b1fb2eaca881a915a93c28b950f95e9f Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Sun, 18 Aug 2024 03:36:25 +0900 Subject: [PATCH 03/63] =?UTF-8?q?[Hotfix]=20Fixed=20the=20bug=20where=20Po?= =?UTF-8?q?k=C3=A9mon=20with=20only=20rare/epic=20shiny=20but=20no=20commo?= =?UTF-8?q?n=20shiny=20were=20unable=20to=20use=20cycle=20shiny=20(#3593)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed the bug where Pokémon with only rare/epic shiny but no common shiny were unable to use cycle shiny * remove unecessary log * fix condition --- src/ui/starter-select-ui-handler.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 03a13e7661a..de56e69f65c 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2975,7 +2975,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant)); currentFilteredContainer.checkIconId(female, formIndex, shiny, variant); } - this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY); + // First, ensure you have the caught attributes for the species else default to bigint 0 + const caughtVariants = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); + // Define the variables based on whether their respective variants have been caught + const isVariant3Caught = !!(caughtVariants & DexAttr.VARIANT_3); + const isVariant2Caught = !!(caughtVariants & DexAttr.VARIANT_2); + const isVariantCaught = !!(caughtVariants & DexAttr.SHINY); + + this.canCycleShiny = isVariantCaught || isVariant2Caught || isVariant3Caught; this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); this.canCycleAbility = [ abilityAttr & AbilityAttr.ABILITY_1, (abilityAttr & AbilityAttr.ABILITY_2) && species.ability2, abilityAttr & AbilityAttr.ABILITY_HIDDEN ].filter(a => a).length > 1; this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey)) From 15584f8f1e5e61114f17a4da56cb6cfb34349f21 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Sun, 18 Aug 2024 04:47:45 +0900 Subject: [PATCH 04/63] fix typecast to BigInt (#3598) --- src/system/game-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index d64aa8f8e91..40f24fc8326 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1709,7 +1709,7 @@ export class GameData { } getFormAttr(formIndex: integer): bigint { - return BigInt(1 << (7 + formIndex)); + return BigInt(1) << BigInt(7 + formIndex); } consolidateDexData(dexData: DexData): void { From e192e57c630c9884255ae53738212dffb91eedf7 Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 17 Aug 2024 15:48:16 -0400 Subject: [PATCH 05/63] [Balance] Balance Hotfixes for August 17 Update (#3594) * [Balance] Balance Hotfixes for August 17 Update * Eternatus Moveset fix * fixed Cresselia passive * fixed Jirachi Egg Moves * fixed Doduo and Arctozolt egg moves --- src/data/egg-moves.ts | 8 ++++---- src/data/pokemon-species.ts | 2 +- src/field/pokemon.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data/egg-moves.ts b/src/data/egg-moves.ts index 657f59bddce..f88ac2c71b2 100644 --- a/src/data/egg-moves.ts +++ b/src/data/egg-moves.ts @@ -37,7 +37,7 @@ export const speciesEggMoves = { [Species.SLOWPOKE]: [ Moves.BOUNCY_BUBBLE, Moves.FLAMETHROWER, Moves.MYSTICAL_POWER, Moves.SHED_TAIL ], [Species.MAGNEMITE]: [ Moves.PARABOLIC_CHARGE, Moves.BODY_PRESS, Moves.ICE_BEAM, Moves.THUNDERCLAP ], [Species.FARFETCHD]: [ Moves.IVY_CUDGEL, Moves.TRIPLE_ARROWS, Moves.ROOST, Moves.VICTORY_DANCE ], - [Species.DODUO]: [ Moves.ICE_SPINNER, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ], + [Species.DODUO]: [ Moves.TRIPLE_AXEL, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ], [Species.SEEL]: [ Moves.FREEZE_DRY, Moves.BOUNCY_BUBBLE, Moves.SLACK_OFF, Moves.STEAM_ERUPTION ], [Species.GRIMER]: [ Moves.SUCKER_PUNCH, Moves.CURSE, Moves.STRENGTH_SAP, Moves.NOXIOUS_TORQUE ], [Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ], @@ -198,7 +198,7 @@ export const speciesEggMoves = { [Species.KYOGRE]: [ Moves.BOUNCY_BUBBLE, Moves.HURRICANE, Moves.FREEZE_DRY, Moves.ELECTRO_SHOT ], [Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ], [Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ], - [Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS, Moves.SHELL_SMASH ], + [Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ], [Species.DEOXYS]: [ Moves.COLLISION_COURSE, Moves.EARTH_POWER, Moves.PARTING_SHOT, Moves.LUMINA_CRASH ], [Species.TURTWIG]: [ Moves.SHELL_SMASH, Moves.MIGHTY_CLEAVE, Moves.ICE_SPINNER, Moves.SAPPY_SEED ], [Species.CHIMCHAR]: [ Moves.FIERY_DANCE, Moves.SECRET_SWORD, Moves.TRIPLE_AXEL, Moves.SACRED_FIRE ], @@ -418,7 +418,7 @@ export const speciesEggMoves = { [Species.CELESTEELA]: [ Moves.RECOVER, Moves.BUZZY_BUZZ, Moves.SANDSEAR_STORM, Moves.OBLIVION_WING ], [Species.KARTANA]: [ Moves.MIGHTY_CLEAVE, Moves.PSYBLADE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ], [Species.GUZZLORD]: [ Moves.SUCKER_PUNCH, Moves.COMEUPPANCE, Moves.SLACK_OFF, Moves.SHED_TAIL ], - [Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.CLANGOROUS_SOUL ], + [Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.DYNAMAX_CANNON ], [Species.MAGEARNA]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.MOONBLAST, Moves.MAKE_IT_RAIN ], [Species.MARSHADOW]: [ Moves.POWER_UP_PUNCH, Moves.TRIPLE_AXEL, Moves.METEOR_MASH, Moves.STORM_THROW ], [Species.POIPOLE]: [ Moves.CORE_ENFORCER, Moves.ICE_BEAM, Moves.SEARING_SHOT, Moves.MALIGNANT_CHAIN ], @@ -458,7 +458,7 @@ export const speciesEggMoves = { [Species.MORPEKO]: [ Moves.TRIPLE_AXEL, Moves.OBSTRUCT, Moves.SWORDS_DANCE, Moves.COLLISION_COURSE ], [Species.CUFANT]: [ Moves.LIQUIDATION, Moves.CURSE, Moves.COMBAT_TORQUE, Moves.GIGATON_HAMMER ], [Species.DRACOZOLT]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.FIRE_LASH, Moves.DRAGON_DANCE ], - [Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], + [Species.ARCTOZOLT]: [ Moves.MOUNTAIN_GALE, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], [Species.DRACOVISH]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.THUNDER_FANG, Moves.DRAGON_DANCE ], [Species.ARCTOVISH]: [ Moves.ICE_FANG, Moves.THUNDER_FANG, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], [Species.DURALUDON]: [ Moves.CORE_ENFORCER, Moves.BODY_PRESS, Moves.RECOVER, Moves.TACHYON_CUTTER ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 762f009e4e4..aa2c29a9725 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3559,7 +3559,7 @@ export const starterPassiveAbilities = { [Species.HEATRAN]: Abilities.EARTH_EATER, [Species.REGIGIGAS]: Abilities.MINDS_EYE, [Species.GIRATINA]: Abilities.SHADOW_SHIELD, - [Species.CRESSELIA]: Abilities.MAGIC_BOUNCE, + [Species.CRESSELIA]: Abilities.UNAWARE, [Species.PHIONE]: Abilities.SIMPLE, [Species.MANAPHY]: Abilities.PRIMORDIAL_SEA, [Species.DARKRAI]: Abilities.UNNERVE, diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 930ffeb700f..4ab0b482916 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3780,7 +3780,7 @@ export class EnemyPokemon extends Pokemon { this.moveset = (formIndex !== undefined ? formIndex : this.formIndex) ? [ new PokemonMove(Moves.DYNAMAX_CANNON), - new PokemonMove(Moves.CROSS_POISON), + new PokemonMove(Moves.SLUDGE_BOMB), new PokemonMove(Moves.FLAMETHROWER), new PokemonMove(Moves.RECOVER, 0, -4) ] From 616219d17eae93d390f7e3ea3ba5ace6fb6cae91 Mon Sep 17 00:00:00 2001 From: Mumble Date: Sat, 17 Aug 2024 12:50:50 -0700 Subject: [PATCH 06/63] [Hotfix] Removed isFreshStartChallenge() check (#3599) * Removed isFreshStartChallenge() check * Better conditional --------- Co-authored-by: Frutescens --- src/phases.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases.ts b/src/phases.ts index 6a9e25b8b5e..da3096b0d2d 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2036,7 +2036,7 @@ export class CommandPhase extends FieldPhase { } break; case Command.BALL: - if (!this.scene.gameMode.isFreshStartChallenge() && this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1))) { + if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1))) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => { From b59cb128bff17d4dfa6d26ec2f58adb1d35ea621 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Sun, 18 Aug 2024 06:01:35 +0900 Subject: [PATCH 07/63] fix female bug. refine variable name also (#3601) --- src/ui/starter-select-ui-handler.ts | 32 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index de56e69f65c..5e942f3e75a 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2295,13 +2295,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { container.cost = this.scene.gameData.getSpeciesStarterValue(container.species.speciesId); // First, ensure you have the caught attributes for the species else default to bigint 0 - const caughtVariants = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0); + const isCaught = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0); // Define the variables based on whether their respective variants have been caught - const isVariant3Caught = !!(caughtVariants & DexAttr.VARIANT_3); - const isVariant2Caught = !!(caughtVariants & DexAttr.VARIANT_2); - const isVariantCaught = !!(caughtVariants & DexAttr.SHINY); - const isCaught = !!(caughtVariants & DexAttr.NON_SHINY); + const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); + const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); + const isVariantCaught = !!(isCaught & DexAttr.SHINY); const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught; const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0; const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked; @@ -2913,6 +2912,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (species) { const dexEntry = this.scene.gameData.dexData[species.speciesId]; const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr; + + const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); + const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); + const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); + const isVariantCaught = !!(isCaught & DexAttr.SHINY); + const isMaleCaught = !!(isCaught & DexAttr.MALE); + const isFemaleCaught = !!(isCaught & DexAttr.FEMALE); + if (!dexEntry.caughtAttr) { const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); @@ -2975,15 +2982,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant)); currentFilteredContainer.checkIconId(female, formIndex, shiny, variant); } - // First, ensure you have the caught attributes for the species else default to bigint 0 - const caughtVariants = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); - // Define the variables based on whether their respective variants have been caught - const isVariant3Caught = !!(caughtVariants & DexAttr.VARIANT_3); - const isVariant2Caught = !!(caughtVariants & DexAttr.VARIANT_2); - const isVariantCaught = !!(caughtVariants & DexAttr.SHINY); this.canCycleShiny = isVariantCaught || isVariant2Caught || isVariant3Caught; - this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); + this.canCycleGender = isMaleCaught && isFemaleCaught; this.canCycleAbility = [ abilityAttr & AbilityAttr.ABILITY_1, (abilityAttr & AbilityAttr.ABILITY_2) && species.ability2, abilityAttr & AbilityAttr.ABILITY_HIDDEN ].filter(a => a).length > 1; this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey)) .map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1; @@ -2992,7 +2993,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (dexEntry.caughtAttr && species.malePercent !== null) { - const gender = !female ? Gender.MALE : Gender.FEMALE; + let gender: Gender; + if ((female && isFemaleCaught) || (!female && !isMaleCaught)) { + gender = Gender.FEMALE; + } else { + gender = Gender.MALE; + } this.pokemonGenderText.setText(getGenderSymbol(gender)); this.pokemonGenderText.setColor(getGenderColor(gender)); this.pokemonGenderText.setShadowColor(getGenderColor(gender, true)); From 2b853bae2588daa6d1bf52b11fb665d38b521663 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 17 Aug 2024 15:25:03 -0700 Subject: [PATCH 08/63] [Hotfix] Fix Pokemon info not fully appearing after switch-out (#3596) * Add hideInfo param to leaveField * Update docs for leaveField --- src/field/pokemon.ts | 8 ++++++-- src/phases.ts | 6 ++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 4ab0b482916..b19fe7ce678 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3223,14 +3223,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Causes a Pokemon to leave the field (such as in preparation for a switch out/escape). * @param clearEffects Indicates if effects should be cleared (true) or passed * to the next pokemon, such as during a baton pass (false) + * @param hideInfo Indicates if this should also play the animation to hide the Pokemon's + * info container. */ - leaveField(clearEffects: boolean = true) { + leaveField(clearEffects: boolean = true, hideInfo: boolean = true) { this.resetTurnData(); if (clearEffects) { this.resetSummonData(); this.resetBattleData(); } - this.hideInfo(); + if (hideInfo) { + this.hideInfo(); + } this.setVisible(false); this.scene.field.remove(this); this.scene.triggerPokemonFormChange(this, SpeciesFormChangeActiveTrigger, true); diff --git a/src/phases.ts b/src/phases.ts index da3096b0d2d..b881f0de819 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1635,7 +1635,7 @@ export class SwitchSummonPhase extends SummonPhase { }) ); this.scene.playSound("pb_rel"); - pokemon.hideInfo(); // this is also done by pokemon.leaveField(), but needs to go earlier for animation purposes + pokemon.hideInfo(); pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, "Sine.easeIn"); this.scene.tweens.add({ targets: pokemon, @@ -1643,9 +1643,7 @@ export class SwitchSummonPhase extends SummonPhase { ease: "Sine.easeIn", scale: 0.5, onComplete: () => { - // 300ms delay on leaveField is necessary to avoid calling hideInfo() twice - // and double-animating the stats panel slideout - this.scene.time.delayedCall(300, () => pokemon.leaveField(!this.batonPass)); + pokemon.leaveField(!this.batonPass, false); this.scene.time.delayedCall(750, () => this.switchAndSummon()); } }); From 5ede6a54c630512f0e4ab7fa9f549412fd4b3e0a Mon Sep 17 00:00:00 2001 From: Mumble Date: Sat, 17 Aug 2024 17:09:28 -0700 Subject: [PATCH 09/63] [Hotfix] End Biome Catch Problems (#3605) * Needs more testing. * removed debugging --------- Co-authored-by: Frutescens --- src/game-mode.ts | 2 +- src/phases.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/game-mode.ts b/src/game-mode.ts index e78b9017c12..f5dadad6f1b 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -62,7 +62,7 @@ export class GameMode implements GameModeConfig { * @returns true if the game mode has that challenge */ hasChallenge(challenge: Challenges): boolean { - return this.challenges.some(c => c.id === challenge); + return this.challenges.some(c => c.id === challenge && c.value !== 0); } /** diff --git a/src/phases.ts b/src/phases.ts index b881f0de819..88acfc825ef 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2034,7 +2034,8 @@ export class CommandPhase extends FieldPhase { } break; case Command.BALL: - if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1))) { + const notInDex = (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1); + if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || notInDex )) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => { From 8704723c9cc7f98121c61753588d4866642c793c Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 17 Aug 2024 18:22:21 -0700 Subject: [PATCH 10/63] Fix missing form change logic for Cramorant (#3603) --- src/data/pokemon-forms.ts | 2 ++ src/test/abilities/gulp_missile.test.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 5180664ce07..95a89c7c640 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -837,6 +837,8 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)), new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeManualTrigger, true), new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeManualTrigger, true), + new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeActiveTrigger(false), true), + new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeActiveTrigger(false), true), ] }; diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts index 2647f765f6e..52ae323839d 100644 --- a/src/test/abilities/gulp_missile.test.ts +++ b/src/test/abilities/gulp_missile.test.ts @@ -84,6 +84,21 @@ describe("Abilities - Gulp Missile", () => { expect(cramorant.formIndex).toBe(GORGING_FORM); }); + it("changes to base form when switched out after Surf or Dive is used", async () => { + await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]); + const cramorant = game.scene.getPlayerPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + await game.toNextTurn(); + + game.doSwitchPokemon(1); + await game.toNextTurn(); // form change is delayed until after end of turn + + expect(cramorant.formIndex).toBe(NORMAL_FORM); + expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined(); + expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeUndefined(); + }); + it("changes form during Dive's charge turn", async () => { await game.startBattle([Species.CRAMORANT]); const cramorant = game.scene.getPlayerPokemon()!; From 0e92366cacc0e4d71313cfa6d1508d80dffefc05 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Sat, 17 Aug 2024 21:23:02 -0400 Subject: [PATCH 11/63] Fixed egg moves being relearnable in daily runs (#3604) --- src/field/pokemon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b19fe7ce678..f1721299ad0 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -922,7 +922,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { */ getLearnableLevelMoves(): Moves[] { let levelMoves = this.getLevelMoves(1, true).map(lm => lm[1]); - if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge()) { + if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) { levelMoves = this.getUnlockedEggMoves().concat(levelMoves); } return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm)); From 5f6cb6ce007acfe0c8e255982106182089fd9109 Mon Sep 17 00:00:00 2001 From: cam Date: Sat, 17 Aug 2024 23:14:25 -0400 Subject: [PATCH 12/63] [Sprite] Floette animation fix - Xatu female variant fix (#3610) * 177-178 icons, variant icons * 178 icons * [HotFix][Sprite] Xatu female variants added * [HotFix][Sprite] Floette json: update to match images * Xatu variant- reverted _masterlist reverted _masterlist.json added anim files for both female variants * [fix] Xatu female: show variants, added back sprite anim Edited _masterlist on correct keys added anim json for back sprites --- public/images/pokemon/back/female/178.png | Bin 5917 -> 6304 bytes .../images/pokemon/back/shiny/female/178.png | Bin 5917 -> 6304 bytes public/images/pokemon/exp/670-blue.json | 2534 +++++++++++++- public/images/pokemon/exp/670-orange.json | 2534 +++++++++++++- public/images/pokemon/exp/670-red.json | 3 +- public/images/pokemon/exp/670-white.json | 2534 +++++++++++++- public/images/pokemon/exp/670-yellow.json | 2534 +++++++++++++- public/images/pokemon/exp/shiny/670-blue.json | 2578 +++++++++++++- .../images/pokemon/exp/shiny/670-orange.json | 2578 +++++++++++++- public/images/pokemon/exp/shiny/670-red.json | 3097 ++++++++--------- .../images/pokemon/exp/shiny/670-white.json | 2578 +++++++++++++- .../images/pokemon/exp/shiny/670-yellow.json | 2578 +++++++++++++- public/images/pokemon/female/178.png | Bin 5100 -> 5314 bytes public/images/pokemon/icons/2/178.png | Bin 326 -> 318 bytes public/images/pokemon/icons/2/178s.png | Bin 326 -> 318 bytes .../images/pokemon/icons/variant/2/177_2.png | Bin 0 -> 271 bytes .../images/pokemon/icons/variant/2/177_3.png | Bin 0 -> 271 bytes .../images/pokemon/icons/variant/2/178_2.png | Bin 0 -> 318 bytes .../images/pokemon/icons/variant/2/178_3.png | Bin 0 -> 318 bytes public/images/pokemon/shiny/female/178.png | Bin 5100 -> 5314 bytes .../images/pokemon/variant/_masterlist.json | 10 + public/images/pokemon/variant/back/177_2.png | Bin 0 -> 7262 bytes public/images/pokemon/variant/back/177_3.png | Bin 0 -> 7254 bytes .../pokemon/variant/back/female/178_2.json | 2372 +++++++++++++ .../pokemon/variant/back/female/178_2.png | Bin 0 -> 6304 bytes .../pokemon/variant/back/female/178_3.json | 2372 +++++++++++++ .../pokemon/variant/back/female/178_3.png | Bin 0 -> 6304 bytes .../images/pokemon/variant/female/178_2.json | 2372 +++++++++++++ .../images/pokemon/variant/female/178_2.png | Bin 0 -> 5314 bytes .../images/pokemon/variant/female/178_3.json | 2372 +++++++++++++ .../images/pokemon/variant/female/178_3.png | Bin 0 -> 5314 bytes 31 files changed, 30255 insertions(+), 2791 deletions(-) create mode 100644 public/images/pokemon/icons/variant/2/177_2.png create mode 100644 public/images/pokemon/icons/variant/2/177_3.png create mode 100644 public/images/pokemon/icons/variant/2/178_2.png create mode 100644 public/images/pokemon/icons/variant/2/178_3.png create mode 100644 public/images/pokemon/variant/back/177_2.png create mode 100644 public/images/pokemon/variant/back/177_3.png create mode 100644 public/images/pokemon/variant/back/female/178_2.json create mode 100644 public/images/pokemon/variant/back/female/178_2.png create mode 100644 public/images/pokemon/variant/back/female/178_3.json create mode 100644 public/images/pokemon/variant/back/female/178_3.png create mode 100644 public/images/pokemon/variant/female/178_2.json create mode 100644 public/images/pokemon/variant/female/178_2.png create mode 100644 public/images/pokemon/variant/female/178_3.json create mode 100644 public/images/pokemon/variant/female/178_3.png diff --git a/public/images/pokemon/back/female/178.png b/public/images/pokemon/back/female/178.png index b6b1aa908d8f6ef64327b80864962739e9f7d3f5..bf4e727088fcc17984ff76199d9b510b011ce30b 100644 GIT binary patch literal 6304 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 Ud#aWikpKVy07*qoM6N<$f;G=33;+NC delta 5093 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 Hu0mjfwJXZ) diff --git a/public/images/pokemon/icons/2/178.png b/public/images/pokemon/icons/2/178.png index 3b6046319572e2316cd72e838de6982730796277..9f4b97ffc1cda1217f3ce7d9be632382f88cbb13 100644 GIT binary patch delta 47 qcmX@cw2x_mA)~=WBNGLw`+iys3=9G#L4Lsu|53q#fNtlBeLDc$)fpfF delta 55 scmdnTbc|_&A*0zuBNGh@~ diff --git a/public/images/pokemon/icons/2/178s.png b/public/images/pokemon/icons/2/178s.png index 8605b01c01e682c131330bdd3a2b7130628a1b06..55edd478de2d94d38076169e01abaa14dda09fd0 100644 GIT binary patch delta 47 rcmX@cw2x_mA)~=WBNK&xmM0%GFfa&|1o;Is{6_@`0=k_i_U!-w4F4LE delta 55 scmdnTbc|_&A*0zuBNGh443CQwF0h1`0x)O>%1>%~n_TxuWBwc%yf z-AOB+Mz*izW88Q|M8#Of^U0ni-iqAQ9_3}2oj7x8%Z|mj4;)grTDeQKaK)nJ1J6QR zR+-&6?{k)`N=RYe#_)po(UW2gqkg^kxJEkMB*`r0^uCGQm!p}AUNFb&03E{M>FVdQ I&MBb@04C>fT>t<8 literal 0 HcmV?d00001 diff --git a/public/images/pokemon/icons/variant/2/177_3.png b/public/images/pokemon/icons/variant/2/177_3.png new file mode 100644 index 0000000000000000000000000000000000000000..2952d8f4926778a4415008a65c5c5b3abf33e9d0 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<^!3-obnb*7rQjEnx?oJHr&dIz4a?}HSLR^8g zf`WpQW20yB@uY<>ny&mwQ+AkT;b@^#5$ZUtJ$-*rP|*MX|2HSZo(3xAEeY}qW&rZx zK$pdFEl{G?)5S5wqWA4ZPrd^R9IOHM4;)_qJs-WLkXvt-n(wc0y|@XAOYP&iHoVNb zJ88w!$o92-j2n-Ls2Iz5KH0OxTakO(qr42W6K5`M*|GTcfkWz6D|d+&u2__O;8|$P zDzh8sea>=K2`S9m7+&x`dQz-m)UOvG*GPw(B$=h0-Zzo^ax_!X3+8wophFluUHx3v IIVCg!08f2x00000 literal 0 HcmV?d00001 diff --git a/public/images/pokemon/icons/variant/2/178_2.png b/public/images/pokemon/icons/variant/2/178_2.png new file mode 100644 index 0000000000000000000000000000000000000000..060c25138e0bda912df694bb03849639b5210bfb GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<^!3-obnb*7rQjEnx?oJHr&dIz4ats1|LR^8g zf`UR&P*947ahIpl@sjBO|NkqyM|kAcn5L!p&S+cu{p6Blrvsf~A9fV|f6@0?QW9jI zKuM5aFauC2GB^;>?F^J#;OXKRV$u8dvbPYEAqUF^6SXdh8Ncse^GJZqllPbDt*v|NlQu#IQSOBG=pt!5xoEcK;VtT5uew zN1!CgFPH(S6d4={=ynFmE%0=446*2ad)Zrv$&iEPf{9v}#EjqfuklR_U3X|lf%@xk z-Y1uD?cb-#@I1n0&Vmn*7kmj)5^`e=zaK6t^v*@ewC2VWt#Hk@CB~g6&n|6XJIN`# z-D%sDGpkju3!da$7|qEme^_0)RQuv`zEeGSJieTc$h)gpVyu?bjn%A#dSdRNwJFf5M)QKM(e=SC`wt+ETzN(*|@agQu&X%Q~loCIIwU Bgm?e| literal 0 HcmV?d00001 diff --git a/public/images/pokemon/shiny/female/178.png b/public/images/pokemon/shiny/female/178.png index 7695b06e1558fe1ba4aa6d1ae63fa69e7a20470a..b0d983307e4cb741cf9a420e0373bf1de2a58c41 100644 GIT binary patch literal 5314 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 Ul*sRr7ytkO07*qoM6N<$f~8X?sQ>@~ literal 5100 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 Mq^0;t;W_eu0AYLGw*UYD literal 0 HcmV?d00001 diff --git a/public/images/pokemon/variant/back/177_3.png b/public/images/pokemon/variant/back/177_3.png new file mode 100644 index 0000000000000000000000000000000000000000..04ec33986cd511dee258fd7c72693912ae801081 GIT binary patch literal 7254 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 C^TLk+ literal 0 HcmV?d00001 diff --git a/public/images/pokemon/variant/back/female/178_2.json b/public/images/pokemon/variant/back/female/178_2.json new file mode 100644 index 00000000000..202894b474c --- /dev/null +++ b/public/images/pokemon/variant/back/female/178_2.json @@ -0,0 +1,2372 @@ +{ + "textures": [ + { + "image": "178_2.png", + "format": "RGBA8888", + "size": { + "w": 263, + "h": 263 + }, + "scale": 1, + "frames": [ + { + "filename": "0101.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 67, + "h": 58 + }, + "frame": { + "x": 0, + "y": 0, + "w": 67, + "h": 58 + } + }, + { + "filename": "0102.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 67, + "h": 58 + }, + "frame": { + "x": 0, + "y": 0, + "w": 67, + "h": 58 + } + }, + { + "filename": "0105.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 3, + "y": 0, + "w": 64, + "h": 58 + }, + "frame": { + "x": 0, + "y": 58, + "w": 64, + "h": 58 + } + }, + { + "filename": "0106.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 3, + "y": 0, + "w": 64, + "h": 58 + }, + "frame": { + "x": 0, + "y": 58, + "w": 64, + "h": 58 + } + }, + { + "filename": "0103.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 58, + "h": 57 + }, + "frame": { + "x": 67, + "y": 0, + "w": 58, + "h": 57 + } + }, + { + "filename": "0104.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 58, + "h": 57 + }, + "frame": { + "x": 67, + "y": 0, + "w": 58, + "h": 57 + } + }, + { + "filename": "0097.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 59, + "h": 54 + }, + "frame": { + "x": 0, + "y": 116, + "w": 59, + "h": 54 + } + }, + { + "filename": "0098.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 59, + "h": 54 + }, + "frame": { + "x": 0, + "y": 116, + "w": 59, + "h": 54 + } + }, + { + "filename": "0107.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 7, + "y": 2, + "w": 55, + "h": 57 + }, + "frame": { + "x": 125, + "y": 0, + "w": 55, + "h": 57 + } + }, + { + "filename": "0108.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 7, + "y": 2, + "w": 55, + "h": 57 + }, + "frame": { + "x": 125, + "y": 0, + "w": 55, + "h": 57 + } + }, + { + "filename": "0099.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 4, + "y": 2, + "w": 54, + "h": 57 + }, + "frame": { + "x": 0, + "y": 170, + "w": 54, + "h": 57 + } + }, + { + "filename": "0100.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 4, + "y": 2, + "w": 54, + "h": 57 + }, + "frame": { + "x": 0, + "y": 170, + "w": 54, + "h": 57 + } + }, + { + "filename": "0095.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 54, + "h": 52 + }, + "frame": { + "x": 180, + "y": 0, + "w": 54, + "h": 52 + } + }, + { + "filename": "0096.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 54, + "h": 52 + }, + "frame": { + "x": 180, + "y": 0, + "w": 54, + "h": 52 + } + }, + { + "filename": "0109.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 3, + "w": 48, + "h": 56 + }, + "frame": { + "x": 54, + "y": 170, + "w": 48, + "h": 56 + } + }, + { + "filename": "0110.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 3, + "w": 48, + "h": 56 + }, + "frame": { + "x": 54, + "y": 170, + "w": 48, + "h": 56 + } + }, + { + "filename": "0111.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 5, + "w": 48, + "h": 54 + }, + "frame": { + "x": 59, + "y": 116, + "w": 48, + "h": 54 + } + }, + { + "filename": "0112.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 5, + "w": 48, + "h": 54 + }, + "frame": { + "x": 59, + "y": 116, + "w": 48, + "h": 54 + } + }, + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0002.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0015.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0016.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0029.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0030.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0043.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0044.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0057.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0058.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0071.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0072.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 102, + "y": 170, + "w": 48, + "h": 52 + } + }, + { + "filename": "0007.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0008.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0009.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0010.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0035.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0036.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0037.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0038.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0063.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0064.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0065.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0066.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 52, + "h": 52 + }, + "frame": { + "x": 180, + "y": 52, + "w": 52, + "h": 52 + } + }, + { + "filename": "0003.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0004.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0013.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0014.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0031.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0032.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0041.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0042.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0059.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0060.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0069.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0070.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 50, + "h": 52 + }, + "frame": { + "x": 64, + "y": 58, + "w": 50, + "h": 52 + } + }, + { + "filename": "0005.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0006.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0011.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0012.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0033.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0034.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0039.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0040.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0061.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0062.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0067.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0068.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 51, + "h": 52 + }, + "frame": { + "x": 114, + "y": 57, + "w": 51, + "h": 52 + } + }, + { + "filename": "0017.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0018.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0027.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0028.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0045.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0046.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0055.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0056.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0073.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0074.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0083.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0084.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 11, + "y": 7, + "w": 47, + "h": 52 + }, + "frame": { + "x": 107, + "y": 110, + "w": 47, + "h": 52 + } + }, + { + "filename": "0019.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0020.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0025.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0026.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0047.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0048.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0053.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0054.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0075.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0076.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0081.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0082.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 154, + "y": 109, + "w": 45, + "h": 52 + } + }, + { + "filename": "0021.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0022.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0023.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0024.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0049.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0050.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0051.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0052.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0077.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0078.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0079.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0080.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 13, + "y": 7, + "w": 45, + "h": 52 + }, + "frame": { + "x": 199, + "y": 104, + "w": 45, + "h": 52 + } + }, + { + "filename": "0085.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 199, + "y": 156, + "w": 48, + "h": 52 + } + }, + { + "filename": "0086.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 7, + "w": 48, + "h": 52 + }, + "frame": { + "x": 199, + "y": 156, + "w": 48, + "h": 52 + } + }, + { + "filename": "0087.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 48, + "h": 51 + }, + "frame": { + "x": 150, + "y": 162, + "w": 48, + "h": 51 + } + }, + { + "filename": "0088.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 48, + "h": 51 + }, + "frame": { + "x": 150, + "y": 162, + "w": 48, + "h": 51 + } + }, + { + "filename": "0089.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 9, + "w": 48, + "h": 50 + }, + "frame": { + "x": 150, + "y": 213, + "w": 48, + "h": 50 + } + }, + { + "filename": "0090.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 9, + "w": 48, + "h": 50 + }, + "frame": { + "x": 150, + "y": 213, + "w": 48, + "h": 50 + } + }, + { + "filename": "0091.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 9, + "w": 48, + "h": 50 + }, + "frame": { + "x": 150, + "y": 213, + "w": 48, + "h": 50 + } + }, + { + "filename": "0092.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 9, + "w": 48, + "h": 50 + }, + "frame": { + "x": 150, + "y": 213, + "w": 48, + "h": 50 + } + }, + { + "filename": "0093.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 50, + "h": 51 + }, + "frame": { + "x": 198, + "y": 208, + "w": 50, + "h": 51 + } + }, + { + "filename": "0094.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 67, + "h": 59 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 50, + "h": 51 + }, + "frame": { + "x": 198, + "y": 208, + "w": 50, + "h": 51 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:09a3b8263891ad99a615fcb08d56ef56:420667b66547b2d5cc8ddbc8c794dd00:319c95b9f5acf1139a5c6761349cd6ab$" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/178_2.png b/public/images/pokemon/variant/back/female/178_2.png new file mode 100644 index 0000000000000000000000000000000000000000..7d2785dc0af5cd7e1b0ac3b16350f2b860b66be1 GIT binary patch literal 6304 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 UIDq;fjQ{`u07*qoM6N<$f_9f6`v3p{ literal 0 HcmV?d00001 diff --git a/public/images/pokemon/variant/female/178_3.json b/public/images/pokemon/variant/female/178_3.json new file mode 100644 index 00000000000..2e851f20d9d --- /dev/null +++ b/public/images/pokemon/variant/female/178_3.json @@ -0,0 +1,2372 @@ +{ + "textures": [ + { + "image": "178_3.png", + "format": "RGBA8888", + "size": { + "w": 224, + "h": 224 + }, + "scale": 1, + "frames": [ + { + "filename": "0101.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 45, + "h": 60 + }, + "frame": { + "x": 0, + "y": 0, + "w": 45, + "h": 60 + } + }, + { + "filename": "0102.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 45, + "h": 60 + }, + "frame": { + "x": 0, + "y": 0, + "w": 45, + "h": 60 + } + }, + { + "filename": "0103.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 0, + "w": 43, + "h": 60 + }, + "frame": { + "x": 45, + "y": 0, + "w": 43, + "h": 60 + } + }, + { + "filename": "0104.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 0, + "w": 43, + "h": 60 + }, + "frame": { + "x": 45, + "y": 0, + "w": 43, + "h": 60 + } + }, + { + "filename": "0105.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 43, + "h": 60 + }, + "frame": { + "x": 88, + "y": 0, + "w": 43, + "h": 60 + } + }, + { + "filename": "0106.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 43, + "h": 60 + }, + "frame": { + "x": 88, + "y": 0, + "w": 43, + "h": 60 + } + }, + { + "filename": "0099.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 1, + "w": 41, + "h": 59 + }, + "frame": { + "x": 131, + "y": 0, + "w": 41, + "h": 59 + } + }, + { + "filename": "0100.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 1, + "w": 41, + "h": 59 + }, + "frame": { + "x": 131, + "y": 0, + "w": 41, + "h": 59 + } + }, + { + "filename": "0107.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 39, + "h": 59 + }, + "frame": { + "x": 131, + "y": 59, + "w": 39, + "h": 59 + } + }, + { + "filename": "0108.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 39, + "h": 59 + }, + "frame": { + "x": 131, + "y": 59, + "w": 39, + "h": 59 + } + }, + { + "filename": "0109.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 37, + "h": 59 + }, + "frame": { + "x": 0, + "y": 60, + "w": 37, + "h": 59 + } + }, + { + "filename": "0110.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 1, + "w": 37, + "h": 59 + }, + "frame": { + "x": 0, + "y": 60, + "w": 37, + "h": 59 + } + }, + { + "filename": "0097.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 40, + "h": 57 + }, + "frame": { + "x": 37, + "y": 60, + "w": 40, + "h": 57 + } + }, + { + "filename": "0098.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 40, + "h": 57 + }, + "frame": { + "x": 37, + "y": 60, + "w": 40, + "h": 57 + } + }, + { + "filename": "0007.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0008.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0009.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0010.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0035.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0036.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0037.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0038.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0063.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0064.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0065.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0066.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 6, + "w": 40, + "h": 54 + }, + "frame": { + "x": 37, + "y": 117, + "w": 40, + "h": 54 + } + }, + { + "filename": "0111.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 3, + "w": 36, + "h": 57 + }, + "frame": { + "x": 0, + "y": 119, + "w": 36, + "h": 57 + } + }, + { + "filename": "0112.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 3, + "w": 36, + "h": 57 + }, + "frame": { + "x": 0, + "y": 119, + "w": 36, + "h": 57 + } + }, + { + "filename": "0003.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0004.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0013.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0014.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0031.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0032.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0041.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0042.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0059.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0060.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0069.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0070.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 60, + "w": 37, + "h": 55 + } + }, + { + "filename": "0095.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 115, + "w": 37, + "h": 55 + } + }, + { + "filename": "0096.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 1, + "y": 5, + "w": 37, + "h": 55 + }, + "frame": { + "x": 77, + "y": 115, + "w": 37, + "h": 55 + } + }, + { + "filename": "0005.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0006.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0011.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0012.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0033.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0034.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0039.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0040.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0061.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0062.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0067.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0068.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 38, + "h": 54 + }, + "frame": { + "x": 114, + "y": 118, + "w": 38, + "h": 54 + } + }, + { + "filename": "0087.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 36, + "h": 54 + }, + "frame": { + "x": 77, + "y": 170, + "w": 36, + "h": 54 + } + }, + { + "filename": "0088.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 36, + "h": 54 + }, + "frame": { + "x": 77, + "y": 170, + "w": 36, + "h": 54 + } + }, + { + "filename": "0089.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 7, + "w": 36, + "h": 53 + }, + "frame": { + "x": 36, + "y": 171, + "w": 36, + "h": 53 + } + }, + { + "filename": "0090.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 7, + "w": 36, + "h": 53 + }, + "frame": { + "x": 36, + "y": 171, + "w": 36, + "h": 53 + } + }, + { + "filename": "0091.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 7, + "w": 36, + "h": 53 + }, + "frame": { + "x": 36, + "y": 171, + "w": 36, + "h": 53 + } + }, + { + "filename": "0092.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 7, + "w": 36, + "h": 53 + }, + "frame": { + "x": 36, + "y": 171, + "w": 36, + "h": 53 + } + }, + { + "filename": "0001.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0002.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0015.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0016.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0029.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0030.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0043.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0044.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0057.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0058.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0071.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0072.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0085.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0086.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 152, + "y": 118, + "w": 36, + "h": 55 + } + }, + { + "filename": "0017.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0018.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0027.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0028.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0045.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0046.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0055.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0056.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0073.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0074.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0083.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0084.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 36, + "h": 55 + }, + "frame": { + "x": 170, + "y": 59, + "w": 36, + "h": 55 + } + }, + { + "filename": "0093.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 36, + "h": 54 + }, + "frame": { + "x": 172, + "y": 0, + "w": 36, + "h": 54 + } + }, + { + "filename": "0094.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 6, + "w": 36, + "h": 54 + }, + "frame": { + "x": 172, + "y": 0, + "w": 36, + "h": 54 + } + }, + { + "filename": "0019.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0020.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0025.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0026.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0047.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0048.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0053.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0054.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0075.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0076.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0081.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0082.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 35, + "h": 55 + }, + "frame": { + "x": 188, + "y": 114, + "w": 35, + "h": 55 + } + }, + { + "filename": "0021.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0022.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0023.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0024.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0049.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0050.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0051.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0052.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0077.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0078.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0079.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + }, + { + "filename": "0080.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 45, + "h": 60 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 34, + "h": 55 + }, + "frame": { + "x": 188, + "y": 169, + "w": 34, + "h": 55 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:898a0175e268e2bf429019b4b00a4414:3e0d176fabaa6df9ef39756046ad4ad5:319c95b9f5acf1139a5c6761349cd6ab$" + } +} diff --git a/public/images/pokemon/variant/female/178_3.png b/public/images/pokemon/variant/female/178_3.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca5fe14c721f2d80087c6c56b882f929c87b832 GIT binary patch literal 5314 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 UIDq;fjQ{`u07*qoM6N<$g8t_q-2eap literal 0 HcmV?d00001 From abced6cf0261a5daba718f55296cff219b7d1a53 Mon Sep 17 00:00:00 2001 From: cam Date: Sat, 17 Aug 2024 23:17:21 -0400 Subject: [PATCH 13/63] [Sprite] Lumineon female spritesheet fix (#3608) fix from Vari --- public/images/pokemon/back/female/457.png | Bin 23501 -> 23970 bytes public/images/pokemon/female/457.png | Bin 20837 -> 21579 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/pokemon/back/female/457.png b/public/images/pokemon/back/female/457.png index 852684481293db6901e75b6e3068e58424a2b6af..04e1ae12ff4b23faa3154330b8eb199b4fdd2d33 100644 GIT binary patch literal 23970 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⧀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 Y-Gb9kWy-z-ias1a~ABLIK^@$X4S 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 z zFWTb#X6QAb(E|0QwIfO+|6NaT5kT%tdL2irC&vmkU?eC?Sv|b$TU74Eu%l?s6*v{m z)>Ntk#-mA%*dxcF2WUdp$Jj=r=A8!NSC-=p#+CKA z8hoayk^>yKq8@ZR+z0$^nh4zqW{*6*&5RgF<$&$Te=lgRpYLuJpVf&~b3Sh;2VE>hAcGdiv zqn0bcT2pEsywk(m?h_Q+oiEByt^}3Ul1ng?2YhPcWG{8Nf6$3)H9fJ4VSl~HDHR|> z6W*77tLJCK-5S4_lE52d0OV>9cTx}JFvm;5|EB&#!fcw)cmsQk%B*vKmaypW?PvJX zZVLc%ID-ynGdW=(iyk~bu)8w?np_Nl^K|w{{^V*1wO{d^-Zpq?cqjM0GJRwT zQAPc6>XH_%G>+fQ)aL{4c`X5K_DwuzsGMUe{wu!@x4l71ibSCz3xLCU!sVvu{PnOg zD4dl1*q=rf2v>50(*s(N=e$Ss-@n}n9}`oN1{=NWu&n4ymb#xjUIg&D2xhCi8o1-e zHnNi9_{8^l1}97b8u{Jv4H;qCBf|l{pyVeW7UO*!We@KFe9i&PeNZas9(|4ojMd!5 zi-p8`GM%5SK?G2w(;EL5f5prEtqv9*L3^C@k!*%~Q0vU}(rOeyDbm@^++ZPk3z3l3 z(y{E0OYQYF_2o1H7nxb!a|w~zV2$9N&=iu9H?<=Xm_K)jDJ0+(o6JFTa_#I!Nn>K? z;`Osb>syWkvVGI5suB8k(l(Smf|r*Wz94@W$cW?W2mlrAEpDOPzQWWHGW-ouB#U~z zhN#>zpn{UQ35%%mMy+tLffJNH$QvnX1*4m6aZ*%(9Qec=ae;xE*afr;ZjwOEGOLA= zpJ0xh(5tkrfjV->%gF-JcG`pOe#;(tTq889Y%6R>1H42WJ^?#3(<>-qa*uY&F@xxo z2(hA1TAQKvKAQl6_Qqa9B}4;N7@0~Xf3#1}u4@%IpUWr0o`(G(06?`bM$qhClh7GC z1a)e9B&FlO2nhK+j`^I(HI0oH^V{cMVj4d?Hurs=oXgjbqD$5HpqT|H2hK}Hn#@FR z!K=eA6DRFS7X9*)3$_DAP7dH-z`pHN7#VX)oC6Ued& zsgK*F@2psu=I3BMx16%kh&-xsCp~1uL@o;Ncr!101f@6%D1J$J6zyBz{8k{kjsPN= zm&(iQJ@OrPqi4b`zR#QrPVPY|GBc%IOHOp<$*ZUo-fq zBml-svYZ5JTw|+#!E1bf-yRLTE>9VPN6oFLQ6iBo3X7Jjq@R+|%TvAMo5nPe1vjmO z`-9+axq#oPfrAp7r3?0;%Asbqukdj!bzVD5z+fCV>N+1Y(Z~`=Bgc90ne^i`1!D&} zx!|slli%}-=Ka}iG_r`cg3Z={jQ76YJBAOzxp%LLo|>#Asw5(STk1|rgsj4atyE=W z`FLio6V0a?utO=lE!_&XqX3Wm9M>hv-{FN(ZFps6C3`W4Qwweb?s zoW6%QZ}<7FJmZM{X~zE6ED9DZK3RXxjd&KhYMMA2jBMG2SLcPbW@b}ICwqRDqiY~brPloH-R1kxk$ebwBP*5EncaLl{QE=|fJ z@44dPFj`%-oitTQ)8mN7B$dNw5No}y1{B}xz3&s*r(NbfzH)chmorJrn`&I`s(ZE3 z#)h;kQB~=5wjE2D0$ymW_BXv!TguQSn?CfLq5EX2zN-Xnbpz16dBWbyQR7TXUK>8F zxS*yU;jF_G!6I=JiE+LzK7YXiP@zc6fLL^W(LM(o;y@?5Fj6GJ7c#B!xJ}Wg-uQCf zKc$dz`kvD9ZO6;r@!~g6B`lU4D*RAe!i|np6JN_evICl%Xc^QWhId4ygB>*Aevgxr zJ@+|6o}DS3{uCaVik*J%m)VilJw%K?+uCXm1RNa9>d&SvFiPWs&IIR`$xQmW5J<9U z1oAAEC5EHER`#oSPaqw$m`?h04-oyNnN*>^^Y_h^*-Q3v)L}@=g>q+BW{;>gVN<&@ z(Zx^y4UY*@(%fpholu_i`l9X+yTT$!qJ?zFRj2O?chSS-{K()z)?=)lkGBc^F)RnhhXd{XG)8xK`S8c5{UVe!@SQHf4R;&r3yW0}mwOr@oixxH50$SEFZTydR&Kg!6fio{`&-$pfx01@Xej zN~#}#<4<^eCE7~uEWApRXRRnR`^kYGL3opTPnEgRh$?;<)@Jy$&|!D}n%#xPRU`*6 zRUZLry7MLdDY7%-j(usP1nI3Mr-w*5YK2gONe3Kojw1uq1ss^wmC-4F8KC+i^oUe> z@+g`ck**hdF2dI%wG)b}y!W1466Lw~CJ$@P?Y%rud(ZGNN}U05`RT_yEM1ld67#f% zpe z@z7{DfrZcAZDn2;outlA3#h%KR*Jbt`*_#G=3!VcI-!Gsa;=e$845QNk06*+>V~6VIZ0X0O?lJqzNFG#?f$nqaibHB;tJg8CVkw(Uv7iqNg;? z-|5YS0#+a&&3-AqEMytNYk;lw)h`2dx&)u~X?jE?0YScpxMz9+VKu`&H4|VleR))) zGx?ICVP4_&V;^-CZ+*03 zGPt)?3Mx+4NL6gFsPTJkP3tDuSppFCgNJ0!E%dnN)mhuozL7w23Zo-Ah99o7c`TU< zc1_PFSt9(xmD-0@dEkI&q$m1MKf|IhOw5|PeBVeKme$prbIvE-VgBz_X>r(y&Op4% zuo5y@Rx?L)hQ%g>#}yB~gF#(Imq}Vt`k4IW5C(fDB3H2P1=0dXPpcwP|AuE>Y?gi@dZv zfgS}QZFaO>JlNURfbDqybr453CzOiMFDzW)M|1b}&6DUDgaL8dR1Z+1KQuarH|% zZnsu}NHcOHJqi_JL{b>lr5rKmBg2w8Wt!hH6WV(6%S+C|jvn=ZI;hU2-q4kI^!zNz zr9BO=mL7!EoCm(Vfhq!1E&Jh3Gp#GHBcjk<5!&jjhe4E_9p|pQy4Y>7Xvm=u;72S$ zQF0NOs0Z@Vp*L4g%g9_@lcF!Q;FUtcR0JM3=B5$b)RKH{Ki3`9TxvV*#L5 zXB4NY|0n`@r9p7){|+iKz*>A)#CyQ~FFiZj^4U_Pf7+DeSKtKW>94iu59IXUe|rUm z5CF2Yqb(hs8_5s%K3en7a7#;|1h_9 z>(Rqr9q%BizTMOSA?*!svS}nWNiym}C4HQ~#!(}p`1M+ZX<3+_aUQ6z4{6RQ+F1pN_41tUjGU}WCVPHF%Wsl zlcIB9JCd(3N3c8T6=K){w{R_0fmdnki^kc!wEJRVAr2&z!Wj_>0$0ahs2Z(=bWt!B zaBH)F=%fADHt#_I83tgBq+5tSgpTAPZFpML2ic+ayZ;lg3CvF&YZZ?EeEo=C+9#B^5NYiTP<=Od6o}bj$fAe~8 zDFtjV@c6aYUGL%vz=Bn-Hhs|>+R(Z~!dIo+XyjE5o_VA7$K-fp^4$T<-wf&Pfj?%U zEz8JERT7GC!^(rhV~x>TLR~Q#23a8TEI68P06#&<2E8JIeVjFfvp-#3Ss=CL!{Vo) zxkuMU=QbfiT$nVbIS*xNA4y6;#6r)S`~z7kO2a<2amYICq1feskvF|{jslCYK}>R1 zUzTP{XlKKxSx&M#93#3MC}$Ds6n@UQz97Gv#o6^+NHB%L{(~NWXf7>sNQj?|PKCPv zxw_LKrimc0TB*unsfx~rBbt2LJF``i6oH@Goz;bes1%t1W2tr3#|yp_bax#$!#QuE z?(#rE)1T||U)UiKm70OdV2H-EPvh&xyipAVdGD2^3IK;M?&fRP7DWKIps|)25e<~u z<@qlHKHTZ}Flm2BQ5%@Q%K~0pv-MVmiDYI+&=QM{8(ypv zvn{WO#tMYCRH;<|JRCF6CJNre^R?WP#gyUk2ngrcK=$4ADT|OYVN^+bkGt7$Y|px3 z5Cd?0o1w>w?(BMGhSRwe41{PR0?6&8QD$rhQ0j1Xe!G_#pfzxWoi9|NwA@DEN`C|d z$N{VJ@|!7F9WNPDStWL0!DE-cw7l6ZlZ{NgJ(MIyQUFn9!snO0JqkTfKj# zi^03ez0IEv;A6a^&#lAiJ>*$aCcb=!Y5n=3@=jGw+m!Lc486C!?qwEG9F39>q*5QV ztMg?l_@^caLumq9XnABGX67eEMBw~>2<@p1mov|*u}ngpVj2koDg)kBL5BqTWac7B)B zr#W}vD`+0%Vv8YMk;?q;*Yj7AB=`VL6#Bug5OVDM4%VqoJ;L?0UNBtYNuRG&$)pyQ z&Y1_%0tL8*kJN_ZS3{&*h;ko=&lI-2lumGtSAKcCKsdw*OiJKHGj-YA+LQCEl4(q4 z%(pWO__kwn=}^Ap1rHw@$4?KoIXFr)W>5mQV$DiIyfO39R*gjIi$3&yMy~HGb~-c= zEwb|OpP2JTI-$Wkgf?F2X_A*o5?9X~iQK(q#H@1QtyTBjsC?;WN>(;dY&U>*kkyjL z#s&HGIUk}YMABlEZLuV>R#+jm53-=FBRV8F#4*SkWOy{qy+&K`k8N%I|LyW4W$m7> z4BCw>d{7{$vEJq(ZCsRefg3pXN48XuD-iEb9htL4kc7l9Q(xTlCa z6YTFhIe@2JWk12QYHSDPp-d!QV;eP~UCQ~~rL)6>@m=%vcj-cJ?Lx5MgrF4uLw%!X ztz=)G?>>iLuV9Pbl+<~0PP{Gm|IGq)WCVGTfPeAyiw{=M z=!CU*z7mi8*%ugc*dzdDFCk$vwp!Ewlg${=8pGWbrcOSvVbE16O#MYe-J72(*2;@w zXgf=~IbH+prO$3m&j;t{$$goqfMLY)H-}p}>lz{uzyJ9U5M} z`l=ako<^_5J*SVXx^IFm2pXGq8dOKCPIIVAJcadx%VWI~uI*S{sUf9gUuG6cG*E&I zDJ6U>bF}JcJHzS|m4L&{9;=iwL3N`$uWyc)Ck<4Yzc7lRdTF zOESUH+}SLvj8E?*xTz;u5(2c*TIjBlcQEq;9I%|r$I*9-PVllFuNIr%8^#I8Fa{kW zFH2q`0@;yqu%K@SLtF;mdK~m#l5lB?nV>Q8aG>_ZbAfjVdVxwOAsY-g zMef8}!s34oYGX&r&w}*#jcq{#$}cap(a{dW+HzmHK!gs|MlW(DQC2-5X^5wJ`bodGgEj{BW%gb_kunJ)9R=F1KBGV;wZTRU87*0jcf@E_YRG329p=Fe25V)Gj4mi zuOtcHtN1WQ7nb4+xr{~~nY!V3@38i5$wq%pXyc_Zl@w};Z2ToCzuNeAMrI@TpEjJ;Y$&b&m(GXCHLkh83H+TC4qmsEv1;>CIlu5wU4u9A?VPEBibtFd2WJUB4TWSH;EUQ^XU z#hNgRmM=S5#c9m*}xaEXm8C*2nO^y(*QB4#cZPbKp6#7LgNmRW~aN@GlFCF zJVrC)ThQ3#@p60>9>ehcX7|KKPp;uOR^BMH(q(iyO30;J86Etdp`J%w$)DoJR2qmt zKj)(IfJ6D>x1q3~O%BNY0+OY2j*1f}!N3P9YzeL?aM*0qIr}hLssW=&+=xIgBPqc3 z@!(*K0hIxE_pfR6=Y7|Ut0_6LU|vgmWgz+Dw@oCS#s{ZC?z3MhJb)g2_Q8UwX+7>f z`8~97?SF-v%YU%-AC{bf=7U`H$kIh|yKn4<)|(;3$2)d^V; z|1W#1lYMR^CL3s{7Dxl*wVE1rVSQ4dU^saCJBJG|mL5oc&aT42?#PU4_6G);AjC+Dqhd>5)pCm#SAuOhm?DbUYA6aaD}1IQ33XBlG)am zX@lNDH$c_bH1B7t$?U0!5+75k^$Y&QOvf4Wpbpi;G#EKIdFoK;E~}(F@$dBt?^#Pn zU3BQxJ8s>37a5Pw2f_`W&gXj%LmwtuuvULtjAY9MwZ=+F{cP-iTEJ*X)5yfw!V7=q zI#UO}xOxnSmbT<8yz?OXC1ZR2&N5bn?hsnc1J_rs+@QEQS-DNX(g1hKX@NAwfU|*WF}E7?b$B@~%W)!~)o8DD$UlVN6@A@(akklg zOS3F<7|VX7bXY=*$kkm@$kI-hmYLhMFnY(POh|#~`_C+IVI+g3&eNW*aQc6J;|)F5 z9=)`Gb0)1LsFi!Ls~ldf6!cF7`s7L)PVc)RB z{HoBsE~8J3+b9q_dYH}-VDl+&#jk6>=G9!+1aYp|y@1V|0HE%{j}#&w*GJ_Hq%A!C z(~JqKNl>p!(q+F-E!AzQf@NdS``zb*g6(fO|8;-kbFV32>6~Hzp@+FdJN+pTPjhUR z2FwQoE;%ks{!9e!y*=+CB)B|yfw2?uHm#pR{51g|e4@=X6 zlnN(tyts;ym+Z9vrTki*SpR9~4k4X)tWqsiG$NyK>8$;T={Sat2p;poIY*m}3s=q1 zI^;+&Quf+t4&UbeOc*1<$>eO-)G?sW7MF?3zhQcG@#N!xiX>QNCvyJvIWs<*OjM@1zTS6MJOLbU10Qo!7jdo5oqOfX{N@KMOMBXXqiUK2Nh$%vood9D;% zI7T3tT{kB3a=OHF^f|*X!9yfepa4+wlBVaw;`M*Iet|#M+L@IJ7wWE9sft)loQ89i z=04y4_A3a!+5mN1b^0Vh^(O|Pgw2=ZeOYg%{bP6sl2OLb@?6)u#^{2;EOFUOHz%(3 zEB;&AbF^}VpuvuXh{2AtT9Pk?h`a@`E#A|M7E`fTj#Ah7f-MC? zX>IM(NYs(uco1{Pr3p5XATUoKEcKUFCB5|A2fY6I_md79(9~ze=4p)^{(EmDH{98@ zO6$u2<%Z0CBn3dODN7PrZK$`wAjp8kFuLI7tQ~a>Cx2pOyzu$mcO5MY{#Wr|^KAJN ztFX>s@Y}vs^JL?a3kVzor*V_AW<;^D=TMNU?M zS>&Ao!C$BN<-1wK3o$!AA}`^SW>#H4;^^U|lga=aG}x(5J41VrVv&wF*|e$(_Fu;b zJ>~e!#_l02JBYa+N_unL)-vf$%hQ(TXCFrli2+lQ`LEu%vW3Nqx#)phU2J*Dw=ZUy z=gEuZm;ZI00n&rqD`&|h>FhNOyq-9VN@7cEbMk6;2_wA`f=h|W$qeNsBw>w}MX3=X z|7~UEeuuPaUZtb_(sj2~3)Xa+q;=7I z4-zzkzj)rBq?-3?6dyqCZ7)Wx$SQSj&~|yMT-cKyi?1)(M4=z5o0tLs=k9^R6B6Uy zMaz|~TKEo=H#_~$5cK52(+-rwB<(ruFqUXq{~-Zvka9!fb<0Kmin5h6N!aX*AO=K8 zliwpOK0*Sx&N?Uf&tcswQCf4i?-Pv0Jj}fSG|1xQ%`{+YG+uycZ6trk$K@jC%a{Js zg!_%yMt43|_4P_J7u)5at2m9z$P4uk0+9@)!>FYqON5k z99UKR`O<8Fo2bE`OraTzE6@S6WH`PNzL4ln(9QLA=Y*oTU9~6=Uks)%+>h%0cE%g6 zg^!!@&5{|Wmu1>Cp`#}SkYKo({35_A0P*en1o*}+b;h5YY~xu0@!T#Ke-V+_31GPf z!=U%%xwAeC$#DgiYENw$oCs4Tc zgYCv$*nM*bycO8o^t!0SdbHgI*~2T8=jl%{Nf3RXO`e-u?yO z)8M!j5c)|-lpV$4}N-~Us1TQBh7yHdp?z|hT_#n&+ zNEFcS!AIKPD?qs)g!?JD4w$$f*RO^gm=%EJl_&q0+XpBd+ibV-H+=_gU?$tODY+XRqzptf5WQhOscZlo^6?f4~Yi{1v}P zW$i>R=B-%N%WNJEeRMI;gCs6F1d%_^sdde`$yVDvR6goYW0DAm@v@(#mFa$xh{`GU zoeCzAbNjPT@lH0+gA2=x4s_ksKr(IHTZL8D$owG+%RNl(N#ZsNj6hmh1^bVwzkuLV z#eAYI(&56CN1Y4aiDmzyH6xx8D`UeV?QcM<^0=V4`Pq5e9`0^dxZiB1KS8a2m}|T% zAkTpC_5gkufW@Kauy+dM<}{%Q@rYo(i3wnk zPRl7f*p5wGK$;zvU|G%TA`C_l`Z5)rA359TLNtQ?YD{lBwQS?T_%Ok56tdmLLC{yP zhfgTqhf%PfNx=9i8TOgVXhekm>~)e;-Z1-``25(kBp`g7f-=@RsNvlcDHbpms`(g% zKkv?F|C&?@tL%{SuJ~0&Tl-Xazrd$>;}E(X1Cl2XX+;ZUzAax_TW4-wsA< zMW?ua4cR$B7pd*WP`o2StZ~Ehlo0fm#l)slMEO$odGDyWhx1;GK%>$Ra_i}P=blXe34 zeofUciz_dwP-|8qZrPMniPr8uK{(YdEiSsZFCXGD7NUWI%^&w^p^IHUh6cJ_eQWzK zf-#nL-XNAfIkm=Ei##+~Qzh0|%`UqBNha?}w)SIQZI@=D+=x z`P4G4PpNu`{w=aM679pP?(f%^S16}h>}J<+nEkks@N*f?Bzox+BL`qlSJ{JZ&w;yF z(~*XHMZJxj{lMDSH@AT$eX$Fq75 z@oM={);q3(?3)}$>NdOaAEElGr5$DA5=xpI2ETiywe!HeZZi71I`LEA{*okX@^P%98)hBf-kD!w@0yf}UV1 zsiNWZ=-+awo)0_KAMT0cUS9vMOsegp$Kj)@|NTj^CfJ|{(~5d8m9fO|pyz5=my@4Y zF;uOR;mqE5w@RdF#sw(^a@!Vl`=>I%Z@a*)@j!9`Fw|!Y`uOqJRo(+Vp`pSt-QW}3 zq@;aj~%<=Jj1TR^l%2 zD|^)8l%(cuL2n+h@3ljrKjXe(J`x@moF%!*?SER3H<$s zzQ~4}9bVw{(NTW=(@;C0jF!`dWMuR!mmL6^Myp9 zTx%c5((iR2X@ehvji*l~TuR2A^~NPy;ipO&D$bhYno4N#=pevwGI9%o$-GMGrxHc9 z@zIIhlu?kS;HF3e=d2gE{%>H}_=QIho_06f(8asN7#|LfO&9lZRHxaVdEkQyUBR*(B0 zt$2qkp{W`l#(z+Mn*5tAC>j)`7rN|%xQ8~3M}>J{cEVjx6#W9N6R1ZwyVxWVhX|>Y zGKz7}+!V7M$RFJ8&$Xpej-Nia-A%q~JX*J-S=|mm@{Pa+B&*428Ow&8%F;R+j#)Oj zB|8tC?Em^k?v=WQY6VY?>?;=LNQnYwmPSUlxg_)lT~QZW`&{+%f9`#GIlov}8AS{G z0A4&UOMHYZd8m`CVT_(}>Y#yoX^~ff94iOdi62Y#WNpBIC-OsW#f}Xb-owr{`BRC* zHs_Z?QYdbv?xMhfCO#pJY~EB0HStksb?rv*!vAa1=d7jcat8HDrM3B#qHHzeqzW=d z?Efgv>2OMI!U+7+_YK8GXpX=IdF-TBB7OkaL)O@r;h99>0o{q(iFozCuB1@d823e} zhZ-m@&CWhSga^=szg-a>BzFV(2f7xH`oaUZPvlnc|KCc}D^pA3vu{p|d?#jVSE z5zF}x=q4{k9H*(=MBU7CIFpO6sm43op~bhn4w!*oWMtPjh_3$yeH%QqTbnD2G4!}= zpBaesVR~+gJVOQSFsz? zO`4Ppmn#P5NVKbB09;GB$WXdH6rf3^RjFK}PXmy^MR^Zixt4v?%JomBzZ7muWXbZ8 zp9Ql9K3@G~TWfYC`7u-^4x{#f=Rt1RY?`#@G*#pnk+w>5B9oR(gTN+Gm=Uvg8_r(YdKfl*4aCHJ1R!jgXDm&l~ZUGSwIH_)>h z9==H^S091-Cs^rumDQ;@^XEYUi6HOOx4^byAPa9Ph7RDSKG0Dz?9T&-Us&eEB6n0+ zh^B=c?D!`b3m?S(TRi%Y)AqRUYcDC8NB}C9c?j4?{kC{yr9fv098~Od?)uJ zh2c2rTj(g!o5+j9)8NzriIVp^hIR1(XQB5WeR|y6#|owympeqn9q4sMDt<46$=#M- zt3)mHz%!mA(`z80WWNeQVl+EPQ(_)bJI+ zuxdba@Grako^1uVK`1gpj*o@MUsgSpu_(a6mesJ^RcUVo_CQtas1g##M~ESCruO4i zLVw0c{7S74ipcVu-ivP66!=n^c|?;w+8|!1$PKE^pGn00;BtQ&tXK@}`SEzJ@ok1^ z!yCO$f+Iww6&V`5{9f(*7Q4*@!&FKmQlK6>GM{JJtcCjpCrJ9r#B((xkjXqv$sF7- zQp&)r!bc;bb!tV)R?+MdZ}i=kQ8Tt}``s^{<`3oT(}fSHgN`8GpWh8Eq+TZQ5+=P7 zvL!iA;RR}2)Np|~o2{0=g^2JnEE$^Rwa;65W2CXx8Uv7m<5YUwI==8$q|S(0gud3Bu=zoPdf$C<|*Owu}d|S3pd!;?t0nTHy@bsgJ2_@ zWqsM=qa|fU{?{g>h0GEX21HxJPGt&zeS8I(L?$Ms$M>`aDZEPT9< zYls`@PbhuNRWF~JE>VFo9eV2ep~J8rG6Pa2L)*J-k?X{ZNk#I7fd|X6Y;o@h&MLMr z_NfbwDiVFqHl%@4{17hFQ}Q~Z6w6kQ`bAaFI57F-z#8q7;sQUZWVZYmb386SSQ$bX zrM!$w`gykl@GG!6z&$lWbJ`9QAnofTcRsiS+$tovfhmAnds8eed1;ak^RvARjG7Wt&;cWuB?F3V zcO(X1P^*!N)3^o%*Qcd_@6YbNFSMq08#J7IvuA%#g04g$tCh9L-=i%zK>Q_wl&X8;os5 z|IIG6d)7u&f=?K4?%@+|8c$)bdY`$v85nD{Iqcp3?BB}iS2F9jcUz6bWLBKAdoNt| zvwvUI;+Zu6`@8UK5l$in$Gn$A&=$v6^r|R7^Ai$@L#bi+V-U_B!inBa^vM%njvfgY z#u~*ZMW<1Yv)z;g^_xYcbiJ!{!&5<2j%D@Z+U-1APucGMN)y2eQ|a%PTGUt{9R|>+4FoEDE`?_?K2kmO+qaM8{kIq zsx^pZxAR}m*>z0tu3;NDTxB${LRyn_`Uu}BgY@-M>!OgKtRdDfupWH|cB}g^!Iw$? z%n@$K_m3rW#+o}Kj(+ZPO&YM+I49q|E~J720JL-e{udzMvw7#A6PM13bzB2|p@j|( zWnL=1E+b8=bci(D9pn+TT-M%&=Pf9S|`o!wSkmzsCezH+@IZXnCXTcWslF49$ zXE5!YYR^k79XH~lgE4ZzFz`jvy32~`=LtjmQLYp6#U!T2KXJTmTzv0An(iH!vb$VE z7WaPZ2j}Lm{vPw=$^bV?VVYyc1f6s!GV7!A@hb`n;y0=6cr|Cey-{F;eT_$nAOed- zX_?E9y0_wAmP)^x?Me{N3v{>jHX6(|??|fQ_P2@!ZIVCYS?eV(p-R^N#*q8rOL(OH zYF=B)D!XMQor;Gd2Pmj5%|9K3^vQoyW@%@7)s;hgvHtE@)xq5oB0`IuFs^HI>yoBs zt;Dp)7r@c?zda;Q)P3arG5pWtV7&i5`Fw-WKk@%`bLQ_*_HQ2_QOMm`vM)Er*dkg8 zDa?#z#vn_X8)M0meH&Y{hq7cawrokZ+_thd){-(tWM4v~3|UhXVNBzD`5w>l9LMu7 zJl9XxFP|T-&lNOp!dI0r zTdSJSPs6InW?k>p;O)_YGn_RMa9y1}3(j3cBKN7{Uv=-b2 z^a7&-*GYNzPkf0=u>!2_4etA-%x-!0`)u=clN_zeDPxXemb`#)UpyZ#CTah0g2Sq@ z2pj4-OSg8;GgxcPy(2FhnhtVvv(m_VIA-qqt0h%GHkyqyTj_Uu679bv7j-}<$hT72-8$y3|c;My|$Et`0>~K?g%yotL{NX3?GV| zN3yRG6GP=fkoO1gTCz_UFsFkhkz8qM-7U&|)ec$_{%(R!Pxo$xxk!Y8{gae8;6*xfGoqwiD zKApzKMGn_b><^_eqAGYn#Wdt*sG1ZW$)Sa5Q!lKRwHpp3!wG;8Z}uLGcUpg9sihyJ zf9Y4MDY>aVG8KTi3ruV*6ipJ}^4u}R5t$w+Eo^TeaY9|OEVzkX|TVu**z?K7Bjc{wzW`bn43CoXO0 zrj+wC&9r_q6WW!*|0499tqj2gg{JdVcw1@ke5MEmJ-Nak!V+d^JN6|W#&Oxk4<5FKS7c3uQ|^vDui0ho+mAG^qCIXmmYpt(A<|QS>-Roh(*Ija_y6-*!Aq z8AaP>={201{xbQgy&_Y$)V1|;pM{MXU0+I8T(3TDT2xu&%wjGVGOtb;MfQ7FVKv&V z80xdFz4f&c(0Ow&{{CY>CxCTNbnz|_LhRX4LGiYCkP{ zyW#S(}0F6!wI3288b%thm#QYG5pj@~C`2ltjOWP)^2mR}gh9-SSLcoH0{wlcLhMPds`uTUK?-Pj8Fo>!#1Zsrfm;w_B&BmJDI{30v+0+?050ST^@oDeA{(bq zx;vPb2ewT$i_FKr)2YB(UKuj8=kl>^#Zpz>%C!n2>^=!o8}F#stAk?=2#TK1`9D}T zjO)njirG$NP}pbILx7zVwZBsvbo*ePwq@;#)>kY;ZY?b9FL~C6w!8fbJCZ~B_WV<# z_69DeRb=n+7t4_*{n2%`FSW>l;9Br&^@GU9#AirJXJdOE+BX`q|8Gb%-6qJV+C@+) zk4^sll8|EvH6yNZF{D%*CenESdws=@x!da{~ zEr_Q~Kgpyvgpa9J_gr~7_gf0OXoe$AX5{0SpFs@V=#aX#D9WpZwU-N|vm+g2sv`A- zA^UwhN?iG5PB5rjLWlrWCvqHH>5dq>M;f4rE#Z;)3?1A6=sg7ENTZa`UF!W5^P=SZ znH*P`DtNx)DS&F#MJ9R%CKX^Z#^K^AZ-tmZ4u*9Z2cftv@!W!#RR_+h>t1KG0{Pie_|ZW0tYl)cl>2hjynxGMCblgr%ZIs?Mm{= znJLZI`s`g!cT>cg0YdTlwVC=54)*Vl)b4mEp9H@2(8tuVhz`9=mfPB>O00v8lJtb; zOBf#iH2fD9yuGqQrmkXZ_H!?W7?51#jsP%zrQ+E?M5uLDn?BzLh#E<7tDoG}2HmSP z+O7kB5|PB36)dD|l>B!!4mBI;ExvBxr1Gq}vUJK;qG3FcFpgR_95T-yD|-&P zfBRDoC?Rlk{D`@y-Y-8|N-BYLD`>K)*dIo2uj53H$IGT|WNjfk<|Bvom{GI)*un{aYtp{Sr&B_lc=3_|*9@L1HtB5`wFw-sSqP!IT2Qih zD#SstW?f3Tj6>3-JiX13Wz%Pn846YtobtO3n(%Ol$3`SQ|k8ag9yF38f`|H=eTWx0LEdc zeGW4!y)I7NuBCm3IObmwcsbTg%(_B)TmW))?jruLd)=)GG;EKRh%JAYq zT46Q;9$d+>C5*U${-PO@BuQQ-EvM-4;zAm>WSZ2YZ#rM-cUIX`fd^Alc6H$&67NiI zp%jY1gUEfk^_mVBLx9$w=)V5GdDjpWd^t`u#0@CzinBms2jeqzk}k$;>%QOtEA#MG z6z?U9`~lzwG7TTp=+^80i5@U!=`h*xKb~$d5J{OIBcfRUeDE&}dedgv=V*df@~WfL zUu*2pHqM9leKSrr)=)A{6i4WA#;LhiXVfHvW5Pv?NGSr91t|r!v*pHYu^dH8Qsc%P>8&gpg6TA+WN)YAdR%zVfd+AIDzfK(S%&o@T zJwnvL7&a)r#}4$_r!LBCcg#LyGVD{6UN`sqn#_8J5_~*_FRvh(dV9^_3zD<@FW;9I z*~$z6xq726qW osHo^Q59sX3$jBn>|Mk)%$tF Date: Sat, 17 Aug 2024 20:28:06 -0700 Subject: [PATCH 14/63] [Bug][Hotfix] Final Boss MBH no longer transferrable (#3611) * Should fix it. * typedocs fixes --------- Co-authored-by: Frutescens --- src/battle-scene.ts | 6 ++++-- src/modifier/modifier.ts | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index b2e5635b642..a8edf7b3af0 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -5,7 +5,7 @@ import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon"; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species"; import { Constructor } from "#app/utils"; import * as Utils from "./utils"; -import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier"; +import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, TurnHeldItemTransferModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier"; import { PokeballType } from "./data/pokeball"; import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims"; import { Phase } from "./phase"; @@ -2666,7 +2666,9 @@ export default class BattleScene extends SceneBase { if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { this.fadeOutBgm(Utils.fixedInt(2000), false); this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, undefined, () => { - this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true); + const finalBossMBH = getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as TurnHeldItemTransferModifier; + finalBossMBH.setTransferrableFalse(); + this.addEnemyModifier(finalBossMBH, false, true); pokemon.generateAndPopulateMoveset(1); this.setFieldScale(0.75); this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index a32f3c019f4..1dff041a14e 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2338,7 +2338,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { * @see {@linkcode modifierTypes[MINI_BLACK_HOLE]} */ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { - readonly isTransferrable: boolean = true; + isTransferrable: boolean = true; constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { super(type, pokemonId, stackCount); } @@ -2362,6 +2362,10 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { getMaxHeldItemCount(pokemon: Pokemon): integer { return 1; } + + setTransferrableFalse(): void { + this.isTransferrable = false; + } } /** From 0e6c2952ca4e68fa25230b5bfb0ffaba57068b07 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sat, 17 Aug 2024 21:05:04 -0700 Subject: [PATCH 15/63] Make Disguise properly reset form on arena reset when fainted (#3612) --- src/battle-scene.ts | 4 +- src/data/ability.ts | 2 + src/test/abilities/disguise.test.ts | 66 ++++++++++++++++++++++++----- src/test/utils/phaseInterceptor.ts | 2 + 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index a8edf7b3af0..674b4e256f9 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -37,7 +37,7 @@ import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin"; import { addUiThemeOverrides } from "./ui/ui-theme"; import PokemonData from "./system/pokemon-data"; import { Nature } from "./data/nature"; -import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem } from "./data/pokemon-forms"; +import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem, SpeciesFormChange } from "./data/pokemon-forms"; import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase"; import { getTypeRgb } from "./data/type"; import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler"; @@ -2579,7 +2579,7 @@ export default class BattleScene extends SceneBase { // in case this is NECROZMA, determine which forms this const matchingFormChangeOpts = pokemonFormChanges[pokemon.species.speciesId].filter(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon)); - let matchingFormChange; + let matchingFormChange: SpeciesFormChange | null; if (pokemon.species.speciesId === Species.NECROZMA && matchingFormChangeOpts.length > 1) { // Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves. const formChangeItemModifiers = (this.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]).filter(m => m.active).map(m => m.formChangeItem); diff --git a/src/data/ability.ts b/src/data/ability.ts index abc45273131..cfd900d621c 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -5039,6 +5039,7 @@ export function initAbilities() { (pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }), (pokemon) => Math.floor(pokemon.getMaxHp() / 8)) .attr(PostBattleInitFormChangeAbAttr, () => 0) + .bypassFaint() .ignorable(), new Ability(Abilities.BATTLE_BOND, 7) .attr(PostVictoryFormChangeAbAttr, () => 2) @@ -5191,6 +5192,7 @@ export function initAbilities() { .attr(FormBlockDamageAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0, BattlerTagType.ICE_FACE, (pokemon, abilityName) => i18next.t("abilityTriggers:iceFaceAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName })) .attr(PostBattleInitFormChangeAbAttr, () => 0) + .bypassFaint() .ignorable(), new Ability(Abilities.POWER_SPOT, 8) .attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3), diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index 183295f6f41..8b1b959bea8 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -2,12 +2,12 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; -import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; import { StatusEffect } from "#app/data/status-effect.js"; -import { MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases.js"; +import { CommandPhase, MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { Mode } from "#app/ui/ui.js"; const TIMEOUT = 20 * 1000; @@ -38,7 +38,7 @@ describe("Abilities - Disguise", () => { game.override.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]); }, TIMEOUT); - it("takes no damage from attacking move and transforms to Busted form, taking 1/8 max HP damage from the disguise breaking", async () => { + it("takes no damage from attacking move and transforms to Busted form, takes 1/8 max HP damage from the disguise breaking", async () => { await game.startBattle(); const mimikyu = game.scene.getEnemyPokemon()!; @@ -134,17 +134,30 @@ describe("Abilities - Disguise", () => { expect(mimikyu.formIndex).toBe(bustedForm); }, TIMEOUT); - it("reverts to Disguised on arena reset", async () => { - game.override.startingWave(4); + it("persists form change when wave changes with no arena reset", async () => { + game.override.starterSpecies(0); + game.override.starterForms({ + [Species.MIMIKYU]: bustedForm + }); + await game.startBattle([Species.FURRET, Species.MIMIKYU]); + const mimikyu = game.scene.getParty()[1]!; + expect(mimikyu.formIndex).toBe(bustedForm); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.doKillOpponents(); + await game.toNextWave(); + + expect(mimikyu.formIndex).toBe(bustedForm); + }, TIMEOUT); + + it("reverts to Disguised form on arena reset", async () => { + game.override.startingWave(4); game.override.starterSpecies(Species.MIMIKYU); game.override.starterForms({ [Species.MIMIKYU]: bustedForm }); - game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyAbility(Abilities.BALL_FETCH); - await game.startBattle(); const mimikyu = game.scene.getPlayerPokemon()!; @@ -153,10 +166,41 @@ describe("Abilities - Disguise", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.doKillOpponents(); - await game.phaseInterceptor.to(TurnEndPhase); - game.doSelectModifier(); - await game.phaseInterceptor.to(TurnInitPhase); + await game.toNextWave(); expect(mimikyu.formIndex).toBe(disguisedForm); }, TIMEOUT); + + it("reverts to Disguised form on biome change when fainted", async () => { + game.override.startingWave(10); + game.override.starterSpecies(0); + game.override.starterForms({ + [Species.MIMIKYU]: bustedForm + }); + + await game.startBattle([Species.MIMIKYU, Species.FURRET]); + + const mimikyu1 = game.scene.getPlayerPokemon()!; + + expect(mimikyu1.formIndex).toBe(bustedForm); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.killPokemon(mimikyu1); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.doKillOpponents(); + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { // TODO: Make tests run in set mode instead of switch mode + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + + game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + game.setMode(Mode.MESSAGE); + game.endPhase(); + }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); + await game.phaseInterceptor.to("PartyHealPhase"); + + expect(mimikyu1.formIndex).toBe(disguisedForm); + }, TIMEOUT); }); diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 34f79f93b6e..5a8b4ae01b2 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -15,6 +15,7 @@ import { MovePhase, NewBattlePhase, NextEncounterPhase, + PartyHealPhase, PostSummonPhase, SelectGenderPhase, SelectModifierPhase, @@ -92,6 +93,7 @@ export default class PhaseInterceptor { [QuietFormChangePhase, this.startPhase], [SwitchPhase, this.startPhase], [SwitchSummonPhase, this.startPhase], + [PartyHealPhase, this.startPhase], ]; private endBySetMode = [ From 58bf18af88a96c8f011dc9b42fbfbd6f9af3cadd Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Sun, 18 Aug 2024 15:39:08 +1000 Subject: [PATCH 16/63] Fixed issue with falsy issue within condition to get a stat for IV scanner --- src/ui/battle-message-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 1c7dfb27630..7a30e2787df 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -226,7 +226,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { highestIv = ivs[s]; } }); - if (shownStat) { + if (shownStat !== null && shownStat !== undefined) { shownStats.push(shownStat); statsPool.splice(statsPool.indexOf(shownStat), 1); } From 69c1389ec4ceda8e9389129118a4456edbffe15c Mon Sep 17 00:00:00 2001 From: KimJeongSun Date: Sun, 18 Aug 2024 15:12:20 +0900 Subject: [PATCH 17/63] add fix setting code to prevent form/variant bug when default form/variant setting is wrong. in addition, that fix code include gender fix, so i revert old gender fix. update wrong log message. --- src/ui/starter-select-ui-handler.ts | 96 ++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 5e942f3e75a..9f2df1f2329 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2916,14 +2916,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); + const isDefaultVariantCaught = !!(isCaught & DexAttr.DEFAULT_VARIANT); const isVariantCaught = !!(isCaught & DexAttr.SHINY); const isMaleCaught = !!(isCaught & DexAttr.MALE); const isFemaleCaught = !!(isCaught & DexAttr.FEMALE); + const starterAttributes = this.starterPreferences[species.speciesId]; + + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); + const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); + const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); + if (!dexEntry.caughtAttr) { - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); - const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); - const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); if (shiny === undefined || shiny !== props.shiny) { shiny = props.shiny; } @@ -2942,6 +2946,83 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (natureIndex === undefined || natureIndex !== defaultNature) { natureIndex = defaultNature; } + } else { + // compare current shiny, formIndex, female, variant, abilityIndex, natureIndex with the caught ones + // if the current ones are not caught, we need to find the next caught ones + if (shiny) { + if (!(isVariantCaught || isVariant2Caught || isVariant3Caught)) { + shiny = false; + starterAttributes.shiny = false; + variant = 0; + starterAttributes.variant = 0; + } else { + shiny = true; + starterAttributes.shiny = true; + if (variant === 0 && !isDefaultVariantCaught) { + if (isVariant2Caught) { + variant = 1; + starterAttributes.variant = 1; + } else if (isVariant3Caught) { + variant = 2; + starterAttributes.variant = 2; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } else if (variant === 1 && !isVariant2Caught) { + if (isVariantCaught) { + variant = 0; + starterAttributes.variant = 0; + } else if (isVariant3Caught) { + variant = 2; + starterAttributes.variant = 2; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } else if (variant === 2 && !isVariant3Caught) { + if (isVariantCaught) { + variant = 0; + starterAttributes.variant = 0; + } else if (isVariant2Caught) { + variant = 1; + starterAttributes.variant = 1; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } + } + } + if (female) { + if (!isFemaleCaught) { + female = false; + starterAttributes.female = false; + } + } else { + if (!isMaleCaught) { + female = true; + starterAttributes.female = true; + } + } + + if (species.forms) { + const formCount = species.forms.length; + let newFormIndex = formIndex??0; + if (species.forms[newFormIndex]) { + const isValidForm = species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex); + if (!isValidForm) { + do { + newFormIndex = (newFormIndex + 1) % formCount; + if (species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) { + break; + } + } while (newFormIndex !== props.formIndex); + formIndex = newFormIndex; + starterAttributes.form = formIndex; + } + } + } } this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default? @@ -2993,12 +3074,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (dexEntry.caughtAttr && species.malePercent !== null) { - let gender: Gender; - if ((female && isFemaleCaught) || (!female && !isMaleCaught)) { - gender = Gender.FEMALE; - } else { - gender = Gender.MALE; - } + const gender = !female ? Gender.MALE : Gender.FEMALE; this.pokemonGenderText.setText(getGenderSymbol(gender)); this.pokemonGenderText.setColor(getGenderColor(gender)); this.pokemonGenderText.setShadowColor(getGenderColor(gender, true)); @@ -3479,7 +3555,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { checkIconId(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, female: boolean, formIndex: number, shiny: boolean, variant: number) { if (icon.frame.name !== species.getIconId(female, formIndex, shiny, variant)) { - console.log(`${species.name}'s variant icon does not exist. Replacing with default.`); + console.log(`${species.name}'s icon ${icon.frame.name} does not match getIconId with female: ${female}, formIndex: ${formIndex}, shiny: ${shiny}, variant: ${variant}`); icon.setTexture(species.getIconAtlasKey(formIndex, false, variant)); icon.setFrame(species.getIconId(female, formIndex, false, variant)); } From 1b7a161934930c1de4493182f82386ff2b223073 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 18 Aug 2024 09:52:32 -0700 Subject: [PATCH 18/63] [Hotfix] Fix Memory Mushroom not showing relearner moves (#3619) * Fix Memory Mushroom not showing relearner moves * Fix rollout test --- src/field/pokemon.ts | 2 +- src/test/moves/rollout.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f1721299ad0..10851451a1a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -921,7 +921,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * by how many learnable moves there are for the {@linkcode Pokemon}. */ getLearnableLevelMoves(): Moves[] { - let levelMoves = this.getLevelMoves(1, true).map(lm => lm[1]); + let levelMoves = this.getLevelMoves(1, true, false, true).map(lm => lm[1]); if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) { levelMoves = this.getUnlockedEggMoves().concat(levelMoves); } diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts index ad323c447f5..728fe1ecd45 100644 --- a/src/test/moves/rollout.test.ts +++ b/src/test/moves/rollout.test.ts @@ -12,6 +12,7 @@ import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Rollout", () => { let phaserGame: Phaser.Game; let game: GameManager; + const TIMEOUT = 20 * 1000; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -77,5 +78,5 @@ describe("Moves - Rollout", () => { // reset expect(turn6Dmg).toBeGreaterThanOrEqual(turn1Dmg - variance); expect(turn6Dmg).toBeLessThanOrEqual(turn1Dmg + variance); - }); + }, TIMEOUT); }); From 67da7956119afe32f7ec178a32c14d1488fec6cc Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sun, 18 Aug 2024 10:29:11 -0700 Subject: [PATCH 19/63] Rewrite player faint logic in FaintPhase (#3614) --- src/phases.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/phases.ts b/src/phases.ts index 88acfc825ef..565914879e4 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -4033,13 +4033,24 @@ export class FaintPhase extends PokemonPhase { } if (this.player) { - const nonFaintedLegalPartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); - const nonFaintedPartyMemberCount = nonFaintedLegalPartyMembers.length; - if (!nonFaintedPartyMemberCount) { + /** The total number of Pokemon in the player's party that can legally fight */ + const legalPlayerPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); + /** The total number of legal player Pokemon that aren't currently on the field */ + const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); + if (!legalPlayerPokemon.length) { + /** If the player doesn't have any legal Pokemon, end the game */ this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } else if (nonFaintedPartyMemberCount === 1 && this.scene.currentBattle.double) { + } else if (this.scene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) { + /** + * If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon + * is already on the field, unshift a phase that moves that Pokemon to center position. + */ this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); - } else if (nonFaintedPartyMemberCount >= this.scene.currentBattle.getBattlerCount()) { + } else if (legalPlayerPartyPokemon.length > 0) { + /** + * If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field, + * push a phase that prompts the player to summon a Pokemon from their party. + */ this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false)); } } else { From c8ed89e186dfeb06f521caaee643ef30a2bfe653 Mon Sep 17 00:00:00 2001 From: cam Date: Sun, 18 Aug 2024 14:44:50 -0400 Subject: [PATCH 20/63] 867 runerigus sprite (#3629) cropped static frames, fixed cropped sprite set runerigus exp to use the shiny exp's animation verified all hex colors are unchanged - fixed ultra necrozma exp front variant swapped arrays. - xatu female eye color fix --- public/images/pokemon/867.png | Bin 2128 -> 1047 bytes public/images/pokemon/back/867.png | Bin 1617 -> 800 bytes public/images/pokemon/back/shiny/867.png | Bin 743 -> 793 bytes public/images/pokemon/exp/867.json | 1590 +++++++++-------- public/images/pokemon/exp/867.png | Bin 23716 -> 13409 bytes public/images/pokemon/exp/back/867.png | Bin 7341 -> 3724 bytes public/images/pokemon/exp/back/shiny/867.png | Bin 3270 -> 3715 bytes public/images/pokemon/shiny/867.png | Bin 976 -> 1043 bytes .../pokemon/variant/back/female/178_2.png | Bin 6304 -> 6305 bytes .../pokemon/variant/back/female/178_3.png | Bin 6304 -> 6305 bytes .../images/pokemon/variant/exp/800-ultra.json | 32 +- 11 files changed, 842 insertions(+), 780 deletions(-) diff --git a/public/images/pokemon/867.png b/public/images/pokemon/867.png index bd07a7a48375858f3ed2506c81e51befc2c02db8..2fe8856d74df6113ece362f16ddf144140f82469 100644 GIT binary patch literal 1047 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 P00000NkvXXu0mjf&XWG+ diff --git a/public/images/pokemon/back/shiny/867.png b/public/images/pokemon/back/shiny/867.png index fce3fe4e37eaa10d77894bfd02c7d8da05536297..accb87844f1c680b67e46ba371405a992adc6d83 100644 GIT binary patch delta 750 zcmV5(BMe+P6@PE!E?|NsC0 z|D}JX`v3p}pGibPR9Jqa*agmie?PDZ&UyddX7~rT!GZm%V?Es2RjnQSRPJDBlM4HuAJda8HmT((A8Rw` z{B#EfbhRs-=o2*qe^53nmdFk9(M=D zhCK|_cDY4py*!63u(0(_>Cmfr?`?j*UMAWSwuZ4COtVhEI=jj3fp)%wcj`U5UR$9@ zOs0<`=a}3T#(x`Kz--ztZ(jKIuXn=Cps8%e<^dk{s8Kxfd(AYtfz<$ z$1*oRz?;i<$J~?mZZyaf*e68$$;qYb^(4j<&}h*?YF|go5D+*CZ-w$CXi-3lYIjm- z0_ZbZMqo9Z2N|S9k8$x~yv~f(e_CjC^btIwHkPDK->^lEZ6Mu(H+|0m-uhfa4A&vKT$K#o#tv{ju%09~ zMOV7?+t>pNua>{M=p4!O8trMo)$Efxdq}Su1c`VRbY0FK$p~B$Eoj8_jVy}^{eTWL zqh)$M-pTm|%uP(0wr{qdn{6~pF3QYd+1wYb7J#g>e=G>;gKfEV9{nzK$|k>bZNR0v zYr?#iFYRyVkXhD+I*|K4&yA2V$=|qSpg(Se%uAOKTI!riI2_kxEqT}lopqU-7LEI| zq@&S0e}@=TewB7IjhE1ygYI^6i`Df4jdMC=4`OaGXRZZpG`J$IgJ7}7UhG4Z zJy86;Oe&h@SI4yetE5)E9#8JOwq^X*Jd|C-fP?=&e}58ozTs{!=e;NH7KHXR#*6lQ gHMYNUz5d|Ae==DedM}{`Q~&?~07*qoM6N<$f`sjD`Tzg` delta 700 zcmV;t0z>_o2ImEk7YbPf0{{R3rzMq~kuD^E0d!JMQvg8b*k%9#0)R!%Iy%a=nku)zv+9krb^hCtxO(GoZl3U5D`z{ulmBA-ZP+HM{B52`nw@84Nx#c$hBASTAqs6EDU*#pe&7*4Z9u>QCUCSd2O&X+{a2myz`wHNw5SQDalhkUW z44hIDeO)<&k*=^{jjmR|LlP5*%E-KGNa_xjpSKwxc2km!+;Dl&6bR}J4(_e zo|F^m+N@}hH->e$X@HjasGLZMh(a`f$r3}|?UMTiPq0zTztvaW46RX}D1$XrCm)Oj zI;w*!As;N3$uoj3l1s+P!@xdhHQr#+i2%_l^)ids6+dd{u<6lbnd*`V{S+Eq(vSwW z2(p}{5v^18l!4G3SgGC4wrb}BKAV2Pd=6BzH7ajPUi?DV;mYG75Q77Q5Wasl9YW ztVwR9^MJJM>(niylzE=hAWHe3j`UH^Sv&Xjz%mP`ToJ|}fZ diff --git a/public/images/pokemon/exp/867.json b/public/images/pokemon/exp/867.json index 1a9c7572f43..52e0127509b 100644 --- a/public/images/pokemon/exp/867.json +++ b/public/images/pokemon/exp/867.json @@ -4,8 +4,8 @@ "image": "867.png", "format": "RGBA8888", "size": { - "w": 344, - "h": 344 + "w": 361, + "h": 361 }, "scale": 1, "frames": [ @@ -31,7 +31,7 @@ } }, { - "filename": "0020.png", + "filename": "0021.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -52,7 +52,7 @@ } }, { - "filename": "0035.png", + "filename": "0037.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -94,70 +94,7 @@ } }, { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0034.png", + "filename": "0020.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -199,7 +136,7 @@ } }, { - "filename": "0003.png", + "filename": "0006.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -207,20 +144,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0018.png", + "filename": "0022.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -228,20 +165,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0033.png", + "filename": "0038.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -249,62 +186,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 103, - "h": 65 - }, - "frame": { - "x": 0, - "y": 56, - "w": 103, - "h": 65 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 103, - "h": 65 - }, - "frame": { - "x": 0, - "y": 56, - "w": 103, - "h": 65 - } - }, - { - "filename": "0026.png", + "filename": "0012.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -346,7 +241,7 @@ } }, { - "filename": "0041.png", + "filename": "0044.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -367,7 +262,7 @@ } }, { - "filename": "0043.png", + "filename": "0003.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -375,16 +270,58 @@ "h": 66 }, "spriteSourceSize": { - "x": 5, + "x": 4, "y": 0, - "w": 103, - "h": 65 + "w": 107, + "h": 56 }, "frame": { - "x": 0, + "x": 103, "y": 56, - "w": 103, - "h": 65 + "w": 107, + "h": 56 + } + }, + { + "filename": "0019.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 4, + "y": 0, + "w": 107, + "h": 56 + }, + "frame": { + "x": 103, + "y": 56, + "w": 107, + "h": 56 + } + }, + { + "filename": "0035.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 4, + "y": 0, + "w": 107, + "h": 56 + }, + "frame": { + "x": 103, + "y": 56, + "w": 107, + "h": 56 } }, { @@ -402,14 +339,14 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, { - "filename": "0022.png", + "filename": "0023.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -423,14 +360,14 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, { - "filename": "0037.png", + "filename": "0039.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -444,12 +381,54 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, + { + "filename": "0053.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 1, + "w": 44, + "h": 56 + }, + "frame": { + "x": 317, + "y": 56, + "w": 44, + "h": 56 + } + }, + { + "filename": "0064.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 1, + "w": 44, + "h": 56 + }, + "frame": { + "x": 317, + "y": 56, + "w": 44, + "h": 56 + } + }, { "filename": "0002.png", "rotated": false, @@ -465,14 +444,14 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, { - "filename": "0017.png", + "filename": "0018.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -486,14 +465,14 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, { - "filename": "0032.png", + "filename": "0034.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -507,12 +486,138 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, + { + "filename": "0013.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0029.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0045.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0011.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, + { + "filename": "0027.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, + { + "filename": "0043.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, { "filename": "0008.png", "rotated": false, @@ -524,266 +629,14 @@ "spriteSourceSize": { "x": 6, "y": 0, - "w": 102, + "w": 101, "h": 57 }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 102, - "h": 57 - }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 102, - "h": 57 - }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 99, - "h": 59 - }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { @@ -795,20 +648,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 6, "y": 0, - "w": 99, - "h": 59 + "w": 101, + "h": 57 }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { - "filename": "0039.png", + "filename": "0040.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -816,20 +669,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 6, "y": 0, - "w": 99, - "h": 59 + "w": 101, + "h": 57 }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { - "filename": "0015.png", + "filename": "0010.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -849,6 +702,195 @@ "h": 59 } }, + { + "filename": "0026.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 8, + "y": 0, + "w": 99, + "h": 59 + }, + "frame": { + "x": 0, + "y": 186, + "w": 99, + "h": 59 + } + }, + { + "filename": "0042.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 8, + "y": 0, + "w": 99, + "h": 59 + }, + "frame": { + "x": 0, + "y": 186, + "w": 99, + "h": 59 + } + }, + { + "filename": "0054.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 0, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0055.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0059.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0063.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0060.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 39, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 166, + "w": 44, + "h": 54 + } + }, + { + "filename": "0062.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 39, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 166, + "w": 44, + "h": 54 + } + }, + { + "filename": "0014.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 0, + "w": 97, + "h": 65 + }, + "frame": { + "x": 202, + "y": 173, + "w": 97, + "h": 65 + } + }, { "filename": "0030.png", "rotated": false, @@ -858,20 +900,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 0, - "w": 99, - "h": 59 + "w": 97, + "h": 65 }, "frame": { - "x": 0, - "y": 186, - "w": 99, - "h": 59 + "x": 202, + "y": 173, + "w": 97, + "h": 65 } }, { - "filename": "0045.png", + "filename": "0046.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -879,16 +921,58 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 0, - "w": 99, - "h": 59 + "w": 97, + "h": 65 }, "frame": { - "x": 0, - "y": 186, - "w": 99, - "h": 59 + "x": 202, + "y": 173, + "w": 97, + "h": 65 + } + }, + { + "filename": "0051.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 29, + "y": 1, + "w": 58, + "h": 57 + }, + "frame": { + "x": 299, + "y": 220, + "w": 58, + "h": 57 + } + }, + { + "filename": "0066.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 29, + "y": 1, + "w": 58, + "h": 57 + }, + "frame": { + "x": 299, + "y": 220, + "w": 58, + "h": 57 } }, { @@ -906,8 +990,134 @@ "h": 59 }, "frame": { - "x": 0, - "y": 245, + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0009.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0017.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0025.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0033.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0041.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0068.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, "w": 95, "h": 59 } @@ -921,146 +1131,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 12, - "y": 1, - "w": 90, - "h": 59 - }, - "frame": { - "x": 95, - "y": 245, - "w": 90, - "h": 59 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 22, - "y": 1, - "w": 70, - "h": 59 - }, - "frame": { - "x": 185, - "y": 228, - "w": 70, - "h": 59 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 22, - "y": 1, - "w": 70, - "h": 59 - }, - "frame": { - "x": 185, - "y": 228, - "w": 70, - "h": 59 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, + "x": 8, "y": 0, - "w": 44, - "h": 54 + "w": 95, + "h": 59 }, "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { - "filename": "0052.png", + "filename": "0032.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1068,100 +1152,16 @@ "h": 66 }, "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 + "x": 8, + "y": 0, + "w": 95, + "h": 59 }, "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 39, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 244, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 39, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 244, - "y": 174, - "w": 44, - "h": 54 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { @@ -1173,41 +1173,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 29, - "y": 1, - "w": 58, - "h": 57 + "x": 8, + "y": 0, + "w": 95, + "h": 59 }, "frame": { - "x": 185, - "y": 287, - "w": 58, - "h": 57 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 29, - "y": 1, - "w": 58, - "h": 57 - }, - "frame": { - "x": 185, - "y": 287, - "w": 58, - "h": 57 - } - }, - { - "filename": "0049.png", + "filename": "0052.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1221,14 +1200,14 @@ "h": 56 }, "frame": { - "x": 288, - "y": 174, + "x": 0, + "y": 304, "w": 56, "h": 56 } }, { - "filename": "0062.png", + "filename": "0065.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1242,56 +1221,14 @@ "h": 56 }, "frame": { - "x": 288, - "y": 174, + "x": 0, + "y": 304, "w": 56, "h": 56 } }, { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 1, - "w": 44, - "h": 56 - }, - "frame": { - "x": 243, - "y": 287, - "w": 44, - "h": 56 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 1, - "w": 44, - "h": 56 - }, - "frame": { - "x": 243, - "y": 287, - "w": 44, - "h": 56 - } - }, - { - "filename": "0053.png", + "filename": "0056.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1305,29 +1242,8 @@ "h": 53 }, "frame": { - "x": 255, - "y": 230, - "w": 44, - "h": 53 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 41, - "y": 4, - "w": 44, - "h": 53 - }, - "frame": { - "x": 255, - "y": 230, + "x": 56, + "y": 304, "w": 44, "h": 53 } @@ -1341,20 +1257,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 38, + "x": 41, "y": 4, "w": 44, "h": 53 }, "frame": { - "x": 299, - "y": 230, + "x": 56, + "y": 304, "w": 44, "h": 53 } }, { - "filename": "0054.png", + "filename": "0015.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1362,14 +1278,161 @@ "h": 66 }, "spriteSourceSize": { - "x": 42, + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0031.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0047.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0050.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 22, + "y": 1, + "w": 70, + "h": 59 + }, + "frame": { + "x": 288, + "y": 277, + "w": 70, + "h": 59 + } + }, + { + "filename": "0067.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 22, + "y": 1, + "w": 70, + "h": 59 + }, + "frame": { + "x": 288, + "y": 277, + "w": 70, + "h": 59 + } + }, + { + "filename": "0049.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 12, + "y": 1, + "w": 90, + "h": 59 + }, + "frame": { + "x": 100, + "y": 299, + "w": 90, + "h": 59 + } + }, + { + "filename": "0061.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 37, + "y": 4, + "w": 44, + "h": 53 + }, + "frame": { + "x": 190, + "y": 299, + "w": 44, + "h": 53 + } + }, + { + "filename": "0057.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 43, "y": 5, "w": 44, "h": 52 }, "frame": { - "x": 287, - "y": 283, + "x": 234, + "y": 299, "w": 44, "h": 52 } @@ -1379,7 +1442,6 @@ ], "meta": { "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b8ca75f7f37906e78ed633b32d037b74:92bc79a7ca35490600679451c06105fc:58bcd289dd222ce646aec14ff657c9fc$" + "version": "3.0" } } diff --git a/public/images/pokemon/exp/867.png b/public/images/pokemon/exp/867.png index 689a72694ef90e5dd459be477119a20f39db8e6a..4f8f67842bdd6ee61b2ba0ca2afe8d7ddfd2c852 100644 GIT binary patch literal 13409 zcmYLw1yCGK)GaLT?(P=c-5nMd_XPLg!3pl}&IWha1Pc<}-F4C6?l0f}zgKUny1M4f zx%b?b>aOnTj#3B8qahO`LqS2IDJsZlKtVy<{+AG8{voy{On(0|Xg3XcDX7{>(&K+G zOetJLMh5fYI)_J8Aqk>m7~YWZ=QU7e;lMlg2wip<$Vk1R`%33i;BU=bbj-BTYASs z%fIJGdG$e1&2XE$Fv5(5V8>1Y0IGTJfQ{! z#Ak@VN533E{6ilwZ#cMT`|D$>TmPEv@3Kdc%yEVzz&AvDzt#A9Q6Oo?>B*V+sty0e zyrEnX*)8_&W=DEt+ho&lK8!|LqDZoX(+PVStD39rES>*MMyChFa%fCA&`CV0N1^Ht z-co>}J`>BLMhjs5Ha86q-cZZMSG#zqk)-5-XPIz}*!K_ywQP~TApL#0wCnuv1Jesl zzh?nX6o?S*Lx+5gZs709&r(R2<@;(Rzi8HLtbbEC$-sdK9KPN6P)(3)_Rf6kAJ4{R z$Yq|_>c8^8z4jAX-x3$tGU&aZ`eR&&;*M^Nu9Lk69Jco;ytOyzF@^_o5^N4Ca7R}X zMvD%;P{;_4cXAeqOm*c6GNWhrn#2YWM#v_GMNwZUbnh1r9nq&l0FF z#8We>=Z(RQdG?|FHwz^$wx}`-tQ5C6aTsRiK!+=JGG;=i>)5BTIHXZt{XK3MW@G{B&LgH zS#74+_WGCs??ONY(B)cRB%>21mC7yp*Dq0*AQP6Q;qUDFw=j{hD0lE(zz`q4Z$?VP zQd0QkmU`Jr=SolpBYt6Xh5K{-%j90GyfzrW`qBL78gPU~IO*P{X{#Y_a5F3(Qn>Qf z4tsCnSukp~EeXE&%n<_|Wd!FuQeZ;Tyhv7Ny< z6%rZGtV1IAwQrnfZ=6Ag1t+yu7IMEYTgORqC6>&q6~ux(d`khhINzvQbgVtPrP{L- zbzQ0Pf^;jkW-{eBA>l%=^YX3K^Bvji8bJYy(Nkji#8Bq~gTP|pW_L<#%ZMr@?^YZ< zb&eNR^L+0mA`bdu-&Qh(uHjWhO8%`2^;*^3VeCw~Uf1^Qlrq5?g|^Q;2Nj+jaI6t{ z5x4MpbgPN1+#5{r8gGPy3_y#?&zhfNz6vv_xfC{hoy#2Bg#7luZMO+N8|qXvkSHpo z%trQE$Pxri?F0s|O^(^a|6F$@cf4ln3GzG3Wv-A|!x9Z$e~wV!&JvtSc5aa}v7Q=h zI^Q-HAdyTdW!@4CcF!^4c^kWvU4aEc|{OUD19#T zJ*_jD9QxR|#R&r3h5G}%y-3s5maVouX3T-{;hZgW%940p(+Jv1Un)czZX{rGT^%~G z9y|tc8q{DvI(n;Scfu?^y&vY$2U99^0-IH~+aN6!yE+vFiP7e&jJDN$<`oUiYCe#2xg|Vf4=+O*@Lmg*PK6=o@`kJw4P4E+wLf z8drk{pog_i8*g@hMejzUAm%R8mmEpN#X(%4u^?lq8rjy>G~Ni!ef5SiG4H5|=EcPu z&zO<-1!-8d=*t$+{Ovo`QLw<080F>K^~q?ll5GY)LG;*u z()itfI>u$~Z`y#K&EFrZANntaif*yOgKq6yR4C9UqWIP-yxL@j|9)JMN4q*|o8atW`nUnAl8PO+x?a3Qu5Xdf9*6`dQ=vA-E+98}{3@W< zY%!HbP3SbDnEt9(!1qtAL17z{bVBHM&`E*Au^c|mJF9Aho)iv=ttIVLhXpu^dD`ub<^KxfNNBURokX6_65 zsg898yD2%hq?ufg8kd+J)0vFEiAd@Lw*bNWH?o=FUVvIZalOj$+tuh&=7QT4f01m97z*_c@Py zjG(5ceUQO!9^~s<@`C1lAi~jh{-=Y%3Kt$Qa1#0^K~EagtcZIlvuk)6?V`s$Z&qI8 zTzIgV=@y+ls%`ZU%*+lx5Hl}SI^R=W#hU7d{sxWYh!p?juSgzeB!Cq0$RS@hwlBLx zhc(0oRW$f}q!;TsJUMUqC7|-0o3?UaOhQ3;$qSI2@f?aKldY&n+9(7Htmms=u5~qR z;*Ol0rg@A2){)@#kBZpgnMf@7hs&g`4^5QR4ILLW$$bbER;CpBNDx!(?~FtNXqynI z;!JBo1Jfj9$8(&4iuA?Q3E4NYIRxsS1ymrohaY}Novq#TfQNeOnOG#x+GW&tv5}&w`6bxl#$ZKl zy4%)Bw-%#az{wdL59mGUc~jf6foggV2a7IO)P|5cdzDH?;COH}mK>3SCaRz9ZZt5fwvL z)3c)bR_*y@r2P?!CqF}alb&I(%Fl+G;V-;B>aXK)a9|pf-sG3@C=DClf=d?=7s{72 zqX(PyRKT*7p0L_Ma#gwIWcU1lG8vXIdq9vp65&TiBMjh0p$|pRwSW_p{?f_lH{J79 z@_hYmyHJy6!DoCm!a+C6fN8#DB_rM2@^kSQQ(E0gbVSo(9utZFe+`{=j+1z=nK*VP z&B-OIAfDpS#=*Ikrml=c2}M6Gcc4As>iuTA7`*~5dx+!&r#9v1m!8BM%M?^0?G-IKk$WbWI=T z0&=Vw)=^iAPm1=#N57kNS-s;G+0-W1XXp^T3|Y+)w8X{cbHqU5iakqUC)$(Y*eW_5 z9@DLoRN-e?DiG;}j<;>kPmf5YK=?M+Fy$j^u06Xau>0P$VhWo|*E1c{-@rW#BPwR- z=Vj?wHfl{Arz$*pF2&4%v{I8iRrdm&j)L6)LTtE*wl8fE*Yu!{Z`%mmSyu{X| zhP0U-CE)R~P#kpL{DzU4!326c5Vsb?#p=;chJH!TChavop4WrzY;5=XVDOU_f)SGv zr9TSTH!*43z-}V|CID{MRG=Zl9eMiUb0f?olEEkBzN;Z$R3e1~E~sn+5!a@4{5$0x z5DhRzJIOqcab2EN9=;J30bDUSMRMeJ{dn0naY)dix{s%qh?Ws^ea{~syDJ2)@W9dD z+`P2{Y3ilt)*6x)N-P<1WV{D5#uCwU-CeMVYs_DBPdPp?^oM6`tb~qQ<2o5?}6pA zt)`;EY$h{W*CYdb9|Ww>FH!cwONbve3g1UOpAE=GE`6A(yL@hrQ7C((?fzQdj)TQs zE!Q4Gov!${urY~c#<6FU@(a{?`c^55uH?N4sJmc8`LG^haW4_LQMtgftbM+(7O7W9 zYE9Qc0>8LE(TT{=z!)sc;I80z100YLqrxjA6{UVEsKxBrsm4&>S5g@R04!y-w4MK8 zAwR^Hm&a=Trr*_r-uY<>66jiLQUBpT4#V!yQ+}Qi@RG6_T}%aEN|9n`57wh*G8CuW zJO9YX_gHhX<56{W#1AFd@hjtr+4tK~T4kgn`-9eK8A~qYv1Vb&rAxs19`y$cE(uvG zM?Ln2c*2ZuB4*}WpAZ9Z$47ZtOvK})wS%vxG;swv@GUoM!5wp6KeUvjU>TVwrcPlO zj?&_myu=xD6w-!%1*FV7F|=O1v5yuoq}s~ptHuwZq<2_cj|<@-?@0W|=b&>NmjE0^ zCf1%^VjDlYV-_i@BPnRKsq*wa<>#D@Ie6T_?Zus0C`(FMFs)ybtq>9m$rn$5!mdbF zh9WVpo<}^k`?81E%3acN68iHKYUvWLcdHa~VW>VUwB#f`(PXafM5#V3ZOmTEFEw!$ zsh?&;mx+3EZY7|$Gzm5b;@;bAsS%x6M-@qnYiywuF0TcLY*~p$fvL2^uJ2p!`JKq~ zy`bglPKfw zyh%|z9$hAn95^YV1vSq<3`@9ntv{cvvihn^1237cDzkWEg#0rel+qXyFeh;USZ~B00al1-qU;iOV!;Ka*uzk>?3v1F zW_yyYde)upj1**rT*##lR;oIXn*{5xOCbzHZG7RfJP4rq|YCu(vyA?tDjx33ALURjVF1@8yQS$RRC7@g94saGdT9S@U zE&9h$u6k@ihU^rs^^(`<_d}E_cyNsc-1tKpca=V+L=XYPiU$5hD!Df{_qh&rv8L@T z2Nk*CL|Tr5-MpiSv;Hk^p%e}ZrKPDh+-j+gbT_-Aq>LJC5*&VFfQye}EOC-cem|&E zVx)`~)})P8#Pz+RnWw&dO)2*TcU>m#tP`*FLTEnBD6F4}DKay41|Ui32aKhW01}V} zu_Oqxwh>d2p-^S>bk}=OHp;kpsQdBuH}kF_oSnf9)nX+sf!X$%D=k6~=3OY7B)~HZ zQ7&9==rqL06au=Ud_WO8DWNR%L>denaB&B-W?LHl%gGwbaC{1{EZnJ7ZFId`K}8B2 z*EBtMyn#C20xZI~q?5Z#Ko!<3lO!@gesgCjg!CTK=5(=vT;jJE2p}J8QM!g%6K9kb z2;trTVll`3?2uwbHcsOJ(y+t8nBiEL`{ zJfHp44)g7XqIhiy#L>r!i>#FlQ(NlV|NNn;nQ$kYex$RP{vq}-DftC?{1P_mL81z0 z77mOTtxAz*99wE_)K1AxohLu7KB2N@5-4$MkIeWtA~qOP^NSLQdt5+UN(gaAv1pkV z&$?OXgc_-c+qeWR;#NMOB@)) z%U#*9!?S6i+1y!Lff5=D;MVrVw4pdeZniJ6*#3?5>i8CFcC{*@V<8n+(^zWbr8)zrt+^>f_uuj};Eub2kQd^!16uVyTT7PK&tPix<#_J2kQ z_?2f9**OS=v9MQQR@^TuhhrL%;~Bsz|ldfIKStpyGHg$RA%KEMa|>u4C?Zv zSul~&79&OYUJ{cpt25*%o;}0saC+tvP?)g|8uFw%vD@hBrSVBKC(l;nP^oI3{)V*= zoPc{YNu_@06M^oCwTpwrCD2h{M&YEW+?AjlZ*&Yl44%bZZJ`G;2}M%|9?TfH7Pht4 zOTFE7VQSiTU72bUfWue#imvvoBQ&p=l;UzV3W^Mh4*5S-gAeJTlUS=L#~U0=vHD>g z3+Km~cx4$E%RSSMf1T1nD^9CRWSXyyOL1rH@}#Z`mV60Uuh#c)GsO%1x`8~R0)#e= zcGP@{j!NbLGne72U`F#EDfDpQ>ug>_t+q*NTxwySOQv2$txmb8=3>nJZ0GYVi$KMS z9vMpYv1YB75xUtl`R9k$hEj#vI8aD3Dxx(?GnyRR&YK3`_?xc1DMW1Q!}hn_8iV>U zU?_-h)L%#`FIR&@nvuS_N!W(HI$6p*g;M)FQXlCw`+}sTY(<79vK7)G0LqTR9;J%B zcxAWmkPdMW`r=eA-XmN?yiCiT(#F{?m4zvo!;;1S3CTZ)Dmt*N=8!J7pbpH_%amrf zQI~vQ-`7`J@vg0-3-V>127R8t*9S65Q^@vUu#4l^Qb4aJONhTymZeriT{ry)!HI=5 zut_&d0xLk;cgfziPlEjw@76i-p2~ytKH=ZWo6d4h)FvQ@xMj~2PD;J!JE?%oZTva^ z-v$9d*UF5A$Hnauy*4Fywhpw$1>7H#_&T13Z&ik2PA^Dh;Q_f9re8T(X@VN-4SFlS zKI}AghR#jwiA=DTT7CGLwuEXLU-VmhBbAYalE9<14;C&%z9)XF#&@Y?@dw}AmJc-s z^*)&lu%-v*L5?B0C*2q~ouOp2awm8cyZA9^!q0eSXfd2?&PiN4&yFe@%T!h4^QTdwP`xYF4@qbI*M`D;KQ{5jn?X)b>gn|P9Ew3 zy%IbSAH!U1g&F4+-;ED8NAMBpgWys&Pmoqlx1g-oN3_SL%L7KURnq#QwlSm-iqOp z`xqDM#fT5_PebfGW$L&k?r*U1*+kNZ%aRV(ZtP|NievEF#StBYKE2t@qol|%`%vsZ zWT7hJEE&VjWIRHX*-oU=(G2?K#oP3Rbu?v(VxSvyGA=>VJvVyv1@|b$6El7{v?ehi z)gALdLzM`v$z)6LzfdKTYTFYsFsp?V^7iL4;@mCs#Q(6C29ZvdN6%iVfZ%(r0!er2 zw3vEE_vb|H9~Acf3nZ5)E^C;uO%Gl{gSB^-6V?(Tn(HeV6@EB_bghhx*F*|S-)xlK zO@PXTvO_m^y5YA`P_qu3qDzGBe0sQTT!AqhQ z!&0(OXpumh9)MaIP`26h;R)w9pcKrx@8WEfj8nBsH5xC+A1E&7+*U%}y z!bWCdmrdr(#npEzaJLDvunf^~p_5otWh>Q2xy}M*p5@e`OZBihiMD9b&E(EVV4L)z zUc5f7Ch!~mje*mkBAH(<4j&$jwUeX_y5**kq_Xc6Dt9@pSj_f93Q;_rQkU~uYwz7> zNS&e zc#JCl4sp7x7>_5WvfZcq3;mo1R344h&=z9KF&gJP-dz*l%}N3%wj|~suKN9WFmoJv1dtkcr=Uz)2i z_RTg+@3wbHN6PVsXRo}sT!ja`zH9ueD3n2D6RFcHI60QhW-Fq|irzyi}iGFVz|*gSLY24PbG~+_MLUyA;RDVDAI&G38;d z>H?Nnjox(K!W6*SH_yCl*O{{`zKefn-w$o3~It`|x`s_A+a;|$xiWkG>()u-wK}q*ErKB@- zF_dNko*~KR6+XX6XyT#D@f)tFmeZIQQVYBN%J%gb4aOVc)XdMz9h%@=ymjwBH2RGy zaL`ln^T|>gZ^ZT%(Vk%N4pGlr`>vdGnW83Vh2wRZ1Pg}5 zNy)rJe4}o#-28N0UAtQYvRPB(F^hxow?Dp-><9uNr82sIo7^-sQlC&iXsRdnj+;DC zh_?j+XQeWCxVoh(mH4gYj5k>C@_GeB+EmyP@>c9qSkl;a96mr72(&c&s9)#@*1@$` zMCN>`kXQUANhE~TN$ECsSHr>N-^aiYtkP?*o_fNQqPW9Ij?z;JGcr#y(X#f`?Lq=e zol9}Ke&iHyKd`JG|21hCPT#xG^b31nMrwS~A#MitU|iw2$OlcHUvCoebYXWRzjO#T%xjpl>S98vdcX>`W|FPTmGY6)GKO_tdgvUOGNL?}J0a~fY z2jATVZg@8z@lBM{JQ>!k@H9^y`o*N^-&Rf7%^D+-j_w^}f6<2vF^%3{iTmU_{rppf z)s9q5qtU08h83%!3XgH(&^`Ptm;H&33hbua7v5p7u@`UHPeq*n>BgTU1!;Fu0g1+s zSQ(jD6+Yu-vzTJR}gXwio@E5q_5lGLph>;`R#}vGDxU$6IWiw9>T4P zcwvh}N@!u-hXCigatXLzOeuC!;;puRBPUA|a{HzXv%ojn8qya++~JM2QD?>{YN4QKmc+hwJecM3tjOlkWKB;ZCmG9)UAz6X`R z7F~p(3F`QKpl)+7&S?ipm9@BxE&TVVQy$T<#lb!eDNH}{nT^!T@1(%UPc^<=mH$Ii ztQ6V%WBxM8ktKb^0G*NLiHV3#Z_1P$I9bqL16pd1B+iTt4oKjqaxVI1O3!3EH^`Cg z`Rx5AwX5SgvL?nO+oQcg3+Gdqor9QE0pcC$taJ(p>W$dR6@|TUbndGNpAjleBAhVs z9=daf4K$G~{;KV*XCM>kr8n3DtgCl(RqPZ>xSr%aA5P`A}drr6(%*c&JuNx;DZXpyGQc-Ba3+|d!xO$u8knXFB@K=*ApC(W6Z-P z@#78S3E}q{SfsqdjH>78W+a;&JSF^eLS<;x0|OSgm84%0`Au!6)d$^@Uyn-q;^kg# za{sIkj=qw?l9f-h>WTacW7@`Tn!3T~r!z2IKFrCBm6}J@A0$a2{hgL$D%GRxT0tY8 zUFYBn`n$_OkiDI|=9+tqOwQm0>Hjg|Cw4_D7vY45P6P{AX4~@j7->oa7U;eMjl-6K zxGK==M`;rf?Vp#+mh=i{D~R)p8H@PbI*YRQ*_?-m~LtRHN&mo5+MO{PN zg8acZ{%W`+EJZ_KR);UEJzy^Vu&P#6YkguFoVzg_MOPhx7_y9_ojDK~k(nw+eLzS%~kKLTXO zPc`;Wv`!I(NHgMN$0Eo-t_gAk!e1=(2pE{;=(L7Q^1}CLNQEzR-~E@4Slr)jJHFg- zQdQSgca^=@*e?L3$qCxfYo9^;iRp7&rtg;y!)Eb$pB}1UyJk|3nFv!ty$RjjR=atb z81J7f_@K=%D%?&D_@y{`agwI*N`jm9b*PxG6Tfw@*PZdu+MVYvlgiz0&(SmR=>As| z8-`2aJ(?WmI)^Ewm99s>epG81oGmv{l}YBAU&ESVZcs_ zyWj~%vIHU~?FgEtL*L`aO_UBoPrwUgtE~r6vpVD$=a#PEO8&Ycl-k+Ajz6hsUboIw zMgA$U{?z@GsZ&@q0LMQJt+}f&nPRQ-f7trO?t)YuSD8XbfZ_>A0Mt*JX%bn%eU;lh zG=92q+wTyF`EJNUR~Z|4j>4f6OGRQxp>A7-{=ow2)dGOQjO%V-Cit2J!zP>Ahr&{g z8+)>;$x>Ef#r6~@j~;deWks>FYzz7rDSiV5HYYvJwoucm?AS?To544U5@VjK&_0X2jn6Jml7bbY1uc9

AEr)YqXKi=OLo?%#>feG5W8?bg!mY<> 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 z4));y diff --git a/public/images/pokemon/exp/back/867.png b/public/images/pokemon/exp/back/867.png index 766ce3f39ed80703b473d801230d7cedaf763998..b816f10a0def567345f8a9a7a87e041d4898b70a 100644 GIT binary patch literal 3724 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 M07*qoM6N<$g4SP4<^TWy delta 3246 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 g{(l;-f7U5(BVe+qO`PE!E?|NsC0 z|NsC0eu)%T000AxNklv-@}kI9IwyWjBS>=%FOxxDSo1p2<7xa(`${) z%q~PHUqqyC^rrMuC}$!{s>n%I^Y9R3FdYAq+!+hV#J`k9e;Qea#AqI+7=GMrI<7v8vXoDNN6!Jl8$5hU13p#+1}WtbaK3b{{ z>+?FKWe;BE1MBEMjRnxJ3XABgnrY2K8{v3af1=+h$w#B3vY>yfi}ZXN#{suw^VIR+ zeTP1Nu>Lms_ew5*)yCv?`mNgL@?$_6cV=Iv&j-%*id7vB(#!N)Cu(OFt&Nu6kxnc0 z+e4`i)lnNo8phNEtkdJ0MSNM%?!}snb1i#Fze+w@0T(A_>&^teXh?sZyP;s$UZV3` zKQ3bD?G(cb7k6T({kAszo~saPXotU1c<;{TYky$+CHsp1P4*n)l`H=Na`iFH*e8W{ P00000NkvXXu0mjfr?m7Y delta 926 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 delta 6214 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 diff --git a/public/images/pokemon/variant/back/female/178_3.png b/public/images/pokemon/variant/back/female/178_3.png index 32ffdd895c6950fdcec0edc08b2b41b37a01a7ae..9533621c6d696fda7b3f97abd127ba04cbcc78fd 100644 GIT binary patch delta 6215 zcmV-N7`W%4F`+S#k$?M1L_t(|oZVduo8&4Ajg_u+jj8V0`~Uy!#zzzs6)@G0VfVX_ zxskvT(IlK=Svaz;_w|0ev95icitm=gg+t!n*3~Q@%g4uG^JOa5by?;2av~kY(0ljt zw%*Jke?R{IHBumSDprTy5k#_E#d}?k#Qk(){qKK=6Nh|Caeq*$IKewc@u7%=oLsyH z(_F6R=KlBj@ga=|m5MckXWU|P{~yXN!|*0Rk0GZyYZUXzvF8F6z@N03Mq_U4TOK9} zBep$jk`FNsDit|~R`Z|ni)p-;ZfgX>qaaRWUDa>*H{imm(5+E%gE4e-Yw5sY1jKEH zcX6pmK4&c5x_=Exq2lIe7P)mSrV)VnMmN8j6yeLzt&0bRiV8c9KgFOUirm(8&Fc6j z97-5ix4l_gAn~c#b=@APEyPFjaJQmZ(MK}}&X_P8dIFFPtfPuy>ri)-G z4Eh=sVF3hbhlIkzrzF+9y;*kIt!O-PHmZxMRjX*yj`ZupIv^ z)2>%x0e=h!bZ`D@|JSW^yJv!dJ!a^EjUE{AXCm!0Do&5$)ZXrX#Jzu8A9;ovbJqc3 zmvbI>G-JoVa<$K?NFIf$J)St<+=#pXyZJ*7vJi%Hj0T6p0ZX~y*EZDN#(}M3qf}&% zf>X|?yGgHA%pVGfa6b>jGlT;e(}1pnK~NZUR)0Pme}=Sglp7Kihkd063p`r#+};xm z_l>~8Vi+P089ExfHVn^mP5Xq4|6^^DbEEP@qM|m>J`oJdGmZeVJ^uXJ%Taky4hJ|! zgo9I;eJKB<4RZ;^)aqp_s`2*uL@-za2lIIB&#f4>Ll_7g9ClnJ;#Oaz_$0?47ur{+ z9)Fo6R8dT=Et3i{w{NS%;qO+Df-q2Ho@^X?E~K>$w6CjE|94lbz~{A0oVL=JPWpQiL554q=RW?1!Q6 z0vsA=yeFQ^XpvK&Z4#^SIP3r=eCUdE`+tV->7Fw_^M+Ev;BlzN1nih6Y*TJ@*(N_X zrqq60y#9w#s@NQg06{o5%yjw^k?!e$_}Cxuo|b}v7-JlG4<-&B@jeh1y}t*e7B%dsRA%z1q#@RXj2p-~{vgrLV%H@gin*mA%FwRmi?6gnEU4KD9 zpd}K+ff|zssbP51FdQhqJ2Bf3>XwQ;vxb1-IEpoJNOv@Krf7_r$HDJShVmlfaM(4t zLt6!DTMBZ@r|6U+2Q+Z-;2HX6T#5H+S>(mq{wtEE3VM=KkT-F7--!6>XpR`W~1A)S! zHRcGRLD=?T2u9J`mqY*NW~cw2t*4@n)$G+V#0k9q_*dr+#vPs`8e`tK3O$*`XFx-0 zUrd-B+r^=)qP8t>fyQ4_im7i0PO^=XSt7zc>)_(;WaD)&M zfB7KM81qhzl1Ma)*6!|Whd1b|sOJd8LmlJCc=C03Qqve?N3%5$o1CDu`x}p5nvos^TkB$s!$1Ww)TSs8M=u;f>%g7nm^mDR7Y*&_o%`X?RY8u; zi^ctSw7)RiA;v6ID4eN21b-=^eO|@bI-~enNsO6-!J;=E8jHFrSZYjuHs{~d-O-)B z`C|qeAOjF2eel+$)frPI&FkiCweoyp|(>xr#P7PlJyNZY`ZlDa6t~gbob8(0!=()Eq22 zwnJU|IUfC@Hs{qKTz}JDA7_YPv)1RtrTE1o;bUXu#891iKA27g{M}!UwJy2s3kX_S z{FY~g7EyYRdFHDy;kHJQ^Bg*SrUudN?tf7v9!eZkjeE~=t8-H@0_oVh@UNh zq;)B2@9UYkQEV7L*`ZZ1dCcUQ;A`?inKRJ=2iFvlbmXCWAaakV!4(==E%GXpIj*itZETkTvD_= zXK$Xnh+z)Jj6G^`*Orq7^uMv)sigGOxm^ijXU^*82A&B^}IMz+Ido z^D0=zH6d3Je}AD?sDk0+W1hP>MPgO3j0=Y2jZaKI-(F#g)@kzW-Z_Os< z9x>S_0*ejQADzK%nIZEMP7PM-G2%ufxnWR;;#zaA409rJ-AkznGB4p&pJm)ga^uCF zJ`V#Ju6;A7C-YKH^;yOQ50yhqwtx~BJ~YU`I1QcIwSQz@+NsX<6c2TLN1GT65e63y zZx`bbKUQeSytGrD>z_3bmBU^|MfWjPMk3fGV-LELzM%;5CCIgX6wZ42M8M?50xG%( zHTRJSW?I}fzJPCfyOEN4OIGQ?sa*PJC0WispA-y$srELF17OYxXti-HO|E6!tIYQO z^yo-&`F~3^D6+mMA{arS5{R`J1{n^v-pM;7Z9%_WxLGa{p-jGOMNGQQ;9zt9T^0$w zINNt_VI!wb{ufLM;Tp_qSOY8~9BK)lMd;kqBJ+01l$2AKrhAf~^?y10 z0VD2yZHjD7=0&s1aSCr#6!%$_=FFNyAw|VxJj7)|5wn|Q-T}9ka0+cy7o@rM>UEKh z*%S;dGB4cBnNC@Z!*rU

WN*NJm5wnHO?OnN9&9A)8G(o#uQkoYuwUH;hC#uig3V zka^K!$38WkDwYMFO~rJY1jhV_9Dn#L44<`_7MZutt?fI7AlGNPNYHYINglZyx(eDo z_NGJTrMR^@EV^DH$hBGSVuIGWTePUc-tO+Zbp!q9c~z4<#mnMif>z!D^<-X+S45VR z8J-NfhM)z1dPYs=J-q_UiQ!ewax?#kWx3{dv(M zHCK>%Yhn9_b6@x3`epm=^Y2ydla`l|dD*_f4~8R-&#nG=!05^Lox=AmbH4nSvOZJg zR@D2Ot9s16NRV%%{VgWH;F#x9Hkm57g8DEQ3fklO%H9Af*E-Wyk$-$TOqHUq*bEHn zw-RhIRjh|$zXAsR@m$g-SJWku%6;@6uovysW^m9R&qZx=E7y8tq%!xd zEv8B!!dwy#>f^brO>X5{kBr35eUT94Ux`gV;;4`3vNpMuYdtbj*;BD`U3f`=8;h|_ z?|9>HCpn%A39L-l{C}lI?rXyE^zT=9|6L09@C=wIKJ6VF=WR8J1Gj?3R5z7qrRcx|XhG$tBxGHnl$MYw2U;8GjDX9kwsiv6Ni)x~;<2 zuxTW#O|B(jXzrID2fL3_U+PupzfMBZge!KJ@^eBA-W11Dg2~&8UchJ@W_5SKgXVlM%?X|VDh#Xaq?`K)ot`H^x|r#KEM#G*aE)TUBXL2tzktl zu-oKT?IOEbJ%3*vmV7hyfi8Vj)xR%xm+*67YuKE}S)Z%93%+2q-TGO*xVoMCDjuZ4 zFS;cBoT4?X;8ZGTll!crx0BT?&`|2jGYr~LR?8x8-)vqAZVfA=u)@688wd!)xrZF> z8gX@#=L6eNmN>*Vb8Mbc!L}B3yTwdiII#T6UCmmT!hcj;U0e)#K9I_ho6}*|1g~Pd zY7NVzuo8I>46K`N7BIA38-Rv*KCzk!{Iek*k;Xt!tzqvh3Tu_g5cd^#p~Y*s#sO29 zFazB0odr?KP@Vd+;u?oh>3XX*?3ltjXp>tqH=lUcN*EA@skh`)>O23l-BILtVr+%O zsC1od4S#z_(t1!Cw8`Bbc~l~LW^2*qrEAra-%G+6Onnw#YRIzxZs|JR8kR$0#l}*3 z@A3Gv-xi>^n6;{HW_GQyz8gX^~ z+P+SFop9(?v$k5pGAOJGL6n{f3M=X_3>mB$hJTi8_0^mm0F{TsYVCfRcfrR^^U9&H zGTP)~3TrOROd~t46)S$Hh*H%KkXI9Au9bDs1P*vfS~&_i#$uaMW_#75uLHSFfa@$9>x?_OToaRu)-Sdp=aP~0)}b}$U7)l7>qJ+OTniZ^0J{vwvm6hQ5z-+v z#IopWT`-?Ep@}>SD_+2@_1@mvC_+;08H%1_hSwg^=kUU0wwCCV)_G3}g>}H)Y*AR# zoQ*uomqVshD|+C-SQYKx91B3`?oc@(s(*g8aN}TXZ7{JQ4p_@GYl-OTtcxHsM22oS zG%2iuHn|jq^;E!F7YkbPW%RVdeTK-8!$Cq}Md3gV>^$5^JoDw7cwKZBeKJu&WPoSV zJWXk`8WdJ|j%W>R0|7W-1J9CsCj_j_ry(-H^zd1WX;4@prMb=V8+yhmT(RlH4}UlH z3EaDh^kQa4Cg#)F$^D*R-iGm@&Kz`eR!MmK5Io zIFqgmk!!ltC#dBFa_&%C3TtoRRj!FrpQM(vWg*%$xw%F)P~@5<^@(aZ8@JQen<)lr zvN}g(wVbq=oWEoSnzZDF1FsiZEq^B|;f2Po==y8oxEJ9dNdJmvB!!%L>)p4AwUWL1 z`nJhXMCo7Aj0DRTJEEE`bwqvgxOy)>>&Vi-sFL(Ym7%L;aHT0Kb%bR< z)kcRgDaTK69uSoB$G67AT7OQioIx8>QX~=gfRJ+h1m^*6`WMu4awRlUK&B2TT2hW5 z`#iue=B(+pZ|t|MFT+E(-n~>y7^dD-x=9zPx+AsFc5iVOYz_LLmjC5C$g4k98i9 zqxQ)_-z#Y()Jxg?^16@9=q`pEq80X0^Gxn?hcvqhXAa1u32UYr?sO9AL-+!#;w|~y59`6R{fr8qt zP5qJkX8Dz5 z&ZU1*EvKbW2!AjX+{JCr^m^K_=KkI|4-}N<`aCdI%D;$eIV;|xmtbq*7vP{bV8B6( zS?JYypu&wh4`|bWLW2E;v)zBQT8+-o48-W11NV3J&|01g0Yrs(BfJx|;U)}wk zI1g}G>)P}mWVUuMa$;*7vS-Y5PR&ABKMu;*#dPgne1GmFaVY83UB9aRedcjcSjs|wVAOKca^DmpkzHLGOLG@D zLtGmD8t(7?^T2Sue{GAc=v%`t#A!x;aq`&cJkVS3Uq{ahre>-;#-G3={X-`MbI^VSIrsbEd9?xa_d*?hbS{G5ih@N%s77f3u4-LsL;r=dO7ipj% z?dj=Rqqekd3#9vdb^T^y%~qkDuC z?(gt=o_(S^WMsUQo(21FV!y`L3fol5sa&GGH-Agd%6kI#YdmKn92DmwS>BtbXC*P` zYi#CxNjRU1bCEFbT}02?z>iW%;+)C(RGf=cyd;<-H1w?P5$)SH6FHoN0Xohn|6DZL zVnj#Ja=#qrIh-Dkz~SurrR99`w+nHLk!$E#<}A}VIh_6Vd-@~he6nS(#mF>E&3WhJ zmVf70fJ4CfWXnv8k&DQB#smksueCIs&!H$r7-8qVUVZ*u%TxO)!sjJ*>+^|1 zw_ha^UQ(|z9bC#Yn`VQO{$4(}r=1rp3tl<)m5X_WOX) zv=|xG=l@b126<1^V&trI`-M1+^Im&!v(D|;!NAFTz0uBRw2Xc!3JW9e^+y-=`M(#3 z8D7#C*XMtch}Xr7e^UJ0L|(W2%0QnK|4t$D9%IyNep37!#m_6ud%X4jueg88zq;O~ l^6##9o&0m_T`4bc|Np)hPyDE6RP+D<002ovPDHLkV1mAkLec;L delta 6214 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 diff --git a/public/images/pokemon/variant/exp/800-ultra.json b/public/images/pokemon/variant/exp/800-ultra.json index 53dd9b55df0..cab917ec271 100644 --- a/public/images/pokemon/variant/exp/800-ultra.json +++ b/public/images/pokemon/variant/exp/800-ultra.json @@ -1,21 +1,5 @@ { "1": { - "b0a080": "e552ec", - "f8f8e8": "ffe2ed", - "9b8259": "b021c5", - "e5e4c2": "ffb9f9", - "000000": "000000", - "bc9b4e": "900090", - "f8f8d0": "ff8ae9", - "e8e088": "ff49e7", - "d0b868": "d10cc7", - "7d673b": "510059", - "282828": "282828", - "f84040": "f84040", - "f88888": "1ae2e6", - "c81010": "00c2d2" - }, - "2": { "b0a080": "d96b23", "f8f8e8": "ffe1b8", "9b8259": "b43c06", @@ -30,5 +14,21 @@ "f84040": "f84040", "f88888": "f88888", "c81010": "c81010" + }, + "2": { + "b0a080": "e552ec", + "f8f8e8": "ffe2ed", + "9b8259": "b021c5", + "e5e4c2": "ffb9f9", + "000000": "000000", + "bc9b4e": "900090", + "f8f8d0": "ff8ae9", + "e8e088": "ff49e7", + "d0b868": "d10cc7", + "7d673b": "510059", + "282828": "282828", + "f84040": "f84040", + "f88888": "1ae2e6", + "c81010": "00c2d2" } } \ No newline at end of file From 65af7a56993e19c29681ca1ea9e9799ed4385373 Mon Sep 17 00:00:00 2001 From: Mumble Date: Sun, 18 Aug 2024 13:51:08 -0700 Subject: [PATCH 21/63] [Bug] Preventing the MBH from being stolen in Endless (#3630) * Endless MBH Fix * add import * Revert "add import" This reverts commit 814a4059c2830e972c348d698259535e117850bf. * Revert "Endless MBH Fix" This reverts commit 8eb448130132ff9eed614a2ec576926814008df0. * removed newline --------- Co-authored-by: Frederico Santos Co-authored-by: frutescens --- src/battle-scene.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 674b4e256f9..ae6cea2dcd1 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2419,9 +2419,14 @@ export default class BattleScene extends SceneBase { count = Math.max(count, Math.floor(chances / 2)); } getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance) - .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this)); + .map(mt => { + const enemyModifier = mt.newModifier(enemyPokemon); + if (enemyModifier instanceof TurnHeldItemTransferModifier) { + enemyModifier.setTransferrableFalse(); + } + enemyModifier.add(this.enemyModifiers, false, this); + }); }); - this.updateModifiers(false).then(() => resolve()); }); } From a97803b99b53ae2bec104571fa3e63e70a21824c Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:27:38 +0200 Subject: [PATCH 22/63] [Bug] Fix type-hints for immunity (#3620) * enable mock containers to be found by name * enable mock text to be found by name * add test coverage for type-hints Only for "immunity" and "status moves" --- src/field/pokemon.ts | 6 +- src/test/ui/transfer-item.test.ts | 1 - src/test/ui/type-hints.test.ts | 89 +++++++++++++++++++ src/test/utils/gameManager.ts | 3 + src/test/utils/helpers/settingsHelper.ts | 15 ++++ .../mocks/mocksContainer/mockContainer.ts | 7 +- .../utils/mocks/mocksContainer/mockText.ts | 16 ++-- src/ui/fight-ui-handler.ts | 13 +-- 8 files changed, 131 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/type-hints.test.ts create mode 100644 src/test/utils/helpers/settingsHelper.ts diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 10851451a1a..e38813ed3c0 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1210,11 +1210,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * * @param source - The Pokémon using the move. * @param move - The move being used. - * @returns The type damage multiplier or undefined if it's a status move + * @returns The type damage multiplier or 1 if it's a status move */ - getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined { + getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier { if (move.getMove().category === MoveCategory.STATUS) { - return undefined; + return 1; } return this.getAttackMoveEffectiveness(source, move, !this.battleData?.abilityRevealed); diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index bbb9a823ad9..9315971e484 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -87,7 +87,6 @@ describe("UI - Transfer Items", () => { handler.processInput(Button.ACTION); // select Pokemon expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Transfer"))).toBe(true); - game.phaseInterceptor.unlock(); }); diff --git a/src/test/ui/type-hints.test.ts b/src/test/ui/type-hints.test.ts new file mode 100644 index 00000000000..eb0191812e8 --- /dev/null +++ b/src/test/ui/type-hints.test.ts @@ -0,0 +1,89 @@ +import { Button } from "#app/enums/buttons.js"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { CommandPhase } from "#app/phases"; +import FightUiHandler from "#app/ui/fight-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import MockText from "../utils/mocks/mocksContainer/mockText"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +describe("UI - Type Hints", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(async () => { + game = new GameManager(phaserGame); + game.settings.typeHints(true); //activate type hints + game.override.battleType("single").startingLevel(100).startingWave(1).enemyMoveset(SPLASH_ONLY); + }); + + it("check immunity color", async () => { + game.override + .battleType("single") + .startingLevel(100) + .startingWave(1) + .enemySpecies(Species.FLORGES) + .enemyMoveset(SPLASH_ONLY) + .moveset([Moves.DRAGON_CLAW]); + game.settings.typeHints(true); //activate type hints + + await game.startBattle([Species.RAYQUAZA]); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const dragonClawText = movesContainer + .getAll() + .find((text) => text.text === "Dragon Claw")! as unknown as MockText; + + expect.soft(dragonClawText.color).toBe("#929292"); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); + + it("check status move color", async () => { + game.override.enemySpecies(Species.FLORGES).moveset([Moves.GROWL]); + + await game.startBattle([Species.RAYQUAZA]); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const growlText = movesContainer + .getAll() + .find((text) => text.text === "Growl")! as unknown as MockText; + + expect.soft(growlText.color).toBe(undefined); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 27ba7a215eb..6333179e3b2 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -30,6 +30,7 @@ import { MoveHelper } from "./helpers/moveHelper"; import { vi } from "vitest"; import { ClassicModeHelper } from "./helpers/classicModeHelper"; import { DailyModeHelper } from "./helpers/dailyModeHelper"; +import { SettingsHelper } from "./helpers/settingsHelper"; /** * Class to manage the game state and transitions between phases. @@ -44,6 +45,7 @@ export default class GameManager { public readonly move: MoveHelper; public readonly classicMode: ClassicModeHelper; public readonly dailyMode: DailyModeHelper; + public readonly settings: SettingsHelper; /** * Creates an instance of GameManager. @@ -63,6 +65,7 @@ export default class GameManager { this.move = new MoveHelper(this); this.classicMode = new ClassicModeHelper(this); this.dailyMode = new DailyModeHelper(this); + this.settings = new SettingsHelper(this); } /** diff --git a/src/test/utils/helpers/settingsHelper.ts b/src/test/utils/helpers/settingsHelper.ts new file mode 100644 index 00000000000..dec9e160d51 --- /dev/null +++ b/src/test/utils/helpers/settingsHelper.ts @@ -0,0 +1,15 @@ +import { GameManagerHelper } from "./gameManagerHelper"; + +/** + * Helper to handle settings for tests + */ +export class SettingsHelper extends GameManagerHelper { + + /** + * Disable/Enable type hints settings + * @param enable true to enabled, false to disabled + */ + typeHints(enable: boolean) { + this.game.scene.typeHints = enable; + } +} diff --git a/src/test/utils/mocks/mocksContainer/mockContainer.ts b/src/test/utils/mocks/mocksContainer/mockContainer.ts index d3672cb5235..5babd9e71b2 100644 --- a/src/test/utils/mocks/mocksContainer/mockContainer.ts +++ b/src/test/utils/mocks/mocksContainer/mockContainer.ts @@ -1,4 +1,5 @@ import MockTextureManager from "#test/utils/mocks/mockTextureManager"; +import { vi } from "vitest"; import { MockGameObject } from "../mockGameObject"; export default class MockContainer implements MockGameObject { @@ -13,6 +14,7 @@ export default class MockContainer implements MockGameObject { public frame; protected textureManager; public list: MockGameObject[] = []; + private name?: string; constructor(textureManager: MockTextureManager, x, y) { this.x = x; @@ -159,9 +161,10 @@ export default class MockContainer implements MockGameObject { // Moves this Game Object to be below the given Game Object in the display list. } - setName(name) { + setName = vi.fn((name: string) => { + this.name = name; // return this.phaserSprite.setName(name); - } + }); bringToTop(obj) { // Brings this Game Object to the top of its parents display list. diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts index 5d405efadfd..6b9ecf083fd 100644 --- a/src/test/utils/mocks/mocksContainer/mockText.ts +++ b/src/test/utils/mocks/mocksContainer/mockText.ts @@ -1,4 +1,5 @@ import UI from "#app/ui/ui"; +import { vi } from "vitest"; import { MockGameObject } from "../mockGameObject"; export default class MockText implements MockGameObject { @@ -10,6 +11,8 @@ export default class MockText implements MockGameObject { public list: MockGameObject[] = []; public style; public text = ""; + private name?: string; + public color?: string; constructor(textureManager, x, y, content, styleOptions) { this.scene = textureManager.scene; @@ -190,10 +193,9 @@ export default class MockText implements MockGameObject { }; } - setColor(color) { - // Sets the tint of this Game Object. - // return this.phaserText.setColor(color); - } + setColor = vi.fn((color: string) => { + this.color = color; + }); setShadowColor(color) { // Sets the shadow color. @@ -219,9 +221,9 @@ export default class MockText implements MockGameObject { // return this.phaserText.setAlpha(alpha); } - setName(name) { - // return this.phaserText.setName(name); - } + setName = vi.fn((name: string) => { + this.name = name; + }); setAlign(align) { // return this.phaserText.setAlign(align); diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 8279ab72a70..4ade6ca5d20 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -12,6 +12,8 @@ import {Button} from "#enums/buttons"; import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; export default class FightUiHandler extends UiHandler { + public static readonly MOVES_CONTAINER_NAME = "moves"; + private movesContainer: Phaser.GameObjects.Container; private moveInfoContainer: Phaser.GameObjects.Container; private typeIcon: Phaser.GameObjects.Sprite; @@ -35,7 +37,7 @@ export default class FightUiHandler extends UiHandler { const ui = this.getUi(); this.movesContainer = this.scene.add.container(18, -38.7); - this.movesContainer.setName("moves"); + this.movesContainer.setName(FightUiHandler.MOVES_CONTAINER_NAME); ui.add(this.movesContainer); this.moveInfoContainer = this.scene.add.container(1, 0); @@ -271,11 +273,10 @@ export default class FightUiHandler extends UiHandler { return undefined; } - const moveColors = opponents.map((opponent) => { - return opponent.getMoveEffectiveness(pokemon, pokemonMove); - }).filter((eff) => !!eff).sort((a, b) => b - a).map((effectiveness) => { - return getTypeDamageMultiplierColor(effectiveness, "offense"); - }); + const moveColors = opponents + .map((opponent) => opponent.getMoveEffectiveness(pokemon, pokemonMove)) + .sort((a, b) => b - a) + .map((effectiveness) => getTypeDamageMultiplierColor(effectiveness ?? 0, "offense")); return moveColors[0]; } From cd489c6a608ef3cea48f25e716b5cc1ea47bf484 Mon Sep 17 00:00:00 2001 From: EnochG1 Date: Mon, 19 Aug 2024 08:46:49 +0900 Subject: [PATCH 23/63] fix wrong line break character --- src/locales/ko/move-trigger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/ko/move-trigger.ts b/src/locales/ko/move-trigger.ts index cea60e25333..e93639689d8 100644 --- a/src/locales/ko/move-trigger.ts +++ b/src/locales/ko/move-trigger.ts @@ -8,7 +8,7 @@ export const moveTriggers: SimpleTranslationEntries = { "goingAllOutForAttack": "{{pokemonName}}[[는]]\n전력을 다하기 시작했다!", "regainedHealth": "{{pokemonName}}[[는]]\n기력을 회복했다!", "keptGoingAndCrashed": "{{pokemonName}}[[는]]\n의욕이 넘쳐서 땅에 부딪쳤다!", - "fled": "{{pokemonName}}[[는]]\N도망쳤다!", + "fled": "{{pokemonName}}[[는]]\n도망쳤다!", "cannotBeSwitchedOut": "{{pokemonName}}[[를]]\n돌아오게 할 수 없습니다!", "swappedAbilitiesWithTarget": "{{pokemonName}}[[는]]\n서로의 특성을 교체했다!", "coinsScatteredEverywhere": "돈이 주위에 흩어졌다!", From 1db26dab961451b7185cf492e7666f5044bc2d0a Mon Sep 17 00:00:00 2001 From: Enoch Date: Mon, 19 Aug 2024 08:50:31 +0900 Subject: [PATCH 24/63] fix wrong message key of curse(ghost type) (#3631) Co-authored-by: Frederico Santos --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 79e67ece581..24651bacb2e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4441,7 +4441,7 @@ export class CurseAttr extends MoveEffectAttr { const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2)); user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true); user.scene.queueMessage( - i18next.t("battle:cursedOnAdd", { + i18next.t("battlerTags:cursedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user), pokemonName: getPokemonNameWithAffix(target) }) From a46e35b8ddbabf0e7764dc73efe98c7267dd7440 Mon Sep 17 00:00:00 2001 From: Mumble Date: Sun, 18 Aug 2024 16:59:18 -0700 Subject: [PATCH 25/63] [Hotfix] Steal-able Mini Black Hole Pt 2 (#3632) * Still have no idea where Eternatus is given the MBH.... * typedocs --------- Co-authored-by: frutescens --- src/battle-scene.ts | 8 +------- src/phases.ts | 4 ++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index ae6cea2dcd1..4faf3863e3c 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2419,13 +2419,7 @@ export default class BattleScene extends SceneBase { count = Math.max(count, Math.floor(chances / 2)); } getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance) - .map(mt => { - const enemyModifier = mt.newModifier(enemyPokemon); - if (enemyModifier instanceof TurnHeldItemTransferModifier) { - enemyModifier.setTransferrableFalse(); - } - enemyModifier.add(this.enemyModifiers, false, this); - }); + .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this)); }); this.updateModifiers(false).then(() => resolve()); }); diff --git a/src/phases.ts b/src/phases.ts index 565914879e4..c50d25acf60 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -878,6 +878,10 @@ export class EncounterPhase extends BattlePhase { } else if (!(battle.waveIndex % 1000)) { enemyPokemon.formIndex = 1; enemyPokemon.updateScale(); + const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; + this.scene.removeModifier(bossMBH!); + bossMBH?.setTransferrableFalse(); + this.scene.addEnemyModifier(bossMBH!); } } From 747e4f9360c9a7f297aab82b3da85dbfc3c401e4 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 18 Aug 2024 17:05:53 -0700 Subject: [PATCH 26/63] [Hotfix] Abilities that prevent ATK drops no longer stop other stat drops (#3624) * Abilities that prevent ATK drops no longer stop other stat drops * Apply suggestions from code review Co-authored-by: Mumble * Add `isNullOrUndefined()` utility function --------- --- src/data/ability.ts | 6 +-- src/test/abilities/hyper_cutter.test.ts | 58 +++++++++++++++++++++++++ src/utils.ts | 8 ++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/test/abilities/hyper_cutter.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index cfd900d621c..38ca4eb25d0 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2395,16 +2395,16 @@ export class PreStatChangeAbAttr extends AbAttr { } export class ProtectStatAbAttr extends PreStatChangeAbAttr { - private protectedStat: BattleStat | null; + private protectedStat?: BattleStat; constructor(protectedStat?: BattleStat) { super(); - this.protectedStat = protectedStat ?? null; + this.protectedStat = protectedStat; } applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (!this.protectedStat || stat === this.protectedStat) { + if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) { cancelled.value = true; return true; } diff --git a/src/test/abilities/hyper_cutter.test.ts b/src/test/abilities/hyper_cutter.test.ts new file mode 100644 index 00000000000..9637a80ddb4 --- /dev/null +++ b/src/test/abilities/hyper_cutter.test.ts @@ -0,0 +1,58 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Hyper Cutter", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .moveset([Moves.SAND_ATTACK, Moves.NOBLE_ROAR, Moves.DEFOG, Moves.OCTOLOCK]) + .ability(Abilities.BALL_FETCH) + .enemySpecies(Species.SHUCKLE) + .enemyAbility(Abilities.HYPER_CUTTER) + .enemyMoveset(SPLASH_ONLY); + }); + + // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability) + + it("only prevents ATK drops", async () => { + await game.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.DEFOG)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.NOBLE_ROAR)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.SAND_ATTACK)); + await game.toNextTurn(); + game.override.moveset([Moves.STRING_SHOT]); + game.doAttack(getMovePosition(game.scene, 0, Moves.STRING_SHOT)); + await game.toNextTurn(); + + expect(enemy.summonData.battleStats[BattleStat.ATK]).toEqual(0); + [BattleStat.ACC, BattleStat.DEF, BattleStat.EVA, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD].forEach((stat: number) => expect(enemy.summonData.battleStats[stat]).toBeLessThan(0)); + }); +}); diff --git a/src/utils.ts b/src/utils.ts index aa45c091286..c51ac2b5b0b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -552,3 +552,11 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole } return null; } + +/** + * Returns if an object is null or undefined + * @param object + */ +export function isNullOrUndefined(object: any): boolean { + return null === object || undefined === object; +} From bdde03b0d5b340e256e7800c5571f60ca2aa60a9 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 18 Aug 2024 18:06:52 -0700 Subject: [PATCH 27/63] Grip Claw now shows the proper pokemon nickname (#3634) Co-authored-by: frutescens --- src/modifier/modifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 1dff041a14e..f4ec6c499f4 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2414,7 +2414,7 @@ export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModif } getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { - return i18next.t("modifier:contactHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: pokemon.name, typeName: this.type.name }); + return i18next.t("modifier:contactHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: getPokemonNameWithAffix(pokemon), typeName: this.type.name }); } getMaxHeldItemCount(pokemon: Pokemon): integer { From 098811c0068eca6068b135d0cf16581fb563bdac Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 18 Aug 2024 18:18:43 -0700 Subject: [PATCH 28/63] Main -> Beta (#3635) * Fixed issue with falsy issue within condition to get a stat for IV scanner * add fix setting code to prevent form/variant bug when default form/variant setting is wrong. in addition, that fix code include gender fix, so i revert old gender fix. update wrong log message. * [Hotfix] Fix Memory Mushroom not showing relearner moves (#3619) * Fix Memory Mushroom not showing relearner moves * Fix rollout test * Rewrite player faint logic in FaintPhase (#3614) * 867 runerigus sprite (#3629) cropped static frames, fixed cropped sprite set runerigus exp to use the shiny exp's animation verified all hex colors are unchanged - fixed ultra necrozma exp front variant swapped arrays. - xatu female eye color fix * [Bug] Preventing the MBH from being stolen in Endless (#3630) * Endless MBH Fix * add import * Revert "add import" This reverts commit 814a4059c2830e972c348d698259535e117850bf. * Revert "Endless MBH Fix" This reverts commit 8eb448130132ff9eed614a2ec576926814008df0. * removed newline --------- Co-authored-by: Frederico Santos Co-authored-by: frutescens * [Bug] Fix type-hints for immunity (#3620) * enable mock containers to be found by name * enable mock text to be found by name * add test coverage for type-hints Only for "immunity" and "status moves" * fix wrong message key of curse(ghost type) (#3631) Co-authored-by: Frederico Santos * [Hotfix] Steal-able Mini Black Hole Pt 2 (#3632) * Still have no idea where Eternatus is given the MBH.... * typedocs --------- Co-authored-by: frutescens * [Hotfix] Abilities that prevent ATK drops no longer stop other stat drops (#3624) * Abilities that prevent ATK drops no longer stop other stat drops * Apply suggestions from code review Co-authored-by: Mumble * Add `isNullOrUndefined()` utility function --------- * Grip Claw now shows the proper pokemon nickname (#3634) Co-authored-by: frutescens --------- Co-authored-by: Opaque02 <66582645+Opaque02@users.noreply.github.com> Co-authored-by: KimJeongSun Co-authored-by: Frederico Santos Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> Co-authored-by: cam Co-authored-by: Mumble Co-authored-by: frutescens Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: Enoch Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> --- public/images/pokemon/867.png | Bin 2128 -> 1047 bytes public/images/pokemon/back/867.png | Bin 1617 -> 800 bytes public/images/pokemon/back/shiny/867.png | Bin 743 -> 793 bytes public/images/pokemon/exp/867.json | 1590 +++++++++-------- public/images/pokemon/exp/867.png | Bin 23716 -> 13409 bytes public/images/pokemon/exp/back/867.png | Bin 7341 -> 3724 bytes public/images/pokemon/exp/back/shiny/867.png | Bin 3270 -> 3715 bytes public/images/pokemon/shiny/867.png | Bin 976 -> 1043 bytes .../pokemon/variant/back/female/178_2.png | Bin 6304 -> 6305 bytes .../pokemon/variant/back/female/178_3.png | Bin 6304 -> 6305 bytes .../images/pokemon/variant/exp/800-ultra.json | 32 +- src/battle-scene.ts | 1 - src/data/ability.ts | 6 +- src/data/move.ts | 2 +- src/field/pokemon.ts | 8 +- src/modifier/modifier.ts | 2 +- src/phases.ts | 25 +- src/test/abilities/hyper_cutter.test.ts | 58 + src/test/moves/rollout.test.ts | 3 +- src/test/ui/transfer-item.test.ts | 1 - src/test/ui/type-hints.test.ts | 89 + src/test/utils/gameManager.ts | 3 + src/test/utils/helpers/settingsHelper.ts | 15 + .../mocks/mocksContainer/mockContainer.ts | 7 +- .../utils/mocks/mocksContainer/mockText.ts | 16 +- src/ui/battle-message-ui-handler.ts | 2 +- src/ui/fight-ui-handler.ts | 13 +- src/ui/starter-select-ui-handler.ts | 96 +- src/utils.ts | 8 + 29 files changed, 1154 insertions(+), 823 deletions(-) create mode 100644 src/test/abilities/hyper_cutter.test.ts create mode 100644 src/test/ui/type-hints.test.ts create mode 100644 src/test/utils/helpers/settingsHelper.ts diff --git a/public/images/pokemon/867.png b/public/images/pokemon/867.png index bd07a7a48375858f3ed2506c81e51befc2c02db8..2fe8856d74df6113ece362f16ddf144140f82469 100644 GIT binary patch literal 1047 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 P00000NkvXXu0mjf&XWG+ diff --git a/public/images/pokemon/back/shiny/867.png b/public/images/pokemon/back/shiny/867.png index fce3fe4e37eaa10d77894bfd02c7d8da05536297..accb87844f1c680b67e46ba371405a992adc6d83 100644 GIT binary patch delta 750 zcmV5(BMe+P6@PE!E?|NsC0 z|D}JX`v3p}pGibPR9Jqa*agmie?PDZ&UyddX7~rT!GZm%V?Es2RjnQSRPJDBlM4HuAJda8HmT((A8Rw` z{B#EfbhRs-=o2*qe^53nmdFk9(M=D zhCK|_cDY4py*!63u(0(_>Cmfr?`?j*UMAWSwuZ4COtVhEI=jj3fp)%wcj`U5UR$9@ zOs0<`=a}3T#(x`Kz--ztZ(jKIuXn=Cps8%e<^dk{s8Kxfd(AYtfz<$ z$1*oRz?;i<$J~?mZZyaf*e68$$;qYb^(4j<&}h*?YF|go5D+*CZ-w$CXi-3lYIjm- z0_ZbZMqo9Z2N|S9k8$x~yv~f(e_CjC^btIwHkPDK->^lEZ6Mu(H+|0m-uhfa4A&vKT$K#o#tv{ju%09~ zMOV7?+t>pNua>{M=p4!O8trMo)$Efxdq}Su1c`VRbY0FK$p~B$Eoj8_jVy}^{eTWL zqh)$M-pTm|%uP(0wr{qdn{6~pF3QYd+1wYb7J#g>e=G>;gKfEV9{nzK$|k>bZNR0v zYr?#iFYRyVkXhD+I*|K4&yA2V$=|qSpg(Se%uAOKTI!riI2_kxEqT}lopqU-7LEI| zq@&S0e}@=TewB7IjhE1ygYI^6i`Df4jdMC=4`OaGXRZZpG`J$IgJ7}7UhG4Z zJy86;Oe&h@SI4yetE5)E9#8JOwq^X*Jd|C-fP?=&e}58ozTs{!=e;NH7KHXR#*6lQ gHMYNUz5d|Ae==DedM}{`Q~&?~07*qoM6N<$f`sjD`Tzg` delta 700 zcmV;t0z>_o2ImEk7YbPf0{{R3rzMq~kuD^E0d!JMQvg8b*k%9#0)R!%Iy%a=nku)zv+9krb^hCtxO(GoZl3U5D`z{ulmBA-ZP+HM{B52`nw@84Nx#c$hBASTAqs6EDU*#pe&7*4Z9u>QCUCSd2O&X+{a2myz`wHNw5SQDalhkUW z44hIDeO)<&k*=^{jjmR|LlP5*%E-KGNa_xjpSKwxc2km!+;Dl&6bR}J4(_e zo|F^m+N@}hH->e$X@HjasGLZMh(a`f$r3}|?UMTiPq0zTztvaW46RX}D1$XrCm)Oj zI;w*!As;N3$uoj3l1s+P!@xdhHQr#+i2%_l^)ids6+dd{u<6lbnd*`V{S+Eq(vSwW z2(p}{5v^18l!4G3SgGC4wrb}BKAV2Pd=6BzH7ajPUi?DV;mYG75Q77Q5Wasl9YW ztVwR9^MJJM>(niylzE=hAWHe3j`UH^Sv&Xjz%mP`ToJ|}fZ diff --git a/public/images/pokemon/exp/867.json b/public/images/pokemon/exp/867.json index 1a9c7572f43..52e0127509b 100644 --- a/public/images/pokemon/exp/867.json +++ b/public/images/pokemon/exp/867.json @@ -4,8 +4,8 @@ "image": "867.png", "format": "RGBA8888", "size": { - "w": 344, - "h": 344 + "w": 361, + "h": 361 }, "scale": 1, "frames": [ @@ -31,7 +31,7 @@ } }, { - "filename": "0020.png", + "filename": "0021.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -52,7 +52,7 @@ } }, { - "filename": "0035.png", + "filename": "0037.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -94,70 +94,7 @@ } }, { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 113, - "h": 56 - }, - "frame": { - "x": 114, - "y": 0, - "w": 113, - "h": 56 - } - }, - { - "filename": "0034.png", + "filename": "0020.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -199,7 +136,7 @@ } }, { - "filename": "0003.png", + "filename": "0006.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -207,20 +144,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0018.png", + "filename": "0022.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -228,20 +165,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0033.png", + "filename": "0038.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -249,62 +186,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 4, + "x": 2, "y": 0, - "w": 107, + "w": 112, "h": 56 }, "frame": { "x": 227, "y": 0, - "w": 107, + "w": 112, "h": 56 } }, { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 103, - "h": 65 - }, - "frame": { - "x": 0, - "y": 56, - "w": 103, - "h": 65 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 103, - "h": 65 - }, - "frame": { - "x": 0, - "y": 56, - "w": 103, - "h": 65 - } - }, - { - "filename": "0026.png", + "filename": "0012.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -346,7 +241,7 @@ } }, { - "filename": "0041.png", + "filename": "0044.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -367,7 +262,7 @@ } }, { - "filename": "0043.png", + "filename": "0003.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -375,16 +270,58 @@ "h": 66 }, "spriteSourceSize": { - "x": 5, + "x": 4, "y": 0, - "w": 103, - "h": 65 + "w": 107, + "h": 56 }, "frame": { - "x": 0, + "x": 103, "y": 56, - "w": 103, - "h": 65 + "w": 107, + "h": 56 + } + }, + { + "filename": "0019.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 4, + "y": 0, + "w": 107, + "h": 56 + }, + "frame": { + "x": 103, + "y": 56, + "w": 107, + "h": 56 + } + }, + { + "filename": "0035.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 4, + "y": 0, + "w": 107, + "h": 56 + }, + "frame": { + "x": 103, + "y": 56, + "w": 107, + "h": 56 } }, { @@ -402,14 +339,14 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, { - "filename": "0022.png", + "filename": "0023.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -423,14 +360,14 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, { - "filename": "0037.png", + "filename": "0039.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -444,12 +381,54 @@ "h": 56 }, "frame": { - "x": 103, + "x": 210, "y": 56, "w": 107, "h": 56 } }, + { + "filename": "0053.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 1, + "w": 44, + "h": 56 + }, + "frame": { + "x": 317, + "y": 56, + "w": 44, + "h": 56 + } + }, + { + "filename": "0064.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 1, + "w": 44, + "h": 56 + }, + "frame": { + "x": 317, + "y": 56, + "w": 44, + "h": 56 + } + }, { "filename": "0002.png", "rotated": false, @@ -465,14 +444,14 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, { - "filename": "0017.png", + "filename": "0018.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -486,14 +465,14 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, { - "filename": "0032.png", + "filename": "0034.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -507,12 +486,138 @@ "h": 57 }, "frame": { - "x": 210, - "y": 56, + "x": 103, + "y": 112, "w": 102, "h": 57 } }, + { + "filename": "0013.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0029.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0045.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 101, + "h": 65 + }, + "frame": { + "x": 0, + "y": 121, + "w": 101, + "h": 65 + } + }, + { + "filename": "0011.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, + { + "filename": "0027.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, + { + "filename": "0043.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 101, + "h": 61 + }, + "frame": { + "x": 205, + "y": 112, + "w": 101, + "h": 61 + } + }, { "filename": "0008.png", "rotated": false, @@ -524,266 +629,14 @@ "spriteSourceSize": { "x": 6, "y": 0, - "w": 102, + "w": 101, "h": 57 }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 102, - "h": 57 - }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 102, - "h": 57 - }, - "frame": { - "x": 103, - "y": 112, - "w": 102, - "h": 57 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 101, - "h": 65 - }, - "frame": { - "x": 0, - "y": 121, - "w": 101, - "h": 65 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 101, - "h": 61 - }, - "frame": { - "x": 205, - "y": 113, - "w": 101, - "h": 61 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 99, - "h": 59 - }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { @@ -795,20 +648,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 6, "y": 0, - "w": 99, - "h": 59 + "w": 101, + "h": 57 }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { - "filename": "0039.png", + "filename": "0040.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -816,20 +669,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 6, "y": 0, - "w": 99, - "h": 59 + "w": 101, + "h": 57 }, "frame": { "x": 101, "y": 169, - "w": 99, - "h": 59 + "w": 101, + "h": 57 } }, { - "filename": "0015.png", + "filename": "0010.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -849,6 +702,195 @@ "h": 59 } }, + { + "filename": "0026.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 8, + "y": 0, + "w": 99, + "h": 59 + }, + "frame": { + "x": 0, + "y": 186, + "w": 99, + "h": 59 + } + }, + { + "filename": "0042.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 8, + "y": 0, + "w": 99, + "h": 59 + }, + "frame": { + "x": 0, + "y": 186, + "w": 99, + "h": 59 + } + }, + { + "filename": "0054.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 0, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0055.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0059.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0063.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 40, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 112, + "w": 44, + "h": 54 + } + }, + { + "filename": "0060.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 39, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 166, + "w": 44, + "h": 54 + } + }, + { + "filename": "0062.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 39, + "y": 3, + "w": 44, + "h": 54 + }, + "frame": { + "x": 306, + "y": 166, + "w": 44, + "h": 54 + } + }, + { + "filename": "0014.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 5, + "y": 0, + "w": 97, + "h": 65 + }, + "frame": { + "x": 202, + "y": 173, + "w": 97, + "h": 65 + } + }, { "filename": "0030.png", "rotated": false, @@ -858,20 +900,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 0, - "w": 99, - "h": 59 + "w": 97, + "h": 65 }, "frame": { - "x": 0, - "y": 186, - "w": 99, - "h": 59 + "x": 202, + "y": 173, + "w": 97, + "h": 65 } }, { - "filename": "0045.png", + "filename": "0046.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -879,16 +921,58 @@ "h": 66 }, "spriteSourceSize": { - "x": 8, + "x": 5, "y": 0, - "w": 99, - "h": 59 + "w": 97, + "h": 65 }, "frame": { - "x": 0, - "y": 186, - "w": 99, - "h": 59 + "x": 202, + "y": 173, + "w": 97, + "h": 65 + } + }, + { + "filename": "0051.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 29, + "y": 1, + "w": 58, + "h": 57 + }, + "frame": { + "x": 299, + "y": 220, + "w": 58, + "h": 57 + } + }, + { + "filename": "0066.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 29, + "y": 1, + "w": 58, + "h": 57 + }, + "frame": { + "x": 299, + "y": 220, + "w": 58, + "h": 57 } }, { @@ -906,8 +990,134 @@ "h": 59 }, "frame": { - "x": 0, - "y": 245, + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0009.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0017.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0025.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0033.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0041.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, + "w": 95, + "h": 59 + } + }, + { + "filename": "0068.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 9, + "y": 1, + "w": 95, + "h": 59 + }, + "frame": { + "x": 99, + "y": 226, "w": 95, "h": 59 } @@ -921,146 +1131,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 95, - "h": 59 - }, - "frame": { - "x": 0, - "y": 245, - "w": 95, - "h": 59 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 12, - "y": 1, - "w": 90, - "h": 59 - }, - "frame": { - "x": 95, - "y": 245, - "w": 90, - "h": 59 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 22, - "y": 1, - "w": 70, - "h": 59 - }, - "frame": { - "x": 185, - "y": 228, - "w": 70, - "h": 59 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 22, - "y": 1, - "w": 70, - "h": 59 - }, - "frame": { - "x": 185, - "y": 228, - "w": 70, - "h": 59 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, + "x": 8, "y": 0, - "w": 44, - "h": 54 + "w": 95, + "h": 59 }, "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { - "filename": "0052.png", + "filename": "0032.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1068,100 +1152,16 @@ "h": 66 }, "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 + "x": 8, + "y": 0, + "w": 95, + "h": 59 }, "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 200, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 39, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 244, - "y": 174, - "w": 44, - "h": 54 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 39, - "y": 3, - "w": 44, - "h": 54 - }, - "frame": { - "x": 244, - "y": 174, - "w": 44, - "h": 54 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { @@ -1173,41 +1173,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 29, - "y": 1, - "w": 58, - "h": 57 + "x": 8, + "y": 0, + "w": 95, + "h": 59 }, "frame": { - "x": 185, - "y": 287, - "w": 58, - "h": 57 + "x": 0, + "y": 245, + "w": 95, + "h": 59 } }, { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 29, - "y": 1, - "w": 58, - "h": 57 - }, - "frame": { - "x": 185, - "y": 287, - "w": 58, - "h": 57 - } - }, - { - "filename": "0049.png", + "filename": "0052.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1221,14 +1200,14 @@ "h": 56 }, "frame": { - "x": 288, - "y": 174, + "x": 0, + "y": 304, "w": 56, "h": 56 } }, { - "filename": "0062.png", + "filename": "0065.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1242,56 +1221,14 @@ "h": 56 }, "frame": { - "x": 288, - "y": 174, + "x": 0, + "y": 304, "w": 56, "h": 56 } }, { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 1, - "w": 44, - "h": 56 - }, - "frame": { - "x": 243, - "y": 287, - "w": 44, - "h": 56 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 40, - "y": 1, - "w": 44, - "h": 56 - }, - "frame": { - "x": 243, - "y": 287, - "w": 44, - "h": 56 - } - }, - { - "filename": "0053.png", + "filename": "0056.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1305,29 +1242,8 @@ "h": 53 }, "frame": { - "x": 255, - "y": 230, - "w": 44, - "h": 53 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 114, - "h": 66 - }, - "spriteSourceSize": { - "x": 41, - "y": 4, - "w": 44, - "h": 53 - }, - "frame": { - "x": 255, - "y": 230, + "x": 56, + "y": 304, "w": 44, "h": 53 } @@ -1341,20 +1257,20 @@ "h": 66 }, "spriteSourceSize": { - "x": 38, + "x": 41, "y": 4, "w": 44, "h": 53 }, "frame": { - "x": 299, - "y": 230, + "x": 56, + "y": 304, "w": 44, "h": 53 } }, { - "filename": "0054.png", + "filename": "0015.png", "rotated": false, "trimmed": true, "sourceSize": { @@ -1362,14 +1278,161 @@ "h": 66 }, "spriteSourceSize": { - "x": 42, + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0031.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0047.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 7, + "y": 0, + "w": 94, + "h": 61 + }, + "frame": { + "x": 194, + "y": 238, + "w": 94, + "h": 61 + } + }, + { + "filename": "0050.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 22, + "y": 1, + "w": 70, + "h": 59 + }, + "frame": { + "x": 288, + "y": 277, + "w": 70, + "h": 59 + } + }, + { + "filename": "0067.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 22, + "y": 1, + "w": 70, + "h": 59 + }, + "frame": { + "x": 288, + "y": 277, + "w": 70, + "h": 59 + } + }, + { + "filename": "0049.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 12, + "y": 1, + "w": 90, + "h": 59 + }, + "frame": { + "x": 100, + "y": 299, + "w": 90, + "h": 59 + } + }, + { + "filename": "0061.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 37, + "y": 4, + "w": 44, + "h": 53 + }, + "frame": { + "x": 190, + "y": 299, + "w": 44, + "h": 53 + } + }, + { + "filename": "0057.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 114, + "h": 66 + }, + "spriteSourceSize": { + "x": 43, "y": 5, "w": 44, "h": 52 }, "frame": { - "x": 287, - "y": 283, + "x": 234, + "y": 299, "w": 44, "h": 52 } @@ -1379,7 +1442,6 @@ ], "meta": { "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b8ca75f7f37906e78ed633b32d037b74:92bc79a7ca35490600679451c06105fc:58bcd289dd222ce646aec14ff657c9fc$" + "version": "3.0" } } diff --git a/public/images/pokemon/exp/867.png b/public/images/pokemon/exp/867.png index 689a72694ef90e5dd459be477119a20f39db8e6a..4f8f67842bdd6ee61b2ba0ca2afe8d7ddfd2c852 100644 GIT binary patch literal 13409 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

AEr)YqXKi=OLo?%#>feG5W8?bg!mY<> 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 z4));y diff --git a/public/images/pokemon/exp/back/867.png b/public/images/pokemon/exp/back/867.png index 766ce3f39ed80703b473d801230d7cedaf763998..b816f10a0def567345f8a9a7a87e041d4898b70a 100644 GIT binary patch literal 3724 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 M07*qoM6N<$g4SP4<^TWy delta 3246 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 g{(l;-f7U5(BVe+qO`PE!E?|NsC0 z|NsC0eu)%T000AxNklv-@}kI9IwyWjBS>=%FOxxDSo1p2<7xa(`${) z%q~PHUqqyC^rrMuC}$!{s>n%I^Y9R3FdYAq+!+hV#J`k9e;Qea#AqI+7=GMrI<7v8vXoDNN6!Jl8$5hU13p#+1}WtbaK3b{{ z>+?FKWe;BE1MBEMjRnxJ3XABgnrY2K8{v3af1=+h$w#B3vY>yfi}ZXN#{suw^VIR+ zeTP1Nu>Lms_ew5*)yCv?`mNgL@?$_6cV=Iv&j-%*id7vB(#!N)Cu(OFt&Nu6kxnc0 z+e4`i)lnNo8phNEtkdJ0MSNM%?!}snb1i#Fze+w@0T(A_>&^teXh?sZyP;s$UZV3` zKQ3bD?G(cb7k6T({kAszo~saPXotU1c<;{TYky$+CHsp1P4*n)l`H=Na`iFH*e8W{ P00000NkvXXu0mjfr?m7Y delta 926 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 delta 6214 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 diff --git a/public/images/pokemon/variant/back/female/178_3.png b/public/images/pokemon/variant/back/female/178_3.png index 32ffdd895c6950fdcec0edc08b2b41b37a01a7ae..9533621c6d696fda7b3f97abd127ba04cbcc78fd 100644 GIT binary patch delta 6215 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 delta 6214 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 diff --git a/public/images/pokemon/variant/exp/800-ultra.json b/public/images/pokemon/variant/exp/800-ultra.json index 53dd9b55df0..cab917ec271 100644 --- a/public/images/pokemon/variant/exp/800-ultra.json +++ b/public/images/pokemon/variant/exp/800-ultra.json @@ -1,21 +1,5 @@ { "1": { - "b0a080": "e552ec", - "f8f8e8": "ffe2ed", - "9b8259": "b021c5", - "e5e4c2": "ffb9f9", - "000000": "000000", - "bc9b4e": "900090", - "f8f8d0": "ff8ae9", - "e8e088": "ff49e7", - "d0b868": "d10cc7", - "7d673b": "510059", - "282828": "282828", - "f84040": "f84040", - "f88888": "1ae2e6", - "c81010": "00c2d2" - }, - "2": { "b0a080": "d96b23", "f8f8e8": "ffe1b8", "9b8259": "b43c06", @@ -30,5 +14,21 @@ "f84040": "f84040", "f88888": "f88888", "c81010": "c81010" + }, + "2": { + "b0a080": "e552ec", + "f8f8e8": "ffe2ed", + "9b8259": "b021c5", + "e5e4c2": "ffb9f9", + "000000": "000000", + "bc9b4e": "900090", + "f8f8d0": "ff8ae9", + "e8e088": "ff49e7", + "d0b868": "d10cc7", + "7d673b": "510059", + "282828": "282828", + "f84040": "f84040", + "f88888": "1ae2e6", + "c81010": "00c2d2" } } \ No newline at end of file diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 674b4e256f9..4faf3863e3c 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2421,7 +2421,6 @@ export default class BattleScene extends SceneBase { getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance) .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this)); }); - this.updateModifiers(false).then(() => resolve()); }); } diff --git a/src/data/ability.ts b/src/data/ability.ts index cfd900d621c..38ca4eb25d0 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2395,16 +2395,16 @@ export class PreStatChangeAbAttr extends AbAttr { } export class ProtectStatAbAttr extends PreStatChangeAbAttr { - private protectedStat: BattleStat | null; + private protectedStat?: BattleStat; constructor(protectedStat?: BattleStat) { super(); - this.protectedStat = protectedStat ?? null; + this.protectedStat = protectedStat; } applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (!this.protectedStat || stat === this.protectedStat) { + if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) { cancelled.value = true; return true; } diff --git a/src/data/move.ts b/src/data/move.ts index 79e67ece581..24651bacb2e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4441,7 +4441,7 @@ export class CurseAttr extends MoveEffectAttr { const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2)); user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true); user.scene.queueMessage( - i18next.t("battle:cursedOnAdd", { + i18next.t("battlerTags:cursedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user), pokemonName: getPokemonNameWithAffix(target) }) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f1721299ad0..e38813ed3c0 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -921,7 +921,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * by how many learnable moves there are for the {@linkcode Pokemon}. */ getLearnableLevelMoves(): Moves[] { - let levelMoves = this.getLevelMoves(1, true).map(lm => lm[1]); + let levelMoves = this.getLevelMoves(1, true, false, true).map(lm => lm[1]); if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) { levelMoves = this.getUnlockedEggMoves().concat(levelMoves); } @@ -1210,11 +1210,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * * @param source - The Pokémon using the move. * @param move - The move being used. - * @returns The type damage multiplier or undefined if it's a status move + * @returns The type damage multiplier or 1 if it's a status move */ - getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined { + getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier { if (move.getMove().category === MoveCategory.STATUS) { - return undefined; + return 1; } return this.getAttackMoveEffectiveness(source, move, !this.battleData?.abilityRevealed); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 1dff041a14e..f4ec6c499f4 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2414,7 +2414,7 @@ export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModif } getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { - return i18next.t("modifier:contactHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: pokemon.name, typeName: this.type.name }); + return i18next.t("modifier:contactHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: getPokemonNameWithAffix(pokemon), typeName: this.type.name }); } getMaxHeldItemCount(pokemon: Pokemon): integer { diff --git a/src/phases.ts b/src/phases.ts index 88acfc825ef..c50d25acf60 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -878,6 +878,10 @@ export class EncounterPhase extends BattlePhase { } else if (!(battle.waveIndex % 1000)) { enemyPokemon.formIndex = 1; enemyPokemon.updateScale(); + const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; + this.scene.removeModifier(bossMBH!); + bossMBH?.setTransferrableFalse(); + this.scene.addEnemyModifier(bossMBH!); } } @@ -4033,13 +4037,24 @@ export class FaintPhase extends PokemonPhase { } if (this.player) { - const nonFaintedLegalPartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); - const nonFaintedPartyMemberCount = nonFaintedLegalPartyMembers.length; - if (!nonFaintedPartyMemberCount) { + /** The total number of Pokemon in the player's party that can legally fight */ + const legalPlayerPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); + /** The total number of legal player Pokemon that aren't currently on the field */ + const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); + if (!legalPlayerPokemon.length) { + /** If the player doesn't have any legal Pokemon, end the game */ this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } else if (nonFaintedPartyMemberCount === 1 && this.scene.currentBattle.double) { + } else if (this.scene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) { + /** + * If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon + * is already on the field, unshift a phase that moves that Pokemon to center position. + */ this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); - } else if (nonFaintedPartyMemberCount >= this.scene.currentBattle.getBattlerCount()) { + } else if (legalPlayerPartyPokemon.length > 0) { + /** + * If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field, + * push a phase that prompts the player to summon a Pokemon from their party. + */ this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false)); } } else { diff --git a/src/test/abilities/hyper_cutter.test.ts b/src/test/abilities/hyper_cutter.test.ts new file mode 100644 index 00000000000..9637a80ddb4 --- /dev/null +++ b/src/test/abilities/hyper_cutter.test.ts @@ -0,0 +1,58 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Hyper Cutter", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .moveset([Moves.SAND_ATTACK, Moves.NOBLE_ROAR, Moves.DEFOG, Moves.OCTOLOCK]) + .ability(Abilities.BALL_FETCH) + .enemySpecies(Species.SHUCKLE) + .enemyAbility(Abilities.HYPER_CUTTER) + .enemyMoveset(SPLASH_ONLY); + }); + + // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability) + + it("only prevents ATK drops", async () => { + await game.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.DEFOG)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.NOBLE_ROAR)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.SAND_ATTACK)); + await game.toNextTurn(); + game.override.moveset([Moves.STRING_SHOT]); + game.doAttack(getMovePosition(game.scene, 0, Moves.STRING_SHOT)); + await game.toNextTurn(); + + expect(enemy.summonData.battleStats[BattleStat.ATK]).toEqual(0); + [BattleStat.ACC, BattleStat.DEF, BattleStat.EVA, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD].forEach((stat: number) => expect(enemy.summonData.battleStats[stat]).toBeLessThan(0)); + }); +}); diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts index ad323c447f5..728fe1ecd45 100644 --- a/src/test/moves/rollout.test.ts +++ b/src/test/moves/rollout.test.ts @@ -12,6 +12,7 @@ import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Rollout", () => { let phaserGame: Phaser.Game; let game: GameManager; + const TIMEOUT = 20 * 1000; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -77,5 +78,5 @@ describe("Moves - Rollout", () => { // reset expect(turn6Dmg).toBeGreaterThanOrEqual(turn1Dmg - variance); expect(turn6Dmg).toBeLessThanOrEqual(turn1Dmg + variance); - }); + }, TIMEOUT); }); diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index bbb9a823ad9..9315971e484 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -87,7 +87,6 @@ describe("UI - Transfer Items", () => { handler.processInput(Button.ACTION); // select Pokemon expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Transfer"))).toBe(true); - game.phaseInterceptor.unlock(); }); diff --git a/src/test/ui/type-hints.test.ts b/src/test/ui/type-hints.test.ts new file mode 100644 index 00000000000..eb0191812e8 --- /dev/null +++ b/src/test/ui/type-hints.test.ts @@ -0,0 +1,89 @@ +import { Button } from "#app/enums/buttons.js"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { CommandPhase } from "#app/phases"; +import FightUiHandler from "#app/ui/fight-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import MockText from "../utils/mocks/mocksContainer/mockText"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +describe("UI - Type Hints", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(async () => { + game = new GameManager(phaserGame); + game.settings.typeHints(true); //activate type hints + game.override.battleType("single").startingLevel(100).startingWave(1).enemyMoveset(SPLASH_ONLY); + }); + + it("check immunity color", async () => { + game.override + .battleType("single") + .startingLevel(100) + .startingWave(1) + .enemySpecies(Species.FLORGES) + .enemyMoveset(SPLASH_ONLY) + .moveset([Moves.DRAGON_CLAW]); + game.settings.typeHints(true); //activate type hints + + await game.startBattle([Species.RAYQUAZA]); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const dragonClawText = movesContainer + .getAll() + .find((text) => text.text === "Dragon Claw")! as unknown as MockText; + + expect.soft(dragonClawText.color).toBe("#929292"); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); + + it("check status move color", async () => { + game.override.enemySpecies(Species.FLORGES).moveset([Moves.GROWL]); + + await game.startBattle([Species.RAYQUAZA]); + + game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const growlText = movesContainer + .getAll() + .find((text) => text.text === "Growl")! as unknown as MockText; + + expect.soft(growlText.color).toBe(undefined); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 27ba7a215eb..6333179e3b2 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -30,6 +30,7 @@ import { MoveHelper } from "./helpers/moveHelper"; import { vi } from "vitest"; import { ClassicModeHelper } from "./helpers/classicModeHelper"; import { DailyModeHelper } from "./helpers/dailyModeHelper"; +import { SettingsHelper } from "./helpers/settingsHelper"; /** * Class to manage the game state and transitions between phases. @@ -44,6 +45,7 @@ export default class GameManager { public readonly move: MoveHelper; public readonly classicMode: ClassicModeHelper; public readonly dailyMode: DailyModeHelper; + public readonly settings: SettingsHelper; /** * Creates an instance of GameManager. @@ -63,6 +65,7 @@ export default class GameManager { this.move = new MoveHelper(this); this.classicMode = new ClassicModeHelper(this); this.dailyMode = new DailyModeHelper(this); + this.settings = new SettingsHelper(this); } /** diff --git a/src/test/utils/helpers/settingsHelper.ts b/src/test/utils/helpers/settingsHelper.ts new file mode 100644 index 00000000000..dec9e160d51 --- /dev/null +++ b/src/test/utils/helpers/settingsHelper.ts @@ -0,0 +1,15 @@ +import { GameManagerHelper } from "./gameManagerHelper"; + +/** + * Helper to handle settings for tests + */ +export class SettingsHelper extends GameManagerHelper { + + /** + * Disable/Enable type hints settings + * @param enable true to enabled, false to disabled + */ + typeHints(enable: boolean) { + this.game.scene.typeHints = enable; + } +} diff --git a/src/test/utils/mocks/mocksContainer/mockContainer.ts b/src/test/utils/mocks/mocksContainer/mockContainer.ts index d3672cb5235..5babd9e71b2 100644 --- a/src/test/utils/mocks/mocksContainer/mockContainer.ts +++ b/src/test/utils/mocks/mocksContainer/mockContainer.ts @@ -1,4 +1,5 @@ import MockTextureManager from "#test/utils/mocks/mockTextureManager"; +import { vi } from "vitest"; import { MockGameObject } from "../mockGameObject"; export default class MockContainer implements MockGameObject { @@ -13,6 +14,7 @@ export default class MockContainer implements MockGameObject { public frame; protected textureManager; public list: MockGameObject[] = []; + private name?: string; constructor(textureManager: MockTextureManager, x, y) { this.x = x; @@ -159,9 +161,10 @@ export default class MockContainer implements MockGameObject { // Moves this Game Object to be below the given Game Object in the display list. } - setName(name) { + setName = vi.fn((name: string) => { + this.name = name; // return this.phaserSprite.setName(name); - } + }); bringToTop(obj) { // Brings this Game Object to the top of its parents display list. diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts index 5d405efadfd..6b9ecf083fd 100644 --- a/src/test/utils/mocks/mocksContainer/mockText.ts +++ b/src/test/utils/mocks/mocksContainer/mockText.ts @@ -1,4 +1,5 @@ import UI from "#app/ui/ui"; +import { vi } from "vitest"; import { MockGameObject } from "../mockGameObject"; export default class MockText implements MockGameObject { @@ -10,6 +11,8 @@ export default class MockText implements MockGameObject { public list: MockGameObject[] = []; public style; public text = ""; + private name?: string; + public color?: string; constructor(textureManager, x, y, content, styleOptions) { this.scene = textureManager.scene; @@ -190,10 +193,9 @@ export default class MockText implements MockGameObject { }; } - setColor(color) { - // Sets the tint of this Game Object. - // return this.phaserText.setColor(color); - } + setColor = vi.fn((color: string) => { + this.color = color; + }); setShadowColor(color) { // Sets the shadow color. @@ -219,9 +221,9 @@ export default class MockText implements MockGameObject { // return this.phaserText.setAlpha(alpha); } - setName(name) { - // return this.phaserText.setName(name); - } + setName = vi.fn((name: string) => { + this.name = name; + }); setAlign(align) { // return this.phaserText.setAlign(align); diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 1c7dfb27630..7a30e2787df 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -226,7 +226,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { highestIv = ivs[s]; } }); - if (shownStat) { + if (shownStat !== null && shownStat !== undefined) { shownStats.push(shownStat); statsPool.splice(statsPool.indexOf(shownStat), 1); } diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 8279ab72a70..4ade6ca5d20 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -12,6 +12,8 @@ import {Button} from "#enums/buttons"; import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; export default class FightUiHandler extends UiHandler { + public static readonly MOVES_CONTAINER_NAME = "moves"; + private movesContainer: Phaser.GameObjects.Container; private moveInfoContainer: Phaser.GameObjects.Container; private typeIcon: Phaser.GameObjects.Sprite; @@ -35,7 +37,7 @@ export default class FightUiHandler extends UiHandler { const ui = this.getUi(); this.movesContainer = this.scene.add.container(18, -38.7); - this.movesContainer.setName("moves"); + this.movesContainer.setName(FightUiHandler.MOVES_CONTAINER_NAME); ui.add(this.movesContainer); this.moveInfoContainer = this.scene.add.container(1, 0); @@ -271,11 +273,10 @@ export default class FightUiHandler extends UiHandler { return undefined; } - const moveColors = opponents.map((opponent) => { - return opponent.getMoveEffectiveness(pokemon, pokemonMove); - }).filter((eff) => !!eff).sort((a, b) => b - a).map((effectiveness) => { - return getTypeDamageMultiplierColor(effectiveness, "offense"); - }); + const moveColors = opponents + .map((opponent) => opponent.getMoveEffectiveness(pokemon, pokemonMove)) + .sort((a, b) => b - a) + .map((effectiveness) => getTypeDamageMultiplierColor(effectiveness ?? 0, "offense")); return moveColors[0]; } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 5e942f3e75a..9f2df1f2329 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2916,14 +2916,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0); const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3); const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2); + const isDefaultVariantCaught = !!(isCaught & DexAttr.DEFAULT_VARIANT); const isVariantCaught = !!(isCaught & DexAttr.SHINY); const isMaleCaught = !!(isCaught & DexAttr.MALE); const isFemaleCaught = !!(isCaught & DexAttr.FEMALE); + const starterAttributes = this.starterPreferences[species.speciesId]; + + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); + const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); + const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); + if (!dexEntry.caughtAttr) { - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); - const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); - const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); if (shiny === undefined || shiny !== props.shiny) { shiny = props.shiny; } @@ -2942,6 +2946,83 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (natureIndex === undefined || natureIndex !== defaultNature) { natureIndex = defaultNature; } + } else { + // compare current shiny, formIndex, female, variant, abilityIndex, natureIndex with the caught ones + // if the current ones are not caught, we need to find the next caught ones + if (shiny) { + if (!(isVariantCaught || isVariant2Caught || isVariant3Caught)) { + shiny = false; + starterAttributes.shiny = false; + variant = 0; + starterAttributes.variant = 0; + } else { + shiny = true; + starterAttributes.shiny = true; + if (variant === 0 && !isDefaultVariantCaught) { + if (isVariant2Caught) { + variant = 1; + starterAttributes.variant = 1; + } else if (isVariant3Caught) { + variant = 2; + starterAttributes.variant = 2; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } else if (variant === 1 && !isVariant2Caught) { + if (isVariantCaught) { + variant = 0; + starterAttributes.variant = 0; + } else if (isVariant3Caught) { + variant = 2; + starterAttributes.variant = 2; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } else if (variant === 2 && !isVariant3Caught) { + if (isVariantCaught) { + variant = 0; + starterAttributes.variant = 0; + } else if (isVariant2Caught) { + variant = 1; + starterAttributes.variant = 1; + } else { + variant = 0; + starterAttributes.variant = 0; + } + } + } + } + if (female) { + if (!isFemaleCaught) { + female = false; + starterAttributes.female = false; + } + } else { + if (!isMaleCaught) { + female = true; + starterAttributes.female = true; + } + } + + if (species.forms) { + const formCount = species.forms.length; + let newFormIndex = formIndex??0; + if (species.forms[newFormIndex]) { + const isValidForm = species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex); + if (!isValidForm) { + do { + newFormIndex = (newFormIndex + 1) % formCount; + if (species.forms[newFormIndex].isStarterSelectable && dexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) { + break; + } + } while (newFormIndex !== props.formIndex); + formIndex = newFormIndex; + starterAttributes.form = formIndex; + } + } + } } this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default? @@ -2993,12 +3074,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (dexEntry.caughtAttr && species.malePercent !== null) { - let gender: Gender; - if ((female && isFemaleCaught) || (!female && !isMaleCaught)) { - gender = Gender.FEMALE; - } else { - gender = Gender.MALE; - } + const gender = !female ? Gender.MALE : Gender.FEMALE; this.pokemonGenderText.setText(getGenderSymbol(gender)); this.pokemonGenderText.setColor(getGenderColor(gender)); this.pokemonGenderText.setShadowColor(getGenderColor(gender, true)); @@ -3479,7 +3555,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { checkIconId(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, female: boolean, formIndex: number, shiny: boolean, variant: number) { if (icon.frame.name !== species.getIconId(female, formIndex, shiny, variant)) { - console.log(`${species.name}'s variant icon does not exist. Replacing with default.`); + console.log(`${species.name}'s icon ${icon.frame.name} does not match getIconId with female: ${female}, formIndex: ${formIndex}, shiny: ${shiny}, variant: ${variant}`); icon.setTexture(species.getIconAtlasKey(formIndex, false, variant)); icon.setFrame(species.getIconId(female, formIndex, false, variant)); } diff --git a/src/utils.ts b/src/utils.ts index aa45c091286..c51ac2b5b0b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -552,3 +552,11 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole } return null; } + +/** + * Returns if an object is null or undefined + * @param object + */ +export function isNullOrUndefined(object: any): boolean { + return null === object || undefined === object; +} From ae2ab120dce57cc2ff065f3c756a4a3696a3e909 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Mon, 19 Aug 2024 03:23:52 +0100 Subject: [PATCH 29/63] Deleted phases.ts (#3618) --- src/battle-scene.ts | 18 +- src/data/ability.ts | 5 +- src/data/arena-tag.ts | 5 +- src/data/battler-tags.ts | 7 +- src/data/berry.ts | 3 +- src/data/move.ts | 10 +- src/field/arena.ts | 2 +- src/field/pokemon.ts | 10 +- src/modifier/modifier.ts | 6 +- src/phases.ts | 5861 ----------------- src/phases/add-enemy-buff-modifier-phase.ts | 26 + src/phases/attempt-capture-phase.ts | 288 + src/phases/attempt-run-phase.ts | 56 + src/phases/battle-end-phase.ts | 55 + src/phases/battle-phase.ts | 47 + src/phases/berry-phase.ts | 52 + src/phases/check-switch-phase.ts | 61 + src/phases/command-phase.ts | 288 + src/phases/common-anim-phase.ts | 26 + src/phases/damage-phase.ts | 84 + src/{ => phases}/egg-hatch-phase.ts | 27 +- src/phases/egg-lapse-phase.ts | 35 + src/phases/encounter-phase.ts | 379 ++ src/phases/end-card-phase.ts | 40 + src/phases/end-evolution-phase.ts | 16 + src/phases/enemy-command-phase.ts | 86 + .../enemy-party-member-pokemon-phase.ts | 13 + src/{ => phases}/evolution-phase.ts | 36 +- src/phases/exp-phase.ts | 35 + src/phases/faint-phase.ts | 171 + src/phases/field-phase.ts | 44 + src/{ => phases}/form-change-phase.ts | 148 +- src/phases/game-over-modifier-reward-phase.ts | 27 + src/phases/game-over-phase.ts | 203 + src/phases/hide-party-exp-bar-phase.ts | 14 + src/phases/learn-move-phase.ts | 103 + src/phases/level-cap-phase.ts | 20 + src/phases/level-up-phase.ts | 59 + src/phases/login-phase.ts | 116 + src/phases/message-phase.ts | 38 + src/phases/modifier-reward-phase.ts | 30 + src/phases/money-reward-phase.ts | 34 + src/phases/move-anim-test-phase.ts | 44 + src/phases/move-effect-phase.ts | 447 ++ src/phases/move-end-phase.ts | 23 + src/phases/move-header-phase.ts | 30 + src/phases/move-phase.ts | 329 + src/phases/new-battle-phase.ts | 11 + src/phases/new-biome-encounter-phase.ts | 38 + src/phases/next-encounter-phase.ts | 46 + src/phases/obtain-status-effect-phase.ts | 48 + src/phases/outdated-phase.ts | 13 + src/phases/party-heal-phase.ts | 40 + src/phases/party-member-pokemon-phase.ts | 27 + src/phases/party-status-cure-phase.ts | 48 + .../player-party-member-pokemon-phase.ts | 13 + src/phases/pokemon-heal-phase.ts | 104 + src/phases/pokemon-phase.ts | 29 + src/phases/post-game-over-phase.ts | 46 + src/phases/post-summon-phase.ts | 24 + src/phases/post-turn-status-effect-phase.ts | 61 + src/phases/quiet-form-change-phase.ts | 133 + src/phases/reload-session-phase.ts | 39 + src/phases/return-phase.ts | 26 + src/phases/ribbon-modifier-reward-phase.ts | 33 + src/phases/scan-ivs-phase.ts | 69 + src/phases/select-biome-phase.ts | 84 + src/phases/select-challenge-phase.ts | 17 + src/phases/select-gender-phase.ts | 46 + src/phases/select-modifier-phase.ts | 234 + src/phases/select-starter-phase.ts | 112 + src/phases/select-target-phase.ts | 32 + src/phases/shiny-sparkle-phase.ts | 16 + src/phases/show-ability-phase.ts | 29 + src/phases/show-party-exp-bar-phase.ts | 56 + src/phases/show-trainer-phase.ts | 24 + src/phases/stat-change-phase.ts | 234 + src/phases/summon-missing-phase.ts | 15 + src/phases/summon-phase.ts | 194 + src/phases/switch-biome-phase.ts | 65 + src/phases/switch-phase.ts | 65 + src/phases/switch-summon-phase.ts | 168 + src/phases/test-message-phase.ts | 8 + src/phases/title-phase.ts | 303 + src/phases/toggle-double-position-phase.ts | 31 + src/phases/trainer-message-test-phase.ts | 41 + src/phases/trainer-victory-phase.ts | 65 + src/phases/turn-end-phase.ts | 71 + src/phases/turn-init-phase.ts | 65 + src/phases/turn-start-phase.ts | 172 + src/phases/unavailable-phase.ts | 17 + src/phases/unlock-phase.ts | 27 + src/phases/victory-phase.ts | 151 + src/phases/weather-effect-phase.ts | 67 + src/system/game-data.ts | 3 +- src/system/settings/settings.ts | 10 +- src/system/voucher.ts | 67 +- src/test/abilities/ability_timing.test.ts | 4 +- src/test/abilities/aura_break.test.ts | 2 +- src/test/abilities/battery.test.ts | 3 +- src/test/abilities/battle_bond.test.ts | 4 +- src/test/abilities/costar.test.ts | 3 +- src/test/abilities/disguise.test.ts | 6 +- src/test/abilities/dry_skin.test.ts | 2 +- src/test/abilities/flash_fire.test.ts | 3 +- src/test/abilities/gulp_missile.test.ts | 10 +- src/test/abilities/heatproof.test.ts | 2 +- src/test/abilities/hustle.test.ts | 3 +- src/test/abilities/ice_face.test.ts | 7 +- src/test/abilities/intimidate.test.ts | 7 +- src/test/abilities/intrepid_sword.test.ts | 2 +- src/test/abilities/libero.test.ts | 2 +- src/test/abilities/magic_guard.test.ts | 2 +- src/test/abilities/moxie.test.ts | 4 +- src/test/abilities/mycelium_might.test.ts | 3 +- src/test/abilities/parental_bond.test.ts | 7 +- src/test/abilities/pastel_veil.test.ts | 3 +- src/test/abilities/power_construct.test.ts | 4 +- src/test/abilities/power_spot.test.ts | 3 +- src/test/abilities/protean.test.ts | 2 +- src/test/abilities/quick_draw.test.ts | 2 +- src/test/abilities/sand_veil.test.ts | 4 +- src/test/abilities/sap_sipper.test.ts | 3 +- src/test/abilities/schooling.test.ts | 4 +- src/test/abilities/screen_cleaner.test.ts | 3 +- src/test/abilities/serene_grace.test.ts | 3 +- src/test/abilities/sheer_force.test.ts | 3 +- src/test/abilities/shield_dust.test.ts | 3 +- src/test/abilities/shields_down.test.ts | 4 +- src/test/abilities/stall.test.ts | 2 +- src/test/abilities/steely_spirit.test.ts | 3 +- src/test/abilities/sturdy.test.ts | 3 +- src/test/abilities/sweet_veil.test.ts | 4 +- src/test/abilities/unseen_fist.test.ts | 2 +- src/test/abilities/volt_absorb.test.ts | 2 +- src/test/abilities/wind_power.test.ts | 2 +- src/test/abilities/wind_rider.test.ts | 2 +- src/test/abilities/wonder_skin.test.ts | 2 +- src/test/abilities/zen_mode.test.ts | 13 +- src/test/abilities/zero_to_hero.test.ts | 4 +- src/test/arena/arena_gravity.test.ts | 3 +- src/test/arena/weather_fog.test.ts | 2 +- src/test/arena/weather_strong_winds.test.ts | 2 +- src/test/battle/battle-order.test.ts | 5 +- src/test/battle/battle.test.ts | 30 +- src/test/battle/double_battle.test.ts | 3 +- src/test/battle/special_battle.test.ts | 2 +- src/test/battlerTags/octolock.test.ts | 2 +- src/test/battlerTags/stockpiling.test.ts | 2 +- src/test/items/grip_claw.test.ts | 4 +- src/test/items/leek.test.ts | 2 +- src/test/items/leftovers.test.ts | 3 +- src/test/items/lock_capsule.test.ts | 2 +- src/test/items/scope_lens.test.ts | 2 +- src/test/items/toxic_orb.test.ts | 5 +- src/test/moves/astonish.test.ts | 5 +- src/test/moves/aurora_veil.test.ts | 2 +- src/test/moves/baton_pass.test.ts | 3 +- src/test/moves/beak_blast.test.ts | 4 +- src/test/moves/beat_up.test.ts | 2 +- src/test/moves/belly_drum.test.ts | 2 +- src/test/moves/ceaseless_edge.test.ts | 3 +- src/test/moves/clangorous_soul.test.ts | 2 +- src/test/moves/crafty_shield.test.ts | 3 +- src/test/moves/double_team.test.ts | 2 +- src/test/moves/dragon_rage.test.ts | 2 +- src/test/moves/dragon_tail.test.ts | 4 +- src/test/moves/dynamax_cannon.test.ts | 4 +- src/test/moves/fillet_away.test.ts | 2 +- src/test/moves/fissure.test.ts | 3 +- src/test/moves/flame_burst.test.ts | 3 +- src/test/moves/flower_shield.test.ts | 2 +- src/test/moves/focus_punch.test.ts | 6 +- src/test/moves/follow_me.test.ts | 4 +- src/test/moves/foresight.test.ts | 2 +- src/test/moves/freezy_frost.test.ts | 3 +- src/test/moves/fusion_flare.test.ts | 2 +- src/test/moves/fusion_flare_bolt.test.ts | 5 +- src/test/moves/glaive_rush.test.ts | 3 +- src/test/moves/growth.test.ts | 4 +- src/test/moves/hard_press.test.ts | 2 +- src/test/moves/haze.test.ts | 3 +- src/test/moves/hyper_beam.test.ts | 3 +- src/test/moves/light_screen.test.ts | 2 +- src/test/moves/lucky_chant.test.ts | 3 +- src/test/moves/magnet_rise.test.ts | 3 +- src/test/moves/make_it_rain.test.ts | 3 +- src/test/moves/mat_block.test.ts | 4 +- src/test/moves/miracle_eye.test.ts | 2 +- src/test/moves/multi_target.test.ts | 2 +- src/test/moves/octolock.test.ts | 4 +- src/test/moves/parting_shot.test.ts | 5 +- src/test/moves/protect.test.ts | 2 +- src/test/moves/purify.test.ts | 2 +- src/test/moves/quick_guard.test.ts | 3 +- src/test/moves/rage_powder.test.ts | 4 +- src/test/moves/reflect.test.ts | 2 +- src/test/moves/rollout.test.ts | 2 +- src/test/moves/roost.test.ts | 3 +- src/test/moves/shell_trap.test.ts | 4 +- src/test/moves/spikes.test.ts | 2 +- src/test/moves/spit_up.test.ts | 3 +- src/test/moves/spotlight.test.ts | 4 +- src/test/moves/stockpile.test.ts | 3 +- src/test/moves/swallow.test.ts | 3 +- src/test/moves/tackle.test.ts | 4 +- src/test/moves/tail_whip.test.ts | 4 +- src/test/moves/tailwind.test.ts | 2 +- src/test/moves/thousand_arrows.test.ts | 3 +- src/test/moves/tidy_up.test.ts | 3 +- src/test/moves/u_turn.test.ts | 3 +- src/test/moves/wide_guard.test.ts | 3 +- src/test/phases/phases.test.ts | 4 +- src/test/ui/starter-select.test.ts | 4 +- src/test/ui/transfer-item.test.ts | 3 +- src/test/ui/type-hints.test.ts | 2 +- src/test/utils/gameManager.ts | 13 +- src/test/utils/helpers/classicModeHelper.ts | 3 +- src/test/utils/helpers/dailyModeHelper.ts | 3 +- src/test/utils/helpers/moveHelper.ts | 2 +- src/test/utils/phaseInterceptor.ts | 74 +- src/ui/ball-ui-handler.ts | 2 +- src/ui/challenges-select-ui-handler.ts | 3 +- src/ui/command-ui-handler.ts | 2 +- src/ui/egg-hatch-scene-handler.ts | 2 +- src/ui/fight-ui-handler.ts | 2 +- src/ui/party-ui-handler.ts | 3 +- src/ui/starter-select-ui-handler.ts | 3 +- 228 files changed, 7037 insertions(+), 6279 deletions(-) delete mode 100644 src/phases.ts create mode 100644 src/phases/add-enemy-buff-modifier-phase.ts create mode 100644 src/phases/attempt-capture-phase.ts create mode 100644 src/phases/attempt-run-phase.ts create mode 100644 src/phases/battle-end-phase.ts create mode 100644 src/phases/battle-phase.ts create mode 100644 src/phases/berry-phase.ts create mode 100644 src/phases/check-switch-phase.ts create mode 100644 src/phases/command-phase.ts create mode 100644 src/phases/common-anim-phase.ts create mode 100644 src/phases/damage-phase.ts rename src/{ => phases}/egg-hatch-phase.ts (95%) create mode 100644 src/phases/egg-lapse-phase.ts create mode 100644 src/phases/encounter-phase.ts create mode 100644 src/phases/end-card-phase.ts create mode 100644 src/phases/end-evolution-phase.ts create mode 100644 src/phases/enemy-command-phase.ts create mode 100644 src/phases/enemy-party-member-pokemon-phase.ts rename src/{ => phases}/evolution-phase.ts (96%) create mode 100644 src/phases/exp-phase.ts create mode 100644 src/phases/faint-phase.ts create mode 100644 src/phases/field-phase.ts rename src/{ => phases}/form-change-phase.ts (57%) create mode 100644 src/phases/game-over-modifier-reward-phase.ts create mode 100644 src/phases/game-over-phase.ts create mode 100644 src/phases/hide-party-exp-bar-phase.ts create mode 100644 src/phases/learn-move-phase.ts create mode 100644 src/phases/level-cap-phase.ts create mode 100644 src/phases/level-up-phase.ts create mode 100644 src/phases/login-phase.ts create mode 100644 src/phases/message-phase.ts create mode 100644 src/phases/modifier-reward-phase.ts create mode 100644 src/phases/money-reward-phase.ts create mode 100644 src/phases/move-anim-test-phase.ts create mode 100644 src/phases/move-effect-phase.ts create mode 100644 src/phases/move-end-phase.ts create mode 100644 src/phases/move-header-phase.ts create mode 100644 src/phases/move-phase.ts create mode 100644 src/phases/new-battle-phase.ts create mode 100644 src/phases/new-biome-encounter-phase.ts create mode 100644 src/phases/next-encounter-phase.ts create mode 100644 src/phases/obtain-status-effect-phase.ts create mode 100644 src/phases/outdated-phase.ts create mode 100644 src/phases/party-heal-phase.ts create mode 100644 src/phases/party-member-pokemon-phase.ts create mode 100644 src/phases/party-status-cure-phase.ts create mode 100644 src/phases/player-party-member-pokemon-phase.ts create mode 100644 src/phases/pokemon-heal-phase.ts create mode 100644 src/phases/pokemon-phase.ts create mode 100644 src/phases/post-game-over-phase.ts create mode 100644 src/phases/post-summon-phase.ts create mode 100644 src/phases/post-turn-status-effect-phase.ts create mode 100644 src/phases/quiet-form-change-phase.ts create mode 100644 src/phases/reload-session-phase.ts create mode 100644 src/phases/return-phase.ts create mode 100644 src/phases/ribbon-modifier-reward-phase.ts create mode 100644 src/phases/scan-ivs-phase.ts create mode 100644 src/phases/select-biome-phase.ts create mode 100644 src/phases/select-challenge-phase.ts create mode 100644 src/phases/select-gender-phase.ts create mode 100644 src/phases/select-modifier-phase.ts create mode 100644 src/phases/select-starter-phase.ts create mode 100644 src/phases/select-target-phase.ts create mode 100644 src/phases/shiny-sparkle-phase.ts create mode 100644 src/phases/show-ability-phase.ts create mode 100644 src/phases/show-party-exp-bar-phase.ts create mode 100644 src/phases/show-trainer-phase.ts create mode 100644 src/phases/stat-change-phase.ts create mode 100644 src/phases/summon-missing-phase.ts create mode 100644 src/phases/summon-phase.ts create mode 100644 src/phases/switch-biome-phase.ts create mode 100644 src/phases/switch-phase.ts create mode 100644 src/phases/switch-summon-phase.ts create mode 100644 src/phases/test-message-phase.ts create mode 100644 src/phases/title-phase.ts create mode 100644 src/phases/toggle-double-position-phase.ts create mode 100644 src/phases/trainer-message-test-phase.ts create mode 100644 src/phases/trainer-victory-phase.ts create mode 100644 src/phases/turn-end-phase.ts create mode 100644 src/phases/turn-init-phase.ts create mode 100644 src/phases/turn-start-phase.ts create mode 100644 src/phases/unavailable-phase.ts create mode 100644 src/phases/unlock-phase.ts create mode 100644 src/phases/victory-phase.ts create mode 100644 src/phases/weather-effect-phase.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 4faf3863e3c..b72e79c866d 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,6 +1,5 @@ import Phaser from "phaser"; import UI from "./ui/ui"; -import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase, SummonPhase, ToggleDoublePositionPhase } from "./phases"; import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon"; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species"; import { Constructor } from "#app/utils"; @@ -38,7 +37,7 @@ import { addUiThemeOverrides } from "./ui/ui-theme"; import PokemonData from "./system/pokemon-data"; import { Nature } from "./data/nature"; import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem, SpeciesFormChange } from "./data/pokemon-forms"; -import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase"; +import { FormChangePhase } from "./phases/form-change-phase"; import { getTypeRgb } from "./data/type"; import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler"; import CharSprite from "./ui/char-sprite"; @@ -69,6 +68,21 @@ import i18next from "i18next"; import {TrainerType} from "#enums/trainer-type"; import { battleSpecDialogue } from "./data/dialogue"; import { LoadingScene } from "./loading-scene"; +import { LevelCapPhase } from "./phases/level-cap-phase"; +import { LoginPhase } from "./phases/login-phase"; +import { MessagePhase } from "./phases/message-phase"; +import { MovePhase } from "./phases/move-phase"; +import { NewBiomeEncounterPhase } from "./phases/new-biome-encounter-phase"; +import { NextEncounterPhase } from "./phases/next-encounter-phase"; +import { QuietFormChangePhase } from "./phases/quiet-form-change-phase"; +import { ReturnPhase } from "./phases/return-phase"; +import { SelectBiomePhase } from "./phases/select-biome-phase"; +import { ShowTrainerPhase } from "./phases/show-trainer-phase"; +import { SummonPhase } from "./phases/summon-phase"; +import { SwitchPhase } from "./phases/switch-phase"; +import { TitlePhase } from "./phases/title-phase"; +import { ToggleDoublePositionPhase } from "./phases/toggle-double-position-phase"; +import { TurnInitPhase } from "./phases/turn-init-phase"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; diff --git a/src/data/ability.ts b/src/data/ability.ts index 38ca4eb25d0..8e020849a17 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3,7 +3,6 @@ import { Type } from "./type"; import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import { BattleStat, getBattleStatName } from "./battle-stat"; -import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases"; import { getPokemonNameWithAffix } from "../messages"; import { Weather, WeatherType } from "./weather"; import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags"; @@ -26,6 +25,10 @@ import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; +import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; export class Ability implements Localizable { public id: Abilities; diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index fdfcd4d076a..3394df827fb 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -4,7 +4,6 @@ import * as Utils from "../utils"; import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "./move"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { HitResult, PokemonMove } from "../field/pokemon"; -import { MoveEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases"; import { StatusEffect } from "./status-effect"; import { BattlerIndex } from "../battle"; import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability"; @@ -15,6 +14,10 @@ import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; +import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; export enum ArenaTagSide { BOTH, diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index b059b4cf6b2..ede8d029327 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,5 +1,4 @@ import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims"; -import { CommonAnimPhase, MoveEffectPhase, MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangeCallback, StatChangePhase } from "../phases"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; import { Stat, getStatName } from "./pokemon-stat"; @@ -18,6 +17,12 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import i18next from "#app/plugins/i18n.js"; +import { CommonAnimPhase } from "#app/phases/common-anim-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; +import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; +import { StatChangePhase, StatChangeCallback } from "#app/phases/stat-change-phase.js"; export enum BattlerTagLapseType { FAINT, diff --git a/src/data/berry.ts b/src/data/berry.ts index 30b89848452..e962219ca46 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -1,4 +1,3 @@ -import { PokemonHealPhase, StatChangePhase } from "../phases"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { HitResult } from "../field/pokemon"; import { BattleStat } from "./battle-stat"; @@ -8,6 +7,8 @@ import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } import i18next from "i18next"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; export function getBerryName(berryType: BerryType): string { return i18next.t(`berry:${BerryType[berryType]}.name`); diff --git a/src/data/move.ts b/src/data/move.ts index 24651bacb2e..af3f49bea0d 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1,5 +1,4 @@ import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims"; -import { BattleEndPhase, MoveEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchPhase, SwitchSummonPhase } from "../phases"; import { BattleStat, getBattleStatName } from "./battle-stat"; import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, TrappedTag, TypeBoostTag } from "./battler-tags"; import { getPokemonNameWithAffix } from "../messages"; @@ -28,6 +27,15 @@ import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { MoveUsedEvent } from "#app/events/battle-scene.js"; +import { PartyStatusCurePhase } from "#app/phases/party-status-cure-phase.js"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { NewBattlePhase } from "#app/phases/new-battle-phase.js"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; +import { SwitchPhase } from "#app/phases/switch-phase.js"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; export enum MoveCategory { PHYSICAL, diff --git a/src/field/arena.ts b/src/field/arena.ts index 923a0a4e286..eb3770d61d5 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -4,7 +4,6 @@ import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species"; import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather"; -import { CommonAnimPhase } from "../phases"; import { CommonAnim } from "../data/battle-anims"; import { Type } from "../data/type"; import Move from "../data/move"; @@ -21,6 +20,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { TimeOfDay } from "#enums/time-of-day"; import { TrainerType } from "#enums/trainer-type"; +import { CommonAnimPhase } from "#app/phases/common-anim-phase.js"; export class Arena { public scene: BattleScene; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index e38813ed3c0..6a445a83b4e 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -17,7 +17,6 @@ import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims"; import { Status, StatusEffect, getRandomStatus } from "../data/status-effect"; import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions"; import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms"; -import { DamagePhase, FaintPhase, LearnMovePhase, MoveEffectPhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase, MoveEndPhase } from "../phases"; import { BattleStat } from "../data/battle-stat"; import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag } from "../data/battler-tags"; import { WeatherType } from "../data/weather"; @@ -51,6 +50,15 @@ import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { FaintPhase } from "#app/phases/faint-phase.js"; +import { LearnMovePhase } from "#app/phases/learn-move-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; +import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase.js"; export enum FieldPosition { CENTER, diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index f4ec6c499f4..8a6598f5849 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1,5 +1,4 @@ import * as ModifierTypes from "./modifier-type"; -import { LearnMovePhase, LevelUpPhase, PokemonHealPhase } from "../phases"; import BattleScene from "../battle-scene"; import { getLevelTotalExp } from "../data/exp"; import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball"; @@ -7,7 +6,7 @@ import Pokemon, { PlayerPokemon } from "../field/pokemon"; import { Stat } from "../data/pokemon-stat"; import { addTextObject, TextStyle } from "../ui/text"; import { Type } from "../data/type"; -import { EvolutionPhase } from "../evolution-phase"; +import { EvolutionPhase } from "../phases/evolution-phase"; import { FusionSpeciesFormEvolution, pokemonEvolutions, pokemonPrevolutions } from "../data/pokemon-evolutions"; import { getPokemonNameWithAffix } from "../messages"; import * as Utils from "../utils"; @@ -28,6 +27,9 @@ import i18next from "i18next"; import { allMoves } from "#app/data/move"; import { Abilities } from "#app/enums/abilities"; +import { LearnMovePhase } from "#app/phases/learn-move-phase.js"; +import { LevelUpPhase } from "#app/phases/level-up-phase.js"; +import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; export type ModifierPredicate = (modifier: Modifier) => boolean; diff --git a/src/phases.ts b/src/phases.ts deleted file mode 100644 index c50d25acf60..00000000000 --- a/src/phases.ts +++ /dev/null @@ -1,5861 +0,0 @@ -import BattleScene, { bypassLogin } from "./battle-scene"; -import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon"; -import * as Utils from "./utils"; -import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr, MoveHeaderAttr, MoveCategory } from "./data/move"; -import { Mode } from "./ui/ui"; -import { Command } from "./ui/command-ui-handler"; -import { Stat } from "./data/pokemon-stat"; -import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier, PokemonResetNegativeStatStageModifier } from "./modifier/modifier"; -import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler"; -import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball"; -import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims"; -import { StatusEffect, getStatusEffectActivationText, getStatusEffectCatchRateMultiplier, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText } from "./data/status-effect"; -import { SummaryUiMode } from "./ui/summary-ui-handler"; -import EvolutionSceneHandler from "./ui/evolution-scene-handler"; -import { EvolutionPhase } from "./evolution-phase"; -import { Phase } from "./phase"; -import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat"; -import { biomeLinks, getBiomeName } from "./data/biomes"; -import { ModifierTier } from "./modifier/modifier-tier"; -import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; -import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import { BattlerTagLapseType, CenterOfAttentionTag, EncoreTag, ProtectedTag, SemiInvulnerableTag, TrappedTag } from "./data/battler-tags"; -import { getPokemonNameWithAffix } from "./messages"; -import { Starter } from "./ui/starter-select-ui-handler"; -import { Gender } from "./data/gender"; -import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather"; -import { ArenaTagSide, ArenaTrapTag, ConditionalProtectTag, MistTag, TrickRoomTag } from "./data/arena-tag"; -import { CheckTrappedAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, ChangeMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, PreventBypassSpeedChanceAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, PokemonTypeChangeAbAttr, applyPreAttackAbAttrs, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr, IgnoreMoveEffectsAbAttr, BlockStatusDamageAbAttr, BypassSpeedChanceAbAttr, AddSecondStrikeAbAttr, ReduceBurnDamageAbAttr } from "./data/ability"; -import { Unlockables, getUnlockableName } from "./system/unlockables"; -import { getBiomeKey } from "./field/arena"; -import { BattleType, BattlerIndex, TurnCommand } from "./battle"; -import { ChallengeAchv, HealAchv, LevelAchv, achvs } from "./system/achv"; -import { TrainerSlot, trainerConfigs } from "./data/trainer-config"; -import { EggHatchPhase } from "./egg-hatch-phase"; -import { Egg } from "./data/egg"; -import { vouchers } from "./system/voucher"; -import { clientSessionId, loggedInUser, updateUserInfo } from "./account"; -import { SessionSaveData } from "./system/game-data"; -import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims"; -import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms"; -import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue"; -import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler"; -import { SettingKeys } from "./system/settings/settings"; -import { Tutorial, handleTutorial } from "./tutorial"; -import { TerrainType } from "./data/terrain"; -import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select-ui-handler"; -import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler"; -import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run"; -import { GameMode, GameModes, getGameMode } from "./game-mode"; -import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; -import i18next from "./plugins/i18n"; -import Overrides from "#app/overrides"; -import { TextStyle, addTextObject, getTextColor } from "./ui/text"; -import { Type } from "./data/type"; -import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene"; -import { Abilities } from "#enums/abilities"; -import { ArenaTagType } from "#enums/arena-tag-type"; -import { BattleSpec } from "#enums/battle-spec"; -import { BattleStyle } from "#enums/battle-style"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { Biome } from "#enums/biome"; -import { ExpNotification } from "#enums/exp-notification"; -import { Moves } from "#enums/moves"; -import { PlayerGender } from "#enums/player-gender"; -import { Species } from "#enums/species"; -import { TrainerType } from "#enums/trainer-type"; -import { applyChallenges, ChallengeType } from "./data/challenge"; -import { pokemonEvolutions } from "./data/pokemon-evolutions"; - -const { t } = i18next; - -export class LoginPhase extends Phase { - private showText: boolean; - - constructor(scene: BattleScene, showText?: boolean) { - super(scene); - - this.showText = showText === undefined || !!showText; - } - - start(): void { - super.start(); - - const hasSession = !!Utils.getCookie(Utils.sessionIdKey); - - this.scene.ui.setMode(Mode.LOADING, { buttonActions: [] }); - Utils.executeIf(bypassLogin || hasSession, updateUserInfo).then(response => { - const success = response ? response[0] : false; - const statusCode = response ? response[1] : null; - if (!success) { - if (!statusCode || statusCode === 400) { - if (this.showText) { - this.scene.ui.showText(i18next.t("menu:logInOrCreateAccount")); - } - - this.scene.playSound("menu_open"); - - const loadData = () => { - updateUserInfo().then(success => { - if (!success[0]) { - Utils.removeCookie(Utils.sessionIdKey); - this.scene.reset(true, true); - return; - } - this.scene.gameData.loadSystem().then(() => this.end()); - }); - }; - - this.scene.ui.setMode(Mode.LOGIN_FORM, { - buttonActions: [ - () => { - this.scene.ui.playSelect(); - loadData(); - }, () => { - this.scene.playSound("menu_open"); - this.scene.ui.setMode(Mode.REGISTRATION_FORM, { - buttonActions: [ - () => { - this.scene.ui.playSelect(); - updateUserInfo().then(success => { - if (!success[0]) { - Utils.removeCookie(Utils.sessionIdKey); - this.scene.reset(true, true); - return; - } - this.end(); - } ); - }, () => { - this.scene.unshiftPhase(new LoginPhase(this.scene, false)); - this.end(); - } - ] - }); - }, () => { - const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); - const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID; - const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&prompt=none`; - window.open(discordUrl, "_self"); - }, () => { - const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`); - const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID; - const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&redirect_uri=${redirectUri}&response_type=code&scope=openid`; - window.open(googleUrl, "_self"); - } - ] - }); - } else if (statusCode === 401) { - Utils.removeCookie(Utils.sessionIdKey); - this.scene.reset(true, true); - } else { - this.scene.unshiftPhase(new UnavailablePhase(this.scene)); - super.end(); - } - return null; - } else { - this.scene.gameData.loadSystem().then(success => { - if (success || bypassLogin) { - this.end(); - } else { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(t("menu:failedToLoadSaveData")); - } - }); - } - }); - } - - end(): void { - this.scene.ui.setMode(Mode.MESSAGE); - - if (!this.scene.gameData.gender) { - this.scene.unshiftPhase(new SelectGenderPhase(this.scene)); - } - - handleTutorial(this.scene, Tutorial.Intro).then(() => super.end()); - } -} - -export class TitlePhase extends Phase { - private loaded: boolean; - private lastSessionData: SessionSaveData; - public gameMode: GameModes; - - constructor(scene: BattleScene) { - super(scene); - - this.loaded = false; - } - - start(): void { - super.start(); - - this.scene.ui.clearText(); - this.scene.ui.fadeIn(250); - - this.scene.playBgm("title", true); - - this.scene.gameData.getSession(loggedInUser?.lastSessionSlot ?? -1).then(sessionData => { - if (sessionData) { - this.lastSessionData = sessionData; - const biomeKey = getBiomeKey(sessionData.arena.biome); - const bgTexture = `${biomeKey}_bg`; - this.scene.arenaBg.setTexture(bgTexture); - } - this.showOptions(); - }).catch(err => { - console.error(err); - this.showOptions(); - }); - } - - showOptions(): void { - const options: OptionSelectItem[] = []; - if (loggedInUser && loggedInUser.lastSessionSlot > -1) { - options.push({ - label: i18next.t("continue", {ns: "menu"}), - handler: () => { - this.loadSaveSlot(this.lastSessionData || !loggedInUser ? -1 : loggedInUser.lastSessionSlot); - return true; - } - }); - } - options.push({ - label: i18next.t("menu:newGame"), - handler: () => { - const setModeAndEnd = (gameMode: GameModes) => { - this.gameMode = gameMode; - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - this.end(); - }; - if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { - const options: OptionSelectItem[] = [ - { - label: GameMode.getModeName(GameModes.CLASSIC), - handler: () => { - setModeAndEnd(GameModes.CLASSIC); - return true; - } - }, - { - label: GameMode.getModeName(GameModes.CHALLENGE), - handler: () => { - setModeAndEnd(GameModes.CHALLENGE); - return true; - } - }, - { - label: GameMode.getModeName(GameModes.ENDLESS), - handler: () => { - setModeAndEnd(GameModes.ENDLESS); - return true; - } - } - ]; - if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { - options.push({ - label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), - handler: () => { - setModeAndEnd(GameModes.SPLICED_ENDLESS); - return true; - } - }); - } - options.push({ - label: i18next.t("menu:cancel"), - handler: () => { - this.scene.clearPhaseQueue(); - this.scene.pushPhase(new TitlePhase(this.scene)); - super.end(); - return true; - } - }); - this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options })); - } else { - this.gameMode = GameModes.CLASSIC; - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - this.end(); - } - return true; - } - }, - { - label: i18next.t("menu:loadGame"), - handler: () => { - this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD, - (slotId: integer) => { - if (slotId === -1) { - return this.showOptions(); - } - this.loadSaveSlot(slotId); - }); - return true; - } - }, - { - label: i18next.t("menu:dailyRun"), - handler: () => { - this.initDailyRun(); - return true; - }, - keepOpen: true - }, - { - label: i18next.t("menu:settings"), - handler: () => { - this.scene.ui.setOverlayMode(Mode.SETTINGS); - return true; - }, - keepOpen: true - }); - const config: OptionSelectConfig = { - options: options, - noCancel: true, - yOffset: 47 - }; - this.scene.ui.setMode(Mode.TITLE, config); - } - - loadSaveSlot(slotId: integer): void { - this.scene.sessionSlotId = slotId > -1 || !loggedInUser ? slotId : loggedInUser.lastSessionSlot; - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.resetModeChain(); - this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : undefined).then((success: boolean) => { - if (success) { - this.loaded = true; - this.scene.ui.showText(i18next.t("menu:sessionSuccess"), null, () => this.end()); - } else { - this.end(); - } - }).catch(err => { - console.error(err); - this.scene.ui.showText(i18next.t("menu:failedToLoadSession"), null); - }); - } - - initDailyRun(): void { - this.scene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: integer) => { - this.scene.clearPhaseQueue(); - if (slotId === -1) { - this.scene.pushPhase(new TitlePhase(this.scene)); - return super.end(); - } - this.scene.sessionSlotId = slotId; - - const generateDaily = (seed: string) => { - this.scene.gameMode = getGameMode(GameModes.DAILY); - - this.scene.setSeed(seed); - this.scene.resetSeed(1); - - this.scene.money = this.scene.gameMode.getStartingMoney(); - - const starters = getDailyRunStarters(this.scene, seed); - const startingLevel = this.scene.gameMode.getStartingLevel(); - - const party = this.scene.getParty(); - const loadPokemonAssets: Promise[] = []; - for (const starter of starters) { - const starterProps = this.scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr); - const starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); - const starterGender = starter.species.malePercent !== null - ? !starterProps.female ? Gender.MALE : Gender.FEMALE - : Gender.GENDERLESS; - const starterPokemon = this.scene.addPlayerPokemon(starter.species, startingLevel, starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, undefined, starter.nature); - starterPokemon.setVisible(false); - party.push(starterPokemon); - loadPokemonAssets.push(starterPokemon.loadAssets()); - } - - regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER); - const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier()) - .concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier())) - .concat(getDailyRunStarterModifiers(party)) - .filter((m) => m !== null); - - for (const m of modifiers) { - this.scene.addModifier(m, true, false, false, true); - } - this.scene.updateModifiers(true, true); - - Promise.all(loadPokemonAssets).then(() => { - this.scene.time.delayedCall(500, () => this.scene.playBgm()); - this.scene.gameData.gameStats.dailyRunSessionsPlayed++; - this.scene.newArena(this.scene.gameMode.getStartingBiome(this.scene)); - this.scene.newBattle(); - this.scene.arena.init(); - this.scene.sessionPlayTime = 0; - this.scene.lastSavePlayTime = 0; - this.end(); - }); - }; - - // If Online, calls seed fetch from db to generate daily run. If Offline, generates a daily run based on current date. - if (!Utils.isLocal) { - fetchDailyRunSeed().then(seed => { - if (seed) { - generateDaily(seed); - } else { - throw new Error("Daily run seed is null!"); - } - }).catch(err => { - console.error("Failed to load daily run:\n", err); - }); - } else { - generateDaily(btoa(new Date().toISOString().substring(0, 10))); - } - }); - } - - end(): void { - if (!this.loaded && !this.scene.gameMode.isDaily) { - this.scene.arena.preloadBgm(); - this.scene.gameMode = getGameMode(this.gameMode); - if (this.gameMode === GameModes.CHALLENGE) { - this.scene.pushPhase(new SelectChallengePhase(this.scene)); - } else { - this.scene.pushPhase(new SelectStarterPhase(this.scene)); - } - this.scene.newArena(this.scene.gameMode.getStartingBiome(this.scene)); - } else { - this.scene.playBgm(); - } - - this.scene.pushPhase(new EncounterPhase(this.scene, this.loaded)); - - if (this.loaded) { - const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; - - this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true)); - if (this.scene.currentBattle.double && availablePartyMembers > 1) { - this.scene.pushPhase(new SummonPhase(this.scene, 1, true, true)); - } - - if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) { - const minPartySize = this.scene.currentBattle.double ? 2 : 1; - if (availablePartyMembers > minPartySize) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); - if (this.scene.currentBattle.double) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); - } - } - } - } - - for (const achv of Object.keys(this.scene.gameData.achvUnlocks)) { - if (vouchers.hasOwnProperty(achv)) { - this.scene.validateVoucher(vouchers[achv]); - } - } - - super.end(); - } -} - -export class UnavailablePhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start(): void { - this.scene.ui.setMode(Mode.UNAVAILABLE, () => { - this.scene.unshiftPhase(new LoginPhase(this.scene, true)); - this.end(); - }); - } -} - -export class ReloadSessionPhase extends Phase { - private systemDataStr: string | null; - - constructor(scene: BattleScene, systemDataStr?: string) { - super(scene); - - this.systemDataStr = systemDataStr ?? null; - } - - start(): void { - this.scene.ui.setMode(Mode.SESSION_RELOAD); - - let delayElapsed = false; - let loaded = false; - - this.scene.time.delayedCall(Utils.fixedInt(1500), () => { - if (loaded) { - this.end(); - } else { - delayElapsed = true; - } - }); - - this.scene.gameData.clearLocalData(); - - (this.systemDataStr ? this.scene.gameData.initSystem(this.systemDataStr) : this.scene.gameData.loadSystem()).then(() => { - if (delayElapsed) { - this.end(); - } else { - loaded = true; - } - }); - } -} - -export class OutdatedPhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start(): void { - this.scene.ui.setMode(Mode.OUTDATED); - } -} - -export class SelectGenderPhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start(): void { - super.start(); - - this.scene.ui.showText(i18next.t("menu:boyOrGirl"), null, () => { - this.scene.ui.setMode(Mode.OPTION_SELECT, { - options: [ - { - label: i18next.t("settings:boy"), - handler: () => { - this.scene.gameData.gender = PlayerGender.MALE; - this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 0); - this.scene.gameData.saveSystem().then(() => this.end()); - return true; - } - }, - { - label: i18next.t("settings:girl"), - handler: () => { - this.scene.gameData.gender = PlayerGender.FEMALE; - this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 1); - this.scene.gameData.saveSystem().then(() => this.end()); - return true; - } - } - ] - }); - }); - } - - end(): void { - this.scene.ui.setMode(Mode.MESSAGE); - super.end(); - } -} - -export class SelectChallengePhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.playBgm("menu"); - - this.scene.ui.setMode(Mode.CHALLENGE_SELECT); - } -} - -export class SelectStarterPhase extends Phase { - - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.playBgm("menu"); - - this.scene.ui.setMode(Mode.STARTER_SELECT, (starters: Starter[]) => { - this.scene.ui.clearText(); - this.scene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: integer) => { - if (slotId === -1) { - this.scene.clearPhaseQueue(); - this.scene.pushPhase(new TitlePhase(this.scene)); - return this.end(); - } - this.scene.sessionSlotId = slotId; - this.initBattle(starters); - }); - }); - } - - /** - * Initialize starters before starting the first battle - * @param starters {@linkcode Pokemon} with which to start the first battle - */ - initBattle(starters: Starter[]) { - const party = this.scene.getParty(); - const loadPokemonAssets: Promise[] = []; - starters.forEach((starter: Starter, i: integer) => { - if (!i && Overrides.STARTER_SPECIES_OVERRIDE) { - starter.species = getPokemonSpecies(Overrides.STARTER_SPECIES_OVERRIDE as Species); - } - const starterProps = this.scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr); - let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); - if ( - starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && - starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] - ) { - starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; - } - - let starterGender = starter.species.malePercent !== null - ? !starterProps.female ? Gender.MALE : Gender.FEMALE - : Gender.GENDERLESS; - if (Overrides.GENDER_OVERRIDE !== null) { - starterGender = Overrides.GENDER_OVERRIDE; - } - const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0); - const starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature); - starter.moveset && starterPokemon.tryPopulateMoveset(starter.moveset); - if (starter.passive) { - starterPokemon.passive = true; - } - starterPokemon.luck = this.scene.gameData.getDexAttrLuck(this.scene.gameData.dexData[starter.species.speciesId].caughtAttr); - if (starter.pokerus) { - starterPokemon.pokerus = true; - } - - if (starter.nickname) { - starterPokemon.nickname = starter.nickname; - } - - if (this.scene.gameMode.isSplicedOnly) { - starterPokemon.generateFusionSpecies(true); - } - starterPokemon.setVisible(false); - applyChallenges(this.scene.gameMode, ChallengeType.STARTER_MODIFY, starterPokemon); - party.push(starterPokemon); - loadPokemonAssets.push(starterPokemon.loadAssets()); - }); - overrideModifiers(this.scene); - overrideHeldItems(this.scene, party[0]); - Promise.all(loadPokemonAssets).then(() => { - SoundFade.fadeOut(this.scene, this.scene.sound.get("menu"), 500, true); - this.scene.time.delayedCall(500, () => this.scene.playBgm()); - if (this.scene.gameMode.isClassic) { - this.scene.gameData.gameStats.classicSessionsPlayed++; - } else { - this.scene.gameData.gameStats.endlessSessionsPlayed++; - } - this.scene.newBattle(); - this.scene.arena.init(); - this.scene.sessionPlayTime = 0; - this.scene.lastSavePlayTime = 0; - // Ensures Keldeo (or any future Pokemon that have this type of form change) starts in the correct form - this.scene.getParty().forEach((p: PlayerPokemon) => { - this.scene.triggerPokemonFormChange(p, SpeciesFormChangeMoveLearnedTrigger); - }); - this.end(); - }); - } -} - -export class BattlePhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void { - const sprites = this.scene.currentBattle.trainer?.getSprites()!; // TODO: is this bang correct? - const tintSprites = this.scene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct? - for (let i = 0; i < sprites.length; i++) { - const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; - [sprites[i], tintSprites[i]].map(sprite => { - if (visible) { - sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16; - } - sprite.setVisible(visible); - sprite.clearTint(); - }); - sprites[i].setVisible(visible); - tintSprites[i].setVisible(visible); - sprites[i].clearTint(); - tintSprites[i].clearTint(); - } - this.scene.tweens.add({ - targets: this.scene.currentBattle.trainer, - x: "-=16", - y: "+=16", - alpha: 1, - ease: "Sine.easeInOut", - duration: 750 - }); - } - - hideEnemyTrainer(): void { - this.scene.tweens.add({ - targets: this.scene.currentBattle.trainer, - x: "+=16", - y: "-=16", - alpha: 0, - ease: "Sine.easeInOut", - duration: 750 - }); - } -} - -type PokemonFunc = (pokemon: Pokemon) => void; - -export abstract class FieldPhase extends BattlePhase { - getOrder(): BattlerIndex[] { - const playerField = this.scene.getPlayerField().filter(p => p.isActive()) as Pokemon[]; - const enemyField = this.scene.getEnemyField().filter(p => p.isActive()) as Pokemon[]; - - // We shuffle the list before sorting so speed ties produce random results - let orderedTargets: Pokemon[] = playerField.concat(enemyField); - // We seed it with the current turn to prevent an inconsistency where it - // was varying based on how long since you last reloaded - this.scene.executeWithSeedOffset(() => { - orderedTargets = Utils.randSeedShuffle(orderedTargets); - }, this.scene.currentBattle.turn, this.scene.waveSeed); - - orderedTargets.sort((a: Pokemon, b: Pokemon) => { - const aSpeed = a?.getBattleStat(Stat.SPD) || 0; - const bSpeed = b?.getBattleStat(Stat.SPD) || 0; - - return bSpeed - aSpeed; - }); - - const speedReversed = new Utils.BooleanHolder(false); - this.scene.arena.applyTags(TrickRoomTag, speedReversed); - - if (speedReversed.value) { - orderedTargets = orderedTargets.reverse(); - } - - return orderedTargets.map(t => t.getFieldIndex() + (!t.isPlayer() ? BattlerIndex.ENEMY : 0)); - } - - executeForAll(func: PokemonFunc): void { - const field = this.scene.getField(true).filter(p => p.summonData); - field.forEach(pokemon => func(pokemon)); - } -} - -export abstract class PokemonPhase extends FieldPhase { - protected battlerIndex: BattlerIndex | integer; - public player: boolean; - public fieldIndex: integer; - - constructor(scene: BattleScene, battlerIndex?: BattlerIndex | integer) { - super(scene); - - if (battlerIndex === undefined) { - battlerIndex = scene.getField().find(p => p?.isActive())!.getBattlerIndex(); // TODO: is the bang correct here? - } - - this.battlerIndex = battlerIndex; - this.player = battlerIndex < 2; - this.fieldIndex = battlerIndex % 2; - } - - getPokemon(): Pokemon { - if (this.battlerIndex > BattlerIndex.ENEMY_2) { - return this.scene.getPokemonById(this.battlerIndex)!; //TODO: is this bang correct? - } - return this.scene.getField()[this.battlerIndex]!; //TODO: is this bang correct? - } -} - -export abstract class PartyMemberPokemonPhase extends FieldPhase { - protected partyMemberIndex: integer; - protected fieldIndex: integer; - protected player: boolean; - - constructor(scene: BattleScene, partyMemberIndex: integer, player: boolean) { - super(scene); - - this.partyMemberIndex = partyMemberIndex; - this.fieldIndex = partyMemberIndex < this.scene.currentBattle.getBattlerCount() - ? partyMemberIndex - : -1; - this.player = player; - } - - getParty(): Pokemon[] { - return this.player ? this.scene.getParty() : this.scene.getEnemyParty(); - } - - getPokemon(): Pokemon { - return this.getParty()[this.partyMemberIndex]; - } -} - -export abstract class PlayerPartyMemberPokemonPhase extends PartyMemberPokemonPhase { - constructor(scene: BattleScene, partyMemberIndex: integer) { - super(scene, partyMemberIndex, true); - } - - getPlayerPokemon(): PlayerPokemon { - return super.getPokemon() as PlayerPokemon; - } -} - -export abstract class EnemyPartyMemberPokemonPhase extends PartyMemberPokemonPhase { - constructor(scene: BattleScene, partyMemberIndex: integer) { - super(scene, partyMemberIndex, false); - } - - getEnemyPokemon(): EnemyPokemon { - return super.getPokemon() as EnemyPokemon; - } -} - -export class EncounterPhase extends BattlePhase { - private loaded: boolean; - - constructor(scene: BattleScene, loaded?: boolean) { - super(scene); - - this.loaded = !!loaded; - } - - start() { - super.start(); - - this.scene.updateGameInfo(); - - this.scene.initSession(); - - this.scene.eventTarget.dispatchEvent(new EncounterPhaseEvent()); - - // Failsafe if players somehow skip floor 200 in classic mode - if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) { - this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } - - const loadEnemyAssets: Promise[] = []; - - const battle = this.scene.currentBattle; - - let totalBst = 0; - - battle.enemyLevels?.forEach((level, e) => { - if (!this.loaded) { - if (battle.battleType === BattleType.TRAINER) { - battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here? - } else { - const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true); - battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies)); - if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { - battle.enemyParty[e].ivs = new Array(6).fill(31); - } - this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => { - applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]); - }); - } - } - const enemyPokemon = this.scene.getEnemyParty()[e]; - if (e < (battle.double ? 2 : 1)) { - enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]); - enemyPokemon.resetSummonData(); - } - - if (!this.loaded) { - this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER); - } - - if (enemyPokemon.species.speciesId === Species.ETERNATUS) { - if (this.scene.gameMode.isClassic && (battle.battleSpec === BattleSpec.FINAL_BOSS || this.scene.gameMode.isWaveFinal(battle.waveIndex))) { - if (battle.battleSpec !== BattleSpec.FINAL_BOSS) { - enemyPokemon.formIndex = 1; - enemyPokemon.updateScale(); - } - enemyPokemon.setBoss(); - } else if (!(battle.waveIndex % 1000)) { - enemyPokemon.formIndex = 1; - enemyPokemon.updateScale(); - const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; - this.scene.removeModifier(bossMBH!); - bossMBH?.setTransferrableFalse(); - this.scene.addEnemyModifier(bossMBH!); - } - } - - totalBst += enemyPokemon.getSpeciesForm().baseTotal; - - loadEnemyAssets.push(enemyPokemon.loadAssets()); - - console.log(getPokemonNameWithAffix(enemyPokemon), enemyPokemon.species.speciesId, enemyPokemon.stats); - }); - - if (this.scene.getParty().filter(p => p.isShiny()).length === 6) { - this.scene.validateAchv(achvs.SHINY_PARTY); - } - - if (battle.battleType === BattleType.TRAINER) { - loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct? - } else { - // This block only applies for double battles to init the boss segments (idk why it's split up like this) - if (battle.enemyParty.filter(p => p.isBoss()).length > 1) { - for (const enemyPokemon of battle.enemyParty) { - // If the enemy pokemon is a boss and wasn't populated from data source, then set it up - if (enemyPokemon.isBoss() && !enemyPokemon.isPopulatedFromDataSource) { - enemyPokemon.setBoss(true, Math.ceil(enemyPokemon.bossSegments * (enemyPokemon.getSpeciesForm().baseTotal / totalBst))); - enemyPokemon.initBattleInfo(); - } - } - } - } - - Promise.all(loadEnemyAssets).then(() => { - battle.enemyParty.forEach((enemyPokemon, e) => { - if (e < (battle.double ? 2 : 1)) { - if (battle.battleType === BattleType.WILD) { - this.scene.field.add(enemyPokemon); - battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); - const playerPokemon = this.scene.getPlayerPokemon(); - if (playerPokemon?.visible) { - this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon); - } - enemyPokemon.tint(0, 0.5); - } else if (battle.battleType === BattleType.TRAINER) { - enemyPokemon.setVisible(false); - this.scene.currentBattle.trainer?.tint(0, 0.5); - } - if (battle.double) { - enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT); - } - } - }); - - if (!this.loaded) { - regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); - this.scene.generateEnemyModifiers(); - } - - this.scene.ui.setMode(Mode.MESSAGE).then(() => { - if (!this.loaded) { - //@ts-ignore - this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore - this.scene.disableMenu = false; - if (!success) { - return this.scene.reset(true); - } - this.doEncounter(); - }); - } else { - this.doEncounter(); - } - }); - }); - } - - doEncounter() { - this.scene.playBgm(undefined, true); - this.scene.updateModifiers(false); - this.scene.setFieldScale(1); - - /*if (startingWave > 10) { - for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++) - this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier(), true); - this.scene.updateModifiers(true); - }*/ - - for (const pokemon of this.scene.getParty()) { - if (pokemon) { - pokemon.resetBattleData(); - } - } - - if (!this.loaded) { - this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); - } - - const enemyField = this.scene.getEnemyField(); - this.scene.tweens.add({ - targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(), - x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300, - duration: 2000, - onComplete: () => { - if (!this.tryOverrideForBattleSpec()) { - this.doEncounterCommon(); - } - } - }); - } - - getEncounterMessage(): string { - const enemyField = this.scene.getEnemyField(); - - if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { - return i18next.t("battle:bossAppeared", { bossName: getPokemonNameWithAffix(enemyField[0])}); - } - - if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - if (this.scene.currentBattle.double) { - return i18next.t("battle:trainerAppearedDouble", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); - - } else { - return i18next.t("battle:trainerAppeared", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); - } - } - - return enemyField.length === 1 - ? i18next.t("battle:singleWildAppeared", { pokemonName: enemyField[0].getNameToRender() }) - : i18next.t("battle:multiWildAppeared", { pokemonName1: enemyField[0].getNameToRender(), pokemonName2: enemyField[1].getNameToRender() }); - } - - doEncounterCommon(showEncounterMessage: boolean = true) { - const enemyField = this.scene.getEnemyField(); - - if (this.scene.currentBattle.battleType === BattleType.WILD) { - enemyField.forEach(enemyPokemon => { - enemyPokemon.untint(100, "Sine.easeOut"); - enemyPokemon.cry(); - enemyPokemon.showInfo(); - if (enemyPokemon.isShiny()) { - this.scene.validateAchv(achvs.SEE_SHINY); - } - }); - this.scene.updateFieldScale(); - if (showEncounterMessage) { - this.scene.ui.showText(this.getEncounterMessage(), null, () => this.end(), 1500); - } else { - this.end(); - } - } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - const trainer = this.scene.currentBattle.trainer; - trainer?.untint(100, "Sine.easeOut"); - trainer?.playAnim(); - - const doSummon = () => { - this.scene.currentBattle.started = true; - this.scene.playBgm(undefined); - this.scene.pbTray.showPbTray(this.scene.getParty()); - this.scene.pbTrayEnemy.showPbTray(this.scene.getEnemyParty()); - const doTrainerSummon = () => { - this.hideEnemyTrainer(); - const availablePartyMembers = this.scene.getEnemyParty().filter(p => !p.isFainted()).length; - this.scene.unshiftPhase(new SummonPhase(this.scene, 0, false)); - if (this.scene.currentBattle.double && availablePartyMembers > 1) { - this.scene.unshiftPhase(new SummonPhase(this.scene, 1, false)); - } - this.end(); - }; - if (showEncounterMessage) { - this.scene.ui.showText(this.getEncounterMessage(), null, doTrainerSummon, 1500, true); - } else { - doTrainerSummon(); - } - }; - - const encounterMessages = this.scene.currentBattle.trainer?.getEncounterMessages(); - - if (!encounterMessages?.length) { - doSummon(); - } else { - let message: string; - this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex); - message = message!; // tell TS compiler it's defined now - const showDialogueAndSummon = () => { - this.scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => { - this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doSummon())); - }); - }; - if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { - this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer?.getKey()!, getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); // TODO: is this bang correct? - } else { - showDialogueAndSummon(); - } - } - } - } - - end() { - const enemyField = this.scene.getEnemyField(); - - enemyField.forEach((enemyPokemon, e) => { - if (enemyPokemon.isShiny()) { - this.scene.unshiftPhase(new ShinySparklePhase(this.scene, BattlerIndex.ENEMY + e)); - } - }); - - if (this.scene.currentBattle.battleType !== BattleType.TRAINER) { - enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => { - // if there is not a player party, we can't continue - if (!this.scene.getParty()?.length) { - return false; - } - // how many player pokemon are on the field ? - const pokemonsOnFieldCount = this.scene.getParty().filter(p => p.isOnField()).length; - // if it's a 2vs1, there will never be a 2nd pokemon on our field even - const requiredPokemonsOnField = Math.min(this.scene.getParty().filter((p) => !p.isFainted()).length, 2); - // if it's a double, there should be 2, otherwise 1 - if (this.scene.currentBattle.double) { - return pokemonsOnFieldCount === requiredPokemonsOnField; - } - return pokemonsOnFieldCount === 1; - })); - const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier); - if (ivScannerModifier) { - enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6)))); - } - } - - if (!this.loaded) { - const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); - - if (!availablePartyMembers[0].isOnField()) { - this.scene.pushPhase(new SummonPhase(this.scene, 0)); - } - - if (this.scene.currentBattle.double) { - if (availablePartyMembers.length > 1) { - this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true)); - if (!availablePartyMembers[1].isOnField()) { - this.scene.pushPhase(new SummonPhase(this.scene, 1)); - } - } - } else { - if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { - this.scene.pushPhase(new ReturnPhase(this.scene, 1)); - } - this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false)); - } - - if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) { - const minPartySize = this.scene.currentBattle.double ? 2 : 1; - if (availablePartyMembers.length > minPartySize) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); - if (this.scene.currentBattle.double) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); - } - } - } - } - handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end()); - } - - tryOverrideForBattleSpec(): boolean { - switch (this.scene.currentBattle.battleSpec) { - case BattleSpec.FINAL_BOSS: - const enemy = this.scene.getEnemyPokemon(); - this.scene.ui.showText(this.getEncounterMessage(), null, () => { - const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; - //The two lines below check if English ordinals (1st, 2nd, 3rd, Xth) are used and determine which one to use. - //Otherwise, it defaults to an empty string. - //As of 08-07-24: Spanish and Italian default to the English translations - const ordinalUse = ["en", "es", "it"]; - const currentLanguage = i18next.resolvedLanguage ?? "en"; - const ordinalIndex = (ordinalUse.includes(currentLanguage)) ? ["st", "nd", "rd"][((count + 90) % 100 - 10) % 10 - 1] ?? "th" : ""; - const cycleCount = count.toLocaleString() + ordinalIndex; - const encounterDialogue = i18next.t(`${(this.scene.gameData.gender === PlayerGender.FEMALE) ? "PGF" : "PGM"}battleSpecDialogue:encounter`, {cycleCount: cycleCount}); - this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => { - this.doEncounterCommon(false); - }); - }, 1500, true); - return true; - } - - return false; - } -} - -export class NextEncounterPhase extends EncounterPhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - } - - doEncounter(): void { - this.scene.playBgm(undefined, true); - - for (const pokemon of this.scene.getParty()) { - if (pokemon) { - pokemon.resetBattleData(); - } - } - - this.scene.arenaNextEnemy.setBiome(this.scene.arena.biomeType); - this.scene.arenaNextEnemy.setVisible(true); - - const enemyField = this.scene.getEnemyField(); - this.scene.tweens.add({ - targets: [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer].flat(), - x: "+=300", - duration: 2000, - onComplete: () => { - this.scene.arenaEnemy.setBiome(this.scene.arena.biomeType); - this.scene.arenaEnemy.setX(this.scene.arenaNextEnemy.x); - this.scene.arenaEnemy.setAlpha(1); - this.scene.arenaNextEnemy.setX(this.scene.arenaNextEnemy.x - 300); - this.scene.arenaNextEnemy.setVisible(false); - if (this.scene.lastEnemyTrainer) { - this.scene.lastEnemyTrainer.destroy(); - } - - if (!this.tryOverrideForBattleSpec()) { - this.doEncounterCommon(); - } - } - }); - } -} - -export class NewBiomeEncounterPhase extends NextEncounterPhase { - constructor(scene: BattleScene) { - super(scene); - } - - doEncounter(): void { - this.scene.playBgm(undefined, true); - - for (const pokemon of this.scene.getParty()) { - if (pokemon) { - pokemon.resetBattleData(); - } - } - - this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); - - for (const pokemon of this.scene.getParty().filter(p => p.isOnField())) { - applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null); - } - - const enemyField = this.scene.getEnemyField(); - this.scene.tweens.add({ - targets: [this.scene.arenaEnemy, enemyField].flat(), - x: "+=300", - duration: 2000, - onComplete: () => { - if (!this.tryOverrideForBattleSpec()) { - this.doEncounterCommon(); - } - } - }); - } -} - -export class PostSummonPhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { - super(scene, battlerIndex); - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - - if (pokemon.status?.effect === StatusEffect.TOXIC) { - pokemon.status.turnCount = 0; - } - this.scene.arena.applyTags(ArenaTrapTag, pokemon); - applyPostSummonAbAttrs(PostSummonAbAttr, pokemon).then(() => this.end()); - } -} - -export class SelectBiomePhase extends BattlePhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - const currentBiome = this.scene.arena.biomeType; - - const setNextBiome = (nextBiome: Biome) => { - if (this.scene.currentBattle.waveIndex % 10 === 1) { - this.scene.applyModifiers(MoneyInterestModifier, true, this.scene); - this.scene.unshiftPhase(new PartyHealPhase(this.scene, false)); - } - this.scene.unshiftPhase(new SwitchBiomePhase(this.scene, nextBiome)); - this.end(); - }; - - if ((this.scene.gameMode.isClassic && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex + 9)) - || (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) - || (this.scene.gameMode.hasShortBiomes && !(this.scene.currentBattle.waveIndex % 50))) { - setNextBiome(Biome.END); - } else if (this.scene.gameMode.hasRandomBiomes) { - setNextBiome(this.generateNextBiome()); - } else if (Array.isArray(biomeLinks[currentBiome])) { - let biomes: Biome[] = []; - this.scene.executeWithSeedOffset(() => { - biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) - .filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1])) - .map(b => !Array.isArray(b) ? b : b[0]); - }, this.scene.currentBattle.waveIndex); - if (biomes.length > 1 && this.scene.findModifier(m => m instanceof MapModifier)) { - let biomeChoices: Biome[] = []; - this.scene.executeWithSeedOffset(() => { - biomeChoices = (!Array.isArray(biomeLinks[currentBiome]) - ? [biomeLinks[currentBiome] as Biome] - : biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) - .filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1])) - .map(b => Array.isArray(b) ? b[0] : b); - }, this.scene.currentBattle.waveIndex); - const biomeSelectItems = biomeChoices.map(b => { - const ret: OptionSelectItem = { - label: getBiomeName(b), - handler: () => { - this.scene.ui.setMode(Mode.MESSAGE); - setNextBiome(b); - return true; - } - }; - return ret; - }); - this.scene.ui.setMode(Mode.OPTION_SELECT, { - options: biomeSelectItems, - delay: 1000 - }); - } else { - setNextBiome(biomes[Utils.randSeedInt(biomes.length)]); - } - } else if (biomeLinks.hasOwnProperty(currentBiome)) { - setNextBiome(biomeLinks[currentBiome] as Biome); - } else { - setNextBiome(this.generateNextBiome()); - } - } - - generateNextBiome(): Biome { - if (!(this.scene.currentBattle.waveIndex % 50)) { - return Biome.END; - } - return this.scene.generateRandomBiome(this.scene.currentBattle.waveIndex); - } -} - -export class SwitchBiomePhase extends BattlePhase { - private nextBiome: Biome; - - constructor(scene: BattleScene, nextBiome: Biome) { - super(scene); - - this.nextBiome = nextBiome; - } - - start() { - super.start(); - - if (this.nextBiome === undefined) { - return this.end(); - } - - this.scene.tweens.add({ - targets: [this.scene.arenaEnemy, this.scene.lastEnemyTrainer], - x: "+=300", - duration: 2000, - onComplete: () => { - this.scene.arenaEnemy.setX(this.scene.arenaEnemy.x - 600); - - this.scene.newArena(this.nextBiome); - - const biomeKey = getBiomeKey(this.nextBiome); - const bgTexture = `${biomeKey}_bg`; - this.scene.arenaBgTransition.setTexture(bgTexture); - this.scene.arenaBgTransition.setAlpha(0); - this.scene.arenaBgTransition.setVisible(true); - this.scene.arenaPlayerTransition.setBiome(this.nextBiome); - this.scene.arenaPlayerTransition.setAlpha(0); - this.scene.arenaPlayerTransition.setVisible(true); - - this.scene.tweens.add({ - targets: [this.scene.arenaPlayer, this.scene.arenaBgTransition, this.scene.arenaPlayerTransition], - duration: 1000, - delay: 1000, - ease: "Sine.easeInOut", - alpha: (target: any) => target === this.scene.arenaPlayer ? 0 : 1, - onComplete: () => { - this.scene.arenaBg.setTexture(bgTexture); - this.scene.arenaPlayer.setBiome(this.nextBiome); - this.scene.arenaPlayer.setAlpha(1); - this.scene.arenaEnemy.setBiome(this.nextBiome); - this.scene.arenaEnemy.setAlpha(1); - this.scene.arenaNextEnemy.setBiome(this.nextBiome); - this.scene.arenaBgTransition.setVisible(false); - this.scene.arenaPlayerTransition.setVisible(false); - if (this.scene.lastEnemyTrainer) { - this.scene.lastEnemyTrainer.destroy(); - } - - this.end(); - } - }); - } - }); - } -} - -export class SummonPhase extends PartyMemberPokemonPhase { - private loaded: boolean; - - constructor(scene: BattleScene, fieldIndex: integer, player: boolean = true, loaded: boolean = false) { - super(scene, fieldIndex, player); - - this.loaded = loaded; - } - - start() { - super.start(); - - this.preSummon(); - } - - /** - * Sends out a Pokemon before the battle begins and shows the appropriate messages - */ - preSummon(): void { - const partyMember = this.getPokemon(); - // If the Pokemon about to be sent out is fainted or illegal under a challenge, switch to the first non-fainted legal Pokemon - if (!partyMember.isAllowedInBattle()) { - console.warn("The Pokemon about to be sent out is fainted or illegal under a challenge. Attempting to resolve..."); - - // First check if they're somehow still in play, if so remove them. - if (partyMember.isOnField()) { - partyMember.leaveField(); - } - - const party = this.getParty(); - - // Find the first non-fainted Pokemon index above the current one - const legalIndex = party.findIndex((p, i) => i > this.partyMemberIndex && p.isAllowedInBattle()); - if (legalIndex === -1) { - console.error("Party Details:\n", party); - console.error("All available Pokemon were fainted or illegal!"); - this.scene.clearPhaseQueue(); - this.scene.unshiftPhase(new GameOverPhase(this.scene)); - this.end(); - return; - } - - // Swaps the fainted Pokemon and the first non-fainted legal Pokemon in the party - [party[this.partyMemberIndex], party[legalIndex]] = [party[legalIndex], party[this.partyMemberIndex]]; - console.warn("Swapped %s %O with %s %O", getPokemonNameWithAffix(partyMember), partyMember, getPokemonNameWithAffix(party[0]), party[0]); - } - - if (this.player) { - this.scene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(this.getPokemon()) })); - if (this.player) { - this.scene.pbTray.hide(); - } - this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`); - this.scene.time.delayedCall(562, () => { - this.scene.trainer.setFrame("2"); - this.scene.time.delayedCall(64, () => { - this.scene.trainer.setFrame("3"); - }); - }); - this.scene.tweens.add({ - targets: this.scene.trainer, - x: -36, - duration: 1000, - onComplete: () => this.scene.trainer.setVisible(false) - }); - this.scene.time.delayedCall(750, () => this.summon()); - } else { - const trainerName = this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); - const pokemonName = this.getPokemon().getNameToRender(); - const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName }); - - this.scene.pbTrayEnemy.hide(); - this.scene.ui.showText(message, null, () => this.summon()); - } - } - - summon(): void { - const pokemon = this.getPokemon(); - - const pokeball = this.scene.addFieldSprite(this.player ? 36 : 248, this.player ? 80 : 44, "pb", getPokeballAtlasKey(pokemon.pokeball)); - pokeball.setVisible(false); - pokeball.setOrigin(0.5, 0.625); - this.scene.field.add(pokeball); - - if (this.fieldIndex === 1) { - pokemon.setFieldPosition(FieldPosition.RIGHT, 0); - } else { - const availablePartyMembers = this.getParty().filter(p => p.isAllowedInBattle()).length; - pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT); - } - - const fpOffset = pokemon.getFieldPositionOffset(); - - pokeball.setVisible(true); - - this.scene.tweens.add({ - targets: pokeball, - duration: 650, - x: (this.player ? 100 : 236) + fpOffset[0] - }); - - this.scene.tweens.add({ - targets: pokeball, - duration: 150, - ease: "Cubic.easeOut", - y: (this.player ? 70 : 34) + fpOffset[1], - onComplete: () => { - this.scene.tweens.add({ - targets: pokeball, - duration: 500, - ease: "Cubic.easeIn", - angle: 1440, - y: (this.player ? 132 : 86) + fpOffset[1], - onComplete: () => { - this.scene.playSound("pb_rel"); - pokeball.destroy(); - this.scene.add.existing(pokemon); - this.scene.field.add(pokemon); - if (!this.player) { - const playerPokemon = this.scene.getPlayerPokemon() as Pokemon; - if (playerPokemon?.visible) { - this.scene.field.moveBelow(pokemon, playerPokemon); - } - this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); - } - addPokeballOpenParticles(this.scene, pokemon.x, pokemon.y - 16, pokemon.pokeball); - this.scene.updateModifiers(this.player); - this.scene.updateFieldScale(); - pokemon.showInfo(); - pokemon.playAnim(); - pokemon.setVisible(true); - pokemon.getSprite().setVisible(true); - pokemon.setScale(0.5); - pokemon.tint(getPokeballTintColor(pokemon.pokeball)); - pokemon.untint(250, "Sine.easeIn"); - this.scene.updateFieldScale(); - this.scene.tweens.add({ - targets: pokemon, - duration: 250, - ease: "Sine.easeIn", - scale: pokemon.getSpriteScale(), - onComplete: () => { - pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); - pokemon.getSprite().clearTint(); - pokemon.resetSummonData(); - this.scene.time.delayedCall(1000, () => this.end()); - } - }); - } - }); - } - }); - } - - onEnd(): void { - const pokemon = this.getPokemon(); - - if (pokemon.isShiny()) { - this.scene.unshiftPhase(new ShinySparklePhase(this.scene, pokemon.getBattlerIndex())); - } - - pokemon.resetTurnData(); - - if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) { - this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); - this.queuePostSummon(); - } - } - - queuePostSummon(): void { - this.scene.pushPhase(new PostSummonPhase(this.scene, this.getPokemon().getBattlerIndex())); - } - - end() { - this.onEnd(); - - super.end(); - } -} - -export class SwitchSummonPhase extends SummonPhase { - private slotIndex: integer; - private doReturn: boolean; - private batonPass: boolean; - - private lastPokemon: Pokemon; - - /** - * Constructor for creating a new SwitchSummonPhase - * @param scene {@linkcode BattleScene} the scene the phase is associated with - * @param fieldIndex integer representing position on the battle field - * @param slotIndex integer for the index of pokemon (in party of 6) to switch into - * @param doReturn boolean whether to render "comeback" dialogue - * @param batonPass boolean if the switch is from baton pass - * @param player boolean if the switch is from the player - */ - constructor(scene: BattleScene, fieldIndex: integer, slotIndex: integer, doReturn: boolean, batonPass: boolean, player?: boolean) { - super(scene, fieldIndex, player !== undefined ? player : true); - - this.slotIndex = slotIndex; - this.doReturn = doReturn; - this.batonPass = batonPass; - } - - start(): void { - super.start(); - } - - preSummon(): void { - if (!this.player) { - if (this.slotIndex === -1) { - //@ts-ignore - this.slotIndex = this.scene.currentBattle.trainer?.getNextSummonIndex(!this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); // TODO: what would be the default trainer-slot fallback? - } - if (this.slotIndex > -1) { - this.showEnemyTrainer(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); - this.scene.pbTrayEnemy.showPbTray(this.scene.getEnemyParty()); - } - } - - if (!this.doReturn || (this.slotIndex !== -1 && !(this.player ? this.scene.getParty() : this.scene.getEnemyParty())[this.slotIndex])) { - if (this.player) { - return this.switchAndSummon(); - } else { - this.scene.time.delayedCall(750, () => this.switchAndSummon()); - return; - } - } - - const pokemon = this.getPokemon(); - - if (!this.batonPass) { - (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id)); - } - - this.scene.ui.showText(this.player ? - i18next.t("battle:playerComeBack", { pokemonName: getPokemonNameWithAffix(pokemon) }) : - i18next.t("battle:trainerComeBack", { - trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), - pokemonName: getPokemonNameWithAffix(pokemon) - }) - ); - this.scene.playSound("pb_rel"); - pokemon.hideInfo(); - pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, "Sine.easeIn"); - this.scene.tweens.add({ - targets: pokemon, - duration: 250, - ease: "Sine.easeIn", - scale: 0.5, - onComplete: () => { - pokemon.leaveField(!this.batonPass, false); - this.scene.time.delayedCall(750, () => this.switchAndSummon()); - } - }); - } - - switchAndSummon() { - const party = this.player ? this.getParty() : this.scene.getEnemyParty(); - const switchedInPokemon = party[this.slotIndex]; - this.lastPokemon = this.getPokemon(); - applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); - if (this.batonPass && switchedInPokemon) { - (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedInPokemon.id)); - if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) { - const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier - && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier; - if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) { - this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false); - } - } - } - if (switchedInPokemon) { - party[this.slotIndex] = this.lastPokemon; - party[this.fieldIndex] = switchedInPokemon; - const showTextAndSummon = () => { - this.scene.ui.showText(this.player ? - i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(switchedInPokemon) }) : - i18next.t("battle:trainerGo", { - trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), - pokemonName: this.getPokemon().getNameToRender() - }) - ); - // Ensure improperly persisted summon data (such as tags) is cleared upon switching - if (!this.batonPass) { - switchedInPokemon.resetBattleData(); - switchedInPokemon.resetSummonData(); - } - this.summon(); - }; - if (this.player) { - showTextAndSummon(); - } else { - this.scene.time.delayedCall(1500, () => { - this.hideEnemyTrainer(); - this.scene.pbTrayEnemy.hide(); - showTextAndSummon(); - }); - } - } else { - this.end(); - } - } - - onEnd(): void { - super.onEnd(); - - const pokemon = this.getPokemon(); - - const moveId = this.lastPokemon?.scene.currentBattle.lastMove; - const lastUsedMove = moveId ? allMoves[moveId] : undefined; - - const currentCommand = pokemon.scene.currentBattle.turnCommands[this.fieldIndex]?.command; - const lastPokemonIsForceSwitchedAndNotFainted = lastUsedMove?.hasAttr(ForceSwitchOutAttr) && !this.lastPokemon.isFainted(); - - // Compensate for turn spent summoning - // Or compensate for force switch move if switched out pokemon is not fainted - if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted) { - pokemon.battleSummonData.turnCount--; - } - - if (this.batonPass && pokemon) { - pokemon.transferSummon(this.lastPokemon); - } - - this.lastPokemon?.resetSummonData(); - - this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); - } - - queuePostSummon(): void { - this.scene.unshiftPhase(new PostSummonPhase(this.scene, this.getPokemon().getBattlerIndex())); - } -} - -export class ReturnPhase extends SwitchSummonPhase { - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene, fieldIndex, -1, true, false); - } - - switchAndSummon(): void { - this.end(); - } - - summon(): void { } - - onEnd(): void { - const pokemon = this.getPokemon(); - - pokemon.resetTurnData(); - pokemon.resetSummonData(); - - this.scene.updateFieldScale(); - - this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger); - } -} - -export class ShowTrainerPhase extends BattlePhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.trainer.setVisible(true); - - this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back`); - - this.scene.tweens.add({ - targets: this.scene.trainer, - x: 106, - duration: 1000, - onComplete: () => this.end() - }); - } -} - -export class ToggleDoublePositionPhase extends BattlePhase { - private double: boolean; - - constructor(scene: BattleScene, double: boolean) { - super(scene); - - this.double = double; - } - - start() { - super.start(); - - const playerPokemon = this.scene.getPlayerField().find(p => p.isActive(true)); - if (playerPokemon) { - playerPokemon.setFieldPosition(this.double && this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? FieldPosition.LEFT : FieldPosition.CENTER, 500).then(() => { - if (playerPokemon.getFieldIndex() === 1) { - const party = this.scene.getParty(); - party[1] = party[0]; - party[0] = playerPokemon; - } - this.end(); - }); - } else { - this.end(); - } - } -} - -export class CheckSwitchPhase extends BattlePhase { - protected fieldIndex: integer; - protected useName: boolean; - - constructor(scene: BattleScene, fieldIndex: integer, useName: boolean) { - super(scene); - - this.fieldIndex = fieldIndex; - this.useName = useName; - } - - start() { - super.start(); - - const pokemon = this.scene.getPlayerField()[this.fieldIndex]; - - if (this.scene.battleStyle === BattleStyle.SET) { - super.end(); - return; - } - - if (this.scene.field.getAll().indexOf(pokemon) === -1) { - this.scene.unshiftPhase(new SummonMissingPhase(this.scene, this.fieldIndex)); - super.end(); - return; - } - - if (!this.scene.getParty().slice(1).filter(p => p.isActive()).length) { - super.end(); - return; - } - - if (pokemon.getTag(BattlerTagType.FRENZY)) { - super.end(); - return; - } - - this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? getPokemonNameWithAffix(pokemon) : i18next.t("battle:pokemon") }), null, () => { - this.scene.ui.setMode(Mode.CONFIRM, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex); - this.scene.unshiftPhase(new SwitchPhase(this.scene, this.fieldIndex, false, true)); - this.end(); - }, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.end(); - }); - }); - } -} - -export class SummonMissingPhase extends SummonPhase { - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene, fieldIndex); - } - - preSummon(): void { - this.scene.ui.showText(i18next.t("battle:sendOutPokemon", { pokemonName: getPokemonNameWithAffix(this.getPokemon()) })); - this.scene.time.delayedCall(250, () => this.summon()); - } -} - -export class LevelCapPhase extends FieldPhase { - constructor(scene: BattleScene) { - super(scene); - } - - start(): void { - super.start(); - - this.scene.ui.setMode(Mode.MESSAGE).then(() => { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.showText(i18next.t("battle:levelCapUp", { levelCap: this.scene.getMaxExpLevel() }), null, () => this.end(), null, true); - this.executeForAll(pokemon => pokemon.updateInfo(true)); - }); - } -} - -export class TurnInitPhase extends FieldPhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.getPlayerField().forEach(p => { - // If this pokemon is in play and evolved into something illegal under the current challenge, force a switch - if (p.isOnField() && !p.isAllowedInBattle()) { - this.scene.queueMessage(i18next.t("challenges:illegalEvolution", { "pokemon": p.name }), null, true); - - const allowedPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); - - if (!allowedPokemon.length) { - // If there are no longer any legal pokemon in the party, game over. - this.scene.clearPhaseQueue(); - this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } else if (allowedPokemon.length >= this.scene.currentBattle.getBattlerCount() || (this.scene.currentBattle.double && !allowedPokemon[0].isActive(true))) { - // If there is at least one pokemon in the back that is legal to switch in, force a switch. - p.switchOut(false); - } else { - // If there are no pokemon in the back but we're not game overing, just hide the pokemon. - // This should only happen in double battles. - p.leaveField(); - } - if (allowedPokemon.length === 1 && this.scene.currentBattle.double) { - this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); - } - } - }); - - //this.scene.pushPhase(new MoveAnimTestPhase(this.scene)); - this.scene.eventTarget.dispatchEvent(new TurnInitEvent()); - - this.scene.getField().forEach((pokemon, i) => { - if (pokemon?.isActive()) { - if (pokemon.isPlayer()) { - this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon); - } - - pokemon.resetTurnData(); - - this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY)); - } - }); - - this.scene.pushPhase(new TurnStartPhase(this.scene)); - - this.end(); - } -} - -export class CommandPhase extends FieldPhase { - protected fieldIndex: integer; - - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene); - - this.fieldIndex = fieldIndex; - } - - start() { - super.start(); - - if (this.fieldIndex) { - // If we somehow are attempting to check the right pokemon but there's only one pokemon out - // Switch back to the center pokemon. This can happen rarely in double battles with mid turn switching - if (this.scene.getPlayerField().filter(p => p.isActive()).length === 1) { - this.fieldIndex = FieldPosition.CENTER; - } else { - const allyCommand = this.scene.currentBattle.turnCommands[this.fieldIndex - 1]; - if (allyCommand?.command === Command.BALL || allyCommand?.command === Command.RUN) { - this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand?.command, skip: true }; - } - } - } - - if (this.scene.currentBattle.turnCommands[this.fieldIndex]?.skip) { - return this.end(); - } - - const playerPokemon = this.scene.getPlayerField()[this.fieldIndex]; - - const moveQueue = playerPokemon.getMoveQueue(); - - while (moveQueue.length && moveQueue[0] - && moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m?.moveId === moveQueue[0].move) - || !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m?.moveId === moveQueue[0].move)]!.isUsable(playerPokemon, moveQueue[0].ignorePP))) { // TODO: is the bang correct? - moveQueue.shift(); - } - - if (moveQueue.length) { - const queuedMove = moveQueue[0]; - if (!queuedMove.move) { - this.handleCommand(Command.FIGHT, -1, false); - } else { - const moveIndex = playerPokemon.getMoveset().findIndex(m => m?.moveId === queuedMove.move); - if (moveIndex > -1 && playerPokemon.getMoveset()[moveIndex]!.isUsable(playerPokemon, queuedMove.ignorePP)) { // TODO: is the bang correct? - this.handleCommand(Command.FIGHT, moveIndex, queuedMove.ignorePP, { targets: queuedMove.targets, multiple: queuedMove.targets.length > 1 }); - } else { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - } - } - } else { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - } - } - - handleCommand(command: Command, cursor: integer, ...args: any[]): boolean { - const playerPokemon = this.scene.getPlayerField()[this.fieldIndex]; - const enemyField = this.scene.getEnemyField(); - let success: boolean; - - switch (command) { - case Command.FIGHT: - let useStruggle = false; - if (cursor === -1 || - playerPokemon.trySelectMove(cursor, args[0] as boolean) || - (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m?.isUsable(playerPokemon)).length)) { - const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor]!.moveId : Moves.NONE : Moves.STRUGGLE; // TODO: is the bang correct? - const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args }; - const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2]; - if (!moveId) { - turnCommand.targets = [this.fieldIndex]; - } - console.log(moveTargets, getPokemonNameWithAffix(playerPokemon)); - if (moveTargets.targets.length > 1 && moveTargets.multiple) { - this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); - } - if (moveTargets.targets.length <= 1 || moveTargets.multiple) { - turnCommand.move!.targets = moveTargets.targets; //TODO: is the bang correct here? - } else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) { - turnCommand.move!.targets = playerPokemon.getMoveQueue()[0].targets; //TODO: is the bang correct here? - } else { - this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); - } - this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand; - success = true; - } else if (cursor < playerPokemon.getMoveset().length) { - const move = playerPokemon.getMoveset()[cursor]!; //TODO: is this bang correct? - this.scene.ui.setMode(Mode.MESSAGE); - - // Decides between a Disabled, Not Implemented, or No PP translation message - const errorMessage = - playerPokemon.summonData.disabledMove === move.moveId ? "battle:moveDisabled" : - move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP"; - const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator - - this.scene.ui.showText(i18next.t(errorMessage, { moveName: moveName }), null, () => { - this.scene.ui.clearText(); - this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex); - }, null, true); - } - break; - case Command.BALL: - const notInDex = (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1); - if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || notInDex )) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noPokeballTrainer"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else { - const targets = this.scene.getEnemyField().filter(p => p.isActive(true)).map(p => p.getBattlerIndex()); - if (targets.length > 1) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noPokeballMulti"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else if (cursor < 5) { - const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true)); - if (targetPokemon?.isBoss() && targetPokemon?.bossSegmentIndex >= 1 && !targetPokemon?.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noPokeballStrong"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else { - this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.BALL, cursor: cursor }; - this.scene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets; - if (this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; - } - success = true; - } - } - } - break; - case Command.POKEMON: - case Command.RUN: - const isSwitch = command === Command.POKEMON; - if (!isSwitch && this.scene.arena.biomeType === Biome.END) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noEscapeForce"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:noEscapeTrainer"), null, () => { - this.scene.ui.showText("", 0); - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - }, null, true); - } else { - const trapTag = playerPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; - const trapped = new Utils.BooleanHolder(false); - const batonPass = isSwitch && args[0] as boolean; - const trappedAbMessages: string[] = []; - if (!batonPass) { - enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, true, trappedAbMessages)); - } - if (batonPass || (!trapTag && !trapped.value)) { - this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch - ? { command: Command.POKEMON, cursor: cursor, args: args } - : { command: Command.RUN }; - success = true; - if (!isSwitch && this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; - } - } else if (trapTag) { - if (trapTag.sourceMove === Moves.INGRAIN && trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId)?.isOfType(Type.GHOST)) { - success = true; - this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch - ? { command: Command.POKEMON, cursor: cursor, args: args } - : { command: Command.RUN }; - break; - } - if (!isSwitch) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - this.scene.ui.setMode(Mode.MESSAGE); - } - this.scene.ui.showText( - i18next.t("battle:noEscapePokemon", { - pokemonName: trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId) ? getPokemonNameWithAffix(this.scene.getPokemonById(trapTag.sourceId)!) : "", - moveName: trapTag.getMoveName(), - escapeVerb: isSwitch ? i18next.t("battle:escapeVerbSwitch") : i18next.t("battle:escapeVerbFlee") - }), - null, - () => { - this.scene.ui.showText("", 0); - if (!isSwitch) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - } - }, null, true); - } else if (trapped.value && trappedAbMessages.length > 0) { - if (!isSwitch) { - this.scene.ui.setMode(Mode.MESSAGE); - } - this.scene.ui.showText(trappedAbMessages[0], null, () => { - this.scene.ui.showText("", 0); - if (!isSwitch) { - this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); - } - }, null, true); - } - } - break; - } - - if (success!) { // TODO: is the bang correct? - this.end(); - } - - return success!; // TODO: is the bang correct? - } - - cancel() { - if (this.fieldIndex) { - this.scene.unshiftPhase(new CommandPhase(this.scene, 0)); - this.scene.unshiftPhase(new CommandPhase(this.scene, 1)); - this.end(); - } - } - - checkFightOverride(): boolean { - const pokemon = this.getPokemon(); - - const encoreTag = pokemon.getTag(EncoreTag) as EncoreTag; - - if (!encoreTag) { - return false; - } - - const moveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === encoreTag.moveId); - - if (moveIndex === -1 || !pokemon.getMoveset()[moveIndex]!.isUsable(pokemon)) { // TODO: is this bang correct? - return false; - } - - this.handleCommand(Command.FIGHT, moveIndex, false); - - return true; - } - - getFieldIndex(): integer { - return this.fieldIndex; - } - - getPokemon(): PlayerPokemon { - return this.scene.getPlayerField()[this.fieldIndex]; - } - - end() { - this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); - } -} - -/** - * Phase for determining an enemy AI's action for the next turn. - * During this phase, the enemy decides whether to switch (if it has a trainer) - * or to use a move from its moveset. - * - * For more information on how the Enemy AI works, see docs/enemy-ai.md - * @see {@linkcode Pokemon.getMatchupScore} - * @see {@linkcode EnemyPokemon.getNextMove} - */ -export class EnemyCommandPhase extends FieldPhase { - protected fieldIndex: integer; - - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene); - - this.fieldIndex = fieldIndex; - } - - start() { - super.start(); - - const enemyPokemon = this.scene.getEnemyField()[this.fieldIndex]; - - const battle = this.scene.currentBattle; - - const trainer = battle.trainer; - - /** - * If the enemy has a trainer, decide whether or not the enemy should switch - * to another member in its party. - * - * This block compares the active enemy Pokemon's {@linkcode Pokemon.getMatchupScore | matchup score} - * against the active player Pokemon with the enemy party's other non-fainted Pokemon. If a party - * member's matchup score is 3x the active enemy's score (or 2x for "boss" trainers), - * the enemy will switch to that Pokemon. - */ - if (trainer && !enemyPokemon.getMoveQueue().length) { - const opponents = enemyPokemon.getOpponents(); - - const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; - const trapped = new Utils.BooleanHolder(false); - opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, true, [])); - if (!trapTag && !trapped.value) { - const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true); - - if (partyMemberScores.length) { - const matchupScores = opponents.map(opp => enemyPokemon.getMatchupScore(opp)); - const matchupScore = matchupScores.reduce((total, score) => total += score, 0) / matchupScores.length; - - const sortedPartyMemberScores = trainer.getSortedPartyMemberMatchupScores(partyMemberScores); - - const switchMultiplier = 1 - (battle.enemySwitchCounter ? Math.pow(0.1, (1 / battle.enemySwitchCounter)) : 0); - - if (sortedPartyMemberScores[0][1] * switchMultiplier >= matchupScore * (trainer.config.isBoss ? 2 : 3)) { - const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores); - - battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] = - { command: Command.POKEMON, cursor: index, args: [false] }; - - battle.enemySwitchCounter++; - - return this.end(); - } - } - } - } - - /** Select a move to use (and a target to use it against, if applicable) */ - const nextMove = enemyPokemon.getNextMove(); - - this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] = - { command: Command.FIGHT, move: nextMove }; - - this.scene.currentBattle.enemySwitchCounter = Math.max(this.scene.currentBattle.enemySwitchCounter - 1, 0); - - this.end(); - } -} - -export class SelectTargetPhase extends PokemonPhase { - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene, fieldIndex); - } - - start() { - super.start(); - - const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex]; - const move = turnCommand?.move?.move; - this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => { - this.scene.ui.setMode(Mode.MESSAGE); - if (targets.length < 1) { - this.scene.currentBattle.turnCommands[this.fieldIndex] = null; - this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex)); - } else { - turnCommand!.targets = targets; //TODO: is the bang correct here? - } - if (turnCommand?.command === Command.BALL && this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; //TODO: is the bang correct here? - } - this.end(); - }); - } -} - -export class TurnStartPhase extends FieldPhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - const field = this.scene.getField(); - const order = this.getOrder(); - - const battlerBypassSpeed = {}; - - this.scene.getField(true).filter(p => p.summonData).map(p => { - const bypassSpeed = new Utils.BooleanHolder(false); - const canCheckHeldItems = new Utils.BooleanHolder(true); - applyAbAttrs(BypassSpeedChanceAbAttr, p, null, bypassSpeed); - applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, bypassSpeed, canCheckHeldItems); - if (canCheckHeldItems.value) { - this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); - } - battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed; - }); - - const moveOrder = order.slice(0); - - moveOrder.sort((a, b) => { - const aCommand = this.scene.currentBattle.turnCommands[a]; - const bCommand = this.scene.currentBattle.turnCommands[b]; - - if (aCommand?.command !== bCommand?.command) { - if (aCommand?.command === Command.FIGHT) { - return 1; - } else if (bCommand?.command === Command.FIGHT) { - return -1; - } - } else if (aCommand?.command === Command.FIGHT) { - const aMove = allMoves[aCommand.move!.move];//TODO: is the bang correct here? - const bMove = allMoves[bCommand!.move!.move];//TODO: is the bang correct here? - - const aPriority = new Utils.IntegerHolder(aMove.priority); - const bPriority = new Utils.IntegerHolder(bMove.priority); - - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? - - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? - - if (aPriority.value !== bPriority.value) { - const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value); - const hasSpeedDifference = battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value; - if (bracketDifference === 0 && hasSpeedDifference) { - return battlerBypassSpeed[a].value ? -1 : 1; - } - return aPriority.value < bPriority.value ? 1 : -1; - } - } - - if (battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) { - return battlerBypassSpeed[a].value ? -1 : 1; - } - - const aIndex = order.indexOf(a); - const bIndex = order.indexOf(b); - - return aIndex < bIndex ? -1 : aIndex > bIndex ? 1 : 0; - }); - - let orderIndex = 0; - - for (const o of moveOrder) { - - const pokemon = field[o]; - const turnCommand = this.scene.currentBattle.turnCommands[o]; - - if (turnCommand?.skip) { - continue; - } - - switch (turnCommand?.command) { - case Command.FIGHT: - const queuedMove = turnCommand.move; - pokemon.turnData.order = orderIndex++; - if (!queuedMove) { - continue; - } - const move = pokemon.getMoveset().find(m => m?.moveId === queuedMove.move) || new PokemonMove(queuedMove.move); - if (move.getMove().hasAttr(MoveHeaderAttr)) { - this.scene.unshiftPhase(new MoveHeaderPhase(this.scene, pokemon, move)); - } - if (pokemon.isPlayer()) { - if (turnCommand.cursor === -1) { - this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here? - } else { - const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP);//TODO: is the bang correct here? - this.scene.pushPhase(playerPhase); - } - } else { - this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP));//TODO: is the bang correct here? - } - break; - case Command.BALL: - this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here? - break; - case Command.POKEMON: - this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));//TODO: is the bang correct here? - break; - case Command.RUN: - let runningPokemon = pokemon; - if (this.scene.currentBattle.double) { - const playerActivePokemon = field.filter(pokemon => { - if (!!pokemon) { - return pokemon.isPlayer() && pokemon.isActive(); - } else { - return; - } - }); - // if only one pokemon is alive, use that one - if (playerActivePokemon.length > 1) { - // find which active pokemon has faster speed - const fasterPokemon = playerActivePokemon[0].getStat(Stat.SPD) > playerActivePokemon[1].getStat(Stat.SPD) ? playerActivePokemon[0] : playerActivePokemon[1]; - // check if either active pokemon has the ability "Run Away" - const hasRunAway = playerActivePokemon.find(p => p.hasAbility(Abilities.RUN_AWAY)); - runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon; - } - } - this.scene.unshiftPhase(new AttemptRunPhase(this.scene, runningPokemon.getFieldIndex())); - break; - } - } - - - this.scene.pushPhase(new WeatherEffectPhase(this.scene)); - - for (const o of order) { - if (field[o].status && field[o].status.isPostTurn()) { - this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, o)); - } - } - - this.scene.pushPhase(new BerryPhase(this.scene)); - this.scene.pushPhase(new TurnEndPhase(this.scene)); - - /** - * this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front - * of the queue and dequeues to start the next phase - * this is important since stuff like SwitchSummon, AttemptRun, AttemptCapture Phases break the "flow" and should take precedence - */ - this.end(); - } -} - -/** The phase after attacks where the pokemon eat berries */ -export class BerryPhase extends FieldPhase { - start() { - super.start(); - - this.executeForAll((pokemon) => { - const hasUsableBerry = !!this.scene.findModifier((m) => { - return m instanceof BerryModifier && m.shouldApply([pokemon]); - }, pokemon.isPlayer()); - - if (hasUsableBerry) { - const cancelled = new Utils.BooleanHolder(false); - pokemon.getOpponents().map((opp) => applyAbAttrs(PreventBerryUseAbAttr, opp, cancelled)); - - if (cancelled.value) { - pokemon.scene.queueMessage(i18next.t("abilityTriggers:preventBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); - } else { - this.scene.unshiftPhase( - new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM) - ); - - for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) { - if (berryModifier.consumed) { - if (!--berryModifier.stackCount) { - this.scene.removeModifier(berryModifier); - } else { - berryModifier.consumed = false; - } - } - this.scene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); // Announce a berry was used - } - - this.scene.updateModifiers(pokemon.isPlayer()); - - applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new Utils.BooleanHolder(false)); - } - } - }); - - this.end(); - } -} - -export class TurnEndPhase extends FieldPhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.currentBattle.incrementTurn(this.scene); - this.scene.eventTarget.dispatchEvent(new TurnEndEvent(this.scene.currentBattle.turn)); - - const handlePokemon = (pokemon: Pokemon) => { - pokemon.lapseTags(BattlerTagLapseType.TURN_END); - - if (pokemon.summonData.disabledMove && !--pokemon.summonData.disabledTurns) { - this.scene.pushPhase(new MessagePhase(this.scene, i18next.t("battle:notDisabled", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: allMoves[pokemon.summonData.disabledMove].name }))); - pokemon.summonData.disabledMove = Moves.NONE; - } - - this.scene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon); - - if (this.scene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) { - this.scene.unshiftPhase(new PokemonHealPhase(this.scene, pokemon.getBattlerIndex(), - Math.max(pokemon.getMaxHp() >> 4, 1), i18next.t("battle:turnEndHpRestore", { pokemonName: getPokemonNameWithAffix(pokemon) }), true)); - } - - if (!pokemon.isPlayer()) { - this.scene.applyModifiers(EnemyTurnHealModifier, false, pokemon); - this.scene.applyModifier(EnemyStatusEffectHealChanceModifier, false, pokemon); - } - - applyPostTurnAbAttrs(PostTurnAbAttr, pokemon); - - this.scene.applyModifiers(TurnStatusEffectModifier, pokemon.isPlayer(), pokemon); - - this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon); - - pokemon.battleSummonData.turnCount++; - }; - - this.executeForAll(handlePokemon); - - this.scene.arena.lapseTags(); - - if (this.scene.arena.weather && !this.scene.arena.weather.lapse()) { - this.scene.arena.trySetWeather(WeatherType.NONE, false); - } - - if (this.scene.arena.terrain && !this.scene.arena.terrain.lapse()) { - this.scene.arena.trySetTerrain(TerrainType.NONE, false); - } - - this.end(); - } -} - -export class BattleEndPhase extends BattlePhase { - start() { - super.start(); - - this.scene.currentBattle.addBattleScore(this.scene); - - this.scene.gameData.gameStats.battles++; - if (this.scene.currentBattle.trainer) { - this.scene.gameData.gameStats.trainersDefeated++; - } - if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave) { - this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1; - } - - // Endless graceful end - if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex >= 5850) { - this.scene.clearPhaseQueue(); - this.scene.unshiftPhase(new GameOverPhase(this.scene, true)); - } - - for (const pokemon of this.scene.getField()) { - if (pokemon) { - pokemon.resetBattleSummonData(); - } - } - - for (const pokemon of this.scene.getParty().filter(p => p.isAllowedInBattle())) { - applyPostBattleAbAttrs(PostBattleAbAttr, pokemon); - } - - if (this.scene.currentBattle.moneyScattered) { - this.scene.currentBattle.pickUpScatteredMoney(this.scene); - } - - this.scene.clearEnemyHeldItemModifiers(); - - const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[]; - for (const m of lapsingModifiers) { - const args: any[] = []; - if (m instanceof LapsingPokemonHeldItemModifier) { - args.push(this.scene.getPokemonById(m.pokemonId)); - } - if (!m.lapse(args)) { - this.scene.removeModifier(m); - } - } - - this.scene.updateModifiers().then(() => this.end()); - } -} - -export class NewBattlePhase extends BattlePhase { - start() { - super.start(); - - this.scene.newBattle(); - - this.end(); - } -} - -export class CommonAnimPhase extends PokemonPhase { - private anim: CommonAnim | null; - private targetIndex: integer | undefined; - - constructor(scene: BattleScene, battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex | undefined, anim?: CommonAnim) { - super(scene, battlerIndex); - - this.anim = anim!; // TODO: is this bang correct? - this.targetIndex = targetIndex; - } - - setAnimation(anim: CommonAnim) { - this.anim = anim; - } - - start() { - new CommonBattleAnim(this.anim, this.getPokemon(), this.targetIndex !== undefined ? (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField())[this.targetIndex] : this.getPokemon()).play(this.scene, () => { - this.end(); - }); - } -} - -export class MoveHeaderPhase extends BattlePhase { - public pokemon: Pokemon; - public move: PokemonMove; - - constructor(scene: BattleScene, pokemon: Pokemon, move: PokemonMove) { - super(scene); - - this.pokemon = pokemon; - this.move = move; - } - - canMove(): boolean { - return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon); - } - - start() { - super.start(); - - if (this.canMove()) { - applyMoveAttrs(MoveHeaderAttr, this.pokemon, null, this.move.getMove()).then(() => this.end()); - } else { - this.end(); - } - } -} - -export class MovePhase extends BattlePhase { - public pokemon: Pokemon; - public move: PokemonMove; - public targets: BattlerIndex[]; - protected followUp: boolean; - protected ignorePp: boolean; - protected failed: boolean; - protected cancelled: boolean; - - constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp?: boolean, ignorePp?: boolean) { - super(scene); - - this.pokemon = pokemon; - this.targets = targets; - this.move = move; - this.followUp = !!followUp; - this.ignorePp = !!ignorePp; - this.failed = false; - this.cancelled = false; - } - - canMove(): boolean { - return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, this.ignorePp) && !!this.targets.length; - } - - /**Signifies the current move should fail but still use PP */ - fail(): void { - this.failed = true; - } - - /**Signifies the current move should cancel and retain PP */ - cancel(): void { - this.cancelled = true; - } - - start() { - super.start(); - - console.log(Moves[this.move.moveId]); - - if (!this.canMove()) { - if (this.move.moveId && this.pokemon.summonData?.disabledMove === this.move.moveId) { - this.scene.queueMessage(`${this.move.getName()} is disabled!`); - } - if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) { // if the move PP was reduced from Spite or otherwise, the move fails - this.fail(); - this.showMoveText(); - this.showFailedText(); - } - return this.end(); - } - - if (!this.followUp) { - if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) { - this.scene.arena.setIgnoreAbilities(); - } - } else { - this.pokemon.turnData.hitsLeft = 0; // TODO: is `0` correct? - this.pokemon.turnData.hitCount = 0; // TODO: is `0` correct? - } - - // Move redirection abilities (ie. Storm Drain) only support single target moves - const moveTarget = this.targets.length === 1 - ? new Utils.IntegerHolder(this.targets[0]) - : null; - if (moveTarget) { - const oldTarget = moveTarget.value; - this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget)); - this.pokemon.getOpponents().forEach(p => { - const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag; - if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) { - moveTarget.value = p.getBattlerIndex(); - } - }); - //Check if this move is immune to being redirected, and restore its target to the intended target if it is. - if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().hasAttr(BypassRedirectAttr))) { - //If an ability prevented this move from being redirected, display its ability pop up. - if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().hasAttr(BypassRedirectAttr)) && oldTarget !== moveTarget.value) { - this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr))); - } - moveTarget.value = oldTarget; - } - this.targets[0] = moveTarget.value; - } - - // Check for counterattack moves to switch target - if (this.targets.length === 1 && this.targets[0] === BattlerIndex.ATTACKER) { - if (this.pokemon.turnData.attacksReceived.length) { - const attack = this.pokemon.turnData.attacksReceived[0]; - this.targets[0] = attack.sourceBattlerIndex; - - // account for metal burst and comeuppance hitting remaining targets in double battles - // counterattack will redirect to remaining ally if original attacker faints - if (this.scene.currentBattle.double && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)) { - if (this.scene.getField()[this.targets[0]].hp === 0) { - const opposingField = this.pokemon.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField(); - //@ts-ignore - this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex(); //TODO: fix ts-ignore - } - } - } - if (this.targets[0] === BattlerIndex.ATTACKER) { - this.fail(); // Marks the move as failed for later in doMove - this.showMoveText(); - this.showFailedText(); - } - } - - const targets = this.scene.getField(true).filter(p => { - if (this.targets.indexOf(p.getBattlerIndex()) > -1) { - return true; - } - return false; - }); - - const doMove = () => { - this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails - - this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE); - - let ppUsed = 1; - // Filter all opponents to include only those this move is targeting - const targetedOpponents = this.pokemon.getOpponents().filter(o => this.targets.includes(o.getBattlerIndex())); - for (const opponent of targetedOpponents) { - if (this.move.ppUsed + ppUsed >= this.move.getMovePp()) { // If we're already at max PP usage, stop checking - break; - } - if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) { // Accounting for abilities like Pressure - ppUsed++; - } - } - - if (!this.followUp && this.canMove() && !this.cancelled) { - this.pokemon.lapseTags(BattlerTagLapseType.MOVE); - } - - const moveQueue = this.pokemon.getMoveQueue(); - if (this.cancelled || this.failed) { - if (this.failed) { - this.move.usePp(ppUsed); // Only use PP if the move failed - this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed)); - } - - // Record a failed move so Abilities like Truant don't trigger next turn and soft-lock - this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); - - this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc. - moveQueue.shift(); // Remove the second turn of charge moves - return this.end(); - } - - this.scene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangePreMoveTrigger); - - if (this.move.moveId) { - this.showMoveText(); - } - - // This should only happen when there are no valid targets left on the field - if ((moveQueue.length && moveQueue[0].move === Moves.NONE) || !targets.length) { - this.showFailedText(); - this.cancel(); - - // Record a failed move so Abilities like Truant don't trigger next turn and soft-lock - this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); - - this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc. - - moveQueue.shift(); - return this.end(); - } - - if (!moveQueue.length || !moveQueue.shift()?.ignorePP) { // using .shift here clears out two turn moves once they've been used - this.move.usePp(ppUsed); - this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed)); - } - - if (!allMoves[this.move.moveId].hasAttr(CopyMoveAttr)) { - this.scene.currentBattle.lastMove = this.move.moveId; - } - - // Assume conditions affecting targets only apply to moves with a single target - let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove()); - const cancelled = new Utils.BooleanHolder(false); - let failedText = this.move.getMove().getFailedText(this.pokemon, targets[0], this.move.getMove(), cancelled); - if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove())) { - success = false; - } else if (success && this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.targets, this.move.getMove())) { - success = false; - if (failedText === null) { - failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain?.terrainType!); // TODO: is this bang correct? - } - } - - /** - * Trigger pokemon type change before playing the move animation - * Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse, - * regardless of whether the move successfully executes or not. - */ - if (success || [Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) { - applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); - } - - if (success) { - this.scene.unshiftPhase(this.getEffectPhase()); - } else { - this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual }); - if (!cancelled.value) { - this.showFailedText(failedText); - } - } - // Checks if Dancer ability is triggered - if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !this.followUp) { - // Pokemon with Dancer can be on either side of the battle so we check in both cases - this.scene.getPlayerField().forEach(pokemon => { - applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets); - }); - this.scene.getEnemyField().forEach(pokemon => { - applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets); - }); - } - this.end(); - }; - - if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn()) { - this.pokemon.status.incrementTurn(); - let activated = false; - let healed = false; - - switch (this.pokemon.status.effect) { - case StatusEffect.PARALYSIS: - if (!this.pokemon.randSeedInt(4)) { - activated = true; - this.cancelled = true; - } - break; - case StatusEffect.SLEEP: - applyMoveAttrs(BypassSleepAttr, this.pokemon, null, this.move.getMove()); - healed = this.pokemon.status.turnCount === this.pokemon.status.cureTurn; - activated = !healed && !this.pokemon.getTag(BattlerTagType.BYPASS_SLEEP); - this.cancelled = activated; - break; - case StatusEffect.FREEZE: - healed = !!this.move.getMove().findAttr(attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE)) || !this.pokemon.randSeedInt(5); - activated = !healed; - this.cancelled = activated; - break; - } - - if (activated) { - this.scene.queueMessage(getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); - this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1))); - doMove(); - } else { - if (healed) { - this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); - this.pokemon.resetStatus(); - this.pokemon.updateInfo(); - } - doMove(); - } - } else { - doMove(); - } - } - - getEffectPhase(): MoveEffectPhase { - return new MoveEffectPhase(this.scene, this.pokemon.getBattlerIndex(), this.targets, this.move); - } - - showMoveText(): void { - if (this.move.getMove().hasAttr(ChargeAttr)) { - const lastMove = this.pokemon.getLastXMoves() as TurnMove[]; - if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) { - this.scene.queueMessage(i18next.t("battle:useMove", { - pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), - moveName: this.move.getName() - }), 500); - return; - } - } - - if (this.pokemon.getTag(BattlerTagType.RECHARGING || BattlerTagType.INTERRUPTED)) { - return; - } - - this.scene.queueMessage(i18next.t("battle:useMove", { - pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), - moveName: this.move.getName() - }), 500); - applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents().find(() => true)!, this.move.getMove()); //TODO: is the bang correct here? - } - - showFailedText(failedText: string | null = null): void { - this.scene.queueMessage(failedText || i18next.t("battle:attackFailed")); - } - - end() { - if (!this.followUp && this.canMove()) { - this.scene.unshiftPhase(new MoveEndPhase(this.scene, this.pokemon.getBattlerIndex())); - } - - super.end(); - } -} - -export class MoveEffectPhase extends PokemonPhase { - public move: PokemonMove; - protected targets: BattlerIndex[]; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, targets: BattlerIndex[], move: PokemonMove) { - super(scene, battlerIndex); - this.move = move; - /** - * In double battles, if the right Pokemon selects a spread move and the left Pokemon dies - * with no party members available to switch in, then the right Pokemon takes the index - * of the left Pokemon and gets hit unless this is checked. - */ - if (targets.includes(battlerIndex) && this.move.getMove().moveTarget === MoveTarget.ALL_NEAR_OTHERS) { - const i = targets.indexOf(battlerIndex); - targets.splice(i, i + 1); - } - this.targets = targets; - } - - start() { - super.start(); - - /** The Pokemon using this phase's invoked move */ - const user = this.getUserPokemon(); - /** All Pokemon targeted by this phase's invoked move */ - const targets = this.getTargets(); - - /** If the user was somehow removed from the field, end this phase */ - if (!user?.isOnField()) { - return super.end(); - } - - /** - * Does an effect from this move override other effects on this turn? - * e.g. Charging moves (Fly, etc.) on their first turn of use. - */ - const overridden = new Utils.BooleanHolder(false); - /** The {@linkcode Move} object from {@linkcode allMoves} invoked by this phase */ - const move = this.move.getMove(); - - // Assume single target for override - applyMoveAttrs(OverrideMoveEffectAttr, user, this.getTarget() ?? null, move, overridden, this.move.virtual).then(() => { - // If other effects were overriden, stop this phase before they can be applied - if (overridden.value) { - return this.end(); - } - - user.lapseTags(BattlerTagLapseType.MOVE_EFFECT); - - /** - * If this phase is for the first hit of the invoked move, - * resolve the move's total hit count. This block combines the - * effects of the move itself, Parental Bond, and Multi-Lens to do so. - */ - if (user.turnData.hitsLeft === undefined) { - const hitCount = new Utils.IntegerHolder(1); - // Assume single target for multi hit - applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); - // If Parental Bond is applicable, double the hit count - applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0)); - // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user - if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { - this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); - } - // Set the user's relevant turnData fields to reflect the final hit count - user.turnData.hitCount = hitCount.value; - user.turnData.hitsLeft = hitCount.value; - } - - /** - * Log to be entered into the user's move history once the move result is resolved. - * Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully - * used in the sense of "Does it have an effect on the user?". - */ - const moveHistoryEntry = { move: this.move.moveId, targets: this.targets, result: MoveResult.PENDING, virtual: this.move.virtual }; - - /** - * Stores results of hit checks of the invoked move against all targets, organized by battler index. - * @see {@linkcode hitCheck} - */ - const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); - const hasActiveTargets = targets.some(t => t.isActive(true)); - /** - * If no targets are left for the move to hit (FAIL), or the invoked move is single-target - * (and not random target) and failed the hit check against its target (MISS), log the move - * as FAILed or MISSed (depending on the conditions above) and end this phase. - */ - if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) { - this.stopMultiHit(); - if (hasActiveTargets) { - this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getTarget()? getPokemonNameWithAffix(this.getTarget()!) : "" })); - moveHistoryEntry.result = MoveResult.MISS; - applyMoveAttrs(MissEffectAttr, user, null, move); - } else { - this.scene.queueMessage(i18next.t("battle:attackFailed")); - moveHistoryEntry.result = MoveResult.FAIL; - } - user.pushMoveHistory(moveHistoryEntry); - return this.end(); - } - - /** All move effect attributes are chained together in this array to be applied asynchronously. */ - const applyAttrs: Promise[] = []; - - // Move animation only needs one target - new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()!).play(this.scene, () => { // TODO: is the bang correct here? - /** Has the move successfully hit a target (for damage) yet? */ - let hasHit: boolean = false; - for (const target of targets) { - /** - * If the move missed a target, stop all future hits against that target - * and move on to the next target (if there is one). - */ - if (!targetHitChecks[target.getBattlerIndex()]) { - this.stopMultiHit(target); - this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); - if (moveHistoryEntry.result === MoveResult.PENDING) { - moveHistoryEntry.result = MoveResult.MISS; - } - user.pushMoveHistory(moveHistoryEntry); - applyMoveAttrs(MissEffectAttr, user, null, move); - continue; - } - - /** The {@linkcode ArenaTagSide} to which the target belongs */ - const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; - /** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */ - const hasConditionalProtectApplied = new Utils.BooleanHolder(false); - /** Does the applied conditional protection bypass Protect-ignoring effects? */ - const bypassIgnoreProtect = new Utils.BooleanHolder(false); - // If the move is not targeting a Pokemon on the user's side, try to apply conditional protection effects - if (!this.move.getMove().isAllyTarget()) { - this.scene.arena.applyTagsForSide(ConditionalProtectTag, targetSide, hasConditionalProtectApplied, user, target, move.id, bypassIgnoreProtect); - } - - /** Is the target protected by Protect, etc. or a relevant conditional protection effect? */ - const isProtected = (bypassIgnoreProtect.value || !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target)) - && (hasConditionalProtectApplied.value || target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))); - - /** Does this phase represent the invoked move's first strike? */ - const firstHit = (user.turnData.hitsLeft === user.turnData.hitCount); - - // Only log the move's result on the first strike - if (firstHit) { - user.pushMoveHistory(moveHistoryEntry); - } - - /** - * Since all fail/miss checks have applied, the move is considered successfully applied. - * It's worth noting that if the move has no effect or is protected against, this assignment - * is overwritten and the move is logged as a FAIL. - */ - moveHistoryEntry.result = MoveResult.SUCCESS; - - /** - * Stores the result of applying the invoked move to the target. - * If the target is protected, the result is always `NO_EFFECT`. - * Otherwise, the hit result is based on type effectiveness, immunities, - * and other factors that may negate the attack or status application. - * - * Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated - * (for attack moves) and the target's HP is updated. However, this isn't - * made visible to the user until the resulting {@linkcode DamagePhase} - * is invoked. - */ - const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT; - - /** Does {@linkcode hitResult} indicate that damage was dealt to the target? */ - const dealsDamage = [ - HitResult.EFFECTIVE, - HitResult.SUPER_EFFECTIVE, - HitResult.NOT_VERY_EFFECTIVE, - HitResult.ONE_HIT_KO - ].includes(hitResult); - - /** Is this target the first one hit by the move on its current strike? */ - const firstTarget = dealsDamage && !hasHit; - if (firstTarget) { - hasHit = true; - } - - /** - * If the move has no effect on the target (i.e. the target is protected or immune), - * change the logged move result to FAIL. - */ - if (hitResult === HitResult.NO_EFFECT) { - moveHistoryEntry.result = MoveResult.FAIL; - } - - /** Does this phase represent the invoked move's last strike? */ - const lastHit = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()); - - /** - * If the user can change forms by using the invoked move, - * it only changes forms after the move's last hit - * (see Relic Song's interaction with Parental Bond when used by Meloetta). - */ - if (lastHit) { - this.scene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger); - } - - /** - * Create a Promise that applys *all* effects from the invoked move's MoveEffectAttrs. - * These are ordered by trigger type (see {@linkcode MoveEffectTrigger}), and each trigger - * type requires different conditions to be met with respect to the move's hit result. - */ - applyAttrs.push(new Promise(resolve => { - // Apply all effects with PRE_MOVE triggers (if the target isn't immune to the move) - applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && hitResult !== HitResult.NO_EFFECT, - user, target, move).then(() => { - // All other effects require the move to not have failed or have been cancelled to trigger - if (hitResult !== HitResult.FAIL) { - /** Are the move's effects tied to the first turn of a charge move? */ - const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget() ?? null, move)); - /** - * If the invoked move's effects are meant to trigger during the move's "charge turn," - * ignore all effects after this point. - * Otherwise, apply all self-targeted POST_APPLY effects. - */ - Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_APPLY - && attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => { - // All effects past this point require the move to have hit the target - if (hitResult !== HitResult.NO_EFFECT) { - // Apply all non-self-targeted POST_APPLY effects - applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY - && !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => { - /** - * If the move hit, and the target doesn't have Shield Dust, - * apply the chance to flinch the target gained from King's Rock - */ - if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) { - const flinched = new Utils.BooleanHolder(false); - user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); - if (flinched.value) { - target.addTag(BattlerTagType.FLINCHED, undefined, this.move.moveId, user.id); - } - } - // If the move was not protected against, apply all HIT effects - Utils.executeIf(!isProtected && !chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT - && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => { - // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) - return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { - // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens - target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); - if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) { - target.lapseTag(BattlerTagType.SHELL_TRAP); - } - if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { - user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); - } - })).then(() => { - // Apply the user's post-attack ability effects - applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move.getMove(), hitResult).then(() => { - /** - * If the invoked move is an attack, apply the user's chance to - * steal an item from the target granted by Grip Claw - */ - if (this.move.getMove() instanceof AttackMove) { - this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target); - } - resolve(); - }); - }); - }) - ).then(() => resolve()); - }); - } else { - applyMoveAttrs(NoEffectAttr, user, null, move).then(() => resolve()); - } - }); - } else { - resolve(); - } - }); - })); - } - // Apply the move's POST_TARGET effects on the move's last hit, after all targeted effects have resolved - const postTarget = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()) ? - applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_TARGET, user, null, move) : - null; - - if (!!postTarget) { - if (applyAttrs.length) { // If there is a pending asynchronous move effect, do this after - applyAttrs[applyAttrs.length - 1]?.then(() => postTarget); - } else { // Otherwise, push a new asynchronous move effect - applyAttrs.push(postTarget); - } - } - - // Wait for all move effects to finish applying, then end this phase - Promise.allSettled(applyAttrs).then(() => this.end()); - }); - }); - } - - end() { - const move = this.move.getMove(); - move.type = move.defaultType; - const user = this.getUserPokemon(); - /** - * If this phase isn't for the invoked move's last strike, - * unshift another MoveEffectPhase for the next strike. - * Otherwise, queue a message indicating the number of times the move has struck - * (if the move has struck more than once), then apply the heal from Shell Bell - * to the user. - */ - if (user) { - if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) { - this.scene.unshiftPhase(this.getNewHitPhase()); - } else { - // Queue message for number of hits made by multi-move - // If multi-hit attack only hits once, still want to render a message - const hitsTotal = user.turnData.hitCount! - Math.max(user.turnData.hitsLeft!, 0); // TODO: are those bangs correct? - if (hitsTotal > 1 || (user.turnData.hitsLeft && user.turnData.hitsLeft > 0)) { - // If there are multiple hits, or if there are hits of the multi-hit move left - this.scene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal })); - } - this.scene.applyModifiers(HitHealModifier, this.player, user); - } - } - - super.end(); - } - - /** - * Resolves whether this phase's invoked move hits or misses the given target - * @param target {@linkcode Pokemon} the Pokemon targeted by the invoked move - * @returns `true` if the move does not miss the target; `false` otherwise - */ - hitCheck(target: Pokemon): boolean { - // Moves targeting the user and entry hazards can't miss - if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) { - return true; - } - - const user = this.getUserPokemon()!; // TODO: is this bang correct? - - // Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits. - // However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal - // multi-hit move and proceed with all hits - if (user.turnData.hitsLeft < user.turnData.hitCount) { - if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) { - return true; - } - } - - if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) { - return true; - } - - // If the user should ignore accuracy on a target, check who the user targeted last turn and see if they match - if (user.getTag(BattlerTagType.IGNORE_ACCURACY) && (user.getLastXMoves().find(() => true)?.targets || []).indexOf(target.getBattlerIndex()) !== -1) { - return true; - } - - if (target.getTag(BattlerTagType.ALWAYS_GET_HIT)) { - return true; - } - - const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); - if (semiInvulnerableTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) { - return false; - } - - const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user!, target); // TODO: is the bang correct here? - - if (moveAccuracy === -1) { - return true; - } - - const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove()); - const rand = user.randSeedInt(100, 1); - - return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct? - } - - /** Returns the {@linkcode Pokemon} using this phase's invoked move */ - getUserPokemon(): Pokemon | undefined { - if (this.battlerIndex > BattlerIndex.ENEMY_2) { - return this.scene.getPokemonById(this.battlerIndex) ?? undefined; - } - return (this.player ? this.scene.getPlayerField() : this.scene.getEnemyField())[this.fieldIndex]; - } - - /** Returns an array of all {@linkcode Pokemon} targeted by this phase's invoked move */ - getTargets(): Pokemon[] { - return this.scene.getField(true).filter(p => this.targets.indexOf(p.getBattlerIndex()) > -1); - } - - /** Returns the first target of this phase's invoked move */ - getTarget(): Pokemon | undefined { - return this.getTargets()[0]; - } - - /** - * Removes the given {@linkcode Pokemon} from this phase's target list - * @param target {@linkcode Pokemon} the Pokemon to be removed - */ - removeTarget(target: Pokemon): void { - const targetIndex = this.targets.findIndex(ind => ind === target.getBattlerIndex()); - if (targetIndex !== -1) { - this.targets.splice(this.targets.findIndex(ind => ind === target.getBattlerIndex()), 1); - } - } - - /** - * Prevents subsequent strikes of this phase's invoked move from occurring - * @param target {@linkcode Pokemon} if defined, only stop subsequent - * strikes against this Pokemon - */ - stopMultiHit(target?: Pokemon): void { - /** If given a specific target, remove the target from subsequent strikes */ - if (target) { - this.removeTarget(target); - } - /** - * If no target specified, or the specified target was the last of this move's - * targets, completely cancel all subsequent strikes. - */ - if (!target || this.targets.length === 0 ) { - this.getUserPokemon()!.turnData.hitCount = 1; // TODO: is the bang correct here? - this.getUserPokemon()!.turnData.hitsLeft = 1; // TODO: is the bang correct here? - } - } - - /** Returns a new MoveEffectPhase with the same properties as this phase */ - getNewHitPhase() { - return new MoveEffectPhase(this.scene, this.battlerIndex, this.targets, this.move); - } -} - -export class MoveEndPhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { - super(scene, battlerIndex); - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - if (pokemon.isActive(true)) { - pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE); - } - - this.scene.arena.setIgnoreAbilities(false); - - this.end(); - } -} - -export class MoveAnimTestPhase extends BattlePhase { - private moveQueue: Moves[]; - - constructor(scene: BattleScene, moveQueue?: Moves[]) { - super(scene); - - this.moveQueue = moveQueue || Utils.getEnumValues(Moves).slice(1); - } - - start() { - const moveQueue = this.moveQueue.slice(0); - this.playMoveAnim(moveQueue, true); - } - - playMoveAnim(moveQueue: Moves[], player: boolean) { - const moveId = player ? moveQueue[0] : moveQueue.shift(); - if (moveId === undefined) { - this.playMoveAnim(this.moveQueue.slice(0), true); - return; - } else if (player) { - console.log(Moves[moveId]); - } - - initMoveAnim(this.scene, moveId).then(() => { - loadMoveAnimAssets(this.scene, [moveId], true) - .then(() => { - new MoveAnim(moveId, player ? this.scene.getPlayerPokemon()! : this.scene.getEnemyPokemon()!, (player !== (allMoves[moveId] instanceof SelfStatusMove) ? this.scene.getEnemyPokemon()! : this.scene.getPlayerPokemon()!).getBattlerIndex()).play(this.scene, () => { // TODO: are the bangs correct here? - if (player) { - this.playMoveAnim(moveQueue, false); - } else { - this.playMoveAnim(moveQueue, true); - } - }); - }); - }); - } -} - -export class ShowAbilityPhase extends PokemonPhase { - private passive: boolean; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, passive: boolean = false) { - super(scene, battlerIndex); - - this.passive = passive; - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - - if (pokemon) { - this.scene.abilityBar.showAbility(pokemon, this.passive); - - if (pokemon?.battleData) { - pokemon.battleData.abilityRevealed = true; - } - } - - this.end(); - } -} - -export type StatChangeCallback = (target: Pokemon | null, changed: BattleStat[], relativeChanges: number[]) => void; - -export class StatChangePhase extends PokemonPhase { - private stats: BattleStat[]; - private selfTarget: boolean; - private levels: integer; - private showMessage: boolean; - private ignoreAbilities: boolean; - private canBeCopied: boolean; - private onChange: StatChangeCallback | null; - - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false, canBeCopied: boolean = true, onChange: StatChangeCallback | null = null) { - super(scene, battlerIndex); - - this.selfTarget = selfTarget; - this.stats = stats; - this.levels = levels; - this.showMessage = showMessage; - this.ignoreAbilities = ignoreAbilities; - this.canBeCopied = canBeCopied; - this.onChange = onChange; - } - - start() { - const pokemon = this.getPokemon(); - - let random = false; - - if (this.stats.length === 1 && this.stats[0] === BattleStat.RAND) { - this.stats[0] = this.getRandomStat(); - random = true; - } - - this.aggregateStatChanges(random); - - if (!pokemon.isActive(true)) { - return this.end(); - } - - const filteredStats = this.stats.map(s => s !== BattleStat.RAND ? s : this.getRandomStat()).filter(stat => { - const cancelled = new Utils.BooleanHolder(false); - - if (!this.selfTarget && this.levels < 0) { - this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled); - } - - if (!cancelled.value && !this.selfTarget && this.levels < 0) { - applyPreStatChangeAbAttrs(ProtectStatAbAttr, this.getPokemon(), stat, cancelled); - } - - return !cancelled.value; - }); - - const levels = new Utils.IntegerHolder(this.levels); - - if (!this.ignoreAbilities) { - applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels); - } - - const battleStats = this.getPokemon().summonData.battleStats; - const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats![stat] + levels.value, 6) : Math.max(battleStats![stat] + levels.value, -6)) - battleStats![stat]); - - this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels); - - const end = () => { - if (this.showMessage) { - const messages = this.getStatChangeMessages(filteredStats, levels.value, relLevels); - for (const message of messages) { - this.scene.queueMessage(message); - } - } - - for (const stat of filteredStats) { - pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); - } - - if (levels.value > 0 && this.canBeCopied) { - for (const opponent of pokemon.getOpponents()) { - applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value); - } - } - - applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); - - // Look for any other stat change phases; if this is the last one, do White Herb check - const existingPhase = this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex); - if (!(existingPhase instanceof StatChangePhase)) { - // Apply White Herb if needed - const whiteHerb = this.scene.applyModifier(PokemonResetNegativeStatStageModifier, this.player, pokemon) as PokemonResetNegativeStatStageModifier; - // If the White Herb was applied, consume it - if (whiteHerb) { - --whiteHerb.stackCount; - if (whiteHerb.stackCount <= 0) { - this.scene.removeModifier(whiteHerb); - } - this.scene.updateModifiers(this.player); - } - } - - pokemon.updateInfo(); - - handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end()); - }; - - if (relLevels.filter(l => l).length && this.scene.moveAnimations) { - pokemon.enableMask(); - const pokemonMaskSprite = pokemon.maskSprite; - - const tileX = (this.player ? 106 : 236) * pokemon.getSpriteScale() * this.scene.field.scale; - const tileY = ((this.player ? 148 : 84) + (levels.value >= 1 ? 160 : 0)) * pokemon.getSpriteScale() * this.scene.field.scale; - const tileWidth = 156 * this.scene.field.scale * pokemon.getSpriteScale(); - const tileHeight = 316 * this.scene.field.scale * pokemon.getSpriteScale(); - - // On increase, show the red sprite located at ATK - // On decrease, show the blue sprite located at SPD - const spriteColor = levels.value >= 1 ? BattleStat[BattleStat.ATK].toLowerCase() : BattleStat[BattleStat.SPD].toLowerCase(); - const statSprite = this.scene.add.tileSprite(tileX, tileY, tileWidth, tileHeight, "battle_stats", spriteColor); - statSprite.setPipeline(this.scene.fieldSpritePipeline); - statSprite.setAlpha(0); - statSprite.setScale(6); - statSprite.setOrigin(0.5, 1); - - this.scene.playSound(`stat_${levels.value >= 1 ? "up" : "down"}`); - - statSprite.setMask(new Phaser.Display.Masks.BitmapMask(this.scene, pokemonMaskSprite ?? undefined)); - - this.scene.tweens.add({ - targets: statSprite, - duration: 250, - alpha: 0.8375, - onComplete: () => { - this.scene.tweens.add({ - targets: statSprite, - delay: 1000, - duration: 250, - alpha: 0 - }); - } - }); - - this.scene.tweens.add({ - targets: statSprite, - duration: 1500, - y: `${levels.value >= 1 ? "-" : "+"}=${160 * 6}` - }); - - this.scene.time.delayedCall(1750, () => { - pokemon.disableMask(); - end(); - }); - } else { - end(); - } - } - - getRandomStat(): BattleStat { - const allStats = Utils.getEnumValues(BattleStat); - return this.getPokemon() ? allStats[this.getPokemon()!.randSeedInt(BattleStat.SPD + 1)] : BattleStat.ATK; // TODO: return default ATK on random? idk... - } - - aggregateStatChanges(random: boolean = false): void { - const isAccEva = [BattleStat.ACC, BattleStat.EVA].some(s => this.stats.includes(s)); - let existingPhase: StatChangePhase; - if (this.stats.length === 1) { - while ((existingPhase = (this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex && p.stats.length === 1 - && (p.stats[0] === this.stats[0] || (random && p.stats[0] === BattleStat.RAND)) - && p.selfTarget === this.selfTarget && p.showMessage === this.showMessage && p.ignoreAbilities === this.ignoreAbilities) as StatChangePhase))) { - if (existingPhase.stats[0] === BattleStat.RAND) { - existingPhase.stats[0] = this.getRandomStat(); - if (existingPhase.stats[0] !== this.stats[0]) { - continue; - } - } - this.levels += existingPhase.levels; - - if (!this.scene.tryRemovePhase(p => p === existingPhase)) { - break; - } - } - } - while ((existingPhase = (this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex && p.selfTarget === this.selfTarget - && ([BattleStat.ACC, BattleStat.EVA].some(s => p.stats.includes(s)) === isAccEva) - && p.levels === this.levels && p.showMessage === this.showMessage && p.ignoreAbilities === this.ignoreAbilities) as StatChangePhase))) { - this.stats.push(...existingPhase.stats); - if (!this.scene.tryRemovePhase(p => p === existingPhase)) { - break; - } - } - } - - getStatChangeMessages(stats: BattleStat[], levels: integer, relLevels: integer[]): string[] { - const messages: string[] = []; - - const relLevelStatIndexes = {}; - for (let rl = 0; rl < relLevels.length; rl++) { - const relLevel = relLevels[rl]; - if (!relLevelStatIndexes[relLevel]) { - relLevelStatIndexes[relLevel] = []; - } - relLevelStatIndexes[relLevel].push(rl); - } - - Object.keys(relLevelStatIndexes).forEach(rl => { - const relLevelStats = stats.filter((_, i) => relLevelStatIndexes[rl].includes(i)); - let statsFragment = ""; - - if (relLevelStats.length > 1) { - statsFragment = relLevelStats.length >= 5 - ? i18next.t("battle:stats") - : `${relLevelStats.slice(0, -1).map(s => getBattleStatName(s)).join(", ")}${relLevelStats.length > 2 ? "," : ""} ${i18next.t("battle:statsAnd")} ${getBattleStatName(relLevelStats[relLevelStats.length - 1])}`; - messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1,relLevelStats.length)); - } else { - statsFragment = getBattleStatName(relLevelStats[0]); - messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1,relLevelStats.length)); - } - }); - - return messages; - } -} - -export class WeatherEffectPhase extends CommonAnimPhase { - public weather: Weather | null; - - constructor(scene: BattleScene) { - super(scene, undefined, undefined, CommonAnim.SUNNY + ((scene?.arena?.weather?.weatherType || WeatherType.NONE) - 1)); - this.weather = scene?.arena?.weather; - } - - start() { - // Update weather state with any changes that occurred during the turn - this.weather = this.scene?.arena?.weather; - - if (!this.weather) { - this.end(); - return; - } - - this.setAnimation(CommonAnim.SUNNY + (this.weather.weatherType - 1)); - - if (this.weather.isDamaging()) { - - const cancelled = new Utils.BooleanHolder(false); - - this.executeForAll((pokemon: Pokemon) => applyPreWeatherEffectAbAttrs(SuppressWeatherEffectAbAttr, pokemon, this.weather, cancelled)); - - if (!cancelled.value) { - const inflictDamage = (pokemon: Pokemon) => { - const cancelled = new Utils.BooleanHolder(false); - - applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather , cancelled); - applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); - - if (cancelled.value) { - return; - } - - const damage = Math.ceil(pokemon.getMaxHp() / 16); - - this.scene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct? - pokemon.damageAndUpdate(damage, HitResult.EFFECTIVE, false, false, true); - }; - - this.executeForAll((pokemon: Pokemon) => { - const immune = !pokemon || !!pokemon.getTypes(true, true).filter(t => this.weather?.isTypeDamageImmune(t)).length; - if (!immune) { - inflictDamage(pokemon); - } - }); - } - } - - this.scene.ui.showText(getWeatherLapseMessage(this.weather.weatherType)!, null, () => { // TODO: is this bang correct? - this.executeForAll((pokemon: Pokemon) => applyPostWeatherLapseAbAttrs(PostWeatherLapseAbAttr, pokemon, this.weather)); - - super.start(); - }); - } -} - -export class ObtainStatusEffectPhase extends PokemonPhase { - private statusEffect: StatusEffect | undefined; - private cureTurn: integer | null; - private sourceText: string | null; - private sourcePokemon: Pokemon | null; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, statusEffect?: StatusEffect, cureTurn?: integer | null, sourceText?: string, sourcePokemon?: Pokemon) { - super(scene, battlerIndex); - - this.statusEffect = statusEffect; - this.cureTurn = cureTurn!; // TODO: is this bang correct? - this.sourceText = sourceText!; // TODO: is this bang correct? - this.sourcePokemon = sourcePokemon!; // For tracking which Pokemon caused the status effect // TODO: is this bang correct? - } - - start() { - const pokemon = this.getPokemon(); - if (!pokemon?.status) { - if (pokemon?.trySetStatus(this.statusEffect, false, this.sourcePokemon)) { - if (this.cureTurn) { - pokemon.status!.cureTurn = this.cureTurn; // TODO: is this bang correct? - } - pokemon.updateInfo(true); - new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(this.scene, () => { - this.scene.queueMessage(getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined)); - if (pokemon.status?.isPostTurn()) { - this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, this.battlerIndex)); - } - this.end(); - }); - return; - } - } else if (pokemon.status.effect === this.statusEffect) { - this.scene.queueMessage(getStatusEffectOverlapText(this.statusEffect, getPokemonNameWithAffix(pokemon))); - } - this.end(); - } -} - -export class PostTurnStatusEffectPhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { - super(scene, battlerIndex); - } - - start() { - const pokemon = this.getPokemon(); - if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn()) { - pokemon.status.incrementTurn(); - const cancelled = new Utils.BooleanHolder(false); - applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); - applyAbAttrs(BlockStatusDamageAbAttr, pokemon, cancelled); - - if (!cancelled.value) { - this.scene.queueMessage(getStatusEffectActivationText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); - const damage = new Utils.NumberHolder(0); - switch (pokemon.status.effect) { - case StatusEffect.POISON: - damage.value = Math.max(pokemon.getMaxHp() >> 3, 1); - break; - case StatusEffect.TOXIC: - damage.value = Math.max(Math.floor((pokemon.getMaxHp() / 16) * pokemon.status.turnCount), 1); - break; - case StatusEffect.BURN: - damage.value = Math.max(pokemon.getMaxHp() >> 4, 1); - applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, damage); - break; - } - if (damage.value) { - // Set preventEndure flag to avoid pokemon surviving thanks to focus band, sturdy, endure ... - this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage.value, false, true)); - pokemon.updateInfo(); - } - new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end()); - } else { - this.end(); - } - } else { - this.end(); - } - } - - override end() { - if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { - this.scene.initFinalBossPhaseTwo(this.getPokemon()); - } else { - super.end(); - } - } -} - -export class MessagePhase extends Phase { - private text: string; - private callbackDelay: integer | null; - private prompt: boolean | null; - private promptDelay: integer | null; - - constructor(scene: BattleScene, text: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { - super(scene); - - this.text = text; - this.callbackDelay = callbackDelay!; // TODO: is this bang correct? - this.prompt = prompt!; // TODO: is this bang correct? - this.promptDelay = promptDelay!; // TODO: is this bang correct? - } - - start() { - super.start(); - - if (this.text.indexOf("$") > -1) { - const pageIndex = this.text.indexOf("$"); - this.scene.unshiftPhase(new MessagePhase(this.scene, this.text.slice(pageIndex + 1), this.callbackDelay, this.prompt, this.promptDelay)); - this.text = this.text.slice(0, pageIndex).trim(); - } - - this.scene.ui.showText(this.text, null, () => this.end(), this.callbackDelay || (this.prompt ? 0 : 1500), this.prompt, this.promptDelay); - } - - end() { - if (this.scene.abilityBar.shown) { - this.scene.abilityBar.hide(); - } - - super.end(); - } -} - -export class DamagePhase extends PokemonPhase { - private amount: integer; - private damageResult: DamageResult; - private critical: boolean; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, amount: integer, damageResult?: DamageResult, critical: boolean = false) { - super(scene, battlerIndex); - - this.amount = amount; - this.damageResult = damageResult || HitResult.EFFECTIVE; - this.critical = critical; - } - - start() { - super.start(); - - if (this.damageResult === HitResult.ONE_HIT_KO) { - if (this.scene.moveAnimations) { - this.scene.toggleInvert(true); - } - this.scene.time.delayedCall(Utils.fixedInt(1000), () => { - this.scene.toggleInvert(false); - this.applyDamage(); - }); - return; - } - - this.applyDamage(); - } - - updateAmount(amount: integer): void { - this.amount = amount; - } - - applyDamage() { - switch (this.damageResult) { - case HitResult.EFFECTIVE: - this.scene.playSound("hit"); - break; - case HitResult.SUPER_EFFECTIVE: - case HitResult.ONE_HIT_KO: - this.scene.playSound("hit_strong"); - break; - case HitResult.NOT_VERY_EFFECTIVE: - this.scene.playSound("hit_weak"); - break; - } - - if (this.amount) { - this.scene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical); - } - - if (this.damageResult !== HitResult.OTHER) { - const flashTimer = this.scene.time.addEvent({ - delay: 100, - repeat: 5, - startAt: 200, - callback: () => { - this.getPokemon().getSprite().setVisible(flashTimer.repeatCount % 2 === 0); - if (!flashTimer.repeatCount) { - this.getPokemon().updateInfo().then(() => this.end()); - } - } - }); - } else { - this.getPokemon().updateInfo().then(() => this.end()); - } - } - - override end() { - if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { - this.scene.initFinalBossPhaseTwo(this.getPokemon()); - } else { - super.end(); - } - } -} - -export class FaintPhase extends PokemonPhase { - private preventEndure: boolean; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, preventEndure?: boolean) { - super(scene, battlerIndex); - - this.preventEndure = preventEndure!; // TODO: is this bang correct? - } - - start() { - super.start(); - - if (!this.preventEndure) { - const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, this.getPokemon()) as PokemonInstantReviveModifier; - - if (instantReviveModifier) { - if (!--instantReviveModifier.stackCount) { - this.scene.removeModifier(instantReviveModifier); - } - this.scene.updateModifiers(this.player); - return this.end(); - } - } - - if (!this.tryOverrideForBattleSpec()) { - this.doFaint(); - } - } - - doFaint(): void { - const pokemon = this.getPokemon(); - - - // Track total times pokemon have been KO'd for supreme overlord/last respects - if (pokemon.isPlayer()) { - this.scene.currentBattle.playerFaints += 1; - } else { - this.scene.currentBattle.enemyFaints += 1; - } - - this.scene.queueMessage(i18next.t("battle:fainted", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, true); - - if (pokemon.turnData?.attacksReceived?.length) { - const lastAttack = pokemon.turnData.attacksReceived[0]; - applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct? - } - - const alivePlayField = this.scene.getField(true); - alivePlayField.forEach(p => applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon)); - if (pokemon.turnData?.attacksReceived?.length) { - const defeatSource = this.scene.getPokemonById(pokemon.turnData.attacksReceived[0].sourceId); - if (defeatSource?.isOnField()) { - applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource); - const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move]; - const pvattrs = pvmove.getAttrs(PostVictoryStatChangeAttr); - if (pvattrs.length) { - for (const pvattr of pvattrs) { - pvattr.applyPostVictory(defeatSource, defeatSource, pvmove); - } - } - } - } - - if (this.player) { - /** The total number of Pokemon in the player's party that can legally fight */ - const legalPlayerPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); - /** The total number of legal player Pokemon that aren't currently on the field */ - const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); - if (!legalPlayerPokemon.length) { - /** If the player doesn't have any legal Pokemon, end the game */ - this.scene.unshiftPhase(new GameOverPhase(this.scene)); - } else if (this.scene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) { - /** - * If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon - * is already on the field, unshift a phase that moves that Pokemon to center position. - */ - this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); - } else if (legalPlayerPartyPokemon.length > 0) { - /** - * If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field, - * push a phase that prompts the player to summon a Pokemon from their party. - */ - this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false)); - } - } else { - this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex)); - if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length; - if (hasReservePartyMember) { - this.scene.pushPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, -1, false, false, false)); - } - } - } - - // in double battles redirect potential moves off fainted pokemon - if (this.scene.currentBattle.double) { - const allyPokemon = pokemon.getAlly(); - this.scene.redirectPokemonMoves(pokemon, allyPokemon); - } - - pokemon.lapseTags(BattlerTagLapseType.FAINT); - this.scene.getField(true).filter(p => p !== pokemon).forEach(p => p.removeTagsBySourceId(pokemon.id)); - - pokemon.faintCry(() => { - if (pokemon instanceof PlayerPokemon) { - pokemon.addFriendship(-10); - } - pokemon.hideInfo(); - this.scene.playSound("faint"); - this.scene.tweens.add({ - targets: pokemon, - duration: 500, - y: pokemon.y + 150, - ease: "Sine.easeIn", - onComplete: () => { - pokemon.setVisible(false); - pokemon.y -= 150; - pokemon.trySetStatus(StatusEffect.FAINT); - if (pokemon.isPlayer()) { - this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon); - } else { - this.scene.addFaintedEnemyScore(pokemon as EnemyPokemon); - this.scene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon); - } - this.scene.field.remove(pokemon); - this.end(); - } - }); - }); - } - - tryOverrideForBattleSpec(): boolean { - switch (this.scene.currentBattle.battleSpec) { - case BattleSpec.FINAL_BOSS: - if (!this.player) { - const enemy = this.getPokemon(); - if (enemy.formIndex) { - this.scene.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].secondStageWin, enemy.species.name, null, () => this.doFaint()); - } else { - // Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase - enemy.hp++; - this.scene.unshiftPhase(new DamagePhase(this.scene, enemy.getBattlerIndex(), 0, HitResult.OTHER)); - this.end(); - } - return true; - } - } - - return false; - } -} - -export class VictoryPhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { - super(scene, battlerIndex); - } - - start() { - super.start(); - - this.scene.gameData.gameStats.pokemonDefeated++; - - const participantIds = this.scene.currentBattle.playerParticipantIds; - const party = this.scene.getParty(); - const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier; - const expBalanceModifier = this.scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier; - const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier; - const nonFaintedPartyMembers = party.filter(p => p.hp); - const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.scene.getMaxExpLevel()); - const partyMemberExp: number[] = []; - - if (participantIds.size) { - let expValue = this.getPokemon().getExpValue(); - if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - expValue = Math.floor(expValue * 1.5); - } - for (const partyMember of nonFaintedPartyMembers) { - const pId = partyMember.id; - const participated = participantIds.has(pId); - if (participated) { - partyMember.addFriendship(2); - } - if (!expPartyMembers.includes(partyMember)) { - continue; - } - if (!participated && !expShareModifier) { - partyMemberExp.push(0); - continue; - } - let expMultiplier = 0; - if (participated) { - expMultiplier += (1 / participantIds.size); - if (participantIds.size > 1 && multipleParticipantExpBonusModifier) { - expMultiplier += multipleParticipantExpBonusModifier.getStackCount() * 0.2; - } - } else if (expShareModifier) { - expMultiplier += (expShareModifier.getStackCount() * 0.2) / participantIds.size; - } - if (partyMember.pokerus) { - expMultiplier *= 1.5; - } - if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) { - expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; - } - const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); - this.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); - partyMemberExp.push(Math.floor(pokemonExp.value)); - } - - if (expBalanceModifier) { - let totalLevel = 0; - let totalExp = 0; - expPartyMembers.forEach((expPartyMember, epm) => { - totalExp += partyMemberExp[epm]; - totalLevel += expPartyMember.level; - }); - - const medianLevel = Math.floor(totalLevel / expPartyMembers.length); - - const recipientExpPartyMemberIndexes: number[] = []; - expPartyMembers.forEach((expPartyMember, epm) => { - if (expPartyMember.level <= medianLevel) { - recipientExpPartyMemberIndexes.push(epm); - } - }); - - const splitExp = Math.floor(totalExp / recipientExpPartyMemberIndexes.length); - - expPartyMembers.forEach((_partyMember, pm) => { - partyMemberExp[pm] = Phaser.Math.Linear(partyMemberExp[pm], recipientExpPartyMemberIndexes.indexOf(pm) > -1 ? splitExp : 0, 0.2 * expBalanceModifier.getStackCount()); - }); - } - - for (let pm = 0; pm < expPartyMembers.length; pm++) { - const exp = partyMemberExp[pm]; - - if (exp) { - const partyMemberIndex = party.indexOf(expPartyMembers[pm]); - this.scene.unshiftPhase(expPartyMembers[pm].isOnField() ? new ExpPhase(this.scene, partyMemberIndex, exp) : new ShowPartyExpBarPhase(this.scene, partyMemberIndex, exp)); - } - } - } - - if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType ? !p?.isFainted(true) : p.isOnField())) { - this.scene.pushPhase(new BattleEndPhase(this.scene)); - if (this.scene.currentBattle.battleType === BattleType.TRAINER) { - this.scene.pushPhase(new TrainerVictoryPhase(this.scene)); - } - if (this.scene.gameMode.isEndless || !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) { - this.scene.pushPhase(new EggLapsePhase(this.scene)); - if (this.scene.currentBattle.waveIndex % 10) { - this.scene.pushPhase(new SelectModifierPhase(this.scene)); - } else if (this.scene.gameMode.isDaily) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_CHARM)); - if (this.scene.currentBattle.waveIndex > 10 && !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); - } - } else { - const superExpWave = !this.scene.gameMode.isEndless ? (this.scene.offsetGym ? 0 : 20) : 10; - if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex === 10) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_SHARE)); - } - if (this.scene.currentBattle.waveIndex <= 750 && (this.scene.currentBattle.waveIndex <= 500 || (this.scene.currentBattle.waveIndex % 30) === superExpWave)) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, (this.scene.currentBattle.waveIndex % 30) !== superExpWave || this.scene.currentBattle.waveIndex > 250 ? modifierTypes.EXP_CHARM : modifierTypes.SUPER_EXP_CHARM)); - } - if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50)) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); - } - if (this.scene.gameMode.isEndless && !(this.scene.currentBattle.waveIndex % 50)) { - this.scene.pushPhase(new ModifierRewardPhase(this.scene, !(this.scene.currentBattle.waveIndex % 250) ? modifierTypes.VOUCHER_PREMIUM : modifierTypes.VOUCHER_PLUS)); - this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene)); - } - } - this.scene.pushPhase(new NewBattlePhase(this.scene)); - } else { - this.scene.currentBattle.battleType = BattleType.CLEAR; - this.scene.score += this.scene.gameMode.getClearScoreBonus(); - this.scene.updateScoreText(); - this.scene.pushPhase(new GameOverPhase(this.scene, true)); - } - } - - this.end(); - } -} - -export class TrainerVictoryPhase extends BattlePhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - this.scene.disableMenu = true; - - this.scene.playBgm(this.scene.currentBattle.trainer?.config.victoryBgm); - - this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer?.config.moneyMultiplier!)); // TODO: is this bang correct? - - const modifierRewardFuncs = this.scene.currentBattle.trainer?.config.modifierRewardFuncs!; // TODO: is this bang correct? - for (const modifierRewardFunc of modifierRewardFuncs) { - this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, modifierRewardFunc)); - } - - const trainerType = this.scene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? - if (vouchers.hasOwnProperty(TrainerType[trainerType])) { - if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer?.config.isBoss) { - this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][vouchers[TrainerType[trainerType]].voucherType])); - } - } - - this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }), null, () => { - const victoryMessages = this.scene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct? - let message: string; - this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex); - message = message!; // tell TS compiler it's defined now - - const showMessage = () => { - const originalFunc = showMessageOrEnd; - showMessageOrEnd = () => this.scene.ui.showDialogue(message, this.scene.currentBattle.trainer?.getName(), null, originalFunc); - - showMessageOrEnd(); - }; - let showMessageOrEnd = () => this.end(); - if (victoryMessages?.length) { - if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { - const originalFunc = showMessageOrEnd; - showMessageOrEnd = () => this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => originalFunc())); - this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(this.scene.currentBattle.trainer?.getKey()!, getCharVariantFromDialogue(victoryMessages[0])).then(() => showMessage())); // TODO: is this bang correct? - } else { - showMessage(); - } - } else { - showMessageOrEnd(); - } - }, null, true); - - this.showEnemyTrainer(); - } -} - -export class MoneyRewardPhase extends BattlePhase { - private moneyMultiplier: number; - - constructor(scene: BattleScene, moneyMultiplier: number) { - super(scene); - - this.moneyMultiplier = moneyMultiplier; - } - - start() { - const moneyAmount = new Utils.IntegerHolder(this.scene.getWaveMoneyAmount(this.moneyMultiplier)); - - this.scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); - - if (this.scene.arena.getTag(ArenaTagType.HAPPY_HOUR)) { - moneyAmount.value *= 2; - } - - this.scene.addMoney(moneyAmount.value); - - const userLocale = navigator.language || "en-US"; - const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); - const message = i18next.t("battle:moneyWon", { moneyAmount: formattedMoneyAmount }); - - this.scene.ui.showText(message, null, () => this.end(), null, true); - } -} - -export class ModifierRewardPhase extends BattlePhase { - protected modifierType: ModifierType; - - constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc) { - super(scene); - - this.modifierType = getModifierType(modifierTypeFunc); - } - - start() { - super.start(); - - this.doReward().then(() => this.end()); - } - - doReward(): Promise { - return new Promise(resolve => { - const newModifier = this.modifierType.newModifier(); - this.scene.addModifier(newModifier).then(() => { - this.scene.playSound("item_fanfare"); - this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => resolve(), null, true); - }); - }); - } -} - -export class GameOverModifierRewardPhase extends ModifierRewardPhase { - constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc) { - super(scene, modifierTypeFunc); - } - - doReward(): Promise { - return new Promise(resolve => { - const newModifier = this.modifierType.newModifier(); - this.scene.addModifier(newModifier).then(() => { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.fadeIn(250).then(() => { - this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => { - this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); - resolve(); - }, null, true, 1500); - }); - }); - }); - } -} - -export class RibbonModifierRewardPhase extends ModifierRewardPhase { - private species: PokemonSpecies; - - constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc, species: PokemonSpecies) { - super(scene, modifierTypeFunc); - - this.species = species; - } - - doReward(): Promise { - return new Promise(resolve => { - const newModifier = this.modifierType.newModifier(); - this.scene.addModifier(newModifier).then(() => { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:beatModeFirstTime", { - speciesName: this.species.name, - gameMode: this.scene.gameMode.getName(), - newModifier: newModifier?.type.name - }), null, () => { - resolve(); - }, null, true, 1500); - }); - }); - } -} - -export class GameOverPhase extends BattlePhase { - private victory: boolean; - private firstRibbons: PokemonSpecies[] = []; - - constructor(scene: BattleScene, victory?: boolean) { - super(scene); - - this.victory = !!victory; - } - - start() { - super.start(); - - // Failsafe if players somehow skip floor 200 in classic mode - if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) { - this.victory = true; - } - - if (this.victory && this.scene.gameMode.isEndless) { - this.scene.ui.showDialogue(i18next.t("PGMmiscDialogue:ending_endless"), i18next.t("PGMmiscDialogue:ending_name"), 0, () => this.handleGameOver()); - } else if (this.victory || !this.scene.enableRetries) { - this.handleGameOver(); - } else { - this.scene.ui.showText(i18next.t("battle:retryBattle"), null, () => { - this.scene.ui.setMode(Mode.CONFIRM, () => { - this.scene.ui.fadeOut(1250).then(() => { - this.scene.reset(); - this.scene.clearPhaseQueue(); - this.scene.gameData.loadSession(this.scene, this.scene.sessionSlotId).then(() => { - this.scene.pushPhase(new EncounterPhase(this.scene, true)); - - const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; - - this.scene.pushPhase(new SummonPhase(this.scene, 0)); - if (this.scene.currentBattle.double && availablePartyMembers > 1) { - this.scene.pushPhase(new SummonPhase(this.scene, 1)); - } - if (this.scene.currentBattle.waveIndex > 1 && this.scene.currentBattle.battleType !== BattleType.TRAINER) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); - if (this.scene.currentBattle.double && availablePartyMembers > 1) { - this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); - } - } - - this.scene.ui.fadeIn(1250); - this.end(); - }); - }); - }, () => this.handleGameOver(), false, 0, 0, 1000); - }); - } - } - - handleGameOver(): void { - const doGameOver = (newClear: boolean) => { - this.scene.disableMenu = true; - this.scene.time.delayedCall(1000, () => { - let firstClear = false; - if (this.victory && newClear) { - if (this.scene.gameMode.isClassic) { - firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY); - this.scene.validateAchv(achvs.UNEVOLVED_CLASSIC_VICTORY); - this.scene.gameData.gameStats.sessionsWon++; - for (const pokemon of this.scene.getParty()) { - this.awardRibbon(pokemon); - - if (pokemon.species.getRootSpeciesId() !== pokemon.species.getRootSpeciesId(true)) { - this.awardRibbon(pokemon, true); - } - } - } else if (this.scene.gameMode.isDaily && newClear) { - this.scene.gameData.gameStats.dailyRunSessionsWon++; - } - } - const fadeDuration = this.victory ? 10000 : 5000; - this.scene.fadeOutBgm(fadeDuration, true); - const activeBattlers = this.scene.getField().filter(p => p?.isActive(true)); - activeBattlers.map(p => p.hideInfo()); - this.scene.ui.fadeOut(fadeDuration).then(() => { - activeBattlers.map(a => a.setVisible(false)); - this.scene.setFieldScale(1, true); - this.scene.clearPhaseQueue(); - this.scene.ui.clearText(); - - if (this.victory && this.scene.gameMode.isChallenge) { - this.scene.gameMode.challenges.forEach(c => this.scene.validateAchvs(ChallengeAchv, c)); - } - - const clear = (endCardPhase?: EndCardPhase) => { - if (newClear) { - this.handleUnlocks(); - } - if (this.victory && newClear) { - for (const species of this.firstRibbons) { - this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species)); - } - if (!firstClear) { - this.scene.unshiftPhase(new GameOverModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PREMIUM)); - } - } - this.scene.pushPhase(new PostGameOverPhase(this.scene, endCardPhase)); - this.end(); - }; - - if (this.victory && this.scene.gameMode.isClassic) { - const message = miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1]; - - if (!this.scene.ui.shouldSkipDialogue(message)) { - this.scene.ui.fadeIn(500).then(() => { - this.scene.charSprite.showCharacter(`rival_${this.scene.gameData.gender === PlayerGender.FEMALE ? "m" : "f"}`, getCharVariantFromDialogue(miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1])).then(() => { - this.scene.ui.showDialogue(message, this.scene.gameData.gender === PlayerGender.FEMALE ? trainerConfigs[TrainerType.RIVAL].name : trainerConfigs[TrainerType.RIVAL].nameFemale, null, () => { - this.scene.ui.fadeOut(500).then(() => { - this.scene.charSprite.hide().then(() => { - const endCardPhase = new EndCardPhase(this.scene); - this.scene.unshiftPhase(endCardPhase); - clear(endCardPhase); - }); - }); - }); - }); - }); - } else { - const endCardPhase = new EndCardPhase(this.scene); - this.scene.unshiftPhase(endCardPhase); - clear(endCardPhase); - } - } else { - clear(); - } - }); - }); - }; - - /* Added a local check to see if the game is running offline on victory - If Online, execute apiFetch as intended - If Offline, execute offlineNewClear(), a localStorage implementation of newClear daily run checks */ - if (this.victory) { - if (!Utils.isLocal) { - Utils.apiFetch(`savedata/session/newclear?slot=${this.scene.sessionSlotId}&clientSessionId=${clientSessionId}`, true) - .then(response => response.json()) - .then(newClear => doGameOver(newClear)); - } else { - this.scene.gameData.offlineNewClear(this.scene).then(result => { - doGameOver(result); - }); - } - } else { - doGameOver(false); - } - } - - handleUnlocks(): void { - if (this.victory && this.scene.gameMode.isClassic) { - if (!this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { - this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.ENDLESS_MODE)); - } - if (this.scene.getParty().filter(p => p.fusionSpecies).length && !this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { - this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.SPLICED_ENDLESS_MODE)); - } - if (!this.scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) { - this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); - } - if (!this.scene.gameData.unlocks[Unlockables.EVIOLITE] && this.scene.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)) { - this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.EVIOLITE)); - } - } - } - - awardRibbon(pokemon: Pokemon, forStarter: boolean = false): void { - const speciesId = getPokemonSpecies(pokemon.species.speciesId); - const speciesRibbonCount = this.scene.gameData.incrementRibbonCount(speciesId, forStarter); - // first time classic win, award voucher - if (speciesRibbonCount === 1) { - this.firstRibbons.push(getPokemonSpecies(pokemon.species.getRootSpeciesId(forStarter))); - } - } -} - -export class EndCardPhase extends Phase { - public endCard: Phaser.GameObjects.Image; - public text: Phaser.GameObjects.Text; - - constructor(scene: BattleScene) { - super(scene); - } - - start(): void { - super.start(); - - this.scene.ui.getMessageHandler().bg.setVisible(false); - this.scene.ui.getMessageHandler().nameBoxContainer.setVisible(false); - - this.endCard = this.scene.add.image(0, 0, `end_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}`); - this.endCard.setOrigin(0); - this.endCard.setScale(0.5); - this.scene.field.add(this.endCard); - - this.text = addTextObject(this.scene, this.scene.game.canvas.width / 12, (this.scene.game.canvas.height / 6) - 16, i18next.t("battle:congratulations"), TextStyle.SUMMARY, { fontSize: "128px" }); - this.text.setOrigin(0.5); - this.scene.field.add(this.text); - - this.scene.ui.clearText(); - - this.scene.ui.fadeIn(1000).then(() => { - - this.scene.ui.showText("", null, () => { - this.scene.ui.getMessageHandler().bg.setVisible(true); - this.end(); - }, null, true); - }); - } -} - -export class UnlockPhase extends Phase { - private unlockable: Unlockables; - - constructor(scene: BattleScene, unlockable: Unlockables) { - super(scene); - - this.unlockable = unlockable; - } - - start(): void { - this.scene.time.delayedCall(2000, () => { - this.scene.gameData.unlocks[this.unlockable] = true; - this.scene.playSound("level_up_fanfare"); - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t("battle:unlockedSomething", { unlockedThing: getUnlockableName(this.unlockable) }), null, () => { - this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); - this.end(); - }, null, true, 1500); - }); - } -} - -export class PostGameOverPhase extends Phase { - private endCardPhase: EndCardPhase | null; - - constructor(scene: BattleScene, endCardPhase?: EndCardPhase) { - super(scene); - - this.endCardPhase = endCardPhase!; // TODO: is this bang correct? - } - - start() { - super.start(); - - const saveAndReset = () => { - this.scene.gameData.saveAll(this.scene, true, true, true).then(success => { - if (!success) { - return this.scene.reset(true); - } - this.scene.gameData.tryClearSession(this.scene, this.scene.sessionSlotId).then((success: boolean | [boolean, boolean]) => { - if (!success[0]) { - return this.scene.reset(true); - } - this.scene.reset(); - this.scene.unshiftPhase(new TitlePhase(this.scene)); - this.end(); - }); - }); - }; - - if (this.endCardPhase) { - this.scene.ui.fadeOut(500).then(() => { - this.scene.ui.getMessageHandler().bg.setVisible(true); - - this.endCardPhase?.endCard.destroy(); - this.endCardPhase?.text.destroy(); - saveAndReset(); - }); - } else { - saveAndReset(); - } - } -} - -/** - * Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase} - * for the player (if a switch would be valid for the current battle state). - */ -export class SwitchPhase extends BattlePhase { - protected fieldIndex: integer; - private isModal: boolean; - private doReturn: boolean; - - /** - * Creates a new SwitchPhase - * @param scene {@linkcode BattleScene} Current battle scene - * @param fieldIndex Field index to switch out - * @param isModal Indicates if the switch should be forced (true) or is - * optional (false). - * @param doReturn Indicates if the party member on the field should be - * recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}. - */ - constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) { - super(scene); - - this.fieldIndex = fieldIndex; - this.isModal = isModal; - this.doReturn = doReturn; - } - - start() { - super.start(); - - // Skip modal switch if impossible (no remaining party members that aren't in battle) - if (this.isModal && !this.scene.getParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) { - return super.end(); - } - - // Skip if the fainted party member has been revived already. doReturn is - // only passed as `false` from FaintPhase (as opposed to other usages such - // as ForceSwitchOutAttr or CheckSwitchPhase), so we only want to check this - // if the mon should have already been returned but is still alive and well - // on the field. see also; battle.test.ts - if (this.isModal && !this.doReturn && !this.scene.getParty()[this.fieldIndex].isFainted()) { - return super.end(); - } - - // Check if there is any space still in field - if (this.isModal && this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) { - return super.end(); - } - - // Override field index to 0 in case of double battle where 2/3 remaining legal party members fainted at once - const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? this.fieldIndex : 0; - - this.scene.ui.setMode(Mode.PARTY, this.isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH, fieldIndex, (slotIndex: integer, option: PartyOption) => { - if (slotIndex >= this.scene.currentBattle.getBattlerCount() && slotIndex < 6) { - this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, fieldIndex, slotIndex, this.doReturn, option === PartyOption.PASS_BATON)); - } - this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); - }, PartyUiHandler.FilterNonFainted); - } -} - -export class ExpPhase extends PlayerPartyMemberPokemonPhase { - private expValue: number; - - constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) { - super(scene, partyMemberIndex); - - this.expValue = expValue; - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - const exp = new Utils.NumberHolder(this.expValue); - this.scene.applyModifiers(ExpBoosterModifier, true, exp); - exp.value = Math.floor(exp.value); - this.scene.ui.showText(i18next.t("battle:expGain", { pokemonName: getPokemonNameWithAffix(pokemon), exp: exp.value }), null, () => { - const lastLevel = pokemon.level; - pokemon.addExp(exp.value); - const newLevel = pokemon.level; - if (newLevel > lastLevel) { - this.scene.unshiftPhase(new LevelUpPhase(this.scene, this.partyMemberIndex, lastLevel, newLevel)); - } - pokemon.updateInfo().then(() => this.end()); - }, null, true); - } -} - -export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase { - private expValue: number; - - constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) { - super(scene, partyMemberIndex); - - this.expValue = expValue; - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - const exp = new Utils.NumberHolder(this.expValue); - this.scene.applyModifiers(ExpBoosterModifier, true, exp); - exp.value = Math.floor(exp.value); - - const lastLevel = pokemon.level; - pokemon.addExp(exp.value); - const newLevel = pokemon.level; - if (newLevel > lastLevel) { - this.scene.unshiftPhase(new LevelUpPhase(this.scene, this.partyMemberIndex, lastLevel, newLevel)); - } - this.scene.unshiftPhase(new HidePartyExpBarPhase(this.scene)); - pokemon.updateInfo(); - - if (this.scene.expParty === ExpNotification.SKIP) { - this.end(); - } else if (this.scene.expParty === ExpNotification.ONLY_LEVEL_UP) { - if (newLevel > lastLevel) { // this means if we level up - // instead of displaying the exp gain in the small frame, we display the new level - // we use the same method for mode 0 & 1, by giving a parameter saying to display the exp or the level - this.scene.partyExpBar.showPokemonExp(pokemon, exp.value, this.scene.expParty === ExpNotification.ONLY_LEVEL_UP, newLevel).then(() => { - setTimeout(() => this.end(), 800 / Math.pow(2, this.scene.expGainsSpeed)); - }); - } else { - this.end(); - } - } else if (this.scene.expGainsSpeed < 3) { - this.scene.partyExpBar.showPokemonExp(pokemon, exp.value, false, newLevel).then(() => { - setTimeout(() => this.end(), 500 / Math.pow(2, this.scene.expGainsSpeed)); - }); - } else { - this.end(); - } - - } -} - -export class HidePartyExpBarPhase extends BattlePhase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.partyExpBar.hide().then(() => this.end()); - } -} - -export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { - private lastLevel: integer; - private level: integer; - - constructor(scene: BattleScene, partyMemberIndex: integer, lastLevel: integer, level: integer) { - super(scene, partyMemberIndex); - - this.lastLevel = lastLevel; - this.level = level; - this.scene = scene; - } - - start() { - super.start(); - - if (this.level > this.scene.gameData.gameStats.highestLevel) { - this.scene.gameData.gameStats.highestLevel = this.level; - } - - this.scene.validateAchvs(LevelAchv, new Utils.IntegerHolder(this.level)); - - const pokemon = this.getPokemon(); - const prevStats = pokemon.stats.slice(0); - pokemon.calculateStats(); - pokemon.updateInfo(); - if (this.scene.expParty === ExpNotification.DEFAULT) { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.showText(i18next.t("battle:levelUp", { pokemonName: getPokemonNameWithAffix(this.getPokemon()), level: this.level }), null, () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()), null, true); - } else if (this.scene.expParty === ExpNotification.SKIP) { - this.end(); - } else { - // we still want to display the stats if activated - this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()); - } - if (this.lastLevel < 100) { // this feels like an unnecessary optimization - const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1); - for (const lm of levelMoves) { - this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm[1])); - } - } - if (!pokemon.pauseEvolutions) { - const evolution = pokemon.getEvolution(); - if (evolution) { - this.scene.unshiftPhase(new EvolutionPhase(this.scene, pokemon as PlayerPokemon, evolution, this.lastLevel)); - } - } - } -} - -export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { - private moveId: Moves; - - constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves) { - super(scene, partyMemberIndex); - - this.moveId = moveId; - } - - start() { - super.start(); - - const pokemon = this.getPokemon(); - const move = allMoves[this.moveId]; - - const existingMoveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === move.id); - - if (existingMoveIndex > -1) { - return this.end(); - } - - const emptyMoveIndex = pokemon.getMoveset().length < 4 - ? pokemon.getMoveset().length - : pokemon.getMoveset().findIndex(m => m === null); - - const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler - ? Mode.EVOLUTION_SCENE - : Mode.MESSAGE; - - if (emptyMoveIndex > -1) { - pokemon.setMove(emptyMoveIndex, this.moveId); - initMoveAnim(this.scene, this.moveId).then(() => { - loadMoveAnimAssets(this.scene, [this.moveId], true) - .then(() => { - this.scene.ui.setMode(messageMode).then(() => { - this.scene.playSound("level_up_fanfare"); - this.scene.ui.showText(i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => { - this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true); - this.end(); - }, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true); - }); - }); - }); - } else { - this.scene.ui.setMode(messageMode).then(() => { - this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => { - this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { - this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => { - const noHandler = () => { - this.scene.ui.setMode(messageMode).then(() => { - this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => { - this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { - this.scene.ui.setMode(messageMode); - this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true); - }, () => { - this.scene.ui.setMode(messageMode); - this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); - this.end(); - }); - }); - }); - }; - this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { - this.scene.ui.setMode(messageMode); - this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => { - this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => { - if (moveIndex === 4) { - noHandler(); - return; - } - this.scene.ui.setMode(messageMode).then(() => { - this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => { - this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct? - this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => { - pokemon.setMove(moveIndex, Moves.NONE); - this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); - this.end(); - }, null, true); - }, null, true); - }, null, true); - }); - }); - }, null, true); - }, noHandler); - }); - }, null, true); - }, null, true); - }); - } - } -} - -export class PokemonHealPhase extends CommonAnimPhase { - private hpHealed: integer; - private message: string | null; - private showFullHpMessage: boolean; - private skipAnim: boolean; - private revive: boolean; - private healStatus: boolean; - private preventFullHeal: boolean; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string | null, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false) { - super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP); - - this.hpHealed = hpHealed; - this.message = message; - this.showFullHpMessage = showFullHpMessage; - this.skipAnim = skipAnim; - this.revive = revive; - this.healStatus = healStatus; - this.preventFullHeal = preventFullHeal; - } - - start() { - if (!this.skipAnim && (this.revive || this.getPokemon().hp) && !this.getPokemon().isFullHp()) { - super.start(); - } else { - this.end(); - } - } - - end() { - const pokemon = this.getPokemon(); - - if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) { - super.end(); - return; - } - - const hasMessage = !!this.message; - const healOrDamage = (!pokemon.isFullHp() || this.hpHealed < 0); - let lastStatusEffect = StatusEffect.NONE; - - if (healOrDamage) { - const hpRestoreMultiplier = new Utils.IntegerHolder(1); - if (!this.revive) { - this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); - } - const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); - if (healAmount.value < 0) { - pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL as DamageResult); - healAmount.value = 0; - } - // Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock) - if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp()) { - healAmount.value = (pokemon.getMaxHp() - pokemon.hp) - 1; - } - healAmount.value = pokemon.heal(healAmount.value); - if (healAmount.value) { - this.scene.damageNumberHandler.add(pokemon, healAmount.value, HitResult.HEAL); - } - if (pokemon.isPlayer()) { - this.scene.validateAchvs(HealAchv, healAmount); - if (healAmount.value > this.scene.gameData.gameStats.highestHeal) { - this.scene.gameData.gameStats.highestHeal = healAmount.value; - } - } - if (this.healStatus && !this.revive && pokemon.status) { - lastStatusEffect = pokemon.status.effect; - pokemon.resetStatus(); - } - pokemon.updateInfo().then(() => super.end()); - } else if (this.healStatus && !this.revive && pokemon.status) { - lastStatusEffect = pokemon.status.effect; - pokemon.resetStatus(); - pokemon.updateInfo().then(() => super.end()); - } else if (this.showFullHpMessage) { - this.message = i18next.t("battle:hpIsFull", { pokemonName: getPokemonNameWithAffix(pokemon) }); - } - - if (this.message) { - this.scene.queueMessage(this.message); - } - - if (this.healStatus && lastStatusEffect && !hasMessage) { - this.scene.queueMessage(getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon))); - } - - if (!healOrDamage && !lastStatusEffect) { - super.end(); - } - } -} - -export class AttemptCapturePhase extends PokemonPhase { - private pokeballType: PokeballType; - private pokeball: Phaser.GameObjects.Sprite; - private originalY: number; - - constructor(scene: BattleScene, targetIndex: integer, pokeballType: PokeballType) { - super(scene, BattlerIndex.ENEMY + targetIndex); - - this.pokeballType = pokeballType; - } - - start() { - super.start(); - - const pokemon = this.getPokemon() as EnemyPokemon; - - if (!pokemon?.hp) { - return this.end(); - } - - this.scene.pokeballCounts[this.pokeballType]--; - - this.originalY = pokemon.y; - - const _3m = 3 * pokemon.getMaxHp(); - const _2h = 2 * pokemon.hp; - const catchRate = pokemon.species.catchRate; - const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); - const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; - const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); - const y = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x))); - const fpOffset = pokemon.getFieldPositionOffset(); - - const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); - this.pokeball = this.scene.addFieldSprite(16, 80, "pb", pokeballAtlasKey); - this.pokeball.setOrigin(0.5, 0.625); - this.scene.field.add(this.pokeball); - - this.scene.playSound("pb_throw"); - this.scene.time.delayedCall(300, () => { - this.scene.field.moveBelow(this.pokeball as Phaser.GameObjects.GameObject, pokemon); - }); - - this.scene.tweens.add({ - targets: this.pokeball, - x: { value: 236 + fpOffset[0], ease: "Linear" }, - y: { value: 16 + fpOffset[1], ease: "Cubic.easeOut" }, - duration: 500, - onComplete: () => { - this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); - this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}_open`)); - this.scene.playSound("pb_rel"); - pokemon.tint(getPokeballTintColor(this.pokeballType)); - - addPokeballOpenParticles(this.scene, this.pokeball.x, this.pokeball.y, this.pokeballType); - - this.scene.tweens.add({ - targets: pokemon, - duration: 500, - ease: "Sine.easeIn", - scale: 0.25, - y: 20, - onComplete: () => { - this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); - pokemon.setVisible(false); - this.scene.playSound("pb_catch"); - this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}`)); - - const doShake = () => { - let shakeCount = 0; - const pbX = this.pokeball.x; - const shakeCounter = this.scene.tweens.addCounter({ - from: 0, - to: 1, - repeat: 4, - yoyo: true, - ease: "Cubic.easeOut", - duration: 250, - repeatDelay: 500, - onUpdate: t => { - if (shakeCount && shakeCount < 4) { - const value = t.getValue(); - const directionMultiplier = shakeCount % 2 === 1 ? 1 : -1; - this.pokeball.setX(pbX + value * 4 * directionMultiplier); - this.pokeball.setAngle(value * 27.5 * directionMultiplier); - } - }, - onRepeat: () => { - if (!pokemon.species.isObtainable()) { - shakeCounter.stop(); - this.failCatch(shakeCount); - } else if (shakeCount++ < 3) { - if (pokeballMultiplier === -1 || pokemon.randSeedInt(65536) < y) { - this.scene.playSound("pb_move"); - } else { - shakeCounter.stop(); - this.failCatch(shakeCount); - } - } else { - this.scene.playSound("pb_lock"); - addPokeballCaptureStars(this.scene, this.pokeball); - - const pbTint = this.scene.add.sprite(this.pokeball.x, this.pokeball.y, "pb", "pb"); - pbTint.setOrigin(this.pokeball.originX, this.pokeball.originY); - pbTint.setTintFill(0); - pbTint.setAlpha(0); - this.scene.field.add(pbTint); - this.scene.tweens.add({ - targets: pbTint, - alpha: 0.375, - duration: 200, - easing: "Sine.easeOut", - onComplete: () => { - this.scene.tweens.add({ - targets: pbTint, - alpha: 0, - duration: 200, - easing: "Sine.easeIn", - onComplete: () => pbTint.destroy() - }); - } - }); - } - }, - onComplete: () => { - this.catch(); - } - }); - }; - - this.scene.time.delayedCall(250, () => doPokeballBounceAnim(this.scene, this.pokeball, 16, 72, 350, doShake)); - } - }); - } - }); - } - - failCatch(shakeCount: integer) { - const pokemon = this.getPokemon(); - - this.scene.playSound("pb_rel"); - pokemon.setY(this.originalY); - if (pokemon.status?.effect !== StatusEffect.SLEEP) { - pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); - } - pokemon.tint(getPokeballTintColor(this.pokeballType)); - pokemon.setVisible(true); - pokemon.untint(250, "Sine.easeOut"); - - const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); - this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); - this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}_open`)); - - this.scene.tweens.add({ - targets: pokemon, - duration: 250, - ease: "Sine.easeOut", - scale: 1 - }); - - this.scene.currentBattle.lastUsedPokeball = this.pokeballType; - this.removePb(); - this.end(); - } - - catch() { - const pokemon = this.getPokemon() as EnemyPokemon; - - const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm(); - - if (speciesForm.abilityHidden && (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1) { - this.scene.validateAchv(achvs.HIDDEN_ABILITY); - } - - if (pokemon.species.subLegendary) { - this.scene.validateAchv(achvs.CATCH_SUB_LEGENDARY); - } - - if (pokemon.species.legendary) { - this.scene.validateAchv(achvs.CATCH_LEGENDARY); - } - - if (pokemon.species.mythical) { - this.scene.validateAchv(achvs.CATCH_MYTHICAL); - } - - this.scene.pokemonInfoContainer.show(pokemon, true); - - this.scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs); - - this.scene.ui.showText(i18next.t("battle:pokemonCaught", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { - const end = () => { - this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex)); - this.scene.pokemonInfoContainer.hide(); - this.removePb(); - this.end(); - }; - const removePokemon = () => { - this.scene.addFaintedEnemyScore(pokemon); - this.scene.getPlayerField().filter(p => p.isActive(true)).forEach(playerPokemon => playerPokemon.removeTagsBySourceId(pokemon.id)); - pokemon.hp = 0; - pokemon.trySetStatus(StatusEffect.FAINT); - this.scene.clearEnemyHeldItemModifiers(); - this.scene.field.remove(pokemon, true); - }; - const addToParty = () => { - const newPokemon = pokemon.addToParty(this.pokeballType); - const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier, false); - if (this.scene.getParty().filter(p => p.isShiny()).length === 6) { - this.scene.validateAchv(achvs.SHINY_PARTY); - } - Promise.all(modifiers.map(m => this.scene.addModifier(m, true))).then(() => { - this.scene.updateModifiers(true); - removePokemon(); - if (newPokemon) { - newPokemon.loadAssets().then(end); - } else { - end(); - } - }); - }; - Promise.all([pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon)]).then(() => { - if (this.scene.getParty().length === 6) { - const promptRelease = () => { - this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => { - this.scene.pokemonInfoContainer.makeRoomForConfirmUi(1, true); - this.scene.ui.setMode(Mode.CONFIRM, () => { - const newPokemon = this.scene.addPlayerPokemon(pokemon.species, pokemon.level, pokemon.abilityIndex, pokemon.formIndex, pokemon.gender, pokemon.shiny, pokemon.variant, pokemon.ivs, pokemon.nature, pokemon); - this.scene.ui.setMode(Mode.SUMMARY, newPokemon, 0, SummaryUiMode.DEFAULT, () => { - this.scene.ui.setMode(Mode.MESSAGE).then(() => { - promptRelease(); - }); - }, false); - }, () => { - this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => { - this.scene.ui.setMode(Mode.MESSAGE).then(() => { - if (slotIndex < 6) { - addToParty(); - } else { - promptRelease(); - } - }); - }); - }, () => { - this.scene.ui.setMode(Mode.MESSAGE).then(() => { - removePokemon(); - end(); - }); - }, "fullParty"); - }); - }; - promptRelease(); - } else { - addToParty(); - } - }); - }, 0, true); - } - - removePb() { - this.scene.tweens.add({ - targets: this.pokeball, - duration: 250, - delay: 250, - ease: "Sine.easeIn", - alpha: 0, - onComplete: () => this.pokeball.destroy() - }); - } -} - -export class AttemptRunPhase extends PokemonPhase { - constructor(scene: BattleScene, fieldIndex: integer) { - super(scene, fieldIndex); - } - - start() { - super.start(); - - const playerPokemon = this.getPokemon(); - const enemyField = this.scene.getEnemyField(); - - const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length; - - const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256); - applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance); - - if (playerPokemon.randSeedInt(256) < escapeChance.value) { - this.scene.playSound("flee"); - this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500); - - this.scene.tweens.add({ - targets: [this.scene.arenaEnemy, enemyField].flat(), - alpha: 0, - duration: 250, - ease: "Sine.easeIn", - onComplete: () => enemyField.forEach(enemyPokemon => enemyPokemon.destroy()) - }); - - this.scene.clearEnemyHeldItemModifiers(); - - enemyField.forEach(enemyPokemon => { - enemyPokemon.hideInfo().then(() => enemyPokemon.destroy()); - enemyPokemon.hp = 0; - enemyPokemon.trySetStatus(StatusEffect.FAINT); - }); - - this.scene.pushPhase(new BattleEndPhase(this.scene)); - this.scene.pushPhase(new NewBattlePhase(this.scene)); - } else { - this.scene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500); - } - - this.end(); - } -} - -export class SelectModifierPhase extends BattlePhase { - private rerollCount: integer; - private modifierTiers: ModifierTier[]; - - constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[]) { - super(scene); - - this.rerollCount = rerollCount; - this.modifierTiers = modifierTiers!; // TODO: is this bang correct? - } - - start() { - super.start(); - - if (!this.rerollCount) { - this.updateSeed(); - } else { - this.scene.reroll = false; - } - - const party = this.scene.getParty(); - regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount); - const modifierCount = new Utils.IntegerHolder(3); - if (this.isPlayer()) { - this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount); - } - const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value); - - const modifierSelectCallback = (rowCursor: integer, cursor: integer) => { - if (rowCursor < 0 || cursor < 0) { - this.scene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => { - this.scene.ui.setOverlayMode(Mode.CONFIRM, () => { - this.scene.ui.revertMode(); - this.scene.ui.setMode(Mode.MESSAGE); - super.end(); - }, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers))); - }); - return false; - } - let modifierType: ModifierType; - let cost: integer; - switch (rowCursor) { - case 0: - switch (cursor) { - case 0: - const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers); - if (this.scene.money < rerollCost) { - this.scene.ui.playError(); - return false; - } else { - this.scene.reroll = true; - this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[])); - this.scene.ui.clearText(); - this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); - if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { - this.scene.money -= rerollCost; - this.scene.updateMoneyText(); - this.scene.animateMoneyChanged(false); - } - this.scene.playSound("buy"); - } - break; - case 1: - this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => { - if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) { - const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && m.isTransferrable && m.pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; - const itemModifier = itemModifiers[itemIndex]; - this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity); - } else { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - } - }, PartyUiHandler.FilterItemMaxStacks); - break; - case 2: - this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - }); - break; - case 3: - this.scene.lockModifierTiers = !this.scene.lockModifierTiers; - const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler; - uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - uiHandler.updateLockRaritiesText(); - uiHandler.updateRerollCostText(); - return false; - } - return true; - case 1: - if (typeOptions[cursor].type) { - modifierType = typeOptions[cursor].type; - } - break; - default: - const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1)); - const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT]; - if (shopOption.type) { - modifierType = shopOption.type; - } - cost = shopOption.cost; - break; - } - - if (cost! && (this.scene.money < cost) && !Overrides.WAIVE_ROLL_FEE_OVERRIDE) { // TODO: is the bang on cost correct? - this.scene.ui.playError(); - return false; - } - - const applyModifier = (modifier: Modifier, playSound: boolean = false) => { - const result = this.scene.addModifier(modifier, false, playSound); - if (cost) { - result.then(success => { - if (success) { - if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { - this.scene.money -= cost; - this.scene.updateMoneyText(); - this.scene.animateMoneyChanged(false); - } - this.scene.playSound("buy"); - (this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText(); - } else { - this.scene.ui.playError(); - } - }); - } else { - const doEnd = () => { - this.scene.ui.clearText(); - this.scene.ui.setMode(Mode.MESSAGE); - super.end(); - }; - if (result instanceof Promise) { - result.then(() => doEnd()); - } else { - doEnd(); - } - } - }; - - if (modifierType! instanceof PokemonModifierType) { //TODO: is the bang correct? - if (modifierType instanceof FusePokemonModifierType) { - this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => { - if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { - const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct? - applyModifier(modifier, true); - }); - } else { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - } - }, modifierType.selectFilter); - } else { - const pokemonModifierType = modifierType as PokemonModifierType; - const isMoveModifier = modifierType instanceof PokemonMoveModifierType; - const isTmModifier = modifierType instanceof TmModifierType; - const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType; - const isPpRestoreModifier = (modifierType instanceof PokemonPpRestoreModifierType || modifierType instanceof PokemonPpUpModifierType); - const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER - : isTmModifier ? PartyUiMode.TM_MODIFIER - : isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER - : PartyUiMode.MODIFIER; - const tmMoveId = isTmModifier - ? (modifierType as TmModifierType).moveId - : undefined; - this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => { - if (slotIndex < 6) { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { - const modifier = !isMoveModifier - ? !isRememberMoveModifier - ? modifierType.newModifier(party[slotIndex]) - : modifierType.newModifier(party[slotIndex], option as integer) - : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1); - applyModifier(modifier!, true); // TODO: is the bang correct? - }); - } else { - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - } - }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier); - } - } else { - applyModifier(modifierType!.newModifier()!); // TODO: is the bang correct? - } - - return !cost!;// TODO: is the bang correct? - }; - this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - } - - updateSeed(): void { - this.scene.resetSeed(); - } - - isPlayer(): boolean { - return true; - } - - getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): integer { - let baseValue = 0; - if (Overrides.WAIVE_ROLL_FEE_OVERRIDE) { - return baseValue; - } else if (lockRarities) { - const tierValues = [50, 125, 300, 750, 2000]; - for (const opt of typeOptions) { - baseValue += tierValues[opt.type.tier ?? 0]; - } - } else { - baseValue = 250; - } - return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount), Number.MAX_SAFE_INTEGER); - } - - getPoolType(): ModifierPoolType { - return ModifierPoolType.PLAYER; - } - - getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] { - return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined); - } - - addModifier(modifier: Modifier): Promise { - return this.scene.addModifier(modifier, false, true); - } -} - -export class EggLapsePhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - const eggsToHatch: Egg[] = this.scene.gameData.eggs.filter((egg: Egg) => { - return Overrides.EGG_IMMEDIATE_HATCH_OVERRIDE ? true : --egg.hatchWaves < 1; - }); - - let eggCount: integer = eggsToHatch.length; - - if (eggCount) { - this.scene.queueMessage(i18next.t("battle:eggHatching")); - - for (const egg of eggsToHatch) { - this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg, eggCount)); - if (eggCount > 0) { - eggCount--; - } - } - - } - this.end(); - } -} - -export class AddEnemyBuffModifierPhase extends Phase { - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - const waveIndex = this.scene.currentBattle.waveIndex; - const tier = !(waveIndex % 1000) ? ModifierTier.ULTRA : !(waveIndex % 250) ? ModifierTier.GREAT : ModifierTier.COMMON; - - regenerateModifierPoolThresholds(this.scene.getEnemyParty(), ModifierPoolType.ENEMY_BUFF); - - const count = Math.ceil(waveIndex / 250); - for (let i = 0; i < count; i++) { - this.scene.addEnemyModifier(getEnemyBuffModifierForWave(tier, this.scene.findModifiers(m => m instanceof EnemyPersistentModifier, false), this.scene), true, true); - } - this.scene.updateModifiers(false, true).then(() => this.end()); - } -} - -/** - * Cures the party of all non-volatile status conditions, shows a message - * @param {BattleScene} scene The current scene - * @param {Pokemon} user The user of the move that cures the party - * @param {string} message The message that should be displayed - * @param {Abilities} abilityCondition Pokemon with this ability will not be affected ie. Soundproof - */ -export class PartyStatusCurePhase extends BattlePhase { - private user: Pokemon; - private message: string; - private abilityCondition: Abilities; - - constructor(scene: BattleScene, user: Pokemon, message: string, abilityCondition: Abilities) { - super(scene); - - this.user = user; - this.message = message; - this.abilityCondition = abilityCondition; - } - - start() { - super.start(); - for (const pokemon of this.scene.getParty()) { - if (!pokemon.isOnField() || pokemon === this.user) { - pokemon.resetStatus(false); - pokemon.updateInfo(true); - } else { - if (!pokemon.hasAbility(this.abilityCondition)) { - pokemon.resetStatus(); - pokemon.updateInfo(true); - } else { - // Manually show ability bar, since we're not hooked into the targeting system - pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, pokemon.getPassiveAbility()?.id === this.abilityCondition)); - } - } - } - if (this.message) { - this.scene.queueMessage(this.message); - } - this.end(); - } -} - -export class PartyHealPhase extends BattlePhase { - private resumeBgm: boolean; - - constructor(scene: BattleScene, resumeBgm: boolean) { - super(scene); - - this.resumeBgm = resumeBgm; - } - - start() { - super.start(); - - const bgmPlaying = this.scene.isBgmPlaying(); - if (bgmPlaying) { - this.scene.fadeOutBgm(1000, false); - } - this.scene.ui.fadeOut(1000).then(() => { - for (const pokemon of this.scene.getParty()) { - pokemon.hp = pokemon.getMaxHp(); - pokemon.resetStatus(); - for (const move of pokemon.moveset) { - move!.ppUsed = 0; // TODO: is this bang correct? - } - pokemon.updateInfo(true); - } - const healSong = this.scene.playSoundWithoutBgm("heal"); - this.scene.time.delayedCall(Utils.fixedInt(healSong.totalDuration * 1000), () => { - healSong.destroy(); - if (this.resumeBgm && bgmPlaying) { - this.scene.playBgm(); - } - this.scene.ui.fadeIn(500).then(() => this.end()); - }); - }); - } -} - -export class ShinySparklePhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { - super(scene, battlerIndex); - } - - start() { - super.start(); - - this.getPokemon().sparkle(); - this.scene.time.delayedCall(1000, () => this.end()); - } -} - -export class ScanIvsPhase extends PokemonPhase { - private shownIvs: integer; - - constructor(scene: BattleScene, battlerIndex: BattlerIndex, shownIvs: integer) { - super(scene, battlerIndex); - - this.shownIvs = shownIvs; - } - - start() { - super.start(); - - if (!this.shownIvs) { - return this.end(); - } - - const pokemon = this.getPokemon(); - - let enemyIvs: number[] = []; - let statsContainer: Phaser.GameObjects.Sprite[] = []; - let statsContainerLabels: Phaser.GameObjects.Sprite[] = []; - const enemyField = this.scene.getEnemyField(); - const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible - for (let e = 0; e < enemyField.length; e++) { - enemyIvs = enemyField[e].ivs; - const currentIvs = this.scene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists - const ivsToShow = this.scene.ui.getMessageHandler().getTopIvs(enemyIvs, this.shownIvs); - statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[]; - statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0); - for (let s = 0; s < statsContainerLabels.length; s++) { - const ivStat = Stat[statsContainerLabels[s].frame.name]; - if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) { - const hexColour = enemyIvs[ivStat] === 31 ? getTextColor(TextStyle.PERFECT_IV, false, uiTheme) : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme); - const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color; - statsContainerLabels[s].setTint(hexTextColour); - } - statsContainerLabels[s].setVisible(true); - } - } - - if (!this.scene.hideIvs) { - this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { - this.scene.ui.setMode(Mode.CONFIRM, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { - this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); - }); - }, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - this.end(); - }); - }); - } else { - this.end(); - } - } -} - -export class TrainerMessageTestPhase extends BattlePhase { - private trainerTypes: TrainerType[]; - - constructor(scene: BattleScene, ...trainerTypes: TrainerType[]) { - super(scene); - - this.trainerTypes = trainerTypes; - } - - start() { - super.start(); - - const testMessages: string[] = []; - - for (const t of Object.keys(trainerConfigs)) { - const type = parseInt(t); - if (this.trainerTypes.length && !this.trainerTypes.find(tt => tt === type as TrainerType)) { - continue; - } - const config = trainerConfigs[type]; - [config.encounterMessages, config.femaleEncounterMessages, config.victoryMessages, config.femaleVictoryMessages, config.defeatMessages, config.femaleDefeatMessages] - .map(messages => { - if (messages?.length) { - testMessages.push(...messages); - } - }); - } - - for (const message of testMessages) { - this.scene.pushPhase(new TestMessagePhase(this.scene, message)); - } - - this.end(); - } -} - -export class TestMessagePhase extends MessagePhase { - constructor(scene: BattleScene, message: string) { - super(scene, message, null, true); - } -} diff --git a/src/phases/add-enemy-buff-modifier-phase.ts b/src/phases/add-enemy-buff-modifier-phase.ts new file mode 100644 index 00000000000..a9936eb765d --- /dev/null +++ b/src/phases/add-enemy-buff-modifier-phase.ts @@ -0,0 +1,26 @@ +import BattleScene from "#app/battle-scene.js"; +import { ModifierTier } from "#app/modifier/modifier-tier.js"; +import { regenerateModifierPoolThresholds, ModifierPoolType, getEnemyBuffModifierForWave } from "#app/modifier/modifier-type.js"; +import { EnemyPersistentModifier } from "#app/modifier/modifier.js"; +import { Phase } from "#app/phase.js"; + +export class AddEnemyBuffModifierPhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + const waveIndex = this.scene.currentBattle.waveIndex; + const tier = !(waveIndex % 1000) ? ModifierTier.ULTRA : !(waveIndex % 250) ? ModifierTier.GREAT : ModifierTier.COMMON; + + regenerateModifierPoolThresholds(this.scene.getEnemyParty(), ModifierPoolType.ENEMY_BUFF); + + const count = Math.ceil(waveIndex / 250); + for (let i = 0; i < count; i++) { + this.scene.addEnemyModifier(getEnemyBuffModifierForWave(tier, this.scene.findModifiers(m => m instanceof EnemyPersistentModifier, false), this.scene), true, true); + } + this.scene.updateModifiers(false, true).then(() => this.end()); + } +} diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts new file mode 100644 index 00000000000..3c165a25157 --- /dev/null +++ b/src/phases/attempt-capture-phase.ts @@ -0,0 +1,288 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { getPokeballCatchMultiplier, getPokeballAtlasKey, getPokeballTintColor, doPokeballBounceAnim } from "#app/data/pokeball.js"; +import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect.js"; +import { PokeballType } from "#app/enums/pokeball.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { addPokeballOpenParticles, addPokeballCaptureStars } from "#app/field/anims.js"; +import { EnemyPokemon } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { PokemonHeldItemModifier } from "#app/modifier/modifier.js"; +import { achvs } from "#app/system/achv.js"; +import { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler.js"; +import { SummaryUiMode } from "#app/ui/summary-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { PokemonPhase } from "./pokemon-phase"; +import { VictoryPhase } from "./victory-phase"; + +export class AttemptCapturePhase extends PokemonPhase { + private pokeballType: PokeballType; + private pokeball: Phaser.GameObjects.Sprite; + private originalY: number; + + constructor(scene: BattleScene, targetIndex: integer, pokeballType: PokeballType) { + super(scene, BattlerIndex.ENEMY + targetIndex); + + this.pokeballType = pokeballType; + } + + start() { + super.start(); + + const pokemon = this.getPokemon() as EnemyPokemon; + + if (!pokemon?.hp) { + return this.end(); + } + + this.scene.pokeballCounts[this.pokeballType]--; + + this.originalY = pokemon.y; + + const _3m = 3 * pokemon.getMaxHp(); + const _2h = 2 * pokemon.hp; + const catchRate = pokemon.species.catchRate; + const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); + const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; + const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); + const y = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x))); + const fpOffset = pokemon.getFieldPositionOffset(); + + const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); + this.pokeball = this.scene.addFieldSprite(16, 80, "pb", pokeballAtlasKey); + this.pokeball.setOrigin(0.5, 0.625); + this.scene.field.add(this.pokeball); + + this.scene.playSound("pb_throw"); + this.scene.time.delayedCall(300, () => { + this.scene.field.moveBelow(this.pokeball as Phaser.GameObjects.GameObject, pokemon); + }); + + this.scene.tweens.add({ + targets: this.pokeball, + x: { value: 236 + fpOffset[0], ease: "Linear" }, + y: { value: 16 + fpOffset[1], ease: "Cubic.easeOut" }, + duration: 500, + onComplete: () => { + this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); + this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}_open`)); + this.scene.playSound("pb_rel"); + pokemon.tint(getPokeballTintColor(this.pokeballType)); + + addPokeballOpenParticles(this.scene, this.pokeball.x, this.pokeball.y, this.pokeballType); + + this.scene.tweens.add({ + targets: pokemon, + duration: 500, + ease: "Sine.easeIn", + scale: 0.25, + y: 20, + onComplete: () => { + this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); + pokemon.setVisible(false); + this.scene.playSound("pb_catch"); + this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}`)); + + const doShake = () => { + let shakeCount = 0; + const pbX = this.pokeball.x; + const shakeCounter = this.scene.tweens.addCounter({ + from: 0, + to: 1, + repeat: 4, + yoyo: true, + ease: "Cubic.easeOut", + duration: 250, + repeatDelay: 500, + onUpdate: t => { + if (shakeCount && shakeCount < 4) { + const value = t.getValue(); + const directionMultiplier = shakeCount % 2 === 1 ? 1 : -1; + this.pokeball.setX(pbX + value * 4 * directionMultiplier); + this.pokeball.setAngle(value * 27.5 * directionMultiplier); + } + }, + onRepeat: () => { + if (!pokemon.species.isObtainable()) { + shakeCounter.stop(); + this.failCatch(shakeCount); + } else if (shakeCount++ < 3) { + if (pokeballMultiplier === -1 || pokemon.randSeedInt(65536) < y) { + this.scene.playSound("pb_move"); + } else { + shakeCounter.stop(); + this.failCatch(shakeCount); + } + } else { + this.scene.playSound("pb_lock"); + addPokeballCaptureStars(this.scene, this.pokeball); + + const pbTint = this.scene.add.sprite(this.pokeball.x, this.pokeball.y, "pb", "pb"); + pbTint.setOrigin(this.pokeball.originX, this.pokeball.originY); + pbTint.setTintFill(0); + pbTint.setAlpha(0); + this.scene.field.add(pbTint); + this.scene.tweens.add({ + targets: pbTint, + alpha: 0.375, + duration: 200, + easing: "Sine.easeOut", + onComplete: () => { + this.scene.tweens.add({ + targets: pbTint, + alpha: 0, + duration: 200, + easing: "Sine.easeIn", + onComplete: () => pbTint.destroy() + }); + } + }); + } + }, + onComplete: () => { + this.catch(); + } + }); + }; + + this.scene.time.delayedCall(250, () => doPokeballBounceAnim(this.scene, this.pokeball, 16, 72, 350, doShake)); + } + }); + } + }); + } + + failCatch(shakeCount: integer) { + const pokemon = this.getPokemon(); + + this.scene.playSound("pb_rel"); + pokemon.setY(this.originalY); + if (pokemon.status?.effect !== StatusEffect.SLEEP) { + pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); + } + pokemon.tint(getPokeballTintColor(this.pokeballType)); + pokemon.setVisible(true); + pokemon.untint(250, "Sine.easeOut"); + + const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); + this.pokeball.setTexture("pb", `${pokeballAtlasKey}_opening`); + this.scene.time.delayedCall(17, () => this.pokeball.setTexture("pb", `${pokeballAtlasKey}_open`)); + + this.scene.tweens.add({ + targets: pokemon, + duration: 250, + ease: "Sine.easeOut", + scale: 1 + }); + + this.scene.currentBattle.lastUsedPokeball = this.pokeballType; + this.removePb(); + this.end(); + } + + catch() { + const pokemon = this.getPokemon() as EnemyPokemon; + + const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm(); + + if (speciesForm.abilityHidden && (pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex) === speciesForm.getAbilityCount() - 1) { + this.scene.validateAchv(achvs.HIDDEN_ABILITY); + } + + if (pokemon.species.subLegendary) { + this.scene.validateAchv(achvs.CATCH_SUB_LEGENDARY); + } + + if (pokemon.species.legendary) { + this.scene.validateAchv(achvs.CATCH_LEGENDARY); + } + + if (pokemon.species.mythical) { + this.scene.validateAchv(achvs.CATCH_MYTHICAL); + } + + this.scene.pokemonInfoContainer.show(pokemon, true); + + this.scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs); + + this.scene.ui.showText(i18next.t("battle:pokemonCaught", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + const end = () => { + this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex)); + this.scene.pokemonInfoContainer.hide(); + this.removePb(); + this.end(); + }; + const removePokemon = () => { + this.scene.addFaintedEnemyScore(pokemon); + this.scene.getPlayerField().filter(p => p.isActive(true)).forEach(playerPokemon => playerPokemon.removeTagsBySourceId(pokemon.id)); + pokemon.hp = 0; + pokemon.trySetStatus(StatusEffect.FAINT); + this.scene.clearEnemyHeldItemModifiers(); + this.scene.field.remove(pokemon, true); + }; + const addToParty = () => { + const newPokemon = pokemon.addToParty(this.pokeballType); + const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier, false); + if (this.scene.getParty().filter(p => p.isShiny()).length === 6) { + this.scene.validateAchv(achvs.SHINY_PARTY); + } + Promise.all(modifiers.map(m => this.scene.addModifier(m, true))).then(() => { + this.scene.updateModifiers(true); + removePokemon(); + if (newPokemon) { + newPokemon.loadAssets().then(end); + } else { + end(); + } + }); + }; + Promise.all([pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon)]).then(() => { + if (this.scene.getParty().length === 6) { + const promptRelease = () => { + this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => { + this.scene.pokemonInfoContainer.makeRoomForConfirmUi(1, true); + this.scene.ui.setMode(Mode.CONFIRM, () => { + const newPokemon = this.scene.addPlayerPokemon(pokemon.species, pokemon.level, pokemon.abilityIndex, pokemon.formIndex, pokemon.gender, pokemon.shiny, pokemon.variant, pokemon.ivs, pokemon.nature, pokemon); + this.scene.ui.setMode(Mode.SUMMARY, newPokemon, 0, SummaryUiMode.DEFAULT, () => { + this.scene.ui.setMode(Mode.MESSAGE).then(() => { + promptRelease(); + }); + }, false); + }, () => { + this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => { + this.scene.ui.setMode(Mode.MESSAGE).then(() => { + if (slotIndex < 6) { + addToParty(); + } else { + promptRelease(); + } + }); + }); + }, () => { + this.scene.ui.setMode(Mode.MESSAGE).then(() => { + removePokemon(); + end(); + }); + }, "fullParty"); + }); + }; + promptRelease(); + } else { + addToParty(); + } + }); + }, 0, true); + } + + removePb() { + this.scene.tweens.add({ + targets: this.pokeball, + duration: 250, + delay: 250, + ease: "Sine.easeIn", + alpha: 0, + onComplete: () => this.pokeball.destroy() + }); + } +} diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts new file mode 100644 index 00000000000..9781ca6d360 --- /dev/null +++ b/src/phases/attempt-run-phase.ts @@ -0,0 +1,56 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyAbAttrs, RunSuccessAbAttr } from "#app/data/ability.js"; +import { Stat } from "#app/enums/stat.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import Pokemon from "#app/field/pokemon.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattleEndPhase } from "./battle-end-phase"; +import { NewBattlePhase } from "./new-battle-phase"; +import { PokemonPhase } from "./pokemon-phase"; + +export class AttemptRunPhase extends PokemonPhase { + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene, fieldIndex); + } + + start() { + super.start(); + + const playerPokemon = this.getPokemon(); + const enemyField = this.scene.getEnemyField(); + + const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length; + + const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256); + applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance); + + if (playerPokemon.randSeedInt(256) < escapeChance.value) { + this.scene.playSound("flee"); + this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500); + + this.scene.tweens.add({ + targets: [this.scene.arenaEnemy, enemyField].flat(), + alpha: 0, + duration: 250, + ease: "Sine.easeIn", + onComplete: () => enemyField.forEach(enemyPokemon => enemyPokemon.destroy()) + }); + + this.scene.clearEnemyHeldItemModifiers(); + + enemyField.forEach(enemyPokemon => { + enemyPokemon.hideInfo().then(() => enemyPokemon.destroy()); + enemyPokemon.hp = 0; + enemyPokemon.trySetStatus(StatusEffect.FAINT); + }); + + this.scene.pushPhase(new BattleEndPhase(this.scene)); + this.scene.pushPhase(new NewBattlePhase(this.scene)); + } else { + this.scene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500); + } + + this.end(); + } +} diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts new file mode 100644 index 00000000000..a9999370cdd --- /dev/null +++ b/src/phases/battle-end-phase.ts @@ -0,0 +1,55 @@ +import { applyPostBattleAbAttrs, PostBattleAbAttr } from "#app/data/ability.js"; +import { LapsingPersistentModifier, LapsingPokemonHeldItemModifier } from "#app/modifier/modifier.js"; +import { BattlePhase } from "./battle-phase"; +import { GameOverPhase } from "./game-over-phase"; + +export class BattleEndPhase extends BattlePhase { + start() { + super.start(); + + this.scene.currentBattle.addBattleScore(this.scene); + + this.scene.gameData.gameStats.battles++; + if (this.scene.currentBattle.trainer) { + this.scene.gameData.gameStats.trainersDefeated++; + } + if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave) { + this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1; + } + + // Endless graceful end + if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex >= 5850) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new GameOverPhase(this.scene, true)); + } + + for (const pokemon of this.scene.getField()) { + if (pokemon) { + pokemon.resetBattleSummonData(); + } + } + + for (const pokemon of this.scene.getParty().filter(p => p.isAllowedInBattle())) { + applyPostBattleAbAttrs(PostBattleAbAttr, pokemon); + } + + if (this.scene.currentBattle.moneyScattered) { + this.scene.currentBattle.pickUpScatteredMoney(this.scene); + } + + this.scene.clearEnemyHeldItemModifiers(); + + const lapsingModifiers = this.scene.findModifiers(m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[]; + for (const m of lapsingModifiers) { + const args: any[] = []; + if (m instanceof LapsingPokemonHeldItemModifier) { + args.push(this.scene.getPokemonById(m.pokemonId)); + } + if (!m.lapse(args)) { + this.scene.removeModifier(m); + } + } + + this.scene.updateModifiers().then(() => this.end()); + } +} diff --git a/src/phases/battle-phase.ts b/src/phases/battle-phase.ts new file mode 100644 index 00000000000..3e7e0e28596 --- /dev/null +++ b/src/phases/battle-phase.ts @@ -0,0 +1,47 @@ +import BattleScene from "#app/battle-scene.js"; +import { TrainerSlot } from "#app/data/trainer-config.js"; +import { Phase } from "#app/phase.js"; + +export class BattlePhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void { + const sprites = this.scene.currentBattle.trainer?.getSprites()!; // TODO: is this bang correct? + const tintSprites = this.scene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct? + for (let i = 0; i < sprites.length; i++) { + const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; + [sprites[i], tintSprites[i]].map(sprite => { + if (visible) { + sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16; + } + sprite.setVisible(visible); + sprite.clearTint(); + }); + sprites[i].setVisible(visible); + tintSprites[i].setVisible(visible); + sprites[i].clearTint(); + tintSprites[i].clearTint(); + } + this.scene.tweens.add({ + targets: this.scene.currentBattle.trainer, + x: "-=16", + y: "+=16", + alpha: 1, + ease: "Sine.easeInOut", + duration: 750 + }); + } + + hideEnemyTrainer(): void { + this.scene.tweens.add({ + targets: this.scene.currentBattle.trainer, + x: "+=16", + y: "-=16", + alpha: 0, + ease: "Sine.easeInOut", + duration: 750 + }); + } +} diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts new file mode 100644 index 00000000000..504fb6ec163 --- /dev/null +++ b/src/phases/berry-phase.ts @@ -0,0 +1,52 @@ +import { applyAbAttrs, PreventBerryUseAbAttr, HealFromBerryUseAbAttr } from "#app/data/ability.js"; +import { CommonAnim } from "#app/data/battle-anims.js"; +import { BerryUsedEvent } from "#app/events/battle-scene.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { BerryModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { FieldPhase } from "./field-phase"; +import { CommonAnimPhase } from "./common-anim-phase"; + +/** The phase after attacks where the pokemon eat berries */ +export class BerryPhase extends FieldPhase { + start() { + super.start(); + + this.executeForAll((pokemon) => { + const hasUsableBerry = !!this.scene.findModifier((m) => { + return m instanceof BerryModifier && m.shouldApply([pokemon]); + }, pokemon.isPlayer()); + + if (hasUsableBerry) { + const cancelled = new Utils.BooleanHolder(false); + pokemon.getOpponents().map((opp) => applyAbAttrs(PreventBerryUseAbAttr, opp, cancelled)); + + if (cancelled.value) { + pokemon.scene.queueMessage(i18next.t("abilityTriggers:preventBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); + } else { + this.scene.unshiftPhase( + new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM) + ); + + for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) { + if (berryModifier.consumed) { + if (!--berryModifier.stackCount) { + this.scene.removeModifier(berryModifier); + } else { + berryModifier.consumed = false; + } + } + this.scene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); // Announce a berry was used + } + + this.scene.updateModifiers(pokemon.isPlayer()); + + applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new Utils.BooleanHolder(false)); + } + } + }); + + this.end(); + } +} diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts new file mode 100644 index 00000000000..cd8f2b00c46 --- /dev/null +++ b/src/phases/check-switch-phase.ts @@ -0,0 +1,61 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattleStyle } from "#app/enums/battle-style.js"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { BattlePhase } from "./battle-phase"; +import { PostSummonPhase } from "./post-summon-phase"; +import { SummonMissingPhase } from "./summon-missing-phase"; +import { SwitchPhase } from "./switch-phase"; + +export class CheckSwitchPhase extends BattlePhase { + protected fieldIndex: integer; + protected useName: boolean; + + constructor(scene: BattleScene, fieldIndex: integer, useName: boolean) { + super(scene); + + this.fieldIndex = fieldIndex; + this.useName = useName; + } + + start() { + super.start(); + + const pokemon = this.scene.getPlayerField()[this.fieldIndex]; + + if (this.scene.battleStyle === BattleStyle.SET) { + super.end(); + return; + } + + if (this.scene.field.getAll().indexOf(pokemon) === -1) { + this.scene.unshiftPhase(new SummonMissingPhase(this.scene, this.fieldIndex)); + super.end(); + return; + } + + if (!this.scene.getParty().slice(1).filter(p => p.isActive()).length) { + super.end(); + return; + } + + if (pokemon.getTag(BattlerTagType.FRENZY)) { + super.end(); + return; + } + + this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? getPokemonNameWithAffix(pokemon) : i18next.t("battle:pokemon") }), null, () => { + this.scene.ui.setMode(Mode.CONFIRM, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex); + this.scene.unshiftPhase(new SwitchPhase(this.scene, this.fieldIndex, false, true)); + this.end(); + }, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.end(); + }); + }); + } +} diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts new file mode 100644 index 00000000000..5d466e5d3b6 --- /dev/null +++ b/src/phases/command-phase.ts @@ -0,0 +1,288 @@ +import BattleScene from "#app/battle-scene.js"; +import { TurnCommand, BattleType } from "#app/battle.js"; +import { applyCheckTrappedAbAttrs, CheckTrappedAbAttr } from "#app/data/ability.js"; +import { TrappedTag, EncoreTag } from "#app/data/battler-tags.js"; +import { MoveTargetSet, getMoveTargets } from "#app/data/move.js"; +import { speciesStarters } from "#app/data/pokemon-species.js"; +import { Type } from "#app/data/type.js"; +import { Abilities } from "#app/enums/abilities.js"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { Biome } from "#app/enums/biome.js"; +import { Moves } from "#app/enums/moves.js"; +import { PokeballType } from "#app/enums/pokeball.js"; +import { FieldPosition, PlayerPokemon } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { Command } from "#app/ui/command-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { FieldPhase } from "./field-phase"; +import { SelectTargetPhase } from "./select-target-phase"; + +export class CommandPhase extends FieldPhase { + protected fieldIndex: integer; + + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene); + + this.fieldIndex = fieldIndex; + } + + start() { + super.start(); + + if (this.fieldIndex) { + // If we somehow are attempting to check the right pokemon but there's only one pokemon out + // Switch back to the center pokemon. This can happen rarely in double battles with mid turn switching + if (this.scene.getPlayerField().filter(p => p.isActive()).length === 1) { + this.fieldIndex = FieldPosition.CENTER; + } else { + const allyCommand = this.scene.currentBattle.turnCommands[this.fieldIndex - 1]; + if (allyCommand?.command === Command.BALL || allyCommand?.command === Command.RUN) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand?.command, skip: true }; + } + } + } + + if (this.scene.currentBattle.turnCommands[this.fieldIndex]?.skip) { + return this.end(); + } + + const playerPokemon = this.scene.getPlayerField()[this.fieldIndex]; + + const moveQueue = playerPokemon.getMoveQueue(); + + while (moveQueue.length && moveQueue[0] + && moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m?.moveId === moveQueue[0].move) + || !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m?.moveId === moveQueue[0].move)]!.isUsable(playerPokemon, moveQueue[0].ignorePP))) { // TODO: is the bang correct? + moveQueue.shift(); + } + + if (moveQueue.length) { + const queuedMove = moveQueue[0]; + if (!queuedMove.move) { + this.handleCommand(Command.FIGHT, -1, false); + } else { + const moveIndex = playerPokemon.getMoveset().findIndex(m => m?.moveId === queuedMove.move); + if (moveIndex > -1 && playerPokemon.getMoveset()[moveIndex]!.isUsable(playerPokemon, queuedMove.ignorePP)) { // TODO: is the bang correct? + this.handleCommand(Command.FIGHT, moveIndex, queuedMove.ignorePP, { targets: queuedMove.targets, multiple: queuedMove.targets.length > 1 }); + } else { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + } + } + } else { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + } + } + + handleCommand(command: Command, cursor: integer, ...args: any[]): boolean { + const playerPokemon = this.scene.getPlayerField()[this.fieldIndex]; + const enemyField = this.scene.getEnemyField(); + let success: boolean; + + switch (command) { + case Command.FIGHT: + let useStruggle = false; + if (cursor === -1 || + playerPokemon.trySelectMove(cursor, args[0] as boolean) || + (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m?.isUsable(playerPokemon)).length)) { + const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor]!.moveId : Moves.NONE : Moves.STRUGGLE; // TODO: is the bang correct? + const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args }; + const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2]; + if (!moveId) { + turnCommand.targets = [this.fieldIndex]; + } + console.log(moveTargets, getPokemonNameWithAffix(playerPokemon)); + if (moveTargets.targets.length > 1 && moveTargets.multiple) { + this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); + } + if (moveTargets.targets.length <= 1 || moveTargets.multiple) { + turnCommand.move!.targets = moveTargets.targets; //TODO: is the bang correct here? + } else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) { + turnCommand.move!.targets = playerPokemon.getMoveQueue()[0].targets; //TODO: is the bang correct here? + } else { + this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); + } + this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand; + success = true; + } else if (cursor < playerPokemon.getMoveset().length) { + const move = playerPokemon.getMoveset()[cursor]!; //TODO: is this bang correct? + this.scene.ui.setMode(Mode.MESSAGE); + + // Decides between a Disabled, Not Implemented, or No PP translation message + const errorMessage = + playerPokemon.summonData.disabledMove === move.moveId ? "battle:moveDisabled" : + move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP"; + const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator + + this.scene.ui.showText(i18next.t(errorMessage, { moveName: moveName }), null, () => { + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex); + }, null, true); + } + break; + case Command.BALL: + const notInDex = (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1); + if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || notInDex )) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noPokeballTrainer"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else { + const targets = this.scene.getEnemyField().filter(p => p.isActive(true)).map(p => p.getBattlerIndex()); + if (targets.length > 1) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noPokeballMulti"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else if (cursor < 5) { + const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true)); + if (targetPokemon?.isBoss() && targetPokemon?.bossSegmentIndex >= 1 && !targetPokemon?.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noPokeballStrong"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else { + this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.BALL, cursor: cursor }; + this.scene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets; + if (this.fieldIndex) { + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; + } + success = true; + } + } + } + break; + case Command.POKEMON: + case Command.RUN: + const isSwitch = command === Command.POKEMON; + if (!isSwitch && this.scene.arena.biomeType === Biome.END) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noEscapeForce"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:noEscapeTrainer"), null, () => { + this.scene.ui.showText("", 0); + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + }, null, true); + } else { + const trapTag = playerPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; + const trapped = new Utils.BooleanHolder(false); + const batonPass = isSwitch && args[0] as boolean; + const trappedAbMessages: string[] = []; + if (!batonPass) { + enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, true, trappedAbMessages)); + } + if (batonPass || (!trapTag && !trapped.value)) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch + ? { command: Command.POKEMON, cursor: cursor, args: args } + : { command: Command.RUN }; + success = true; + if (!isSwitch && this.fieldIndex) { + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; + } + } else if (trapTag) { + if (trapTag.sourceMove === Moves.INGRAIN && trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId)?.isOfType(Type.GHOST)) { + success = true; + this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch + ? { command: Command.POKEMON, cursor: cursor, args: args } + : { command: Command.RUN }; + break; + } + if (!isSwitch) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + this.scene.ui.setMode(Mode.MESSAGE); + } + this.scene.ui.showText( + i18next.t("battle:noEscapePokemon", { + pokemonName: trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId) ? getPokemonNameWithAffix(this.scene.getPokemonById(trapTag.sourceId)!) : "", + moveName: trapTag.getMoveName(), + escapeVerb: isSwitch ? i18next.t("battle:escapeVerbSwitch") : i18next.t("battle:escapeVerbFlee") + }), + null, + () => { + this.scene.ui.showText("", 0); + if (!isSwitch) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + } + }, null, true); + } else if (trapped.value && trappedAbMessages.length > 0) { + if (!isSwitch) { + this.scene.ui.setMode(Mode.MESSAGE); + } + this.scene.ui.showText(trappedAbMessages[0], null, () => { + this.scene.ui.showText("", 0); + if (!isSwitch) { + this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); + } + }, null, true); + } + } + break; + } + + if (success!) { // TODO: is the bang correct? + this.end(); + } + + return success!; // TODO: is the bang correct? + } + + cancel() { + if (this.fieldIndex) { + this.scene.unshiftPhase(new CommandPhase(this.scene, 0)); + this.scene.unshiftPhase(new CommandPhase(this.scene, 1)); + this.end(); + } + } + + checkFightOverride(): boolean { + const pokemon = this.getPokemon(); + + const encoreTag = pokemon.getTag(EncoreTag) as EncoreTag; + + if (!encoreTag) { + return false; + } + + const moveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === encoreTag.moveId); + + if (moveIndex === -1 || !pokemon.getMoveset()[moveIndex]!.isUsable(pokemon)) { // TODO: is this bang correct? + return false; + } + + this.handleCommand(Command.FIGHT, moveIndex, false); + + return true; + } + + getFieldIndex(): integer { + return this.fieldIndex; + } + + getPokemon(): PlayerPokemon { + return this.scene.getPlayerField()[this.fieldIndex]; + } + + end() { + this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + } +} diff --git a/src/phases/common-anim-phase.ts b/src/phases/common-anim-phase.ts new file mode 100644 index 00000000000..d3663abe3b6 --- /dev/null +++ b/src/phases/common-anim-phase.ts @@ -0,0 +1,26 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class CommonAnimPhase extends PokemonPhase { + private anim: CommonAnim | null; + private targetIndex: integer | undefined; + + constructor(scene: BattleScene, battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex | undefined, anim?: CommonAnim) { + super(scene, battlerIndex); + + this.anim = anim!; // TODO: is this bang correct? + this.targetIndex = targetIndex; + } + + setAnimation(anim: CommonAnim) { + this.anim = anim; + } + + start() { + new CommonBattleAnim(this.anim, this.getPokemon(), this.targetIndex !== undefined ? (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField())[this.targetIndex] : this.getPokemon()).play(this.scene, () => { + this.end(); + }); + } +} diff --git a/src/phases/damage-phase.ts b/src/phases/damage-phase.ts new file mode 100644 index 00000000000..9f63ce35cf2 --- /dev/null +++ b/src/phases/damage-phase.ts @@ -0,0 +1,84 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { BattleSpec } from "#app/enums/battle-spec.js"; +import { DamageResult, HitResult } from "#app/field/pokemon.js"; +import * as Utils from "#app/utils.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class DamagePhase extends PokemonPhase { + private amount: integer; + private damageResult: DamageResult; + private critical: boolean; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, amount: integer, damageResult?: DamageResult, critical: boolean = false) { + super(scene, battlerIndex); + + this.amount = amount; + this.damageResult = damageResult || HitResult.EFFECTIVE; + this.critical = critical; + } + + start() { + super.start(); + + if (this.damageResult === HitResult.ONE_HIT_KO) { + if (this.scene.moveAnimations) { + this.scene.toggleInvert(true); + } + this.scene.time.delayedCall(Utils.fixedInt(1000), () => { + this.scene.toggleInvert(false); + this.applyDamage(); + }); + return; + } + + this.applyDamage(); + } + + updateAmount(amount: integer): void { + this.amount = amount; + } + + applyDamage() { + switch (this.damageResult) { + case HitResult.EFFECTIVE: + this.scene.playSound("hit"); + break; + case HitResult.SUPER_EFFECTIVE: + case HitResult.ONE_HIT_KO: + this.scene.playSound("hit_strong"); + break; + case HitResult.NOT_VERY_EFFECTIVE: + this.scene.playSound("hit_weak"); + break; + } + + if (this.amount) { + this.scene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical); + } + + if (this.damageResult !== HitResult.OTHER) { + const flashTimer = this.scene.time.addEvent({ + delay: 100, + repeat: 5, + startAt: 200, + callback: () => { + this.getPokemon().getSprite().setVisible(flashTimer.repeatCount % 2 === 0); + if (!flashTimer.repeatCount) { + this.getPokemon().updateInfo().then(() => this.end()); + } + } + }); + } else { + this.getPokemon().updateInfo().then(() => this.end()); + } + } + + override end() { + if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { + this.scene.initFinalBossPhaseTwo(this.getPokemon()); + } else { + super.end(); + } + } +} diff --git a/src/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts similarity index 95% rename from src/egg-hatch-phase.ts rename to src/phases/egg-hatch-phase.ts index 73c88cbde37..6f3f0b37905 100644 --- a/src/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -1,18 +1,17 @@ -import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; +import BattleScene, { AnySound } from "#app/battle-scene.js"; +import { Egg, EGG_SEED } from "#app/data/egg.js"; +import { EggCountChangedEvent } from "#app/events/egg.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { Phase } from "#app/phase.js"; +import { achvs } from "#app/system/achv.js"; +import EggCounterContainer from "#app/ui/egg-counter-container.js"; +import EggHatchSceneHandler from "#app/ui/egg-hatch-scene-handler.js"; +import PokemonInfoContainer from "#app/ui/pokemon-info-container.js"; +import { Mode } from "#app/ui/ui.js"; import i18next from "i18next"; -import { Phase } from "./phase"; -import BattleScene, { AnySound } from "./battle-scene"; -import * as Utils from "./utils"; -import { Mode } from "./ui/ui"; -import { EGG_SEED, Egg } from "./data/egg"; -import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler"; -import { PlayerPokemon } from "./field/pokemon"; -import { achvs } from "./system/achv"; -import PokemonInfoContainer from "./ui/pokemon-info-container"; -import EggCounterContainer from "./ui/egg-counter-container"; -import { EggCountChangedEvent } from "./events/egg"; -import { getPokemonNameWithAffix } from "./messages"; - +import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; +import * as Utils from "#app/utils.js"; /** * Class that represents egg hatching */ diff --git a/src/phases/egg-lapse-phase.ts b/src/phases/egg-lapse-phase.ts new file mode 100644 index 00000000000..50d7106f229 --- /dev/null +++ b/src/phases/egg-lapse-phase.ts @@ -0,0 +1,35 @@ +import BattleScene from "#app/battle-scene.js"; +import { Egg } from "#app/data/egg.js"; +import { Phase } from "#app/phase.js"; +import i18next from "i18next"; +import Overrides from "#app/overrides"; +import { EggHatchPhase } from "./egg-hatch-phase"; + +export class EggLapsePhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + const eggsToHatch: Egg[] = this.scene.gameData.eggs.filter((egg: Egg) => { + return Overrides.EGG_IMMEDIATE_HATCH_OVERRIDE ? true : --egg.hatchWaves < 1; + }); + + let eggCount: integer = eggsToHatch.length; + + if (eggCount) { + this.scene.queueMessage(i18next.t("battle:eggHatching")); + + for (const egg of eggsToHatch) { + this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg, eggCount)); + if (eggCount > 0) { + eggCount--; + } + } + + } + this.end(); + } +} diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts new file mode 100644 index 00000000000..739bb1d93f1 --- /dev/null +++ b/src/phases/encounter-phase.ts @@ -0,0 +1,379 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattleType, BattlerIndex } from "#app/battle.js"; +import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability.js"; +import { getCharVariantFromDialogue } from "#app/data/dialogue.js"; +import { TrainerSlot } from "#app/data/trainer-config.js"; +import { getRandomWeatherType } from "#app/data/weather.js"; +import { BattleSpec } from "#app/enums/battle-spec.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { Species } from "#app/enums/species.js"; +import { EncounterPhaseEvent } from "#app/events/battle-scene.js"; +import Pokemon, { FieldPosition } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { regenerateModifierPoolThresholds, ModifierPoolType } from "#app/modifier/modifier-type.js"; +import { IvScannerModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier.js"; +import { achvs } from "#app/system/achv.js"; +import { handleTutorial, Tutorial } from "#app/tutorial.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { BattlePhase } from "./battle-phase"; +import * as Utils from "#app/utils.js"; +import { CheckSwitchPhase } from "./check-switch-phase"; +import { GameOverPhase } from "./game-over-phase"; +import { PostSummonPhase } from "./post-summon-phase"; +import { ReturnPhase } from "./return-phase"; +import { ScanIvsPhase } from "./scan-ivs-phase"; +import { ShinySparklePhase } from "./shiny-sparkle-phase"; +import { SummonPhase } from "./summon-phase"; +import { ToggleDoublePositionPhase } from "./toggle-double-position-phase"; + +export class EncounterPhase extends BattlePhase { + private loaded: boolean; + + constructor(scene: BattleScene, loaded?: boolean) { + super(scene); + + this.loaded = !!loaded; + } + + start() { + super.start(); + + this.scene.updateGameInfo(); + + this.scene.initSession(); + + this.scene.eventTarget.dispatchEvent(new EncounterPhaseEvent()); + + // Failsafe if players somehow skip floor 200 in classic mode + if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) { + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + } + + const loadEnemyAssets: Promise[] = []; + + const battle = this.scene.currentBattle; + + let totalBst = 0; + + battle.enemyLevels?.forEach((level, e) => { + if (!this.loaded) { + if (battle.battleType === BattleType.TRAINER) { + battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here? + } else { + const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true); + battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies)); + if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { + battle.enemyParty[e].ivs = new Array(6).fill(31); + } + this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => { + applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]); + }); + } + } + const enemyPokemon = this.scene.getEnemyParty()[e]; + if (e < (battle.double ? 2 : 1)) { + enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]); + enemyPokemon.resetSummonData(); + } + + if (!this.loaded) { + this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER); + } + + if (enemyPokemon.species.speciesId === Species.ETERNATUS) { + if (this.scene.gameMode.isClassic && (battle.battleSpec === BattleSpec.FINAL_BOSS || this.scene.gameMode.isWaveFinal(battle.waveIndex))) { + if (battle.battleSpec !== BattleSpec.FINAL_BOSS) { + enemyPokemon.formIndex = 1; + enemyPokemon.updateScale(); + } + enemyPokemon.setBoss(); + } else if (!(battle.waveIndex % 1000)) { + enemyPokemon.formIndex = 1; + enemyPokemon.updateScale(); + const bossMBH = this.scene.findModifier(m => m instanceof TurnHeldItemTransferModifier && m.pokemonId === enemyPokemon.id, false) as TurnHeldItemTransferModifier; + this.scene.removeModifier(bossMBH!); + bossMBH?.setTransferrableFalse(); + this.scene.addEnemyModifier(bossMBH!); + } + } + + totalBst += enemyPokemon.getSpeciesForm().baseTotal; + + loadEnemyAssets.push(enemyPokemon.loadAssets()); + + console.log(getPokemonNameWithAffix(enemyPokemon), enemyPokemon.species.speciesId, enemyPokemon.stats); + }); + + if (this.scene.getParty().filter(p => p.isShiny()).length === 6) { + this.scene.validateAchv(achvs.SHINY_PARTY); + } + + if (battle.battleType === BattleType.TRAINER) { + loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct? + } else { + // This block only applies for double battles to init the boss segments (idk why it's split up like this) + if (battle.enemyParty.filter(p => p.isBoss()).length > 1) { + for (const enemyPokemon of battle.enemyParty) { + // If the enemy pokemon is a boss and wasn't populated from data source, then set it up + if (enemyPokemon.isBoss() && !enemyPokemon.isPopulatedFromDataSource) { + enemyPokemon.setBoss(true, Math.ceil(enemyPokemon.bossSegments * (enemyPokemon.getSpeciesForm().baseTotal / totalBst))); + enemyPokemon.initBattleInfo(); + } + } + } + } + + Promise.all(loadEnemyAssets).then(() => { + battle.enemyParty.forEach((enemyPokemon, e) => { + if (e < (battle.double ? 2 : 1)) { + if (battle.battleType === BattleType.WILD) { + this.scene.field.add(enemyPokemon); + battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); + const playerPokemon = this.scene.getPlayerPokemon(); + if (playerPokemon?.visible) { + this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon); + } + enemyPokemon.tint(0, 0.5); + } else if (battle.battleType === BattleType.TRAINER) { + enemyPokemon.setVisible(false); + this.scene.currentBattle.trainer?.tint(0, 0.5); + } + if (battle.double) { + enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT); + } + } + }); + + if (!this.loaded) { + regenerateModifierPoolThresholds(this.scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD); + this.scene.generateEnemyModifiers(); + } + + this.scene.ui.setMode(Mode.MESSAGE).then(() => { + if (!this.loaded) { + //@ts-ignore + this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore + this.scene.disableMenu = false; + if (!success) { + return this.scene.reset(true); + } + this.doEncounter(); + }); + } else { + this.doEncounter(); + } + }); + }); + } + + doEncounter() { + this.scene.playBgm(undefined, true); + this.scene.updateModifiers(false); + this.scene.setFieldScale(1); + + /*if (startingWave > 10) { + for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++) + this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier(), true); + this.scene.updateModifiers(true); + }*/ + + for (const pokemon of this.scene.getParty()) { + if (pokemon) { + pokemon.resetBattleData(); + } + } + + if (!this.loaded) { + this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); + } + + const enemyField = this.scene.getEnemyField(); + this.scene.tweens.add({ + targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(), + x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300, + duration: 2000, + onComplete: () => { + if (!this.tryOverrideForBattleSpec()) { + this.doEncounterCommon(); + } + } + }); + } + + getEncounterMessage(): string { + const enemyField = this.scene.getEnemyField(); + + if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { + return i18next.t("battle:bossAppeared", { bossName: getPokemonNameWithAffix(enemyField[0])}); + } + + if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + if (this.scene.currentBattle.double) { + return i18next.t("battle:trainerAppearedDouble", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); + + } else { + return i18next.t("battle:trainerAppeared", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); + } + } + + return enemyField.length === 1 + ? i18next.t("battle:singleWildAppeared", { pokemonName: enemyField[0].getNameToRender() }) + : i18next.t("battle:multiWildAppeared", { pokemonName1: enemyField[0].getNameToRender(), pokemonName2: enemyField[1].getNameToRender() }); + } + + doEncounterCommon(showEncounterMessage: boolean = true) { + const enemyField = this.scene.getEnemyField(); + + if (this.scene.currentBattle.battleType === BattleType.WILD) { + enemyField.forEach(enemyPokemon => { + enemyPokemon.untint(100, "Sine.easeOut"); + enemyPokemon.cry(); + enemyPokemon.showInfo(); + if (enemyPokemon.isShiny()) { + this.scene.validateAchv(achvs.SEE_SHINY); + } + }); + this.scene.updateFieldScale(); + if (showEncounterMessage) { + this.scene.ui.showText(this.getEncounterMessage(), null, () => this.end(), 1500); + } else { + this.end(); + } + } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + const trainer = this.scene.currentBattle.trainer; + trainer?.untint(100, "Sine.easeOut"); + trainer?.playAnim(); + + const doSummon = () => { + this.scene.currentBattle.started = true; + this.scene.playBgm(undefined); + this.scene.pbTray.showPbTray(this.scene.getParty()); + this.scene.pbTrayEnemy.showPbTray(this.scene.getEnemyParty()); + const doTrainerSummon = () => { + this.hideEnemyTrainer(); + const availablePartyMembers = this.scene.getEnemyParty().filter(p => !p.isFainted()).length; + this.scene.unshiftPhase(new SummonPhase(this.scene, 0, false)); + if (this.scene.currentBattle.double && availablePartyMembers > 1) { + this.scene.unshiftPhase(new SummonPhase(this.scene, 1, false)); + } + this.end(); + }; + if (showEncounterMessage) { + this.scene.ui.showText(this.getEncounterMessage(), null, doTrainerSummon, 1500, true); + } else { + doTrainerSummon(); + } + }; + + const encounterMessages = this.scene.currentBattle.trainer?.getEncounterMessages(); + + if (!encounterMessages?.length) { + doSummon(); + } else { + let message: string; + this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex); + message = message!; // tell TS compiler it's defined now + const showDialogueAndSummon = () => { + this.scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => { + this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doSummon())); + }); + }; + if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { + this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer?.getKey()!, getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); // TODO: is this bang correct? + } else { + showDialogueAndSummon(); + } + } + } + } + + end() { + const enemyField = this.scene.getEnemyField(); + + enemyField.forEach((enemyPokemon, e) => { + if (enemyPokemon.isShiny()) { + this.scene.unshiftPhase(new ShinySparklePhase(this.scene, BattlerIndex.ENEMY + e)); + } + }); + + if (this.scene.currentBattle.battleType !== BattleType.TRAINER) { + enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => { + // if there is not a player party, we can't continue + if (!this.scene.getParty()?.length) { + return false; + } + // how many player pokemon are on the field ? + const pokemonsOnFieldCount = this.scene.getParty().filter(p => p.isOnField()).length; + // if it's a 2vs1, there will never be a 2nd pokemon on our field even + const requiredPokemonsOnField = Math.min(this.scene.getParty().filter((p) => !p.isFainted()).length, 2); + // if it's a double, there should be 2, otherwise 1 + if (this.scene.currentBattle.double) { + return pokemonsOnFieldCount === requiredPokemonsOnField; + } + return pokemonsOnFieldCount === 1; + })); + const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier); + if (ivScannerModifier) { + enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6)))); + } + } + + if (!this.loaded) { + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()); + + if (!availablePartyMembers[0].isOnField()) { + this.scene.pushPhase(new SummonPhase(this.scene, 0)); + } + + if (this.scene.currentBattle.double) { + if (availablePartyMembers.length > 1) { + this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, true)); + if (!availablePartyMembers[1].isOnField()) { + this.scene.pushPhase(new SummonPhase(this.scene, 1)); + } + } + } else { + if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { + this.scene.pushPhase(new ReturnPhase(this.scene, 1)); + } + this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false)); + } + + if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) { + const minPartySize = this.scene.currentBattle.double ? 2 : 1; + if (availablePartyMembers.length > minPartySize) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); + if (this.scene.currentBattle.double) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); + } + } + } + } + handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end()); + } + + tryOverrideForBattleSpec(): boolean { + switch (this.scene.currentBattle.battleSpec) { + case BattleSpec.FINAL_BOSS: + const enemy = this.scene.getEnemyPokemon(); + this.scene.ui.showText(this.getEncounterMessage(), null, () => { + const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; + //The two lines below check if English ordinals (1st, 2nd, 3rd, Xth) are used and determine which one to use. + //Otherwise, it defaults to an empty string. + //As of 08-07-24: Spanish and Italian default to the English translations + const ordinalUse = ["en", "es", "it"]; + const currentLanguage = i18next.resolvedLanguage ?? "en"; + const ordinalIndex = (ordinalUse.includes(currentLanguage)) ? ["st", "nd", "rd"][((count + 90) % 100 - 10) % 10 - 1] ?? "th" : ""; + const cycleCount = count.toLocaleString() + ordinalIndex; + const encounterDialogue = i18next.t(`${(this.scene.gameData.gender === PlayerGender.FEMALE) ? "PGF" : "PGM"}battleSpecDialogue:encounter`, {cycleCount: cycleCount}); + this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => { + this.doEncounterCommon(false); + }); + }, 1500, true); + return true; + } + + return false; + } +} diff --git a/src/phases/end-card-phase.ts b/src/phases/end-card-phase.ts new file mode 100644 index 00000000000..0b70664b993 --- /dev/null +++ b/src/phases/end-card-phase.ts @@ -0,0 +1,40 @@ +import BattleScene from "#app/battle-scene.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { Phase } from "#app/phase.js"; +import { addTextObject, TextStyle } from "#app/ui/text.js"; +import i18next from "i18next"; + +export class EndCardPhase extends Phase { + public endCard: Phaser.GameObjects.Image; + public text: Phaser.GameObjects.Text; + + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + super.start(); + + this.scene.ui.getMessageHandler().bg.setVisible(false); + this.scene.ui.getMessageHandler().nameBoxContainer.setVisible(false); + + this.endCard = this.scene.add.image(0, 0, `end_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}`); + this.endCard.setOrigin(0); + this.endCard.setScale(0.5); + this.scene.field.add(this.endCard); + + this.text = addTextObject(this.scene, this.scene.game.canvas.width / 12, (this.scene.game.canvas.height / 6) - 16, i18next.t("battle:congratulations"), TextStyle.SUMMARY, { fontSize: "128px" }); + this.text.setOrigin(0.5); + this.scene.field.add(this.text); + + this.scene.ui.clearText(); + + this.scene.ui.fadeIn(1000).then(() => { + + this.scene.ui.showText("", null, () => { + this.scene.ui.getMessageHandler().bg.setVisible(true); + this.end(); + }, null, true); + }); + } +} diff --git a/src/phases/end-evolution-phase.ts b/src/phases/end-evolution-phase.ts new file mode 100644 index 00000000000..2a6d492a425 --- /dev/null +++ b/src/phases/end-evolution-phase.ts @@ -0,0 +1,16 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Mode } from "#app/ui/ui.js"; + +export class EndEvolutionPhase extends Phase { + + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.ui.setModeForceTransition(Mode.MESSAGE).then(() => this.end()); + } +} diff --git a/src/phases/enemy-command-phase.ts b/src/phases/enemy-command-phase.ts new file mode 100644 index 00000000000..d7f553681c2 --- /dev/null +++ b/src/phases/enemy-command-phase.ts @@ -0,0 +1,86 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyCheckTrappedAbAttrs, CheckTrappedAbAttr } from "#app/data/ability.js"; +import { TrappedTag } from "#app/data/battler-tags.js"; +import { Command } from "#app/ui/command-ui-handler.js"; +import * as Utils from "#app/utils.js"; +import { FieldPhase } from "./field-phase"; + +/** + * Phase for determining an enemy AI's action for the next turn. + * During this phase, the enemy decides whether to switch (if it has a trainer) + * or to use a move from its moveset. + * + * For more information on how the Enemy AI works, see docs/enemy-ai.md + * @see {@linkcode Pokemon.getMatchupScore} + * @see {@linkcode EnemyPokemon.getNextMove} + */ +export class EnemyCommandPhase extends FieldPhase { + protected fieldIndex: integer; + + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene); + + this.fieldIndex = fieldIndex; + } + + start() { + super.start(); + + const enemyPokemon = this.scene.getEnemyField()[this.fieldIndex]; + + const battle = this.scene.currentBattle; + + const trainer = battle.trainer; + + /** + * If the enemy has a trainer, decide whether or not the enemy should switch + * to another member in its party. + * + * This block compares the active enemy Pokemon's {@linkcode Pokemon.getMatchupScore | matchup score} + * against the active player Pokemon with the enemy party's other non-fainted Pokemon. If a party + * member's matchup score is 3x the active enemy's score (or 2x for "boss" trainers), + * the enemy will switch to that Pokemon. + */ + if (trainer && !enemyPokemon.getMoveQueue().length) { + const opponents = enemyPokemon.getOpponents(); + + const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; + const trapped = new Utils.BooleanHolder(false); + opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, true, [])); + if (!trapTag && !trapped.value) { + const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true); + + if (partyMemberScores.length) { + const matchupScores = opponents.map(opp => enemyPokemon.getMatchupScore(opp)); + const matchupScore = matchupScores.reduce((total, score) => total += score, 0) / matchupScores.length; + + const sortedPartyMemberScores = trainer.getSortedPartyMemberMatchupScores(partyMemberScores); + + const switchMultiplier = 1 - (battle.enemySwitchCounter ? Math.pow(0.1, (1 / battle.enemySwitchCounter)) : 0); + + if (sortedPartyMemberScores[0][1] * switchMultiplier >= matchupScore * (trainer.config.isBoss ? 2 : 3)) { + const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores); + + battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] = + { command: Command.POKEMON, cursor: index, args: [false] }; + + battle.enemySwitchCounter++; + + return this.end(); + } + } + } + } + + /** Select a move to use (and a target to use it against, if applicable) */ + const nextMove = enemyPokemon.getNextMove(); + + this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] = + { command: Command.FIGHT, move: nextMove }; + + this.scene.currentBattle.enemySwitchCounter = Math.max(this.scene.currentBattle.enemySwitchCounter - 1, 0); + + this.end(); + } +} diff --git a/src/phases/enemy-party-member-pokemon-phase.ts b/src/phases/enemy-party-member-pokemon-phase.ts new file mode 100644 index 00000000000..10af0913f93 --- /dev/null +++ b/src/phases/enemy-party-member-pokemon-phase.ts @@ -0,0 +1,13 @@ +import BattleScene from "#app/battle-scene.js"; +import { EnemyPokemon } from "#app/field/pokemon.js"; +import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase"; + +export abstract class EnemyPartyMemberPokemonPhase extends PartyMemberPokemonPhase { + constructor(scene: BattleScene, partyMemberIndex: integer) { + super(scene, partyMemberIndex, false); + } + + getEnemyPokemon(): EnemyPokemon { + return super.getPokemon() as EnemyPokemon; + } +} diff --git a/src/evolution-phase.ts b/src/phases/evolution-phase.ts similarity index 96% rename from src/evolution-phase.ts rename to src/phases/evolution-phase.ts index 7b50a6368f6..398450ec693 100644 --- a/src/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -1,16 +1,17 @@ import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import { Phase } from "./phase"; -import BattleScene from "./battle-scene"; -import { SpeciesFormEvolution } from "./data/pokemon-evolutions"; -import EvolutionSceneHandler from "./ui/evolution-scene-handler"; -import * as Utils from "./utils"; -import { Mode } from "./ui/ui"; -import { LearnMovePhase } from "./phases"; -import { cos, sin } from "./field/anims"; -import { PlayerPokemon } from "./field/pokemon"; -import { getTypeRgb } from "./data/type"; +import { Phase } from "../phase"; +import BattleScene from "../battle-scene"; +import { SpeciesFormEvolution } from "../data/pokemon-evolutions"; +import EvolutionSceneHandler from "../ui/evolution-scene-handler"; +import * as Utils from "../utils"; +import { Mode } from "../ui/ui"; +import { cos, sin } from "../field/anims"; +import { PlayerPokemon } from "../field/pokemon"; +import { getTypeRgb } from "../data/type"; import i18next from "i18next"; -import { getPokemonNameWithAffix } from "./messages"; +import { getPokemonNameWithAffix } from "../messages"; +import { LearnMovePhase } from "./learn-move-phase"; +import { EndEvolutionPhase } from "./end-evolution-phase"; export class EvolutionPhase extends Phase { protected pokemon: PlayerPokemon; @@ -530,16 +531,3 @@ export class EvolutionPhase extends Phase { updateParticle(); } } - -export class EndEvolutionPhase extends Phase { - - constructor(scene: BattleScene) { - super(scene); - } - - start() { - super.start(); - - this.scene.ui.setModeForceTransition(Mode.MESSAGE).then(() => this.end()); - } -} diff --git a/src/phases/exp-phase.ts b/src/phases/exp-phase.ts new file mode 100644 index 00000000000..9c2ba95d550 --- /dev/null +++ b/src/phases/exp-phase.ts @@ -0,0 +1,35 @@ +import BattleScene from "#app/battle-scene.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { ExpBoosterModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; +import { LevelUpPhase } from "./level-up-phase"; + +export class ExpPhase extends PlayerPartyMemberPokemonPhase { + private expValue: number; + + constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) { + super(scene, partyMemberIndex); + + this.expValue = expValue; + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + const exp = new Utils.NumberHolder(this.expValue); + this.scene.applyModifiers(ExpBoosterModifier, true, exp); + exp.value = Math.floor(exp.value); + this.scene.ui.showText(i18next.t("battle:expGain", { pokemonName: getPokemonNameWithAffix(pokemon), exp: exp.value }), null, () => { + const lastLevel = pokemon.level; + pokemon.addExp(exp.value); + const newLevel = pokemon.level; + if (newLevel > lastLevel) { + this.scene.unshiftPhase(new LevelUpPhase(this.scene, this.partyMemberIndex, lastLevel, newLevel)); + } + pokemon.updateInfo().then(() => this.end()); + }, null, true); + } +} diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts new file mode 100644 index 00000000000..14727f992d2 --- /dev/null +++ b/src/phases/faint-phase.ts @@ -0,0 +1,171 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex, BattleType } from "#app/battle.js"; +import { applyPostFaintAbAttrs, PostFaintAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr } from "#app/data/ability.js"; +import { BattlerTagLapseType } from "#app/data/battler-tags.js"; +import { battleSpecDialogue } from "#app/data/dialogue.js"; +import { allMoves, PostVictoryStatChangeAttr } from "#app/data/move.js"; +import { BattleSpec } from "#app/enums/battle-spec.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { PokemonMove, EnemyPokemon, PlayerPokemon, HitResult } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { PokemonInstantReviveModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import { DamagePhase } from "./damage-phase"; +import { PokemonPhase } from "./pokemon-phase"; +import { SwitchSummonPhase } from "./switch-summon-phase"; +import { ToggleDoublePositionPhase } from "./toggle-double-position-phase"; +import { GameOverPhase } from "./game-over-phase"; +import { SwitchPhase } from "./switch-phase"; +import { VictoryPhase } from "./victory-phase"; + +export class FaintPhase extends PokemonPhase { + private preventEndure: boolean; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, preventEndure?: boolean) { + super(scene, battlerIndex); + + this.preventEndure = preventEndure!; // TODO: is this bang correct? + } + + start() { + super.start(); + + if (!this.preventEndure) { + const instantReviveModifier = this.scene.applyModifier(PokemonInstantReviveModifier, this.player, this.getPokemon()) as PokemonInstantReviveModifier; + + if (instantReviveModifier) { + if (!--instantReviveModifier.stackCount) { + this.scene.removeModifier(instantReviveModifier); + } + this.scene.updateModifiers(this.player); + return this.end(); + } + } + + if (!this.tryOverrideForBattleSpec()) { + this.doFaint(); + } + } + + doFaint(): void { + const pokemon = this.getPokemon(); + + + // Track total times pokemon have been KO'd for supreme overlord/last respects + if (pokemon.isPlayer()) { + this.scene.currentBattle.playerFaints += 1; + } else { + this.scene.currentBattle.enemyFaints += 1; + } + + this.scene.queueMessage(i18next.t("battle:fainted", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, true); + + if (pokemon.turnData?.attacksReceived?.length) { + const lastAttack = pokemon.turnData.attacksReceived[0]; + applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct? + } + + const alivePlayField = this.scene.getField(true); + alivePlayField.forEach(p => applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon)); + if (pokemon.turnData?.attacksReceived?.length) { + const defeatSource = this.scene.getPokemonById(pokemon.turnData.attacksReceived[0].sourceId); + if (defeatSource?.isOnField()) { + applyPostVictoryAbAttrs(PostVictoryAbAttr, defeatSource); + const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move]; + const pvattrs = pvmove.getAttrs(PostVictoryStatChangeAttr); + if (pvattrs.length) { + for (const pvattr of pvattrs) { + pvattr.applyPostVictory(defeatSource, defeatSource, pvmove); + } + } + } + } + + if (this.player) { + /** The total number of Pokemon in the player's party that can legally fight */ + const legalPlayerPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); + /** The total number of legal player Pokemon that aren't currently on the field */ + const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); + if (!legalPlayerPokemon.length) { + /** If the player doesn't have any legal Pokemon, end the game */ + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + } else if (this.scene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) { + /** + * If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon + * is already on the field, unshift a phase that moves that Pokemon to center position. + */ + this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); + } else if (legalPlayerPartyPokemon.length > 0) { + /** + * If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field, + * push a phase that prompts the player to summon a Pokemon from their party. + */ + this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false)); + } + } else { + this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex)); + if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length; + if (hasReservePartyMember) { + this.scene.pushPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, -1, false, false, false)); + } + } + } + + // in double battles redirect potential moves off fainted pokemon + if (this.scene.currentBattle.double) { + const allyPokemon = pokemon.getAlly(); + this.scene.redirectPokemonMoves(pokemon, allyPokemon); + } + + pokemon.lapseTags(BattlerTagLapseType.FAINT); + this.scene.getField(true).filter(p => p !== pokemon).forEach(p => p.removeTagsBySourceId(pokemon.id)); + + pokemon.faintCry(() => { + if (pokemon instanceof PlayerPokemon) { + pokemon.addFriendship(-10); + } + pokemon.hideInfo(); + this.scene.playSound("faint"); + this.scene.tweens.add({ + targets: pokemon, + duration: 500, + y: pokemon.y + 150, + ease: "Sine.easeIn", + onComplete: () => { + pokemon.setVisible(false); + pokemon.y -= 150; + pokemon.trySetStatus(StatusEffect.FAINT); + if (pokemon.isPlayer()) { + this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon); + } else { + this.scene.addFaintedEnemyScore(pokemon as EnemyPokemon); + this.scene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon); + } + this.scene.field.remove(pokemon); + this.end(); + } + }); + }); + } + + tryOverrideForBattleSpec(): boolean { + switch (this.scene.currentBattle.battleSpec) { + case BattleSpec.FINAL_BOSS: + if (!this.player) { + const enemy = this.getPokemon(); + if (enemy.formIndex) { + this.scene.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].secondStageWin, enemy.species.name, null, () => this.doFaint()); + } else { + // Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase + enemy.hp++; + this.scene.unshiftPhase(new DamagePhase(this.scene, enemy.getBattlerIndex(), 0, HitResult.OTHER)); + this.end(); + } + return true; + } + } + + return false; + } +} diff --git a/src/phases/field-phase.ts b/src/phases/field-phase.ts new file mode 100644 index 00000000000..a9622271f14 --- /dev/null +++ b/src/phases/field-phase.ts @@ -0,0 +1,44 @@ +import { BattlerIndex } from "#app/battle.js"; +import { TrickRoomTag } from "#app/data/arena-tag.js"; +import { Stat } from "#app/enums/stat.js"; +import Pokemon from "#app/field/pokemon.js"; +import { BattlePhase } from "./battle-phase"; +import * as Utils from "#app/utils.js"; + +type PokemonFunc = (pokemon: Pokemon) => void; + +export abstract class FieldPhase extends BattlePhase { + getOrder(): BattlerIndex[] { + const playerField = this.scene.getPlayerField().filter(p => p.isActive()) as Pokemon[]; + const enemyField = this.scene.getEnemyField().filter(p => p.isActive()) as Pokemon[]; + + // We shuffle the list before sorting so speed ties produce random results + let orderedTargets: Pokemon[] = playerField.concat(enemyField); + // We seed it with the current turn to prevent an inconsistency where it + // was varying based on how long since you last reloaded + this.scene.executeWithSeedOffset(() => { + orderedTargets = Utils.randSeedShuffle(orderedTargets); + }, this.scene.currentBattle.turn, this.scene.waveSeed); + + orderedTargets.sort((a: Pokemon, b: Pokemon) => { + const aSpeed = a?.getBattleStat(Stat.SPD) || 0; + const bSpeed = b?.getBattleStat(Stat.SPD) || 0; + + return bSpeed - aSpeed; + }); + + const speedReversed = new Utils.BooleanHolder(false); + this.scene.arena.applyTags(TrickRoomTag, speedReversed); + + if (speedReversed.value) { + orderedTargets = orderedTargets.reverse(); + } + + return orderedTargets.map(t => t.getFieldIndex() + (!t.isPlayer() ? BattlerIndex.ENEMY : 0)); + } + + executeForAll(func: PokemonFunc): void { + const field = this.scene.getField(true).filter(p => p.summonData); + field.forEach(pokemon => func(pokemon)); + } +} diff --git a/src/form-change-phase.ts b/src/phases/form-change-phase.ts similarity index 57% rename from src/form-change-phase.ts rename to src/phases/form-change-phase.ts index 5acbc4fb77c..88e0dd00ce1 100644 --- a/src/form-change-phase.ts +++ b/src/phases/form-change-phase.ts @@ -1,17 +1,14 @@ -import BattleScene from "./battle-scene"; -import * as Utils from "./utils"; -import { SpeciesFormKey } from "./data/pokemon-species"; -import { achvs } from "./system/achv"; -import { SpeciesFormChange, getSpeciesFormChangeMessage } from "./data/pokemon-forms"; -import { EndEvolutionPhase, EvolutionPhase } from "./evolution-phase"; -import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon"; -import { Mode } from "./ui/ui"; -import PartyUiHandler from "./ui/party-ui-handler"; -import { BattleSpec } from "#enums/battle-spec"; -import { BattlePhase, MovePhase, PokemonHealPhase } from "./phases"; -import { getTypeRgb } from "./data/type"; -import { getPokemonNameWithAffix } from "./messages"; -import { SemiInvulnerableTag } from "./data/battler-tags"; +import BattleScene from "../battle-scene"; +import * as Utils from "../utils"; +import { SpeciesFormKey } from "../data/pokemon-species"; +import { achvs } from "../system/achv"; +import { SpeciesFormChange, getSpeciesFormChangeMessage } from "../data/pokemon-forms"; +import { PlayerPokemon } from "../field/pokemon"; +import { Mode } from "../ui/ui"; +import PartyUiHandler from "../ui/party-ui-handler"; +import { getPokemonNameWithAffix } from "../messages"; +import { EndEvolutionPhase } from "./end-evolution-phase"; +import { EvolutionPhase } from "./evolution-phase"; export class FormChangePhase extends EvolutionPhase { private formChange: SpeciesFormChange; @@ -175,126 +172,3 @@ export class FormChangePhase extends EvolutionPhase { } } } - -export class QuietFormChangePhase extends BattlePhase { - protected pokemon: Pokemon; - protected formChange: SpeciesFormChange; - - constructor(scene: BattleScene, pokemon: Pokemon, formChange: SpeciesFormChange) { - super(scene); - this.pokemon = pokemon; - this.formChange = formChange; - } - - start(): void { - super.start(); - - if (this.pokemon.formIndex === this.pokemon.species.forms.findIndex(f => f.formKey === this.formChange.formKey)) { - return this.end(); - } - - const preName = getPokemonNameWithAffix(this.pokemon); - - if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag)) { - this.pokemon.changeForm(this.formChange).then(() => { - this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); - }); - return; - } - - const getPokemonSprite = () => { - const sprite = this.scene.addPokemonSprite(this.pokemon, this.pokemon.x + this.pokemon.getSprite().x, this.pokemon.y + this.pokemon.getSprite().y, "pkmn__sub"); - sprite.setOrigin(0.5, 1); - sprite.play(this.pokemon.getBattleSpriteKey()).stop(); - sprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) }); - [ "spriteColors", "fusionSpriteColors" ].map(k => { - if (this.pokemon.summonData?.speciesForm) { - k += "Base"; - } - sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; - }); - this.scene.field.add(sprite); - return sprite; - }; - - const [ pokemonTintSprite, pokemonFormTintSprite ] = [ getPokemonSprite(), getPokemonSprite() ]; - - this.pokemon.getSprite().on("animationupdate", (_anim, frame) => { - if (frame.textureKey === pokemonTintSprite.texture.key) { - pokemonTintSprite.setFrame(frame.textureFrame); - } else { - pokemonFormTintSprite.setFrame(frame.textureFrame); - } - }); - - pokemonTintSprite.setAlpha(0); - pokemonTintSprite.setTintFill(0xFFFFFF); - pokemonFormTintSprite.setVisible(false); - pokemonFormTintSprite.setTintFill(0xFFFFFF); - - this.scene.playSound("PRSFX- Transform"); - - this.scene.tweens.add({ - targets: pokemonTintSprite, - alpha: 1, - duration: 1000, - ease: "Cubic.easeIn", - onComplete: () => { - this.pokemon.setVisible(false); - this.pokemon.changeForm(this.formChange).then(() => { - pokemonFormTintSprite.setScale(0.01); - pokemonFormTintSprite.play(this.pokemon.getBattleSpriteKey()).stop(); - pokemonFormTintSprite.setVisible(true); - this.scene.tweens.add({ - targets: pokemonTintSprite, - delay: 250, - scale: 0.01, - ease: "Cubic.easeInOut", - duration: 500, - onComplete: () => pokemonTintSprite.destroy() - }); - this.scene.tweens.add({ - targets: pokemonFormTintSprite, - delay: 250, - scale: this.pokemon.getSpriteScale(), - ease: "Cubic.easeInOut", - duration: 500, - onComplete: () => { - this.pokemon.setVisible(true); - this.scene.tweens.add({ - targets: pokemonFormTintSprite, - delay: 250, - alpha: 0, - ease: "Cubic.easeOut", - duration: 1000, - onComplete: () => { - pokemonTintSprite.setVisible(false); - this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); - } - }); - } - }); - }); - } - }); - } - - end(): void { - if (this.pokemon.scene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon instanceof EnemyPokemon) { - this.scene.playBgm(); - this.scene.unshiftPhase(new PokemonHealPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true)); - this.pokemon.findAndRemoveTags(() => true); - this.pokemon.bossSegments = 5; - this.pokemon.bossSegmentIndex = 4; - this.pokemon.initBattleInfo(); - this.pokemon.cry(); - - const movePhase = this.scene.findPhase(p => p instanceof MovePhase && p.pokemon === this.pokemon) as MovePhase; - if (movePhase) { - movePhase.cancel(); - } - } - - super.end(); - } -} diff --git a/src/phases/game-over-modifier-reward-phase.ts b/src/phases/game-over-modifier-reward-phase.ts new file mode 100644 index 00000000000..e2f4d134cba --- /dev/null +++ b/src/phases/game-over-modifier-reward-phase.ts @@ -0,0 +1,27 @@ +import BattleScene from "#app/battle-scene.js"; +import { ModifierTypeFunc } from "#app/modifier/modifier-type.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { ModifierRewardPhase } from "./modifier-reward-phase"; + +export class GameOverModifierRewardPhase extends ModifierRewardPhase { + constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc) { + super(scene, modifierTypeFunc); + } + + doReward(): Promise { + return new Promise(resolve => { + const newModifier = this.modifierType.newModifier(); + this.scene.addModifier(newModifier).then(() => { + this.scene.playSound("level_up_fanfare"); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.fadeIn(250).then(() => { + this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => { + this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); + resolve(); + }, null, true, 1500); + }); + }); + }); + } +} diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts new file mode 100644 index 00000000000..4beed489f29 --- /dev/null +++ b/src/phases/game-over-phase.ts @@ -0,0 +1,203 @@ +import { clientSessionId } from "#app/account.js"; +import BattleScene from "#app/battle-scene.js"; +import { BattleType } from "#app/battle.js"; +import { miscDialogue, getCharVariantFromDialogue } from "#app/data/dialogue.js"; +import { pokemonEvolutions } from "#app/data/pokemon-evolutions.js"; +import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species.js"; +import { trainerConfigs } from "#app/data/trainer-config.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { TrainerType } from "#app/enums/trainer-type.js"; +import Pokemon from "#app/field/pokemon.js"; +import { modifierTypes } from "#app/modifier/modifier-type.js"; +import { achvs, ChallengeAchv } from "#app/system/achv.js"; +import { Unlockables } from "#app/system/unlockables.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; +import { CheckSwitchPhase } from "./check-switch-phase"; +import { EncounterPhase } from "./encounter-phase"; +import { GameOverModifierRewardPhase } from "./game-over-modifier-reward-phase"; +import { RibbonModifierRewardPhase } from "./ribbon-modifier-reward-phase"; +import { SummonPhase } from "./summon-phase"; +import { EndCardPhase } from "./end-card-phase"; +import { PostGameOverPhase } from "./post-game-over-phase"; +import { UnlockPhase } from "./unlock-phase"; + +export class GameOverPhase extends BattlePhase { + private victory: boolean; + private firstRibbons: PokemonSpecies[] = []; + + constructor(scene: BattleScene, victory?: boolean) { + super(scene); + + this.victory = !!victory; + } + + start() { + super.start(); + + // Failsafe if players somehow skip floor 200 in classic mode + if (this.scene.gameMode.isClassic && this.scene.currentBattle.waveIndex > 200) { + this.victory = true; + } + + if (this.victory && this.scene.gameMode.isEndless) { + this.scene.ui.showDialogue(i18next.t("PGMmiscDialogue:ending_endless"), i18next.t("PGMmiscDialogue:ending_name"), 0, () => this.handleGameOver()); + } else if (this.victory || !this.scene.enableRetries) { + this.handleGameOver(); + } else { + this.scene.ui.showText(i18next.t("battle:retryBattle"), null, () => { + this.scene.ui.setMode(Mode.CONFIRM, () => { + this.scene.ui.fadeOut(1250).then(() => { + this.scene.reset(); + this.scene.clearPhaseQueue(); + this.scene.gameData.loadSession(this.scene, this.scene.sessionSlotId).then(() => { + this.scene.pushPhase(new EncounterPhase(this.scene, true)); + + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; + + this.scene.pushPhase(new SummonPhase(this.scene, 0)); + if (this.scene.currentBattle.double && availablePartyMembers > 1) { + this.scene.pushPhase(new SummonPhase(this.scene, 1)); + } + if (this.scene.currentBattle.waveIndex > 1 && this.scene.currentBattle.battleType !== BattleType.TRAINER) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); + if (this.scene.currentBattle.double && availablePartyMembers > 1) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); + } + } + + this.scene.ui.fadeIn(1250); + this.end(); + }); + }); + }, () => this.handleGameOver(), false, 0, 0, 1000); + }); + } + } + + handleGameOver(): void { + const doGameOver = (newClear: boolean) => { + this.scene.disableMenu = true; + this.scene.time.delayedCall(1000, () => { + let firstClear = false; + if (this.victory && newClear) { + if (this.scene.gameMode.isClassic) { + firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY); + this.scene.validateAchv(achvs.UNEVOLVED_CLASSIC_VICTORY); + this.scene.gameData.gameStats.sessionsWon++; + for (const pokemon of this.scene.getParty()) { + this.awardRibbon(pokemon); + + if (pokemon.species.getRootSpeciesId() !== pokemon.species.getRootSpeciesId(true)) { + this.awardRibbon(pokemon, true); + } + } + } else if (this.scene.gameMode.isDaily && newClear) { + this.scene.gameData.gameStats.dailyRunSessionsWon++; + } + } + const fadeDuration = this.victory ? 10000 : 5000; + this.scene.fadeOutBgm(fadeDuration, true); + const activeBattlers = this.scene.getField().filter(p => p?.isActive(true)); + activeBattlers.map(p => p.hideInfo()); + this.scene.ui.fadeOut(fadeDuration).then(() => { + activeBattlers.map(a => a.setVisible(false)); + this.scene.setFieldScale(1, true); + this.scene.clearPhaseQueue(); + this.scene.ui.clearText(); + + if (this.victory && this.scene.gameMode.isChallenge) { + this.scene.gameMode.challenges.forEach(c => this.scene.validateAchvs(ChallengeAchv, c)); + } + + const clear = (endCardPhase?: EndCardPhase) => { + if (newClear) { + this.handleUnlocks(); + } + if (this.victory && newClear) { + for (const species of this.firstRibbons) { + this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species)); + } + if (!firstClear) { + this.scene.unshiftPhase(new GameOverModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PREMIUM)); + } + } + this.scene.pushPhase(new PostGameOverPhase(this.scene, endCardPhase)); + this.end(); + }; + + if (this.victory && this.scene.gameMode.isClassic) { + const message = miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1]; + + if (!this.scene.ui.shouldSkipDialogue(message)) { + this.scene.ui.fadeIn(500).then(() => { + this.scene.charSprite.showCharacter(`rival_${this.scene.gameData.gender === PlayerGender.FEMALE ? "m" : "f"}`, getCharVariantFromDialogue(miscDialogue.ending[this.scene.gameData.gender === PlayerGender.FEMALE ? 0 : 1])).then(() => { + this.scene.ui.showDialogue(message, this.scene.gameData.gender === PlayerGender.FEMALE ? trainerConfigs[TrainerType.RIVAL].name : trainerConfigs[TrainerType.RIVAL].nameFemale, null, () => { + this.scene.ui.fadeOut(500).then(() => { + this.scene.charSprite.hide().then(() => { + const endCardPhase = new EndCardPhase(this.scene); + this.scene.unshiftPhase(endCardPhase); + clear(endCardPhase); + }); + }); + }); + }); + }); + } else { + const endCardPhase = new EndCardPhase(this.scene); + this.scene.unshiftPhase(endCardPhase); + clear(endCardPhase); + } + } else { + clear(); + } + }); + }); + }; + + /* Added a local check to see if the game is running offline on victory + If Online, execute apiFetch as intended + If Offline, execute offlineNewClear(), a localStorage implementation of newClear daily run checks */ + if (this.victory) { + if (!Utils.isLocal) { + Utils.apiFetch(`savedata/session/newclear?slot=${this.scene.sessionSlotId}&clientSessionId=${clientSessionId}`, true) + .then(response => response.json()) + .then(newClear => doGameOver(newClear)); + } else { + this.scene.gameData.offlineNewClear(this.scene).then(result => { + doGameOver(result); + }); + } + } else { + doGameOver(false); + } + } + + handleUnlocks(): void { + if (this.victory && this.scene.gameMode.isClassic) { + if (!this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.ENDLESS_MODE)); + } + if (this.scene.getParty().filter(p => p.fusionSpecies).length && !this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.SPLICED_ENDLESS_MODE)); + } + if (!this.scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) { + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); + } + if (!this.scene.gameData.unlocks[Unlockables.EVIOLITE] && this.scene.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)) { + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.EVIOLITE)); + } + } + } + + awardRibbon(pokemon: Pokemon, forStarter: boolean = false): void { + const speciesId = getPokemonSpecies(pokemon.species.speciesId); + const speciesRibbonCount = this.scene.gameData.incrementRibbonCount(speciesId, forStarter); + // first time classic win, award voucher + if (speciesRibbonCount === 1) { + this.firstRibbons.push(getPokemonSpecies(pokemon.species.getRootSpeciesId(forStarter))); + } + } +} diff --git a/src/phases/hide-party-exp-bar-phase.ts b/src/phases/hide-party-exp-bar-phase.ts new file mode 100644 index 00000000000..c2c9d96462e --- /dev/null +++ b/src/phases/hide-party-exp-bar-phase.ts @@ -0,0 +1,14 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlePhase } from "./battle-phase"; + +export class HidePartyExpBarPhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.partyExpBar.hide().then(() => this.end()); + } +} diff --git a/src/phases/learn-move-phase.ts b/src/phases/learn-move-phase.ts new file mode 100644 index 00000000000..e30fc0c3d10 --- /dev/null +++ b/src/phases/learn-move-phase.ts @@ -0,0 +1,103 @@ +import BattleScene from "#app/battle-scene.js"; +import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims.js"; +import { allMoves } from "#app/data/move.js"; +import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms.js"; +import { Moves } from "#app/enums/moves.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import EvolutionSceneHandler from "#app/ui/evolution-scene-handler.js"; +import { SummaryUiMode } from "#app/ui/summary-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; + +export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { + private moveId: Moves; + + constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves) { + super(scene, partyMemberIndex); + + this.moveId = moveId; + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + const move = allMoves[this.moveId]; + + const existingMoveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === move.id); + + if (existingMoveIndex > -1) { + return this.end(); + } + + const emptyMoveIndex = pokemon.getMoveset().length < 4 + ? pokemon.getMoveset().length + : pokemon.getMoveset().findIndex(m => m === null); + + const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler + ? Mode.EVOLUTION_SCENE + : Mode.MESSAGE; + + if (emptyMoveIndex > -1) { + pokemon.setMove(emptyMoveIndex, this.moveId); + initMoveAnim(this.scene, this.moveId).then(() => { + loadMoveAnimAssets(this.scene, [this.moveId], true) + .then(() => { + this.scene.ui.setMode(messageMode).then(() => { + this.scene.playSound("level_up_fanfare"); + this.scene.ui.showText(i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => { + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true); + this.end(); + }, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true); + }); + }); + }); + } else { + this.scene.ui.setMode(messageMode).then(() => { + this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => { + this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => { + const noHandler = () => { + this.scene.ui.setMode(messageMode).then(() => { + this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => { + this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { + this.scene.ui.setMode(messageMode); + this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true); + }, () => { + this.scene.ui.setMode(messageMode); + this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); + this.end(); + }); + }); + }); + }; + this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { + this.scene.ui.setMode(messageMode); + this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => { + this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => { + if (moveIndex === 4) { + noHandler(); + return; + } + this.scene.ui.setMode(messageMode).then(() => { + this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => { + this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct? + this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => { + pokemon.setMove(moveIndex, Moves.NONE); + this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); + this.end(); + }, null, true); + }, null, true); + }, null, true); + }); + }); + }, null, true); + }, noHandler); + }); + }, null, true); + }, null, true); + }); + } + } +} diff --git a/src/phases/level-cap-phase.ts b/src/phases/level-cap-phase.ts new file mode 100644 index 00000000000..4a07e7d131e --- /dev/null +++ b/src/phases/level-cap-phase.ts @@ -0,0 +1,20 @@ +import BattleScene from "#app/battle-scene.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { FieldPhase } from "./field-phase"; + +export class LevelCapPhase extends FieldPhase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + super.start(); + + this.scene.ui.setMode(Mode.MESSAGE).then(() => { + this.scene.playSound("level_up_fanfare"); + this.scene.ui.showText(i18next.t("battle:levelCapUp", { levelCap: this.scene.getMaxExpLevel() }), null, () => this.end(), null, true); + this.executeForAll(pokemon => pokemon.updateInfo(true)); + }); + } +} diff --git a/src/phases/level-up-phase.ts b/src/phases/level-up-phase.ts new file mode 100644 index 00000000000..a8a6b8f3d80 --- /dev/null +++ b/src/phases/level-up-phase.ts @@ -0,0 +1,59 @@ +import BattleScene from "#app/battle-scene.js"; +import { ExpNotification } from "#app/enums/exp-notification.js"; +import { EvolutionPhase } from "#app/phases/evolution-phase.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { LevelAchv } from "#app/system/achv.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; +import { LearnMovePhase } from "./learn-move-phase"; + +export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { + private lastLevel: integer; + private level: integer; + + constructor(scene: BattleScene, partyMemberIndex: integer, lastLevel: integer, level: integer) { + super(scene, partyMemberIndex); + + this.lastLevel = lastLevel; + this.level = level; + this.scene = scene; + } + + start() { + super.start(); + + if (this.level > this.scene.gameData.gameStats.highestLevel) { + this.scene.gameData.gameStats.highestLevel = this.level; + } + + this.scene.validateAchvs(LevelAchv, new Utils.IntegerHolder(this.level)); + + const pokemon = this.getPokemon(); + const prevStats = pokemon.stats.slice(0); + pokemon.calculateStats(); + pokemon.updateInfo(); + if (this.scene.expParty === ExpNotification.DEFAULT) { + this.scene.playSound("level_up_fanfare"); + this.scene.ui.showText(i18next.t("battle:levelUp", { pokemonName: getPokemonNameWithAffix(this.getPokemon()), level: this.level }), null, () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()), null, true); + } else if (this.scene.expParty === ExpNotification.SKIP) { + this.end(); + } else { + // we still want to display the stats if activated + this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()); + } + if (this.lastLevel < 100) { // this feels like an unnecessary optimization + const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1); + for (const lm of levelMoves) { + this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm[1])); + } + } + if (!pokemon.pauseEvolutions) { + const evolution = pokemon.getEvolution(); + if (evolution) { + this.scene.unshiftPhase(new EvolutionPhase(this.scene, pokemon as PlayerPokemon, evolution, this.lastLevel)); + } + } + } +} diff --git a/src/phases/login-phase.ts b/src/phases/login-phase.ts new file mode 100644 index 00000000000..b58cc9bca1f --- /dev/null +++ b/src/phases/login-phase.ts @@ -0,0 +1,116 @@ +import { updateUserInfo } from "#app/account.js"; +import BattleScene, { bypassLogin } from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { handleTutorial, Tutorial } from "#app/tutorial.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next, { t } from "i18next"; +import * as Utils from "#app/utils.js"; +import { SelectGenderPhase } from "./select-gender-phase"; +import { UnavailablePhase } from "./unavailable-phase"; + +export class LoginPhase extends Phase { + private showText: boolean; + + constructor(scene: BattleScene, showText?: boolean) { + super(scene); + + this.showText = showText === undefined || !!showText; + } + + start(): void { + super.start(); + + const hasSession = !!Utils.getCookie(Utils.sessionIdKey); + + this.scene.ui.setMode(Mode.LOADING, { buttonActions: [] }); + Utils.executeIf(bypassLogin || hasSession, updateUserInfo).then(response => { + const success = response ? response[0] : false; + const statusCode = response ? response[1] : null; + if (!success) { + if (!statusCode || statusCode === 400) { + if (this.showText) { + this.scene.ui.showText(i18next.t("menu:logInOrCreateAccount")); + } + + this.scene.playSound("menu_open"); + + const loadData = () => { + updateUserInfo().then(success => { + if (!success[0]) { + Utils.removeCookie(Utils.sessionIdKey); + this.scene.reset(true, true); + return; + } + this.scene.gameData.loadSystem().then(() => this.end()); + }); + }; + + this.scene.ui.setMode(Mode.LOGIN_FORM, { + buttonActions: [ + () => { + this.scene.ui.playSelect(); + loadData(); + }, () => { + this.scene.playSound("menu_open"); + this.scene.ui.setMode(Mode.REGISTRATION_FORM, { + buttonActions: [ + () => { + this.scene.ui.playSelect(); + updateUserInfo().then(success => { + if (!success[0]) { + Utils.removeCookie(Utils.sessionIdKey); + this.scene.reset(true, true); + return; + } + this.end(); + } ); + }, () => { + this.scene.unshiftPhase(new LoginPhase(this.scene, false)); + this.end(); + } + ] + }); + }, () => { + const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); + const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID; + const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&prompt=none`; + window.open(discordUrl, "_self"); + }, () => { + const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`); + const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID; + const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&redirect_uri=${redirectUri}&response_type=code&scope=openid`; + window.open(googleUrl, "_self"); + } + ] + }); + } else if (statusCode === 401) { + Utils.removeCookie(Utils.sessionIdKey); + this.scene.reset(true, true); + } else { + this.scene.unshiftPhase(new UnavailablePhase(this.scene)); + super.end(); + } + return null; + } else { + this.scene.gameData.loadSystem().then(success => { + if (success || bypassLogin) { + this.end(); + } else { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(t("menu:failedToLoadSaveData")); + } + }); + } + }); + } + + end(): void { + this.scene.ui.setMode(Mode.MESSAGE); + + if (!this.scene.gameData.gender) { + this.scene.unshiftPhase(new SelectGenderPhase(this.scene)); + } + + handleTutorial(this.scene, Tutorial.Intro).then(() => super.end()); + } +} diff --git a/src/phases/message-phase.ts b/src/phases/message-phase.ts new file mode 100644 index 00000000000..46e907ae2ba --- /dev/null +++ b/src/phases/message-phase.ts @@ -0,0 +1,38 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; + +export class MessagePhase extends Phase { + private text: string; + private callbackDelay: integer | null; + private prompt: boolean | null; + private promptDelay: integer | null; + + constructor(scene: BattleScene, text: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { + super(scene); + + this.text = text; + this.callbackDelay = callbackDelay!; // TODO: is this bang correct? + this.prompt = prompt!; // TODO: is this bang correct? + this.promptDelay = promptDelay!; // TODO: is this bang correct? + } + + start() { + super.start(); + + if (this.text.indexOf("$") > -1) { + const pageIndex = this.text.indexOf("$"); + this.scene.unshiftPhase(new MessagePhase(this.scene, this.text.slice(pageIndex + 1), this.callbackDelay, this.prompt, this.promptDelay)); + this.text = this.text.slice(0, pageIndex).trim(); + } + + this.scene.ui.showText(this.text, null, () => this.end(), this.callbackDelay || (this.prompt ? 0 : 1500), this.prompt, this.promptDelay); + } + + end() { + if (this.scene.abilityBar.shown) { + this.scene.abilityBar.hide(); + } + + super.end(); + } +} diff --git a/src/phases/modifier-reward-phase.ts b/src/phases/modifier-reward-phase.ts new file mode 100644 index 00000000000..4d083a367a6 --- /dev/null +++ b/src/phases/modifier-reward-phase.ts @@ -0,0 +1,30 @@ +import BattleScene from "#app/battle-scene.js"; +import { ModifierType, ModifierTypeFunc, getModifierType } from "#app/modifier/modifier-type.js"; +import i18next from "i18next"; +import { BattlePhase } from "./battle-phase"; + +export class ModifierRewardPhase extends BattlePhase { + protected modifierType: ModifierType; + + constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc) { + super(scene); + + this.modifierType = getModifierType(modifierTypeFunc); + } + + start() { + super.start(); + + this.doReward().then(() => this.end()); + } + + doReward(): Promise { + return new Promise(resolve => { + const newModifier = this.modifierType.newModifier(); + this.scene.addModifier(newModifier).then(() => { + this.scene.playSound("item_fanfare"); + this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => resolve(), null, true); + }); + }); + } +} diff --git a/src/phases/money-reward-phase.ts b/src/phases/money-reward-phase.ts new file mode 100644 index 00000000000..e0bff608972 --- /dev/null +++ b/src/phases/money-reward-phase.ts @@ -0,0 +1,34 @@ +import BattleScene from "#app/battle-scene.js"; +import { ArenaTagType } from "#app/enums/arena-tag-type.js"; +import { MoneyMultiplierModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; + +export class MoneyRewardPhase extends BattlePhase { + private moneyMultiplier: number; + + constructor(scene: BattleScene, moneyMultiplier: number) { + super(scene); + + this.moneyMultiplier = moneyMultiplier; + } + + start() { + const moneyAmount = new Utils.IntegerHolder(this.scene.getWaveMoneyAmount(this.moneyMultiplier)); + + this.scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); + + if (this.scene.arena.getTag(ArenaTagType.HAPPY_HOUR)) { + moneyAmount.value *= 2; + } + + this.scene.addMoney(moneyAmount.value); + + const userLocale = navigator.language || "en-US"; + const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); + const message = i18next.t("battle:moneyWon", { moneyAmount: formattedMoneyAmount }); + + this.scene.ui.showText(message, null, () => this.end(), null, true); + } +} diff --git a/src/phases/move-anim-test-phase.ts b/src/phases/move-anim-test-phase.ts new file mode 100644 index 00000000000..7fb3c1d61e7 --- /dev/null +++ b/src/phases/move-anim-test-phase.ts @@ -0,0 +1,44 @@ +import BattleScene from "#app/battle-scene.js"; +import { initMoveAnim, loadMoveAnimAssets, MoveAnim } from "#app/data/battle-anims.js"; +import { allMoves, SelfStatusMove } from "#app/data/move.js"; +import { Moves } from "#app/enums/moves.js"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; + +export class MoveAnimTestPhase extends BattlePhase { + private moveQueue: Moves[]; + + constructor(scene: BattleScene, moveQueue?: Moves[]) { + super(scene); + + this.moveQueue = moveQueue || Utils.getEnumValues(Moves).slice(1); + } + + start() { + const moveQueue = this.moveQueue.slice(0); + this.playMoveAnim(moveQueue, true); + } + + playMoveAnim(moveQueue: Moves[], player: boolean) { + const moveId = player ? moveQueue[0] : moveQueue.shift(); + if (moveId === undefined) { + this.playMoveAnim(this.moveQueue.slice(0), true); + return; + } else if (player) { + console.log(Moves[moveId]); + } + + initMoveAnim(this.scene, moveId).then(() => { + loadMoveAnimAssets(this.scene, [moveId], true) + .then(() => { + new MoveAnim(moveId, player ? this.scene.getPlayerPokemon()! : this.scene.getEnemyPokemon()!, (player !== (allMoves[moveId] instanceof SelfStatusMove) ? this.scene.getEnemyPokemon()! : this.scene.getPlayerPokemon()!).getBattlerIndex()).play(this.scene, () => { // TODO: are the bangs correct here? + if (player) { + this.playMoveAnim(moveQueue, false); + } else { + this.playMoveAnim(moveQueue, true); + } + }); + }); + }); + } +} diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts new file mode 100644 index 00000000000..a5ac913cc5d --- /dev/null +++ b/src/phases/move-effect-phase.ts @@ -0,0 +1,447 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr, applyPostDefendAbAttrs, PostDefendAbAttr, applyPostAttackAbAttrs, PostAttackAbAttr, MaxMultiHitAbAttr, AlwaysHitAbAttr } from "#app/data/ability.js"; +import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js"; +import { MoveAnim } from "#app/data/battle-anims.js"; +import { BattlerTagLapseType, ProtectedTag, SemiInvulnerableTag } from "#app/data/battler-tags.js"; +import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; +import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms.js"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { Moves } from "#app/enums/moves.js"; +import Pokemon, { PokemonMove, MoveResult, HitResult } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { PokemonMultiHitModifier, FlinchChanceModifier, EnemyAttackStatusEffectChanceModifier, ContactHeldItemTransferChanceModifier, HitHealModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class MoveEffectPhase extends PokemonPhase { + public move: PokemonMove; + protected targets: BattlerIndex[]; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, targets: BattlerIndex[], move: PokemonMove) { + super(scene, battlerIndex); + this.move = move; + /** + * In double battles, if the right Pokemon selects a spread move and the left Pokemon dies + * with no party members available to switch in, then the right Pokemon takes the index + * of the left Pokemon and gets hit unless this is checked. + */ + if (targets.includes(battlerIndex) && this.move.getMove().moveTarget === MoveTarget.ALL_NEAR_OTHERS) { + const i = targets.indexOf(battlerIndex); + targets.splice(i, i + 1); + } + this.targets = targets; + } + + start() { + super.start(); + + /** The Pokemon using this phase's invoked move */ + const user = this.getUserPokemon(); + /** All Pokemon targeted by this phase's invoked move */ + const targets = this.getTargets(); + + /** If the user was somehow removed from the field, end this phase */ + if (!user?.isOnField()) { + return super.end(); + } + + /** + * Does an effect from this move override other effects on this turn? + * e.g. Charging moves (Fly, etc.) on their first turn of use. + */ + const overridden = new Utils.BooleanHolder(false); + /** The {@linkcode Move} object from {@linkcode allMoves} invoked by this phase */ + const move = this.move.getMove(); + + // Assume single target for override + applyMoveAttrs(OverrideMoveEffectAttr, user, this.getTarget() ?? null, move, overridden, this.move.virtual).then(() => { + // If other effects were overriden, stop this phase before they can be applied + if (overridden.value) { + return this.end(); + } + + user.lapseTags(BattlerTagLapseType.MOVE_EFFECT); + + /** + * If this phase is for the first hit of the invoked move, + * resolve the move's total hit count. This block combines the + * effects of the move itself, Parental Bond, and Multi-Lens to do so. + */ + if (user.turnData.hitsLeft === undefined) { + const hitCount = new Utils.IntegerHolder(1); + // Assume single target for multi hit + applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); + // If Parental Bond is applicable, double the hit count + applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0)); + // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user + if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { + this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); + } + // Set the user's relevant turnData fields to reflect the final hit count + user.turnData.hitCount = hitCount.value; + user.turnData.hitsLeft = hitCount.value; + } + + /** + * Log to be entered into the user's move history once the move result is resolved. + * Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully + * used in the sense of "Does it have an effect on the user?". + */ + const moveHistoryEntry = { move: this.move.moveId, targets: this.targets, result: MoveResult.PENDING, virtual: this.move.virtual }; + + /** + * Stores results of hit checks of the invoked move against all targets, organized by battler index. + * @see {@linkcode hitCheck} + */ + const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); + const hasActiveTargets = targets.some(t => t.isActive(true)); + /** + * If no targets are left for the move to hit (FAIL), or the invoked move is single-target + * (and not random target) and failed the hit check against its target (MISS), log the move + * as FAILed or MISSed (depending on the conditions above) and end this phase. + */ + if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) { + this.stopMultiHit(); + if (hasActiveTargets) { + this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getTarget()? getPokemonNameWithAffix(this.getTarget()!) : "" })); + moveHistoryEntry.result = MoveResult.MISS; + applyMoveAttrs(MissEffectAttr, user, null, move); + } else { + this.scene.queueMessage(i18next.t("battle:attackFailed")); + moveHistoryEntry.result = MoveResult.FAIL; + } + user.pushMoveHistory(moveHistoryEntry); + return this.end(); + } + + /** All move effect attributes are chained together in this array to be applied asynchronously. */ + const applyAttrs: Promise[] = []; + + // Move animation only needs one target + new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()!).play(this.scene, () => { // TODO: is the bang correct here? + /** Has the move successfully hit a target (for damage) yet? */ + let hasHit: boolean = false; + for (const target of targets) { + /** + * If the move missed a target, stop all future hits against that target + * and move on to the next target (if there is one). + */ + if (!targetHitChecks[target.getBattlerIndex()]) { + this.stopMultiHit(target); + this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); + if (moveHistoryEntry.result === MoveResult.PENDING) { + moveHistoryEntry.result = MoveResult.MISS; + } + user.pushMoveHistory(moveHistoryEntry); + applyMoveAttrs(MissEffectAttr, user, null, move); + continue; + } + + /** The {@linkcode ArenaTagSide} to which the target belongs */ + const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + /** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */ + const hasConditionalProtectApplied = new Utils.BooleanHolder(false); + /** Does the applied conditional protection bypass Protect-ignoring effects? */ + const bypassIgnoreProtect = new Utils.BooleanHolder(false); + // If the move is not targeting a Pokemon on the user's side, try to apply conditional protection effects + if (!this.move.getMove().isAllyTarget()) { + this.scene.arena.applyTagsForSide(ConditionalProtectTag, targetSide, hasConditionalProtectApplied, user, target, move.id, bypassIgnoreProtect); + } + + /** Is the target protected by Protect, etc. or a relevant conditional protection effect? */ + const isProtected = (bypassIgnoreProtect.value || !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target)) + && (hasConditionalProtectApplied.value || target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))); + + /** Does this phase represent the invoked move's first strike? */ + const firstHit = (user.turnData.hitsLeft === user.turnData.hitCount); + + // Only log the move's result on the first strike + if (firstHit) { + user.pushMoveHistory(moveHistoryEntry); + } + + /** + * Since all fail/miss checks have applied, the move is considered successfully applied. + * It's worth noting that if the move has no effect or is protected against, this assignment + * is overwritten and the move is logged as a FAIL. + */ + moveHistoryEntry.result = MoveResult.SUCCESS; + + /** + * Stores the result of applying the invoked move to the target. + * If the target is protected, the result is always `NO_EFFECT`. + * Otherwise, the hit result is based on type effectiveness, immunities, + * and other factors that may negate the attack or status application. + * + * Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated + * (for attack moves) and the target's HP is updated. However, this isn't + * made visible to the user until the resulting {@linkcode DamagePhase} + * is invoked. + */ + const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT; + + /** Does {@linkcode hitResult} indicate that damage was dealt to the target? */ + const dealsDamage = [ + HitResult.EFFECTIVE, + HitResult.SUPER_EFFECTIVE, + HitResult.NOT_VERY_EFFECTIVE, + HitResult.ONE_HIT_KO + ].includes(hitResult); + + /** Is this target the first one hit by the move on its current strike? */ + const firstTarget = dealsDamage && !hasHit; + if (firstTarget) { + hasHit = true; + } + + /** + * If the move has no effect on the target (i.e. the target is protected or immune), + * change the logged move result to FAIL. + */ + if (hitResult === HitResult.NO_EFFECT) { + moveHistoryEntry.result = MoveResult.FAIL; + } + + /** Does this phase represent the invoked move's last strike? */ + const lastHit = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()); + + /** + * If the user can change forms by using the invoked move, + * it only changes forms after the move's last hit + * (see Relic Song's interaction with Parental Bond when used by Meloetta). + */ + if (lastHit) { + this.scene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger); + } + + /** + * Create a Promise that applys *all* effects from the invoked move's MoveEffectAttrs. + * These are ordered by trigger type (see {@linkcode MoveEffectTrigger}), and each trigger + * type requires different conditions to be met with respect to the move's hit result. + */ + applyAttrs.push(new Promise(resolve => { + // Apply all effects with PRE_MOVE triggers (if the target isn't immune to the move) + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && hitResult !== HitResult.NO_EFFECT, + user, target, move).then(() => { + // All other effects require the move to not have failed or have been cancelled to trigger + if (hitResult !== HitResult.FAIL) { + /** Are the move's effects tied to the first turn of a charge move? */ + const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget() ?? null, move)); + /** + * If the invoked move's effects are meant to trigger during the move's "charge turn," + * ignore all effects after this point. + * Otherwise, apply all self-targeted POST_APPLY effects. + */ + Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_APPLY + && attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => { + // All effects past this point require the move to have hit the target + if (hitResult !== HitResult.NO_EFFECT) { + // Apply all non-self-targeted POST_APPLY effects + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY + && !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => { + /** + * If the move hit, and the target doesn't have Shield Dust, + * apply the chance to flinch the target gained from King's Rock + */ + if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) { + const flinched = new Utils.BooleanHolder(false); + user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); + if (flinched.value) { + target.addTag(BattlerTagType.FLINCHED, undefined, this.move.moveId, user.id); + } + } + // If the move was not protected against, apply all HIT effects + Utils.executeIf(!isProtected && !chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT + && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => { + // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) + return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { + // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens + target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); + if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) { + target.lapseTag(BattlerTagType.SHELL_TRAP); + } + if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { + user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); + } + })).then(() => { + // Apply the user's post-attack ability effects + applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move.getMove(), hitResult).then(() => { + /** + * If the invoked move is an attack, apply the user's chance to + * steal an item from the target granted by Grip Claw + */ + if (this.move.getMove() instanceof AttackMove) { + this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target); + } + resolve(); + }); + }); + }) + ).then(() => resolve()); + }); + } else { + applyMoveAttrs(NoEffectAttr, user, null, move).then(() => resolve()); + } + }); + } else { + resolve(); + } + }); + })); + } + // Apply the move's POST_TARGET effects on the move's last hit, after all targeted effects have resolved + const postTarget = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()) ? + applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_TARGET, user, null, move) : + null; + + if (!!postTarget) { + if (applyAttrs.length) { // If there is a pending asynchronous move effect, do this after + applyAttrs[applyAttrs.length - 1]?.then(() => postTarget); + } else { // Otherwise, push a new asynchronous move effect + applyAttrs.push(postTarget); + } + } + + // Wait for all move effects to finish applying, then end this phase + Promise.allSettled(applyAttrs).then(() => this.end()); + }); + }); + } + + end() { + const move = this.move.getMove(); + move.type = move.defaultType; + const user = this.getUserPokemon(); + /** + * If this phase isn't for the invoked move's last strike, + * unshift another MoveEffectPhase for the next strike. + * Otherwise, queue a message indicating the number of times the move has struck + * (if the move has struck more than once), then apply the heal from Shell Bell + * to the user. + */ + if (user) { + if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) { + this.scene.unshiftPhase(this.getNewHitPhase()); + } else { + // Queue message for number of hits made by multi-move + // If multi-hit attack only hits once, still want to render a message + const hitsTotal = user.turnData.hitCount! - Math.max(user.turnData.hitsLeft!, 0); // TODO: are those bangs correct? + if (hitsTotal > 1 || (user.turnData.hitsLeft && user.turnData.hitsLeft > 0)) { + // If there are multiple hits, or if there are hits of the multi-hit move left + this.scene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal })); + } + this.scene.applyModifiers(HitHealModifier, this.player, user); + } + } + + super.end(); + } + + /** + * Resolves whether this phase's invoked move hits or misses the given target + * @param target {@linkcode Pokemon} the Pokemon targeted by the invoked move + * @returns `true` if the move does not miss the target; `false` otherwise + */ + hitCheck(target: Pokemon): boolean { + // Moves targeting the user and entry hazards can't miss + if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) { + return true; + } + + const user = this.getUserPokemon()!; // TODO: is this bang correct? + + // Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits. + // However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal + // multi-hit move and proceed with all hits + if (user.turnData.hitsLeft < user.turnData.hitCount) { + if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) { + return true; + } + } + + if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) { + return true; + } + + // If the user should ignore accuracy on a target, check who the user targeted last turn and see if they match + if (user.getTag(BattlerTagType.IGNORE_ACCURACY) && (user.getLastXMoves().find(() => true)?.targets || []).indexOf(target.getBattlerIndex()) !== -1) { + return true; + } + + if (target.getTag(BattlerTagType.ALWAYS_GET_HIT)) { + return true; + } + + const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); + if (semiInvulnerableTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) { + return false; + } + + const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user!, target); // TODO: is the bang correct here? + + if (moveAccuracy === -1) { + return true; + } + + const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove()); + const rand = user.randSeedInt(100, 1); + + return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct? + } + + /** Returns the {@linkcode Pokemon} using this phase's invoked move */ + getUserPokemon(): Pokemon | undefined { + if (this.battlerIndex > BattlerIndex.ENEMY_2) { + return this.scene.getPokemonById(this.battlerIndex) ?? undefined; + } + return (this.player ? this.scene.getPlayerField() : this.scene.getEnemyField())[this.fieldIndex]; + } + + /** Returns an array of all {@linkcode Pokemon} targeted by this phase's invoked move */ + getTargets(): Pokemon[] { + return this.scene.getField(true).filter(p => this.targets.indexOf(p.getBattlerIndex()) > -1); + } + + /** Returns the first target of this phase's invoked move */ + getTarget(): Pokemon | undefined { + return this.getTargets()[0]; + } + + /** + * Removes the given {@linkcode Pokemon} from this phase's target list + * @param target {@linkcode Pokemon} the Pokemon to be removed + */ + removeTarget(target: Pokemon): void { + const targetIndex = this.targets.findIndex(ind => ind === target.getBattlerIndex()); + if (targetIndex !== -1) { + this.targets.splice(this.targets.findIndex(ind => ind === target.getBattlerIndex()), 1); + } + } + + /** + * Prevents subsequent strikes of this phase's invoked move from occurring + * @param target {@linkcode Pokemon} if defined, only stop subsequent + * strikes against this Pokemon + */ + stopMultiHit(target?: Pokemon): void { + /** If given a specific target, remove the target from subsequent strikes */ + if (target) { + this.removeTarget(target); + } + /** + * If no target specified, or the specified target was the last of this move's + * targets, completely cancel all subsequent strikes. + */ + if (!target || this.targets.length === 0 ) { + this.getUserPokemon()!.turnData.hitCount = 1; // TODO: is the bang correct here? + this.getUserPokemon()!.turnData.hitsLeft = 1; // TODO: is the bang correct here? + } + } + + /** Returns a new MoveEffectPhase with the same properties as this phase */ + getNewHitPhase() { + return new MoveEffectPhase(this.scene, this.battlerIndex, this.targets, this.move); + } +} diff --git a/src/phases/move-end-phase.ts b/src/phases/move-end-phase.ts new file mode 100644 index 00000000000..4bce2185aea --- /dev/null +++ b/src/phases/move-end-phase.ts @@ -0,0 +1,23 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { BattlerTagLapseType } from "#app/data/battler-tags.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class MoveEndPhase extends PokemonPhase { + constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + super(scene, battlerIndex); + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + if (pokemon.isActive(true)) { + pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE); + } + + this.scene.arena.setIgnoreAbilities(false); + + this.end(); + } +} diff --git a/src/phases/move-header-phase.ts b/src/phases/move-header-phase.ts new file mode 100644 index 00000000000..5166f287731 --- /dev/null +++ b/src/phases/move-header-phase.ts @@ -0,0 +1,30 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyMoveAttrs, MoveHeaderAttr } from "#app/data/move.js"; +import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; +import { BattlePhase } from "./battle-phase"; + +export class MoveHeaderPhase extends BattlePhase { + public pokemon: Pokemon; + public move: PokemonMove; + + constructor(scene: BattleScene, pokemon: Pokemon, move: PokemonMove) { + super(scene); + + this.pokemon = pokemon; + this.move = move; + } + + canMove(): boolean { + return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon); + } + + start() { + super.start(); + + if (this.canMove()) { + applyMoveAttrs(MoveHeaderAttr, this.pokemon, null, this.move.getMove()).then(() => this.end()); + } else { + this.end(); + } + } +} diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts new file mode 100644 index 00000000000..b9656df856b --- /dev/null +++ b/src/phases/move-phase.ts @@ -0,0 +1,329 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyAbAttrs, RedirectMoveAbAttr, BlockRedirectAbAttr, IncreasePpAbAttr, applyPreAttackAbAttrs, PokemonTypeChangeAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr } from "#app/data/ability.js"; +import { CommonAnim } from "#app/data/battle-anims.js"; +import { CenterOfAttentionTag, BattlerTagLapseType } from "#app/data/battler-tags.js"; +import { MoveFlags, BypassRedirectAttr, allMoves, CopyMoveAttr, applyMoveAttrs, BypassSleepAttr, HealStatusEffectAttr, ChargeAttr, PreMoveMessageAttr } from "#app/data/move.js"; +import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms.js"; +import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect.js"; +import { Type } from "#app/data/type.js"; +import { getTerrainBlockMessage } from "#app/data/weather.js"; +import { Abilities } from "#app/enums/abilities.js"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { Moves } from "#app/enums/moves.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { MoveUsedEvent } from "#app/events/battle-scene.js"; +import Pokemon, { PokemonMove, MoveResult, TurnMove } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; +import { CommonAnimPhase } from "./common-anim-phase"; +import { MoveEffectPhase } from "./move-effect-phase"; +import { MoveEndPhase } from "./move-end-phase"; +import { ShowAbilityPhase } from "./show-ability-phase"; + +export class MovePhase extends BattlePhase { + public pokemon: Pokemon; + public move: PokemonMove; + public targets: BattlerIndex[]; + protected followUp: boolean; + protected ignorePp: boolean; + protected failed: boolean; + protected cancelled: boolean; + + constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp?: boolean, ignorePp?: boolean) { + super(scene); + + this.pokemon = pokemon; + this.targets = targets; + this.move = move; + this.followUp = !!followUp; + this.ignorePp = !!ignorePp; + this.failed = false; + this.cancelled = false; + } + + canMove(): boolean { + return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, this.ignorePp) && !!this.targets.length; + } + + /**Signifies the current move should fail but still use PP */ + fail(): void { + this.failed = true; + } + + /**Signifies the current move should cancel and retain PP */ + cancel(): void { + this.cancelled = true; + } + + start() { + super.start(); + + console.log(Moves[this.move.moveId]); + + if (!this.canMove()) { + if (this.move.moveId && this.pokemon.summonData?.disabledMove === this.move.moveId) { + this.scene.queueMessage(`${this.move.getName()} is disabled!`); + } + if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) { // if the move PP was reduced from Spite or otherwise, the move fails + this.fail(); + this.showMoveText(); + this.showFailedText(); + } + return this.end(); + } + + if (!this.followUp) { + if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) { + this.scene.arena.setIgnoreAbilities(); + } + } else { + this.pokemon.turnData.hitsLeft = 0; // TODO: is `0` correct? + this.pokemon.turnData.hitCount = 0; // TODO: is `0` correct? + } + + // Move redirection abilities (ie. Storm Drain) only support single target moves + const moveTarget = this.targets.length === 1 + ? new Utils.IntegerHolder(this.targets[0]) + : null; + if (moveTarget) { + const oldTarget = moveTarget.value; + this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget)); + this.pokemon.getOpponents().forEach(p => { + const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag; + if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) { + moveTarget.value = p.getBattlerIndex(); + } + }); + //Check if this move is immune to being redirected, and restore its target to the intended target if it is. + if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) || this.move.getMove().hasAttr(BypassRedirectAttr))) { + //If an ability prevented this move from being redirected, display its ability pop up. + if ((this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr) && !this.move.getMove().hasAttr(BypassRedirectAttr)) && oldTarget !== moveTarget.value) { + this.scene.unshiftPhase(new ShowAbilityPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr))); + } + moveTarget.value = oldTarget; + } + this.targets[0] = moveTarget.value; + } + + // Check for counterattack moves to switch target + if (this.targets.length === 1 && this.targets[0] === BattlerIndex.ATTACKER) { + if (this.pokemon.turnData.attacksReceived.length) { + const attack = this.pokemon.turnData.attacksReceived[0]; + this.targets[0] = attack.sourceBattlerIndex; + + // account for metal burst and comeuppance hitting remaining targets in double battles + // counterattack will redirect to remaining ally if original attacker faints + if (this.scene.currentBattle.double && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)) { + if (this.scene.getField()[this.targets[0]].hp === 0) { + const opposingField = this.pokemon.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField(); + //@ts-ignore + this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex(); //TODO: fix ts-ignore + } + } + } + if (this.targets[0] === BattlerIndex.ATTACKER) { + this.fail(); // Marks the move as failed for later in doMove + this.showMoveText(); + this.showFailedText(); + } + } + + const targets = this.scene.getField(true).filter(p => { + if (this.targets.indexOf(p.getBattlerIndex()) > -1) { + return true; + } + return false; + }); + + const doMove = () => { + this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails + + this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE); + + let ppUsed = 1; + // Filter all opponents to include only those this move is targeting + const targetedOpponents = this.pokemon.getOpponents().filter(o => this.targets.includes(o.getBattlerIndex())); + for (const opponent of targetedOpponents) { + if (this.move.ppUsed + ppUsed >= this.move.getMovePp()) { // If we're already at max PP usage, stop checking + break; + } + if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) { // Accounting for abilities like Pressure + ppUsed++; + } + } + + if (!this.followUp && this.canMove() && !this.cancelled) { + this.pokemon.lapseTags(BattlerTagLapseType.MOVE); + } + + const moveQueue = this.pokemon.getMoveQueue(); + if (this.cancelled || this.failed) { + if (this.failed) { + this.move.usePp(ppUsed); // Only use PP if the move failed + this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed)); + } + + // Record a failed move so Abilities like Truant don't trigger next turn and soft-lock + this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); + + this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc. + moveQueue.shift(); // Remove the second turn of charge moves + return this.end(); + } + + this.scene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangePreMoveTrigger); + + if (this.move.moveId) { + this.showMoveText(); + } + + // This should only happen when there are no valid targets left on the field + if ((moveQueue.length && moveQueue[0].move === Moves.NONE) || !targets.length) { + this.showFailedText(); + this.cancel(); + + // Record a failed move so Abilities like Truant don't trigger next turn and soft-lock + this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); + + this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc. + + moveQueue.shift(); + return this.end(); + } + + if (!moveQueue.length || !moveQueue.shift()?.ignorePP) { // using .shift here clears out two turn moves once they've been used + this.move.usePp(ppUsed); + this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed)); + } + + if (!allMoves[this.move.moveId].hasAttr(CopyMoveAttr)) { + this.scene.currentBattle.lastMove = this.move.moveId; + } + + // Assume conditions affecting targets only apply to moves with a single target + let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove()); + const cancelled = new Utils.BooleanHolder(false); + let failedText = this.move.getMove().getFailedText(this.pokemon, targets[0], this.move.getMove(), cancelled); + if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove())) { + success = false; + } else if (success && this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.targets, this.move.getMove())) { + success = false; + if (failedText === null) { + failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain?.terrainType!); // TODO: is this bang correct? + } + } + + /** + * Trigger pokemon type change before playing the move animation + * Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse, + * regardless of whether the move successfully executes or not. + */ + if (success || [Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) { + applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); + } + + if (success) { + this.scene.unshiftPhase(this.getEffectPhase()); + } else { + this.pokemon.pushMoveHistory({ move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, virtual: this.move.virtual }); + if (!cancelled.value) { + this.showFailedText(failedText); + } + } + // Checks if Dancer ability is triggered + if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !this.followUp) { + // Pokemon with Dancer can be on either side of the battle so we check in both cases + this.scene.getPlayerField().forEach(pokemon => { + applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets); + }); + this.scene.getEnemyField().forEach(pokemon => { + applyPostMoveUsedAbAttrs(PostMoveUsedAbAttr, pokemon, this.move, this.pokemon, this.targets); + }); + } + this.end(); + }; + + if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn()) { + this.pokemon.status.incrementTurn(); + let activated = false; + let healed = false; + + switch (this.pokemon.status.effect) { + case StatusEffect.PARALYSIS: + if (!this.pokemon.randSeedInt(4)) { + activated = true; + this.cancelled = true; + } + break; + case StatusEffect.SLEEP: + applyMoveAttrs(BypassSleepAttr, this.pokemon, null, this.move.getMove()); + healed = this.pokemon.status.turnCount === this.pokemon.status.cureTurn; + activated = !healed && !this.pokemon.getTag(BattlerTagType.BYPASS_SLEEP); + this.cancelled = activated; + break; + case StatusEffect.FREEZE: + healed = !!this.move.getMove().findAttr(attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE)) || !this.pokemon.randSeedInt(5); + activated = !healed; + this.cancelled = activated; + break; + } + + if (activated) { + this.scene.queueMessage(getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); + this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1))); + doMove(); + } else { + if (healed) { + this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon))); + this.pokemon.resetStatus(); + this.pokemon.updateInfo(); + } + doMove(); + } + } else { + doMove(); + } + } + + getEffectPhase(): MoveEffectPhase { + return new MoveEffectPhase(this.scene, this.pokemon.getBattlerIndex(), this.targets, this.move); + } + + showMoveText(): void { + if (this.move.getMove().hasAttr(ChargeAttr)) { + const lastMove = this.pokemon.getLastXMoves() as TurnMove[]; + if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) { + this.scene.queueMessage(i18next.t("battle:useMove", { + pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), + moveName: this.move.getName() + }), 500); + return; + } + } + + if (this.pokemon.getTag(BattlerTagType.RECHARGING || BattlerTagType.INTERRUPTED)) { + return; + } + + this.scene.queueMessage(i18next.t("battle:useMove", { + pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), + moveName: this.move.getName() + }), 500); + applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents().find(() => true)!, this.move.getMove()); //TODO: is the bang correct here? + } + + showFailedText(failedText: string | null = null): void { + this.scene.queueMessage(failedText || i18next.t("battle:attackFailed")); + } + + end() { + if (!this.followUp && this.canMove()) { + this.scene.unshiftPhase(new MoveEndPhase(this.scene, this.pokemon.getBattlerIndex())); + } + + super.end(); + } +} diff --git a/src/phases/new-battle-phase.ts b/src/phases/new-battle-phase.ts new file mode 100644 index 00000000000..5a422c9e6c7 --- /dev/null +++ b/src/phases/new-battle-phase.ts @@ -0,0 +1,11 @@ +import { BattlePhase } from "./battle-phase"; + +export class NewBattlePhase extends BattlePhase { + start() { + super.start(); + + this.scene.newBattle(); + + this.end(); + } +} diff --git a/src/phases/new-biome-encounter-phase.ts b/src/phases/new-biome-encounter-phase.ts new file mode 100644 index 00000000000..c447e78f7b1 --- /dev/null +++ b/src/phases/new-biome-encounter-phase.ts @@ -0,0 +1,38 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyAbAttrs, PostBiomeChangeAbAttr } from "#app/data/ability.js"; +import { getRandomWeatherType } from "#app/data/weather.js"; +import { NextEncounterPhase } from "./next-encounter-phase"; + +export class NewBiomeEncounterPhase extends NextEncounterPhase { + constructor(scene: BattleScene) { + super(scene); + } + + doEncounter(): void { + this.scene.playBgm(undefined, true); + + for (const pokemon of this.scene.getParty()) { + if (pokemon) { + pokemon.resetBattleData(); + } + } + + this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); + + for (const pokemon of this.scene.getParty().filter(p => p.isOnField())) { + applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null); + } + + const enemyField = this.scene.getEnemyField(); + this.scene.tweens.add({ + targets: [this.scene.arenaEnemy, enemyField].flat(), + x: "+=300", + duration: 2000, + onComplete: () => { + if (!this.tryOverrideForBattleSpec()) { + this.doEncounterCommon(); + } + } + }); + } +} diff --git a/src/phases/next-encounter-phase.ts b/src/phases/next-encounter-phase.ts new file mode 100644 index 00000000000..89987534fc0 --- /dev/null +++ b/src/phases/next-encounter-phase.ts @@ -0,0 +1,46 @@ +import BattleScene from "#app/battle-scene.js"; +import { EncounterPhase } from "./encounter-phase"; + +export class NextEncounterPhase extends EncounterPhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + } + + doEncounter(): void { + this.scene.playBgm(undefined, true); + + for (const pokemon of this.scene.getParty()) { + if (pokemon) { + pokemon.resetBattleData(); + } + } + + this.scene.arenaNextEnemy.setBiome(this.scene.arena.biomeType); + this.scene.arenaNextEnemy.setVisible(true); + + const enemyField = this.scene.getEnemyField(); + this.scene.tweens.add({ + targets: [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer].flat(), + x: "+=300", + duration: 2000, + onComplete: () => { + this.scene.arenaEnemy.setBiome(this.scene.arena.biomeType); + this.scene.arenaEnemy.setX(this.scene.arenaNextEnemy.x); + this.scene.arenaEnemy.setAlpha(1); + this.scene.arenaNextEnemy.setX(this.scene.arenaNextEnemy.x - 300); + this.scene.arenaNextEnemy.setVisible(false); + if (this.scene.lastEnemyTrainer) { + this.scene.lastEnemyTrainer.destroy(); + } + + if (!this.tryOverrideForBattleSpec()) { + this.doEncounterCommon(); + } + } + }); + } +} diff --git a/src/phases/obtain-status-effect-phase.ts b/src/phases/obtain-status-effect-phase.ts new file mode 100644 index 00000000000..ac6e66a2e9f --- /dev/null +++ b/src/phases/obtain-status-effect-phase.ts @@ -0,0 +1,48 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims.js"; +import { getStatusEffectObtainText, getStatusEffectOverlapText } from "#app/data/status-effect.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import Pokemon from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { PokemonPhase } from "./pokemon-phase"; +import { PostTurnStatusEffectPhase } from "./post-turn-status-effect-phase"; + +export class ObtainStatusEffectPhase extends PokemonPhase { + private statusEffect: StatusEffect | undefined; + private cureTurn: integer | null; + private sourceText: string | null; + private sourcePokemon: Pokemon | null; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, statusEffect?: StatusEffect, cureTurn?: integer | null, sourceText?: string, sourcePokemon?: Pokemon) { + super(scene, battlerIndex); + + this.statusEffect = statusEffect; + this.cureTurn = cureTurn!; // TODO: is this bang correct? + this.sourceText = sourceText!; // TODO: is this bang correct? + this.sourcePokemon = sourcePokemon!; // For tracking which Pokemon caused the status effect // TODO: is this bang correct? + } + + start() { + const pokemon = this.getPokemon(); + if (!pokemon?.status) { + if (pokemon?.trySetStatus(this.statusEffect, false, this.sourcePokemon)) { + if (this.cureTurn) { + pokemon.status!.cureTurn = this.cureTurn; // TODO: is this bang correct? + } + pokemon.updateInfo(true); + new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(this.scene, () => { + this.scene.queueMessage(getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined)); + if (pokemon.status?.isPostTurn()) { + this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, this.battlerIndex)); + } + this.end(); + }); + return; + } + } else if (pokemon.status.effect === this.statusEffect) { + this.scene.queueMessage(getStatusEffectOverlapText(this.statusEffect, getPokemonNameWithAffix(pokemon))); + } + this.end(); + } +} diff --git a/src/phases/outdated-phase.ts b/src/phases/outdated-phase.ts new file mode 100644 index 00000000000..72d1bb3671d --- /dev/null +++ b/src/phases/outdated-phase.ts @@ -0,0 +1,13 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Mode } from "#app/ui/ui.js"; + +export class OutdatedPhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + this.scene.ui.setMode(Mode.OUTDATED); + } +} diff --git a/src/phases/party-heal-phase.ts b/src/phases/party-heal-phase.ts new file mode 100644 index 00000000000..d9179826a19 --- /dev/null +++ b/src/phases/party-heal-phase.ts @@ -0,0 +1,40 @@ +import BattleScene from "#app/battle-scene.js"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; + +export class PartyHealPhase extends BattlePhase { + private resumeBgm: boolean; + + constructor(scene: BattleScene, resumeBgm: boolean) { + super(scene); + + this.resumeBgm = resumeBgm; + } + + start() { + super.start(); + + const bgmPlaying = this.scene.isBgmPlaying(); + if (bgmPlaying) { + this.scene.fadeOutBgm(1000, false); + } + this.scene.ui.fadeOut(1000).then(() => { + for (const pokemon of this.scene.getParty()) { + pokemon.hp = pokemon.getMaxHp(); + pokemon.resetStatus(); + for (const move of pokemon.moveset) { + move!.ppUsed = 0; // TODO: is this bang correct? + } + pokemon.updateInfo(true); + } + const healSong = this.scene.playSoundWithoutBgm("heal"); + this.scene.time.delayedCall(Utils.fixedInt(healSong.totalDuration * 1000), () => { + healSong.destroy(); + if (this.resumeBgm && bgmPlaying) { + this.scene.playBgm(); + } + this.scene.ui.fadeIn(500).then(() => this.end()); + }); + }); + } +} diff --git a/src/phases/party-member-pokemon-phase.ts b/src/phases/party-member-pokemon-phase.ts new file mode 100644 index 00000000000..1f27826884e --- /dev/null +++ b/src/phases/party-member-pokemon-phase.ts @@ -0,0 +1,27 @@ +import BattleScene from "#app/battle-scene.js"; +import Pokemon from "#app/field/pokemon.js"; +import { FieldPhase } from "./field-phase"; + +export abstract class PartyMemberPokemonPhase extends FieldPhase { + protected partyMemberIndex: integer; + protected fieldIndex: integer; + protected player: boolean; + + constructor(scene: BattleScene, partyMemberIndex: integer, player: boolean) { + super(scene); + + this.partyMemberIndex = partyMemberIndex; + this.fieldIndex = partyMemberIndex < this.scene.currentBattle.getBattlerCount() + ? partyMemberIndex + : -1; + this.player = player; + } + + getParty(): Pokemon[] { + return this.player ? this.scene.getParty() : this.scene.getEnemyParty(); + } + + getPokemon(): Pokemon { + return this.getParty()[this.partyMemberIndex]; + } +} diff --git a/src/phases/party-status-cure-phase.ts b/src/phases/party-status-cure-phase.ts new file mode 100644 index 00000000000..a11aa01b63a --- /dev/null +++ b/src/phases/party-status-cure-phase.ts @@ -0,0 +1,48 @@ +import BattleScene from "#app/battle-scene.js"; +import { Abilities } from "#app/enums/abilities.js"; +import Pokemon from "#app/field/pokemon.js"; +import { BattlePhase } from "./battle-phase"; +import { ShowAbilityPhase } from "./show-ability-phase"; + +/** + * Cures the party of all non-volatile status conditions, shows a message + * @param {BattleScene} scene The current scene + * @param {Pokemon} user The user of the move that cures the party + * @param {string} message The message that should be displayed + * @param {Abilities} abilityCondition Pokemon with this ability will not be affected ie. Soundproof + */ +export class PartyStatusCurePhase extends BattlePhase { + private user: Pokemon; + private message: string; + private abilityCondition: Abilities; + + constructor(scene: BattleScene, user: Pokemon, message: string, abilityCondition: Abilities) { + super(scene); + + this.user = user; + this.message = message; + this.abilityCondition = abilityCondition; + } + + start() { + super.start(); + for (const pokemon of this.scene.getParty()) { + if (!pokemon.isOnField() || pokemon === this.user) { + pokemon.resetStatus(false); + pokemon.updateInfo(true); + } else { + if (!pokemon.hasAbility(this.abilityCondition)) { + pokemon.resetStatus(); + pokemon.updateInfo(true); + } else { + // Manually show ability bar, since we're not hooked into the targeting system + pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, pokemon.getPassiveAbility()?.id === this.abilityCondition)); + } + } + } + if (this.message) { + this.scene.queueMessage(this.message); + } + this.end(); + } +} diff --git a/src/phases/player-party-member-pokemon-phase.ts b/src/phases/player-party-member-pokemon-phase.ts new file mode 100644 index 00000000000..4b1600b33d2 --- /dev/null +++ b/src/phases/player-party-member-pokemon-phase.ts @@ -0,0 +1,13 @@ +import BattleScene from "#app/battle-scene.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; +import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase"; + +export abstract class PlayerPartyMemberPokemonPhase extends PartyMemberPokemonPhase { + constructor(scene: BattleScene, partyMemberIndex: integer) { + super(scene, partyMemberIndex, true); + } + + getPlayerPokemon(): PlayerPokemon { + return super.getPokemon() as PlayerPokemon; + } +} diff --git a/src/phases/pokemon-heal-phase.ts b/src/phases/pokemon-heal-phase.ts new file mode 100644 index 00000000000..6db8aeb4fca --- /dev/null +++ b/src/phases/pokemon-heal-phase.ts @@ -0,0 +1,104 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { CommonAnim } from "#app/data/battle-anims.js"; +import { getStatusEffectHealText } from "#app/data/status-effect.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { HitResult, DamageResult } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { HealingBoosterModifier } from "#app/modifier/modifier.js"; +import { HealAchv } from "#app/system/achv.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { CommonAnimPhase } from "./common-anim-phase"; + +export class PokemonHealPhase extends CommonAnimPhase { + private hpHealed: integer; + private message: string | null; + private showFullHpMessage: boolean; + private skipAnim: boolean; + private revive: boolean; + private healStatus: boolean; + private preventFullHeal: boolean; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string | null, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false) { + super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP); + + this.hpHealed = hpHealed; + this.message = message; + this.showFullHpMessage = showFullHpMessage; + this.skipAnim = skipAnim; + this.revive = revive; + this.healStatus = healStatus; + this.preventFullHeal = preventFullHeal; + } + + start() { + if (!this.skipAnim && (this.revive || this.getPokemon().hp) && !this.getPokemon().isFullHp()) { + super.start(); + } else { + this.end(); + } + } + + end() { + const pokemon = this.getPokemon(); + + if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) { + super.end(); + return; + } + + const hasMessage = !!this.message; + const healOrDamage = (!pokemon.isFullHp() || this.hpHealed < 0); + let lastStatusEffect = StatusEffect.NONE; + + if (healOrDamage) { + const hpRestoreMultiplier = new Utils.IntegerHolder(1); + if (!this.revive) { + this.scene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); + } + const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); + if (healAmount.value < 0) { + pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL as DamageResult); + healAmount.value = 0; + } + // Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock) + if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp()) { + healAmount.value = (pokemon.getMaxHp() - pokemon.hp) - 1; + } + healAmount.value = pokemon.heal(healAmount.value); + if (healAmount.value) { + this.scene.damageNumberHandler.add(pokemon, healAmount.value, HitResult.HEAL); + } + if (pokemon.isPlayer()) { + this.scene.validateAchvs(HealAchv, healAmount); + if (healAmount.value > this.scene.gameData.gameStats.highestHeal) { + this.scene.gameData.gameStats.highestHeal = healAmount.value; + } + } + if (this.healStatus && !this.revive && pokemon.status) { + lastStatusEffect = pokemon.status.effect; + pokemon.resetStatus(); + } + pokemon.updateInfo().then(() => super.end()); + } else if (this.healStatus && !this.revive && pokemon.status) { + lastStatusEffect = pokemon.status.effect; + pokemon.resetStatus(); + pokemon.updateInfo().then(() => super.end()); + } else if (this.showFullHpMessage) { + this.message = i18next.t("battle:hpIsFull", { pokemonName: getPokemonNameWithAffix(pokemon) }); + } + + if (this.message) { + this.scene.queueMessage(this.message); + } + + if (this.healStatus && lastStatusEffect && !hasMessage) { + this.scene.queueMessage(getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon))); + } + + if (!healOrDamage && !lastStatusEffect) { + super.end(); + } + } +} diff --git a/src/phases/pokemon-phase.ts b/src/phases/pokemon-phase.ts new file mode 100644 index 00000000000..871ee57d7a5 --- /dev/null +++ b/src/phases/pokemon-phase.ts @@ -0,0 +1,29 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import Pokemon from "#app/field/pokemon.js"; +import { FieldPhase } from "./field-phase"; + +export abstract class PokemonPhase extends FieldPhase { + protected battlerIndex: BattlerIndex | integer; + public player: boolean; + public fieldIndex: integer; + + constructor(scene: BattleScene, battlerIndex?: BattlerIndex | integer) { + super(scene); + + if (battlerIndex === undefined) { + battlerIndex = scene.getField().find(p => p?.isActive())!.getBattlerIndex(); // TODO: is the bang correct here? + } + + this.battlerIndex = battlerIndex; + this.player = battlerIndex < 2; + this.fieldIndex = battlerIndex % 2; + } + + getPokemon(): Pokemon { + if (this.battlerIndex > BattlerIndex.ENEMY_2) { + return this.scene.getPokemonById(this.battlerIndex)!; //TODO: is this bang correct? + } + return this.scene.getField()[this.battlerIndex]!; //TODO: is this bang correct? + } +} diff --git a/src/phases/post-game-over-phase.ts b/src/phases/post-game-over-phase.ts new file mode 100644 index 00000000000..02413b41a23 --- /dev/null +++ b/src/phases/post-game-over-phase.ts @@ -0,0 +1,46 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { EndCardPhase } from "./end-card-phase"; +import { TitlePhase } from "./title-phase"; + +export class PostGameOverPhase extends Phase { + private endCardPhase: EndCardPhase | null; + + constructor(scene: BattleScene, endCardPhase?: EndCardPhase) { + super(scene); + + this.endCardPhase = endCardPhase!; // TODO: is this bang correct? + } + + start() { + super.start(); + + const saveAndReset = () => { + this.scene.gameData.saveAll(this.scene, true, true, true).then(success => { + if (!success) { + return this.scene.reset(true); + } + this.scene.gameData.tryClearSession(this.scene, this.scene.sessionSlotId).then((success: boolean | [boolean, boolean]) => { + if (!success[0]) { + return this.scene.reset(true); + } + this.scene.reset(); + this.scene.unshiftPhase(new TitlePhase(this.scene)); + this.end(); + }); + }); + }; + + if (this.endCardPhase) { + this.scene.ui.fadeOut(500).then(() => { + this.scene.ui.getMessageHandler().bg.setVisible(true); + + this.endCardPhase?.endCard.destroy(); + this.endCardPhase?.text.destroy(); + saveAndReset(); + }); + } else { + saveAndReset(); + } + } +} diff --git a/src/phases/post-summon-phase.ts b/src/phases/post-summon-phase.ts new file mode 100644 index 00000000000..e671bf30ed1 --- /dev/null +++ b/src/phases/post-summon-phase.ts @@ -0,0 +1,24 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyPostSummonAbAttrs, PostSummonAbAttr } from "#app/data/ability.js"; +import { ArenaTrapTag } from "#app/data/arena-tag.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class PostSummonPhase extends PokemonPhase { + constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + super(scene, battlerIndex); + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + + if (pokemon.status?.effect === StatusEffect.TOXIC) { + pokemon.status.turnCount = 0; + } + this.scene.arena.applyTags(ArenaTrapTag, pokemon); + applyPostSummonAbAttrs(PostSummonAbAttr, pokemon).then(() => this.end()); + } +} diff --git a/src/phases/post-turn-status-effect-phase.ts b/src/phases/post-turn-status-effect-phase.ts new file mode 100644 index 00000000000..8b533f2e90a --- /dev/null +++ b/src/phases/post-turn-status-effect-phase.ts @@ -0,0 +1,61 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyAbAttrs, BlockNonDirectDamageAbAttr, BlockStatusDamageAbAttr, ReduceBurnDamageAbAttr } from "#app/data/ability.js"; +import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims.js"; +import { getStatusEffectActivationText } from "#app/data/status-effect.js"; +import { BattleSpec } from "#app/enums/battle-spec.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import * as Utils from "#app/utils.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class PostTurnStatusEffectPhase extends PokemonPhase { + constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + super(scene, battlerIndex); + } + + start() { + const pokemon = this.getPokemon(); + if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn()) { + pokemon.status.incrementTurn(); + const cancelled = new Utils.BooleanHolder(false); + applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + applyAbAttrs(BlockStatusDamageAbAttr, pokemon, cancelled); + + if (!cancelled.value) { + this.scene.queueMessage(getStatusEffectActivationText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); + const damage = new Utils.NumberHolder(0); + switch (pokemon.status.effect) { + case StatusEffect.POISON: + damage.value = Math.max(pokemon.getMaxHp() >> 3, 1); + break; + case StatusEffect.TOXIC: + damage.value = Math.max(Math.floor((pokemon.getMaxHp() / 16) * pokemon.status.turnCount), 1); + break; + case StatusEffect.BURN: + damage.value = Math.max(pokemon.getMaxHp() >> 4, 1); + applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, damage); + break; + } + if (damage.value) { + // Set preventEndure flag to avoid pokemon surviving thanks to focus band, sturdy, endure ... + this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage.value, false, true)); + pokemon.updateInfo(); + } + new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end()); + } else { + this.end(); + } + } else { + this.end(); + } + } + + override end() { + if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { + this.scene.initFinalBossPhaseTwo(this.getPokemon()); + } else { + super.end(); + } + } +} diff --git a/src/phases/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts new file mode 100644 index 00000000000..3d30d36907e --- /dev/null +++ b/src/phases/quiet-form-change-phase.ts @@ -0,0 +1,133 @@ +import BattleScene from "#app/battle-scene.js"; +import { SemiInvulnerableTag } from "#app/data/battler-tags.js"; +import { SpeciesFormChange, getSpeciesFormChangeMessage } from "#app/data/pokemon-forms.js"; +import { getTypeRgb } from "#app/data/type.js"; +import { BattleSpec } from "#app/enums/battle-spec.js"; +import Pokemon, { EnemyPokemon } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { BattlePhase } from "./battle-phase"; +import { MovePhase } from "./move-phase"; +import { PokemonHealPhase } from "./pokemon-heal-phase"; + +export class QuietFormChangePhase extends BattlePhase { + protected pokemon: Pokemon; + protected formChange: SpeciesFormChange; + + constructor(scene: BattleScene, pokemon: Pokemon, formChange: SpeciesFormChange) { + super(scene); + this.pokemon = pokemon; + this.formChange = formChange; + } + + start(): void { + super.start(); + + if (this.pokemon.formIndex === this.pokemon.species.forms.findIndex(f => f.formKey === this.formChange.formKey)) { + return this.end(); + } + + const preName = getPokemonNameWithAffix(this.pokemon); + + if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag)) { + this.pokemon.changeForm(this.formChange).then(() => { + this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); + }); + return; + } + + const getPokemonSprite = () => { + const sprite = this.scene.addPokemonSprite(this.pokemon, this.pokemon.x + this.pokemon.getSprite().x, this.pokemon.y + this.pokemon.getSprite().y, "pkmn__sub"); + sprite.setOrigin(0.5, 1); + sprite.play(this.pokemon.getBattleSpriteKey()).stop(); + sprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) }); + [ "spriteColors", "fusionSpriteColors" ].map(k => { + if (this.pokemon.summonData?.speciesForm) { + k += "Base"; + } + sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; + }); + this.scene.field.add(sprite); + return sprite; + }; + + const [ pokemonTintSprite, pokemonFormTintSprite ] = [ getPokemonSprite(), getPokemonSprite() ]; + + this.pokemon.getSprite().on("animationupdate", (_anim, frame) => { + if (frame.textureKey === pokemonTintSprite.texture.key) { + pokemonTintSprite.setFrame(frame.textureFrame); + } else { + pokemonFormTintSprite.setFrame(frame.textureFrame); + } + }); + + pokemonTintSprite.setAlpha(0); + pokemonTintSprite.setTintFill(0xFFFFFF); + pokemonFormTintSprite.setVisible(false); + pokemonFormTintSprite.setTintFill(0xFFFFFF); + + this.scene.playSound("PRSFX- Transform"); + + this.scene.tweens.add({ + targets: pokemonTintSprite, + alpha: 1, + duration: 1000, + ease: "Cubic.easeIn", + onComplete: () => { + this.pokemon.setVisible(false); + this.pokemon.changeForm(this.formChange).then(() => { + pokemonFormTintSprite.setScale(0.01); + pokemonFormTintSprite.play(this.pokemon.getBattleSpriteKey()).stop(); + pokemonFormTintSprite.setVisible(true); + this.scene.tweens.add({ + targets: pokemonTintSprite, + delay: 250, + scale: 0.01, + ease: "Cubic.easeInOut", + duration: 500, + onComplete: () => pokemonTintSprite.destroy() + }); + this.scene.tweens.add({ + targets: pokemonFormTintSprite, + delay: 250, + scale: this.pokemon.getSpriteScale(), + ease: "Cubic.easeInOut", + duration: 500, + onComplete: () => { + this.pokemon.setVisible(true); + this.scene.tweens.add({ + targets: pokemonFormTintSprite, + delay: 250, + alpha: 0, + ease: "Cubic.easeOut", + duration: 1000, + onComplete: () => { + pokemonTintSprite.setVisible(false); + this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); + } + }); + } + }); + }); + } + }); + } + + end(): void { + if (this.pokemon.scene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon instanceof EnemyPokemon) { + this.scene.playBgm(); + this.scene.unshiftPhase(new PokemonHealPhase(this.scene, this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true)); + this.pokemon.findAndRemoveTags(() => true); + this.pokemon.bossSegments = 5; + this.pokemon.bossSegmentIndex = 4; + this.pokemon.initBattleInfo(); + this.pokemon.cry(); + + const movePhase = this.scene.findPhase(p => p instanceof MovePhase && p.pokemon === this.pokemon) as MovePhase; + if (movePhase) { + movePhase.cancel(); + } + } + + super.end(); + } +} diff --git a/src/phases/reload-session-phase.ts b/src/phases/reload-session-phase.ts new file mode 100644 index 00000000000..a61c52323bf --- /dev/null +++ b/src/phases/reload-session-phase.ts @@ -0,0 +1,39 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Mode } from "#app/ui/ui.js"; +import * as Utils from "#app/utils.js"; + +export class ReloadSessionPhase extends Phase { + private systemDataStr: string | null; + + constructor(scene: BattleScene, systemDataStr?: string) { + super(scene); + + this.systemDataStr = systemDataStr ?? null; + } + + start(): void { + this.scene.ui.setMode(Mode.SESSION_RELOAD); + + let delayElapsed = false; + let loaded = false; + + this.scene.time.delayedCall(Utils.fixedInt(1500), () => { + if (loaded) { + this.end(); + } else { + delayElapsed = true; + } + }); + + this.scene.gameData.clearLocalData(); + + (this.systemDataStr ? this.scene.gameData.initSystem(this.systemDataStr) : this.scene.gameData.loadSystem()).then(() => { + if (delayElapsed) { + this.end(); + } else { + loaded = true; + } + }); + } +} diff --git a/src/phases/return-phase.ts b/src/phases/return-phase.ts new file mode 100644 index 00000000000..e1753670ad4 --- /dev/null +++ b/src/phases/return-phase.ts @@ -0,0 +1,26 @@ +import BattleScene from "#app/battle-scene.js"; +import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms.js"; +import { SwitchSummonPhase } from "./switch-summon-phase"; + +export class ReturnPhase extends SwitchSummonPhase { + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene, fieldIndex, -1, true, false); + } + + switchAndSummon(): void { + this.end(); + } + + summon(): void { } + + onEnd(): void { + const pokemon = this.getPokemon(); + + pokemon.resetTurnData(); + pokemon.resetSummonData(); + + this.scene.updateFieldScale(); + + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger); + } +} diff --git a/src/phases/ribbon-modifier-reward-phase.ts b/src/phases/ribbon-modifier-reward-phase.ts new file mode 100644 index 00000000000..4a80325b7e7 --- /dev/null +++ b/src/phases/ribbon-modifier-reward-phase.ts @@ -0,0 +1,33 @@ +import BattleScene from "#app/battle-scene.js"; +import PokemonSpecies from "#app/data/pokemon-species.js"; +import { ModifierTypeFunc } from "#app/modifier/modifier-type.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { ModifierRewardPhase } from "./modifier-reward-phase"; + +export class RibbonModifierRewardPhase extends ModifierRewardPhase { + private species: PokemonSpecies; + + constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc, species: PokemonSpecies) { + super(scene, modifierTypeFunc); + + this.species = species; + } + + doReward(): Promise { + return new Promise(resolve => { + const newModifier = this.modifierType.newModifier(); + this.scene.addModifier(newModifier).then(() => { + this.scene.playSound("level_up_fanfare"); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:beatModeFirstTime", { + speciesName: this.species.name, + gameMode: this.scene.gameMode.getName(), + newModifier: newModifier?.type.name + }), null, () => { + resolve(); + }, null, true, 1500); + }); + }); + } +} diff --git a/src/phases/scan-ivs-phase.ts b/src/phases/scan-ivs-phase.ts new file mode 100644 index 00000000000..f5e1a814612 --- /dev/null +++ b/src/phases/scan-ivs-phase.ts @@ -0,0 +1,69 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims.js"; +import { Stat } from "#app/enums/stat.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { getTextColor, TextStyle } from "#app/ui/text.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import { PokemonPhase } from "./pokemon-phase"; + +export class ScanIvsPhase extends PokemonPhase { + private shownIvs: integer; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, shownIvs: integer) { + super(scene, battlerIndex); + + this.shownIvs = shownIvs; + } + + start() { + super.start(); + + if (!this.shownIvs) { + return this.end(); + } + + const pokemon = this.getPokemon(); + + let enemyIvs: number[] = []; + let statsContainer: Phaser.GameObjects.Sprite[] = []; + let statsContainerLabels: Phaser.GameObjects.Sprite[] = []; + const enemyField = this.scene.getEnemyField(); + const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible + for (let e = 0; e < enemyField.length; e++) { + enemyIvs = enemyField[e].ivs; + const currentIvs = this.scene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists + const ivsToShow = this.scene.ui.getMessageHandler().getTopIvs(enemyIvs, this.shownIvs); + statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[]; + statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0); + for (let s = 0; s < statsContainerLabels.length; s++) { + const ivStat = Stat[statsContainerLabels[s].frame.name]; + if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) { + const hexColour = enemyIvs[ivStat] === 31 ? getTextColor(TextStyle.PERFECT_IV, false, uiTheme) : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme); + const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color; + statsContainerLabels[s].setTint(hexTextColour); + } + statsContainerLabels[s].setVisible(true); + } + } + + if (!this.scene.hideIvs) { + this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + this.scene.ui.setMode(Mode.CONFIRM, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { + this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); + }); + }, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + this.end(); + }); + }); + } else { + this.end(); + } + } +} diff --git a/src/phases/select-biome-phase.ts b/src/phases/select-biome-phase.ts new file mode 100644 index 00000000000..68c2cd29f26 --- /dev/null +++ b/src/phases/select-biome-phase.ts @@ -0,0 +1,84 @@ +import BattleScene from "#app/battle-scene.js"; +import { biomeLinks, getBiomeName } from "#app/data/biomes.js"; +import { Biome } from "#app/enums/biome.js"; +import { MoneyInterestModifier, MapModifier } from "#app/modifier/modifier.js"; +import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import { BattlePhase } from "./battle-phase"; +import * as Utils from "#app/utils.js"; +import { PartyHealPhase } from "./party-heal-phase"; +import { SwitchBiomePhase } from "./switch-biome-phase"; + +export class SelectBiomePhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + const currentBiome = this.scene.arena.biomeType; + + const setNextBiome = (nextBiome: Biome) => { + if (this.scene.currentBattle.waveIndex % 10 === 1) { + this.scene.applyModifiers(MoneyInterestModifier, true, this.scene); + this.scene.unshiftPhase(new PartyHealPhase(this.scene, false)); + } + this.scene.unshiftPhase(new SwitchBiomePhase(this.scene, nextBiome)); + this.end(); + }; + + if ((this.scene.gameMode.isClassic && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex + 9)) + || (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) + || (this.scene.gameMode.hasShortBiomes && !(this.scene.currentBattle.waveIndex % 50))) { + setNextBiome(Biome.END); + } else if (this.scene.gameMode.hasRandomBiomes) { + setNextBiome(this.generateNextBiome()); + } else if (Array.isArray(biomeLinks[currentBiome])) { + let biomes: Biome[] = []; + this.scene.executeWithSeedOffset(() => { + biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) + .filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1])) + .map(b => !Array.isArray(b) ? b : b[0]); + }, this.scene.currentBattle.waveIndex); + if (biomes.length > 1 && this.scene.findModifier(m => m instanceof MapModifier)) { + let biomeChoices: Biome[] = []; + this.scene.executeWithSeedOffset(() => { + biomeChoices = (!Array.isArray(biomeLinks[currentBiome]) + ? [biomeLinks[currentBiome] as Biome] + : biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) + .filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1])) + .map(b => Array.isArray(b) ? b[0] : b); + }, this.scene.currentBattle.waveIndex); + const biomeSelectItems = biomeChoices.map(b => { + const ret: OptionSelectItem = { + label: getBiomeName(b), + handler: () => { + this.scene.ui.setMode(Mode.MESSAGE); + setNextBiome(b); + return true; + } + }; + return ret; + }); + this.scene.ui.setMode(Mode.OPTION_SELECT, { + options: biomeSelectItems, + delay: 1000 + }); + } else { + setNextBiome(biomes[Utils.randSeedInt(biomes.length)]); + } + } else if (biomeLinks.hasOwnProperty(currentBiome)) { + setNextBiome(biomeLinks[currentBiome] as Biome); + } else { + setNextBiome(this.generateNextBiome()); + } + } + + generateNextBiome(): Biome { + if (!(this.scene.currentBattle.waveIndex % 50)) { + return Biome.END; + } + return this.scene.generateRandomBiome(this.scene.currentBattle.waveIndex); + } +} diff --git a/src/phases/select-challenge-phase.ts b/src/phases/select-challenge-phase.ts new file mode 100644 index 00000000000..eaf830e0059 --- /dev/null +++ b/src/phases/select-challenge-phase.ts @@ -0,0 +1,17 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Mode } from "#app/ui/ui.js"; + +export class SelectChallengePhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.playBgm("menu"); + + this.scene.ui.setMode(Mode.CHALLENGE_SELECT); + } +} diff --git a/src/phases/select-gender-phase.ts b/src/phases/select-gender-phase.ts new file mode 100644 index 00000000000..3fc6916e233 --- /dev/null +++ b/src/phases/select-gender-phase.ts @@ -0,0 +1,46 @@ +import BattleScene from "#app/battle-scene.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { Phase } from "#app/phase.js"; +import { SettingKeys } from "#app/system/settings/settings.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; + +export class SelectGenderPhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + super.start(); + + this.scene.ui.showText(i18next.t("menu:boyOrGirl"), null, () => { + this.scene.ui.setMode(Mode.OPTION_SELECT, { + options: [ + { + label: i18next.t("settings:boy"), + handler: () => { + this.scene.gameData.gender = PlayerGender.MALE; + this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 0); + this.scene.gameData.saveSystem().then(() => this.end()); + return true; + } + }, + { + label: i18next.t("settings:girl"), + handler: () => { + this.scene.gameData.gender = PlayerGender.FEMALE; + this.scene.gameData.saveSetting(SettingKeys.Player_Gender, 1); + this.scene.gameData.saveSystem().then(() => this.end()); + return true; + } + } + ] + }); + }); + } + + end(): void { + this.scene.ui.setMode(Mode.MESSAGE); + super.end(); + } +} diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts new file mode 100644 index 00000000000..67ae904fb58 --- /dev/null +++ b/src/phases/select-modifier-phase.ts @@ -0,0 +1,234 @@ +import BattleScene from "#app/battle-scene.js"; +import { ModifierTier } from "#app/modifier/modifier-tier.js"; +import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions } from "#app/modifier/modifier-type.js"; +import { ExtraModifierModifier, Modifier, PokemonHeldItemModifier } from "#app/modifier/modifier.js"; +import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler.js"; +import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; +import Overrides from "#app/overrides"; + +export class SelectModifierPhase extends BattlePhase { + private rerollCount: integer; + private modifierTiers: ModifierTier[]; + + constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[]) { + super(scene); + + this.rerollCount = rerollCount; + this.modifierTiers = modifierTiers!; // TODO: is this bang correct? + } + + start() { + super.start(); + + if (!this.rerollCount) { + this.updateSeed(); + } else { + this.scene.reroll = false; + } + + const party = this.scene.getParty(); + regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount); + const modifierCount = new Utils.IntegerHolder(3); + if (this.isPlayer()) { + this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount); + } + const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value); + + const modifierSelectCallback = (rowCursor: integer, cursor: integer) => { + if (rowCursor < 0 || cursor < 0) { + this.scene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => { + this.scene.ui.setOverlayMode(Mode.CONFIRM, () => { + this.scene.ui.revertMode(); + this.scene.ui.setMode(Mode.MESSAGE); + super.end(); + }, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers))); + }); + return false; + } + let modifierType: ModifierType; + let cost: integer; + switch (rowCursor) { + case 0: + switch (cursor) { + case 0: + const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers); + if (this.scene.money < rerollCost) { + this.scene.ui.playError(); + return false; + } else { + this.scene.reroll = true; + this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[])); + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { + this.scene.money -= rerollCost; + this.scene.updateMoneyText(); + this.scene.animateMoneyChanged(false); + } + this.scene.playSound("buy"); + } + break; + case 1: + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => { + if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) { + const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier + && m.isTransferrable && m.pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; + const itemModifier = itemModifiers[itemIndex]; + this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity); + } else { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + } + }, PartyUiHandler.FilterItemMaxStacks); + break; + case 2: + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + }); + break; + case 3: + this.scene.lockModifierTiers = !this.scene.lockModifierTiers; + const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler; + uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + uiHandler.updateLockRaritiesText(); + uiHandler.updateRerollCostText(); + return false; + } + return true; + case 1: + if (typeOptions[cursor].type) { + modifierType = typeOptions[cursor].type; + } + break; + default: + const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1)); + const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT]; + if (shopOption.type) { + modifierType = shopOption.type; + } + cost = shopOption.cost; + break; + } + + if (cost! && (this.scene.money < cost) && !Overrides.WAIVE_ROLL_FEE_OVERRIDE) { // TODO: is the bang on cost correct? + this.scene.ui.playError(); + return false; + } + + const applyModifier = (modifier: Modifier, playSound: boolean = false) => { + const result = this.scene.addModifier(modifier, false, playSound); + if (cost) { + result.then(success => { + if (success) { + if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { + this.scene.money -= cost; + this.scene.updateMoneyText(); + this.scene.animateMoneyChanged(false); + } + this.scene.playSound("buy"); + (this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText(); + } else { + this.scene.ui.playError(); + } + }); + } else { + const doEnd = () => { + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.MESSAGE); + super.end(); + }; + if (result instanceof Promise) { + result.then(() => doEnd()); + } else { + doEnd(); + } + } + }; + + if (modifierType! instanceof PokemonModifierType) { //TODO: is the bang correct? + if (modifierType instanceof FusePokemonModifierType) { + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => { + if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct? + applyModifier(modifier, true); + }); + } else { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + } + }, modifierType.selectFilter); + } else { + const pokemonModifierType = modifierType as PokemonModifierType; + const isMoveModifier = modifierType instanceof PokemonMoveModifierType; + const isTmModifier = modifierType instanceof TmModifierType; + const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType; + const isPpRestoreModifier = (modifierType instanceof PokemonPpRestoreModifierType || modifierType instanceof PokemonPpUpModifierType); + const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER + : isTmModifier ? PartyUiMode.TM_MODIFIER + : isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER + : PartyUiMode.MODIFIER; + const tmMoveId = isTmModifier + ? (modifierType as TmModifierType).moveId + : undefined; + this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => { + if (slotIndex < 6) { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + const modifier = !isMoveModifier + ? !isRememberMoveModifier + ? modifierType.newModifier(party[slotIndex]) + : modifierType.newModifier(party[slotIndex], option as integer) + : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1); + applyModifier(modifier!, true); // TODO: is the bang correct? + }); + } else { + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + } + }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier); + } + } else { + applyModifier(modifierType!.newModifier()!); // TODO: is the bang correct? + } + + return !cost!;// TODO: is the bang correct? + }; + this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); + } + + updateSeed(): void { + this.scene.resetSeed(); + } + + isPlayer(): boolean { + return true; + } + + getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): integer { + let baseValue = 0; + if (Overrides.WAIVE_ROLL_FEE_OVERRIDE) { + return baseValue; + } else if (lockRarities) { + const tierValues = [50, 125, 300, 750, 2000]; + for (const opt of typeOptions) { + baseValue += tierValues[opt.type.tier ?? 0]; + } + } else { + baseValue = 250; + } + return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount), Number.MAX_SAFE_INTEGER); + } + + getPoolType(): ModifierPoolType { + return ModifierPoolType.PLAYER; + } + + getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] { + return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined); + } + + addModifier(modifier: Modifier): Promise { + return this.scene.addModifier(modifier, false, true); + } +} diff --git a/src/phases/select-starter-phase.ts b/src/phases/select-starter-phase.ts new file mode 100644 index 00000000000..ad972a49225 --- /dev/null +++ b/src/phases/select-starter-phase.ts @@ -0,0 +1,112 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; +import { Gender } from "#app/data/gender.js"; +import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms.js"; +import { getPokemonSpecies } from "#app/data/pokemon-species.js"; +import { Species } from "#app/enums/species.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; +import { overrideModifiers, overrideHeldItems } from "#app/modifier/modifier.js"; +import { Phase } from "#app/phase.js"; +import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler.js"; +import { Starter } from "#app/ui/starter-select-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; +import { TitlePhase } from "./title-phase"; +import Overrides from "#app/overrides"; + +export class SelectStarterPhase extends Phase { + + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.playBgm("menu"); + + this.scene.ui.setMode(Mode.STARTER_SELECT, (starters: Starter[]) => { + this.scene.ui.clearText(); + this.scene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: integer) => { + if (slotId === -1) { + this.scene.clearPhaseQueue(); + this.scene.pushPhase(new TitlePhase(this.scene)); + return this.end(); + } + this.scene.sessionSlotId = slotId; + this.initBattle(starters); + }); + }); + } + + /** + * Initialize starters before starting the first battle + * @param starters {@linkcode Pokemon} with which to start the first battle + */ + initBattle(starters: Starter[]) { + const party = this.scene.getParty(); + const loadPokemonAssets: Promise[] = []; + starters.forEach((starter: Starter, i: integer) => { + if (!i && Overrides.STARTER_SPECIES_OVERRIDE) { + starter.species = getPokemonSpecies(Overrides.STARTER_SPECIES_OVERRIDE as Species); + } + const starterProps = this.scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr); + let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); + if ( + starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && + starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] + ) { + starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; + } + + let starterGender = starter.species.malePercent !== null + ? !starterProps.female ? Gender.MALE : Gender.FEMALE + : Gender.GENDERLESS; + if (Overrides.GENDER_OVERRIDE !== null) { + starterGender = Overrides.GENDER_OVERRIDE; + } + const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0); + const starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature); + starter.moveset && starterPokemon.tryPopulateMoveset(starter.moveset); + if (starter.passive) { + starterPokemon.passive = true; + } + starterPokemon.luck = this.scene.gameData.getDexAttrLuck(this.scene.gameData.dexData[starter.species.speciesId].caughtAttr); + if (starter.pokerus) { + starterPokemon.pokerus = true; + } + + if (starter.nickname) { + starterPokemon.nickname = starter.nickname; + } + + if (this.scene.gameMode.isSplicedOnly) { + starterPokemon.generateFusionSpecies(true); + } + starterPokemon.setVisible(false); + applyChallenges(this.scene.gameMode, ChallengeType.STARTER_MODIFY, starterPokemon); + party.push(starterPokemon); + loadPokemonAssets.push(starterPokemon.loadAssets()); + }); + overrideModifiers(this.scene); + overrideHeldItems(this.scene, party[0]); + Promise.all(loadPokemonAssets).then(() => { + SoundFade.fadeOut(this.scene, this.scene.sound.get("menu"), 500, true); + this.scene.time.delayedCall(500, () => this.scene.playBgm()); + if (this.scene.gameMode.isClassic) { + this.scene.gameData.gameStats.classicSessionsPlayed++; + } else { + this.scene.gameData.gameStats.endlessSessionsPlayed++; + } + this.scene.newBattle(); + this.scene.arena.init(); + this.scene.sessionPlayTime = 0; + this.scene.lastSavePlayTime = 0; + // Ensures Keldeo (or any future Pokemon that have this type of form change) starts in the correct form + this.scene.getParty().forEach((p: PlayerPokemon) => { + this.scene.triggerPokemonFormChange(p, SpeciesFormChangeMoveLearnedTrigger); + }); + this.end(); + }); + } +} diff --git a/src/phases/select-target-phase.ts b/src/phases/select-target-phase.ts new file mode 100644 index 00000000000..fe72335e312 --- /dev/null +++ b/src/phases/select-target-phase.ts @@ -0,0 +1,32 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { Command } from "#app/ui/command-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import { CommandPhase } from "./command-phase"; +import { PokemonPhase } from "./pokemon-phase"; + +export class SelectTargetPhase extends PokemonPhase { + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene, fieldIndex); + } + + start() { + super.start(); + + const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex]; + const move = turnCommand?.move?.move; + this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => { + this.scene.ui.setMode(Mode.MESSAGE); + if (targets.length < 1) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = null; + this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex)); + } else { + turnCommand!.targets = targets; //TODO: is the bang correct here? + } + if (turnCommand?.command === Command.BALL && this.fieldIndex) { + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; //TODO: is the bang correct here? + } + this.end(); + }); + } +} diff --git a/src/phases/shiny-sparkle-phase.ts b/src/phases/shiny-sparkle-phase.ts new file mode 100644 index 00000000000..4cd2b68f881 --- /dev/null +++ b/src/phases/shiny-sparkle-phase.ts @@ -0,0 +1,16 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class ShinySparklePhase extends PokemonPhase { + constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + super(scene, battlerIndex); + } + + start() { + super.start(); + + this.getPokemon().sparkle(); + this.scene.time.delayedCall(1000, () => this.end()); + } +} diff --git a/src/phases/show-ability-phase.ts b/src/phases/show-ability-phase.ts new file mode 100644 index 00000000000..ee0b98f7886 --- /dev/null +++ b/src/phases/show-ability-phase.ts @@ -0,0 +1,29 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export class ShowAbilityPhase extends PokemonPhase { + private passive: boolean; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, passive: boolean = false) { + super(scene, battlerIndex); + + this.passive = passive; + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + + if (pokemon) { + this.scene.abilityBar.showAbility(pokemon, this.passive); + + if (pokemon?.battleData) { + pokemon.battleData.abilityRevealed = true; + } + } + + this.end(); + } +} diff --git a/src/phases/show-party-exp-bar-phase.ts b/src/phases/show-party-exp-bar-phase.ts new file mode 100644 index 00000000000..9920472e801 --- /dev/null +++ b/src/phases/show-party-exp-bar-phase.ts @@ -0,0 +1,56 @@ +import BattleScene from "#app/battle-scene.js"; +import { ExpNotification } from "#app/enums/exp-notification.js"; +import { ExpBoosterModifier } from "#app/modifier/modifier.js"; +import * as Utils from "#app/utils.js"; +import { HidePartyExpBarPhase } from "./hide-party-exp-bar-phase"; +import { LevelUpPhase } from "./level-up-phase"; +import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; + +export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase { + private expValue: number; + + constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) { + super(scene, partyMemberIndex); + + this.expValue = expValue; + } + + start() { + super.start(); + + const pokemon = this.getPokemon(); + const exp = new Utils.NumberHolder(this.expValue); + this.scene.applyModifiers(ExpBoosterModifier, true, exp); + exp.value = Math.floor(exp.value); + + const lastLevel = pokemon.level; + pokemon.addExp(exp.value); + const newLevel = pokemon.level; + if (newLevel > lastLevel) { + this.scene.unshiftPhase(new LevelUpPhase(this.scene, this.partyMemberIndex, lastLevel, newLevel)); + } + this.scene.unshiftPhase(new HidePartyExpBarPhase(this.scene)); + pokemon.updateInfo(); + + if (this.scene.expParty === ExpNotification.SKIP) { + this.end(); + } else if (this.scene.expParty === ExpNotification.ONLY_LEVEL_UP) { + if (newLevel > lastLevel) { // this means if we level up + // instead of displaying the exp gain in the small frame, we display the new level + // we use the same method for mode 0 & 1, by giving a parameter saying to display the exp or the level + this.scene.partyExpBar.showPokemonExp(pokemon, exp.value, this.scene.expParty === ExpNotification.ONLY_LEVEL_UP, newLevel).then(() => { + setTimeout(() => this.end(), 800 / Math.pow(2, this.scene.expGainsSpeed)); + }); + } else { + this.end(); + } + } else if (this.scene.expGainsSpeed < 3) { + this.scene.partyExpBar.showPokemonExp(pokemon, exp.value, false, newLevel).then(() => { + setTimeout(() => this.end(), 500 / Math.pow(2, this.scene.expGainsSpeed)); + }); + } else { + this.end(); + } + + } +} diff --git a/src/phases/show-trainer-phase.ts b/src/phases/show-trainer-phase.ts new file mode 100644 index 00000000000..8a869f582d8 --- /dev/null +++ b/src/phases/show-trainer-phase.ts @@ -0,0 +1,24 @@ +import BattleScene from "#app/battle-scene.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { BattlePhase } from "./battle-phase"; + +export class ShowTrainerPhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.trainer.setVisible(true); + + this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back`); + + this.scene.tweens.add({ + targets: this.scene.trainer, + x: 106, + duration: 1000, + onComplete: () => this.end() + }); + } +} diff --git a/src/phases/stat-change-phase.ts b/src/phases/stat-change-phase.ts new file mode 100644 index 00000000000..3469cc62942 --- /dev/null +++ b/src/phases/stat-change-phase.ts @@ -0,0 +1,234 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { applyPreStatChangeAbAttrs, ProtectStatAbAttr, applyAbAttrs, StatChangeMultiplierAbAttr, StatChangeCopyAbAttr, applyPostStatChangeAbAttrs, PostStatChangeAbAttr } from "#app/data/ability.js"; +import { MistTag, ArenaTagSide } from "#app/data/arena-tag.js"; +import { BattleStat, getBattleStatName, getBattleStatLevelChangeDescription } from "#app/data/battle-stat.js"; +import Pokemon from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { PokemonResetNegativeStatStageModifier } from "#app/modifier/modifier.js"; +import { handleTutorial, Tutorial } from "#app/tutorial.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { PokemonPhase } from "./pokemon-phase"; + +export type StatChangeCallback = (target: Pokemon | null, changed: BattleStat[], relativeChanges: number[]) => void; + +export class StatChangePhase extends PokemonPhase { + private stats: BattleStat[]; + private selfTarget: boolean; + private levels: integer; + private showMessage: boolean; + private ignoreAbilities: boolean; + private canBeCopied: boolean; + private onChange: StatChangeCallback | null; + + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false, canBeCopied: boolean = true, onChange: StatChangeCallback | null = null) { + super(scene, battlerIndex); + + this.selfTarget = selfTarget; + this.stats = stats; + this.levels = levels; + this.showMessage = showMessage; + this.ignoreAbilities = ignoreAbilities; + this.canBeCopied = canBeCopied; + this.onChange = onChange; + } + + start() { + const pokemon = this.getPokemon(); + + let random = false; + + if (this.stats.length === 1 && this.stats[0] === BattleStat.RAND) { + this.stats[0] = this.getRandomStat(); + random = true; + } + + this.aggregateStatChanges(random); + + if (!pokemon.isActive(true)) { + return this.end(); + } + + const filteredStats = this.stats.map(s => s !== BattleStat.RAND ? s : this.getRandomStat()).filter(stat => { + const cancelled = new Utils.BooleanHolder(false); + + if (!this.selfTarget && this.levels < 0) { + this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled); + } + + if (!cancelled.value && !this.selfTarget && this.levels < 0) { + applyPreStatChangeAbAttrs(ProtectStatAbAttr, this.getPokemon(), stat, cancelled); + } + + return !cancelled.value; + }); + + const levels = new Utils.IntegerHolder(this.levels); + + if (!this.ignoreAbilities) { + applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels); + } + + const battleStats = this.getPokemon().summonData.battleStats; + const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats![stat] + levels.value, 6) : Math.max(battleStats![stat] + levels.value, -6)) - battleStats![stat]); + + this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels); + + const end = () => { + if (this.showMessage) { + const messages = this.getStatChangeMessages(filteredStats, levels.value, relLevels); + for (const message of messages) { + this.scene.queueMessage(message); + } + } + + for (const stat of filteredStats) { + pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); + } + + if (levels.value > 0 && this.canBeCopied) { + for (const opponent of pokemon.getOpponents()) { + applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value); + } + } + + applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); + + // Look for any other stat change phases; if this is the last one, do White Herb check + const existingPhase = this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex); + if (!(existingPhase instanceof StatChangePhase)) { + // Apply White Herb if needed + const whiteHerb = this.scene.applyModifier(PokemonResetNegativeStatStageModifier, this.player, pokemon) as PokemonResetNegativeStatStageModifier; + // If the White Herb was applied, consume it + if (whiteHerb) { + --whiteHerb.stackCount; + if (whiteHerb.stackCount <= 0) { + this.scene.removeModifier(whiteHerb); + } + this.scene.updateModifiers(this.player); + } + } + + pokemon.updateInfo(); + + handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end()); + }; + + if (relLevels.filter(l => l).length && this.scene.moveAnimations) { + pokemon.enableMask(); + const pokemonMaskSprite = pokemon.maskSprite; + + const tileX = (this.player ? 106 : 236) * pokemon.getSpriteScale() * this.scene.field.scale; + const tileY = ((this.player ? 148 : 84) + (levels.value >= 1 ? 160 : 0)) * pokemon.getSpriteScale() * this.scene.field.scale; + const tileWidth = 156 * this.scene.field.scale * pokemon.getSpriteScale(); + const tileHeight = 316 * this.scene.field.scale * pokemon.getSpriteScale(); + + // On increase, show the red sprite located at ATK + // On decrease, show the blue sprite located at SPD + const spriteColor = levels.value >= 1 ? BattleStat[BattleStat.ATK].toLowerCase() : BattleStat[BattleStat.SPD].toLowerCase(); + const statSprite = this.scene.add.tileSprite(tileX, tileY, tileWidth, tileHeight, "battle_stats", spriteColor); + statSprite.setPipeline(this.scene.fieldSpritePipeline); + statSprite.setAlpha(0); + statSprite.setScale(6); + statSprite.setOrigin(0.5, 1); + + this.scene.playSound(`stat_${levels.value >= 1 ? "up" : "down"}`); + + statSprite.setMask(new Phaser.Display.Masks.BitmapMask(this.scene, pokemonMaskSprite ?? undefined)); + + this.scene.tweens.add({ + targets: statSprite, + duration: 250, + alpha: 0.8375, + onComplete: () => { + this.scene.tweens.add({ + targets: statSprite, + delay: 1000, + duration: 250, + alpha: 0 + }); + } + }); + + this.scene.tweens.add({ + targets: statSprite, + duration: 1500, + y: `${levels.value >= 1 ? "-" : "+"}=${160 * 6}` + }); + + this.scene.time.delayedCall(1750, () => { + pokemon.disableMask(); + end(); + }); + } else { + end(); + } + } + + getRandomStat(): BattleStat { + const allStats = Utils.getEnumValues(BattleStat); + return this.getPokemon() ? allStats[this.getPokemon()!.randSeedInt(BattleStat.SPD + 1)] : BattleStat.ATK; // TODO: return default ATK on random? idk... + } + + aggregateStatChanges(random: boolean = false): void { + const isAccEva = [BattleStat.ACC, BattleStat.EVA].some(s => this.stats.includes(s)); + let existingPhase: StatChangePhase; + if (this.stats.length === 1) { + while ((existingPhase = (this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex && p.stats.length === 1 + && (p.stats[0] === this.stats[0] || (random && p.stats[0] === BattleStat.RAND)) + && p.selfTarget === this.selfTarget && p.showMessage === this.showMessage && p.ignoreAbilities === this.ignoreAbilities) as StatChangePhase))) { + if (existingPhase.stats[0] === BattleStat.RAND) { + existingPhase.stats[0] = this.getRandomStat(); + if (existingPhase.stats[0] !== this.stats[0]) { + continue; + } + } + this.levels += existingPhase.levels; + + if (!this.scene.tryRemovePhase(p => p === existingPhase)) { + break; + } + } + } + while ((existingPhase = (this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex && p.selfTarget === this.selfTarget + && ([BattleStat.ACC, BattleStat.EVA].some(s => p.stats.includes(s)) === isAccEva) + && p.levels === this.levels && p.showMessage === this.showMessage && p.ignoreAbilities === this.ignoreAbilities) as StatChangePhase))) { + this.stats.push(...existingPhase.stats); + if (!this.scene.tryRemovePhase(p => p === existingPhase)) { + break; + } + } + } + + getStatChangeMessages(stats: BattleStat[], levels: integer, relLevels: integer[]): string[] { + const messages: string[] = []; + + const relLevelStatIndexes = {}; + for (let rl = 0; rl < relLevels.length; rl++) { + const relLevel = relLevels[rl]; + if (!relLevelStatIndexes[relLevel]) { + relLevelStatIndexes[relLevel] = []; + } + relLevelStatIndexes[relLevel].push(rl); + } + + Object.keys(relLevelStatIndexes).forEach(rl => { + const relLevelStats = stats.filter((_, i) => relLevelStatIndexes[rl].includes(i)); + let statsFragment = ""; + + if (relLevelStats.length > 1) { + statsFragment = relLevelStats.length >= 5 + ? i18next.t("battle:stats") + : `${relLevelStats.slice(0, -1).map(s => getBattleStatName(s)).join(", ")}${relLevelStats.length > 2 ? "," : ""} ${i18next.t("battle:statsAnd")} ${getBattleStatName(relLevelStats[relLevelStats.length - 1])}`; + messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1,relLevelStats.length)); + } else { + statsFragment = getBattleStatName(relLevelStats[0]); + messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1,relLevelStats.length)); + } + }); + + return messages; + } +} diff --git a/src/phases/summon-missing-phase.ts b/src/phases/summon-missing-phase.ts new file mode 100644 index 00000000000..bb9607285ad --- /dev/null +++ b/src/phases/summon-missing-phase.ts @@ -0,0 +1,15 @@ +import BattleScene from "#app/battle-scene.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import i18next from "i18next"; +import { SummonPhase } from "./summon-phase"; + +export class SummonMissingPhase extends SummonPhase { + constructor(scene: BattleScene, fieldIndex: integer) { + super(scene, fieldIndex); + } + + preSummon(): void { + this.scene.ui.showText(i18next.t("battle:sendOutPokemon", { pokemonName: getPokemonNameWithAffix(this.getPokemon()) })); + this.scene.time.delayedCall(250, () => this.summon()); + } +} diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts new file mode 100644 index 00000000000..50424170ea7 --- /dev/null +++ b/src/phases/summon-phase.ts @@ -0,0 +1,194 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattleType } from "#app/battle.js"; +import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball.js"; +import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms.js"; +import { TrainerSlot } from "#app/data/trainer-config.js"; +import { PlayerGender } from "#app/enums/player-gender.js"; +import { addPokeballOpenParticles } from "#app/field/anims.js"; +import Pokemon, { FieldPosition } from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import i18next from "i18next"; +import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase"; +import { PostSummonPhase } from "./post-summon-phase"; +import { GameOverPhase } from "./game-over-phase"; +import { ShinySparklePhase } from "./shiny-sparkle-phase"; + +export class SummonPhase extends PartyMemberPokemonPhase { + private loaded: boolean; + + constructor(scene: BattleScene, fieldIndex: integer, player: boolean = true, loaded: boolean = false) { + super(scene, fieldIndex, player); + + this.loaded = loaded; + } + + start() { + super.start(); + + this.preSummon(); + } + + /** + * Sends out a Pokemon before the battle begins and shows the appropriate messages + */ + preSummon(): void { + const partyMember = this.getPokemon(); + // If the Pokemon about to be sent out is fainted or illegal under a challenge, switch to the first non-fainted legal Pokemon + if (!partyMember.isAllowedInBattle()) { + console.warn("The Pokemon about to be sent out is fainted or illegal under a challenge. Attempting to resolve..."); + + // First check if they're somehow still in play, if so remove them. + if (partyMember.isOnField()) { + partyMember.leaveField(); + } + + const party = this.getParty(); + + // Find the first non-fainted Pokemon index above the current one + const legalIndex = party.findIndex((p, i) => i > this.partyMemberIndex && p.isAllowedInBattle()); + if (legalIndex === -1) { + console.error("Party Details:\n", party); + console.error("All available Pokemon were fainted or illegal!"); + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + this.end(); + return; + } + + // Swaps the fainted Pokemon and the first non-fainted legal Pokemon in the party + [party[this.partyMemberIndex], party[legalIndex]] = [party[legalIndex], party[this.partyMemberIndex]]; + console.warn("Swapped %s %O with %s %O", getPokemonNameWithAffix(partyMember), partyMember, getPokemonNameWithAffix(party[0]), party[0]); + } + + if (this.player) { + this.scene.ui.showText(i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(this.getPokemon()) })); + if (this.player) { + this.scene.pbTray.hide(); + } + this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? "f" : "m"}_back_pb`); + this.scene.time.delayedCall(562, () => { + this.scene.trainer.setFrame("2"); + this.scene.time.delayedCall(64, () => { + this.scene.trainer.setFrame("3"); + }); + }); + this.scene.tweens.add({ + targets: this.scene.trainer, + x: -36, + duration: 1000, + onComplete: () => this.scene.trainer.setVisible(false) + }); + this.scene.time.delayedCall(750, () => this.summon()); + } else { + const trainerName = this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); + const pokemonName = this.getPokemon().getNameToRender(); + const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName }); + + this.scene.pbTrayEnemy.hide(); + this.scene.ui.showText(message, null, () => this.summon()); + } + } + + summon(): void { + const pokemon = this.getPokemon(); + + const pokeball = this.scene.addFieldSprite(this.player ? 36 : 248, this.player ? 80 : 44, "pb", getPokeballAtlasKey(pokemon.pokeball)); + pokeball.setVisible(false); + pokeball.setOrigin(0.5, 0.625); + this.scene.field.add(pokeball); + + if (this.fieldIndex === 1) { + pokemon.setFieldPosition(FieldPosition.RIGHT, 0); + } else { + const availablePartyMembers = this.getParty().filter(p => p.isAllowedInBattle()).length; + pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT); + } + + const fpOffset = pokemon.getFieldPositionOffset(); + + pokeball.setVisible(true); + + this.scene.tweens.add({ + targets: pokeball, + duration: 650, + x: (this.player ? 100 : 236) + fpOffset[0] + }); + + this.scene.tweens.add({ + targets: pokeball, + duration: 150, + ease: "Cubic.easeOut", + y: (this.player ? 70 : 34) + fpOffset[1], + onComplete: () => { + this.scene.tweens.add({ + targets: pokeball, + duration: 500, + ease: "Cubic.easeIn", + angle: 1440, + y: (this.player ? 132 : 86) + fpOffset[1], + onComplete: () => { + this.scene.playSound("pb_rel"); + pokeball.destroy(); + this.scene.add.existing(pokemon); + this.scene.field.add(pokemon); + if (!this.player) { + const playerPokemon = this.scene.getPlayerPokemon() as Pokemon; + if (playerPokemon?.visible) { + this.scene.field.moveBelow(pokemon, playerPokemon); + } + this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); + } + addPokeballOpenParticles(this.scene, pokemon.x, pokemon.y - 16, pokemon.pokeball); + this.scene.updateModifiers(this.player); + this.scene.updateFieldScale(); + pokemon.showInfo(); + pokemon.playAnim(); + pokemon.setVisible(true); + pokemon.getSprite().setVisible(true); + pokemon.setScale(0.5); + pokemon.tint(getPokeballTintColor(pokemon.pokeball)); + pokemon.untint(250, "Sine.easeIn"); + this.scene.updateFieldScale(); + this.scene.tweens.add({ + targets: pokemon, + duration: 250, + ease: "Sine.easeIn", + scale: pokemon.getSpriteScale(), + onComplete: () => { + pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); + pokemon.getSprite().clearTint(); + pokemon.resetSummonData(); + this.scene.time.delayedCall(1000, () => this.end()); + } + }); + } + }); + } + }); + } + + onEnd(): void { + const pokemon = this.getPokemon(); + + if (pokemon.isShiny()) { + this.scene.unshiftPhase(new ShinySparklePhase(this.scene, pokemon.getBattlerIndex())); + } + + pokemon.resetTurnData(); + + if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) { + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); + this.queuePostSummon(); + } + } + + queuePostSummon(): void { + this.scene.pushPhase(new PostSummonPhase(this.scene, this.getPokemon().getBattlerIndex())); + } + + end() { + this.onEnd(); + + super.end(); + } +} diff --git a/src/phases/switch-biome-phase.ts b/src/phases/switch-biome-phase.ts new file mode 100644 index 00000000000..f20cd59b240 --- /dev/null +++ b/src/phases/switch-biome-phase.ts @@ -0,0 +1,65 @@ +import BattleScene from "#app/battle-scene.js"; +import { Biome } from "#app/enums/biome.js"; +import { getBiomeKey } from "#app/field/arena.js"; +import { BattlePhase } from "./battle-phase"; + +export class SwitchBiomePhase extends BattlePhase { + private nextBiome: Biome; + + constructor(scene: BattleScene, nextBiome: Biome) { + super(scene); + + this.nextBiome = nextBiome; + } + + start() { + super.start(); + + if (this.nextBiome === undefined) { + return this.end(); + } + + this.scene.tweens.add({ + targets: [this.scene.arenaEnemy, this.scene.lastEnemyTrainer], + x: "+=300", + duration: 2000, + onComplete: () => { + this.scene.arenaEnemy.setX(this.scene.arenaEnemy.x - 600); + + this.scene.newArena(this.nextBiome); + + const biomeKey = getBiomeKey(this.nextBiome); + const bgTexture = `${biomeKey}_bg`; + this.scene.arenaBgTransition.setTexture(bgTexture); + this.scene.arenaBgTransition.setAlpha(0); + this.scene.arenaBgTransition.setVisible(true); + this.scene.arenaPlayerTransition.setBiome(this.nextBiome); + this.scene.arenaPlayerTransition.setAlpha(0); + this.scene.arenaPlayerTransition.setVisible(true); + + this.scene.tweens.add({ + targets: [this.scene.arenaPlayer, this.scene.arenaBgTransition, this.scene.arenaPlayerTransition], + duration: 1000, + delay: 1000, + ease: "Sine.easeInOut", + alpha: (target: any) => target === this.scene.arenaPlayer ? 0 : 1, + onComplete: () => { + this.scene.arenaBg.setTexture(bgTexture); + this.scene.arenaPlayer.setBiome(this.nextBiome); + this.scene.arenaPlayer.setAlpha(1); + this.scene.arenaEnemy.setBiome(this.nextBiome); + this.scene.arenaEnemy.setAlpha(1); + this.scene.arenaNextEnemy.setBiome(this.nextBiome); + this.scene.arenaBgTransition.setVisible(false); + this.scene.arenaPlayerTransition.setVisible(false); + if (this.scene.lastEnemyTrainer) { + this.scene.lastEnemyTrainer.destroy(); + } + + this.end(); + } + }); + } + }); + } +} diff --git a/src/phases/switch-phase.ts b/src/phases/switch-phase.ts new file mode 100644 index 00000000000..93b0943febf --- /dev/null +++ b/src/phases/switch-phase.ts @@ -0,0 +1,65 @@ +import BattleScene from "#app/battle-scene.js"; +import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import { BattlePhase } from "./battle-phase"; +import { SwitchSummonPhase } from "./switch-summon-phase"; + +/** + * Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase} + * for the player (if a switch would be valid for the current battle state). + */ +export class SwitchPhase extends BattlePhase { + protected fieldIndex: integer; + private isModal: boolean; + private doReturn: boolean; + + /** + * Creates a new SwitchPhase + * @param scene {@linkcode BattleScene} Current battle scene + * @param fieldIndex Field index to switch out + * @param isModal Indicates if the switch should be forced (true) or is + * optional (false). + * @param doReturn Indicates if the party member on the field should be + * recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}. + */ + constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) { + super(scene); + + this.fieldIndex = fieldIndex; + this.isModal = isModal; + this.doReturn = doReturn; + } + + start() { + super.start(); + + // Skip modal switch if impossible (no remaining party members that aren't in battle) + if (this.isModal && !this.scene.getParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) { + return super.end(); + } + + // Skip if the fainted party member has been revived already. doReturn is + // only passed as `false` from FaintPhase (as opposed to other usages such + // as ForceSwitchOutAttr or CheckSwitchPhase), so we only want to check this + // if the mon should have already been returned but is still alive and well + // on the field. see also; battle.test.ts + if (this.isModal && !this.doReturn && !this.scene.getParty()[this.fieldIndex].isFainted()) { + return super.end(); + } + + // Check if there is any space still in field + if (this.isModal && this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) { + return super.end(); + } + + // Override field index to 0 in case of double battle where 2/3 remaining legal party members fainted at once + const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? this.fieldIndex : 0; + + this.scene.ui.setMode(Mode.PARTY, this.isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH, fieldIndex, (slotIndex: integer, option: PartyOption) => { + if (slotIndex >= this.scene.currentBattle.getBattlerCount() && slotIndex < 6) { + this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, fieldIndex, slotIndex, this.doReturn, option === PartyOption.PASS_BATON)); + } + this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + }, PartyUiHandler.FilterNonFainted); + } +} diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts new file mode 100644 index 00000000000..3e401925cea --- /dev/null +++ b/src/phases/switch-summon-phase.ts @@ -0,0 +1,168 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr } from "#app/data/ability.js"; +import { allMoves, ForceSwitchOutAttr } from "#app/data/move.js"; +import { getPokeballTintColor } from "#app/data/pokeball.js"; +import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms.js"; +import { TrainerSlot } from "#app/data/trainer-config.js"; +import Pokemon from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { SwitchEffectTransferModifier } from "#app/modifier/modifier.js"; +import { Command } from "#app/ui/command-ui-handler.js"; +import i18next from "i18next"; +import { PostSummonPhase } from "./post-summon-phase"; +import { SummonPhase } from "./summon-phase"; + +export class SwitchSummonPhase extends SummonPhase { + private slotIndex: integer; + private doReturn: boolean; + private batonPass: boolean; + + private lastPokemon: Pokemon; + + /** + * Constructor for creating a new SwitchSummonPhase + * @param scene {@linkcode BattleScene} the scene the phase is associated with + * @param fieldIndex integer representing position on the battle field + * @param slotIndex integer for the index of pokemon (in party of 6) to switch into + * @param doReturn boolean whether to render "comeback" dialogue + * @param batonPass boolean if the switch is from baton pass + * @param player boolean if the switch is from the player + */ + constructor(scene: BattleScene, fieldIndex: integer, slotIndex: integer, doReturn: boolean, batonPass: boolean, player?: boolean) { + super(scene, fieldIndex, player !== undefined ? player : true); + + this.slotIndex = slotIndex; + this.doReturn = doReturn; + this.batonPass = batonPass; + } + + start(): void { + super.start(); + } + + preSummon(): void { + if (!this.player) { + if (this.slotIndex === -1) { + //@ts-ignore + this.slotIndex = this.scene.currentBattle.trainer?.getNextSummonIndex(!this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); // TODO: what would be the default trainer-slot fallback? + } + if (this.slotIndex > -1) { + this.showEnemyTrainer(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); + this.scene.pbTrayEnemy.showPbTray(this.scene.getEnemyParty()); + } + } + + if (!this.doReturn || (this.slotIndex !== -1 && !(this.player ? this.scene.getParty() : this.scene.getEnemyParty())[this.slotIndex])) { + if (this.player) { + return this.switchAndSummon(); + } else { + this.scene.time.delayedCall(750, () => this.switchAndSummon()); + return; + } + } + + const pokemon = this.getPokemon(); + + if (!this.batonPass) { + (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id)); + } + + this.scene.ui.showText(this.player ? + i18next.t("battle:playerComeBack", { pokemonName: getPokemonNameWithAffix(pokemon) }) : + i18next.t("battle:trainerComeBack", { + trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), + pokemonName: getPokemonNameWithAffix(pokemon) + }) + ); + this.scene.playSound("pb_rel"); + pokemon.hideInfo(); + pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, "Sine.easeIn"); + this.scene.tweens.add({ + targets: pokemon, + duration: 250, + ease: "Sine.easeIn", + scale: 0.5, + onComplete: () => { + pokemon.leaveField(!this.batonPass, false); + this.scene.time.delayedCall(750, () => this.switchAndSummon()); + } + }); + } + + switchAndSummon() { + const party = this.player ? this.getParty() : this.scene.getEnemyParty(); + const switchedInPokemon = party[this.slotIndex]; + this.lastPokemon = this.getPokemon(); + applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); + if (this.batonPass && switchedInPokemon) { + (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedInPokemon.id)); + if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) { + const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier + && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier; + if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) { + this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false); + } + } + } + if (switchedInPokemon) { + party[this.slotIndex] = this.lastPokemon; + party[this.fieldIndex] = switchedInPokemon; + const showTextAndSummon = () => { + this.scene.ui.showText(this.player ? + i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(switchedInPokemon) }) : + i18next.t("battle:trainerGo", { + trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), + pokemonName: this.getPokemon().getNameToRender() + }) + ); + // Ensure improperly persisted summon data (such as tags) is cleared upon switching + if (!this.batonPass) { + switchedInPokemon.resetBattleData(); + switchedInPokemon.resetSummonData(); + } + this.summon(); + }; + if (this.player) { + showTextAndSummon(); + } else { + this.scene.time.delayedCall(1500, () => { + this.hideEnemyTrainer(); + this.scene.pbTrayEnemy.hide(); + showTextAndSummon(); + }); + } + } else { + this.end(); + } + } + + onEnd(): void { + super.onEnd(); + + const pokemon = this.getPokemon(); + + const moveId = this.lastPokemon?.scene.currentBattle.lastMove; + const lastUsedMove = moveId ? allMoves[moveId] : undefined; + + const currentCommand = pokemon.scene.currentBattle.turnCommands[this.fieldIndex]?.command; + const lastPokemonIsForceSwitchedAndNotFainted = lastUsedMove?.hasAttr(ForceSwitchOutAttr) && !this.lastPokemon.isFainted(); + + // Compensate for turn spent summoning + // Or compensate for force switch move if switched out pokemon is not fainted + if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted) { + pokemon.battleSummonData.turnCount--; + } + + if (this.batonPass && pokemon) { + pokemon.transferSummon(this.lastPokemon); + } + + this.lastPokemon?.resetSummonData(); + + this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); + } + + queuePostSummon(): void { + this.scene.unshiftPhase(new PostSummonPhase(this.scene, this.getPokemon().getBattlerIndex())); + } +} diff --git a/src/phases/test-message-phase.ts b/src/phases/test-message-phase.ts new file mode 100644 index 00000000000..14fed24ef4b --- /dev/null +++ b/src/phases/test-message-phase.ts @@ -0,0 +1,8 @@ +import BattleScene from "#app/battle-scene.js"; +import { MessagePhase } from "./message-phase"; + +export class TestMessagePhase extends MessagePhase { + constructor(scene: BattleScene, message: string) { + super(scene, message, null, true); + } +} diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts new file mode 100644 index 00000000000..c74dca97f5c --- /dev/null +++ b/src/phases/title-phase.ts @@ -0,0 +1,303 @@ +import { loggedInUser } from "#app/account.js"; +import BattleScene from "#app/battle-scene.js"; +import { BattleType } from "#app/battle.js"; +import { getDailyRunStarters, fetchDailyRunSeed } from "#app/data/daily-run.js"; +import { Gender } from "#app/data/gender.js"; +import { getBiomeKey } from "#app/field/arena.js"; +import { GameModes, GameMode, getGameMode } from "#app/game-mode.js"; +import { regenerateModifierPoolThresholds, ModifierPoolType, modifierTypes, getDailyRunStarterModifiers } from "#app/modifier/modifier-type.js"; +import { Phase } from "#app/phase.js"; +import { SessionSaveData } from "#app/system/game-data.js"; +import { Unlockables } from "#app/system/unlockables.js"; +import { vouchers } from "#app/system/voucher.js"; +import { OptionSelectItem, OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler.js"; +import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { Modifier } from "#app/modifier/modifier.js"; +import { CheckSwitchPhase } from "./check-switch-phase"; +import { EncounterPhase } from "./encounter-phase"; +import { SelectChallengePhase } from "./select-challenge-phase"; +import { SelectStarterPhase } from "./select-starter-phase"; +import { SummonPhase } from "./summon-phase"; + + +export class TitlePhase extends Phase { + private loaded: boolean; + private lastSessionData: SessionSaveData; + public gameMode: GameModes; + + constructor(scene: BattleScene) { + super(scene); + + this.loaded = false; + } + + start(): void { + super.start(); + + this.scene.ui.clearText(); + this.scene.ui.fadeIn(250); + + this.scene.playBgm("title", true); + + this.scene.gameData.getSession(loggedInUser?.lastSessionSlot ?? -1).then(sessionData => { + if (sessionData) { + this.lastSessionData = sessionData; + const biomeKey = getBiomeKey(sessionData.arena.biome); + const bgTexture = `${biomeKey}_bg`; + this.scene.arenaBg.setTexture(bgTexture); + } + this.showOptions(); + }).catch(err => { + console.error(err); + this.showOptions(); + }); + } + + showOptions(): void { + const options: OptionSelectItem[] = []; + if (loggedInUser && loggedInUser.lastSessionSlot > -1) { + options.push({ + label: i18next.t("continue", {ns: "menu"}), + handler: () => { + this.loadSaveSlot(this.lastSessionData || !loggedInUser ? -1 : loggedInUser.lastSessionSlot); + return true; + } + }); + } + options.push({ + label: i18next.t("menu:newGame"), + handler: () => { + const setModeAndEnd = (gameMode: GameModes) => { + this.gameMode = gameMode; + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + this.end(); + }; + if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + const options: OptionSelectItem[] = [ + { + label: GameMode.getModeName(GameModes.CLASSIC), + handler: () => { + setModeAndEnd(GameModes.CLASSIC); + return true; + } + }, + { + label: GameMode.getModeName(GameModes.CHALLENGE), + handler: () => { + setModeAndEnd(GameModes.CHALLENGE); + return true; + } + }, + { + label: GameMode.getModeName(GameModes.ENDLESS), + handler: () => { + setModeAndEnd(GameModes.ENDLESS); + return true; + } + } + ]; + if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { + options.push({ + label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), + handler: () => { + setModeAndEnd(GameModes.SPLICED_ENDLESS); + return true; + } + }); + } + options.push({ + label: i18next.t("menu:cancel"), + handler: () => { + this.scene.clearPhaseQueue(); + this.scene.pushPhase(new TitlePhase(this.scene)); + super.end(); + return true; + } + }); + this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options })); + } else { + this.gameMode = GameModes.CLASSIC; + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + this.end(); + } + return true; + } + }, + { + label: i18next.t("menu:loadGame"), + handler: () => { + this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD, + (slotId: integer) => { + if (slotId === -1) { + return this.showOptions(); + } + this.loadSaveSlot(slotId); + }); + return true; + } + }, + { + label: i18next.t("menu:dailyRun"), + handler: () => { + this.initDailyRun(); + return true; + }, + keepOpen: true + }, + { + label: i18next.t("menu:settings"), + handler: () => { + this.scene.ui.setOverlayMode(Mode.SETTINGS); + return true; + }, + keepOpen: true + }); + const config: OptionSelectConfig = { + options: options, + noCancel: true, + yOffset: 47 + }; + this.scene.ui.setMode(Mode.TITLE, config); + } + + loadSaveSlot(slotId: integer): void { + this.scene.sessionSlotId = slotId > -1 || !loggedInUser ? slotId : loggedInUser.lastSessionSlot; + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.resetModeChain(); + this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : undefined).then((success: boolean) => { + if (success) { + this.loaded = true; + this.scene.ui.showText(i18next.t("menu:sessionSuccess"), null, () => this.end()); + } else { + this.end(); + } + }).catch(err => { + console.error(err); + this.scene.ui.showText(i18next.t("menu:failedToLoadSession"), null); + }); + } + + initDailyRun(): void { + this.scene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: integer) => { + this.scene.clearPhaseQueue(); + if (slotId === -1) { + this.scene.pushPhase(new TitlePhase(this.scene)); + return super.end(); + } + this.scene.sessionSlotId = slotId; + + const generateDaily = (seed: string) => { + this.scene.gameMode = getGameMode(GameModes.DAILY); + + this.scene.setSeed(seed); + this.scene.resetSeed(1); + + this.scene.money = this.scene.gameMode.getStartingMoney(); + + const starters = getDailyRunStarters(this.scene, seed); + const startingLevel = this.scene.gameMode.getStartingLevel(); + + const party = this.scene.getParty(); + const loadPokemonAssets: Promise[] = []; + for (const starter of starters) { + const starterProps = this.scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr); + const starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); + const starterGender = starter.species.malePercent !== null + ? !starterProps.female ? Gender.MALE : Gender.FEMALE + : Gender.GENDERLESS; + const starterPokemon = this.scene.addPlayerPokemon(starter.species, startingLevel, starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, undefined, starter.nature); + starterPokemon.setVisible(false); + party.push(starterPokemon); + loadPokemonAssets.push(starterPokemon.loadAssets()); + } + + regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER); + + const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier()) + .concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier())) + .concat(getDailyRunStarterModifiers(party)) + .filter((m) => m !== null); + + for (const m of modifiers) { + this.scene.addModifier(m, true, false, false, true); + } + this.scene.updateModifiers(true, true); + + Promise.all(loadPokemonAssets).then(() => { + this.scene.time.delayedCall(500, () => this.scene.playBgm()); + this.scene.gameData.gameStats.dailyRunSessionsPlayed++; + this.scene.newArena(this.scene.gameMode.getStartingBiome(this.scene)); + this.scene.newBattle(); + this.scene.arena.init(); + this.scene.sessionPlayTime = 0; + this.scene.lastSavePlayTime = 0; + this.end(); + }); + }; + + // If Online, calls seed fetch from db to generate daily run. If Offline, generates a daily run based on current date. + if (!Utils.isLocal) { + fetchDailyRunSeed().then(seed => { + if (seed) { + generateDaily(seed); + } else { + throw new Error("Daily run seed is null!"); + } + }).catch(err => { + console.error("Failed to load daily run:\n", err); + }); + } else { + generateDaily(btoa(new Date().toISOString().substring(0, 10))); + } + }); + } + + end(): void { + if (!this.loaded && !this.scene.gameMode.isDaily) { + this.scene.arena.preloadBgm(); + this.scene.gameMode = getGameMode(this.gameMode); + if (this.gameMode === GameModes.CHALLENGE) { + this.scene.pushPhase(new SelectChallengePhase(this.scene)); + } else { + this.scene.pushPhase(new SelectStarterPhase(this.scene)); + } + this.scene.newArena(this.scene.gameMode.getStartingBiome(this.scene)); + } else { + this.scene.playBgm(); + } + + this.scene.pushPhase(new EncounterPhase(this.scene, this.loaded)); + + if (this.loaded) { + const availablePartyMembers = this.scene.getParty().filter(p => p.isAllowedInBattle()).length; + + this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true)); + if (this.scene.currentBattle.double && availablePartyMembers > 1) { + this.scene.pushPhase(new SummonPhase(this.scene, 1, true, true)); + } + + if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) { + const minPartySize = this.scene.currentBattle.double ? 2 : 1; + if (availablePartyMembers > minPartySize) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double)); + if (this.scene.currentBattle.double) { + this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double)); + } + } + } + } + + for (const achv of Object.keys(this.scene.gameData.achvUnlocks)) { + if (vouchers.hasOwnProperty(achv)) { + this.scene.validateVoucher(vouchers[achv]); + } + } + + super.end(); + } +} diff --git a/src/phases/toggle-double-position-phase.ts b/src/phases/toggle-double-position-phase.ts new file mode 100644 index 00000000000..fe3d0482483 --- /dev/null +++ b/src/phases/toggle-double-position-phase.ts @@ -0,0 +1,31 @@ +import BattleScene from "#app/battle-scene.js"; +import { FieldPosition } from "#app/field/pokemon.js"; +import { BattlePhase } from "./battle-phase"; + +export class ToggleDoublePositionPhase extends BattlePhase { + private double: boolean; + + constructor(scene: BattleScene, double: boolean) { + super(scene); + + this.double = double; + } + + start() { + super.start(); + + const playerPokemon = this.scene.getPlayerField().find(p => p.isActive(true)); + if (playerPokemon) { + playerPokemon.setFieldPosition(this.double && this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? FieldPosition.LEFT : FieldPosition.CENTER, 500).then(() => { + if (playerPokemon.getFieldIndex() === 1) { + const party = this.scene.getParty(); + party[1] = party[0]; + party[0] = playerPokemon; + } + this.end(); + }); + } else { + this.end(); + } + } +} diff --git a/src/phases/trainer-message-test-phase.ts b/src/phases/trainer-message-test-phase.ts new file mode 100644 index 00000000000..4ea451660c3 --- /dev/null +++ b/src/phases/trainer-message-test-phase.ts @@ -0,0 +1,41 @@ +import BattleScene from "#app/battle-scene.js"; +import { trainerConfigs } from "#app/data/trainer-config.js"; +import { TrainerType } from "#app/enums/trainer-type.js"; +import { BattlePhase } from "./battle-phase"; +import { TestMessagePhase } from "./test-message-phase"; + +export class TrainerMessageTestPhase extends BattlePhase { + private trainerTypes: TrainerType[]; + + constructor(scene: BattleScene, ...trainerTypes: TrainerType[]) { + super(scene); + + this.trainerTypes = trainerTypes; + } + + start() { + super.start(); + + const testMessages: string[] = []; + + for (const t of Object.keys(trainerConfigs)) { + const type = parseInt(t); + if (this.trainerTypes.length && !this.trainerTypes.find(tt => tt === type as TrainerType)) { + continue; + } + const config = trainerConfigs[type]; + [config.encounterMessages, config.femaleEncounterMessages, config.victoryMessages, config.femaleVictoryMessages, config.defeatMessages, config.femaleDefeatMessages] + .map(messages => { + if (messages?.length) { + testMessages.push(...messages); + } + }); + } + + for (const message of testMessages) { + this.scene.pushPhase(new TestMessagePhase(this.scene, message)); + } + + this.end(); + } +} diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts new file mode 100644 index 00000000000..7b8ee05de44 --- /dev/null +++ b/src/phases/trainer-victory-phase.ts @@ -0,0 +1,65 @@ +import BattleScene from "#app/battle-scene.js"; +import { getCharVariantFromDialogue } from "#app/data/dialogue.js"; +import { TrainerSlot } from "#app/data/trainer-config.js"; +import { TrainerType } from "#app/enums/trainer-type.js"; +import { modifierTypes } from "#app/modifier/modifier-type.js"; +import { vouchers } from "#app/system/voucher.js"; +import i18next from "i18next"; +import * as Utils from "#app/utils.js"; +import { BattlePhase } from "./battle-phase"; +import { ModifierRewardPhase } from "./modifier-reward-phase"; +import { MoneyRewardPhase } from "./money-reward-phase"; + +export class TrainerVictoryPhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + this.scene.disableMenu = true; + + this.scene.playBgm(this.scene.currentBattle.trainer?.config.victoryBgm); + + this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer?.config.moneyMultiplier!)); // TODO: is this bang correct? + + const modifierRewardFuncs = this.scene.currentBattle.trainer?.config.modifierRewardFuncs!; // TODO: is this bang correct? + for (const modifierRewardFunc of modifierRewardFuncs) { + this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, modifierRewardFunc)); + } + + const trainerType = this.scene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? + if (vouchers.hasOwnProperty(TrainerType[trainerType])) { + if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer?.config.isBoss) { + this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][vouchers[TrainerType[trainerType]].voucherType])); + } + } + + this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }), null, () => { + const victoryMessages = this.scene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct? + let message: string; + this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex); + message = message!; // tell TS compiler it's defined now + + const showMessage = () => { + const originalFunc = showMessageOrEnd; + showMessageOrEnd = () => this.scene.ui.showDialogue(message, this.scene.currentBattle.trainer?.getName(), null, originalFunc); + + showMessageOrEnd(); + }; + let showMessageOrEnd = () => this.end(); + if (victoryMessages?.length) { + if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { + const originalFunc = showMessageOrEnd; + showMessageOrEnd = () => this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => originalFunc())); + this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(this.scene.currentBattle.trainer?.getKey()!, getCharVariantFromDialogue(victoryMessages[0])).then(() => showMessage())); // TODO: is this bang correct? + } else { + showMessage(); + } + } else { + showMessageOrEnd(); + } + }, null, true); + + this.showEnemyTrainer(); + } +} diff --git a/src/phases/turn-end-phase.ts b/src/phases/turn-end-phase.ts new file mode 100644 index 00000000000..62589e99b79 --- /dev/null +++ b/src/phases/turn-end-phase.ts @@ -0,0 +1,71 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyPostTurnAbAttrs, PostTurnAbAttr } from "#app/data/ability.js"; +import { BattlerTagLapseType } from "#app/data/battler-tags.js"; +import { allMoves } from "#app/data/move.js"; +import { TerrainType } from "#app/data/terrain.js"; +import { Moves } from "#app/enums/moves.js"; +import { WeatherType } from "#app/enums/weather-type.js"; +import { TurnEndEvent } from "#app/events/battle-scene.js"; +import Pokemon from "#app/field/pokemon.js"; +import { getPokemonNameWithAffix } from "#app/messages.js"; +import { TurnHealModifier, EnemyTurnHealModifier, EnemyStatusEffectHealChanceModifier, TurnStatusEffectModifier, TurnHeldItemTransferModifier } from "#app/modifier/modifier.js"; +import i18next from "i18next"; +import { FieldPhase } from "./field-phase"; +import { MessagePhase } from "./message-phase"; +import { PokemonHealPhase } from "./pokemon-heal-phase"; + +export class TurnEndPhase extends FieldPhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.currentBattle.incrementTurn(this.scene); + this.scene.eventTarget.dispatchEvent(new TurnEndEvent(this.scene.currentBattle.turn)); + + const handlePokemon = (pokemon: Pokemon) => { + pokemon.lapseTags(BattlerTagLapseType.TURN_END); + + if (pokemon.summonData.disabledMove && !--pokemon.summonData.disabledTurns) { + this.scene.pushPhase(new MessagePhase(this.scene, i18next.t("battle:notDisabled", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: allMoves[pokemon.summonData.disabledMove].name }))); + pokemon.summonData.disabledMove = Moves.NONE; + } + + this.scene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon); + + if (this.scene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) { + this.scene.unshiftPhase(new PokemonHealPhase(this.scene, pokemon.getBattlerIndex(), + Math.max(pokemon.getMaxHp() >> 4, 1), i18next.t("battle:turnEndHpRestore", { pokemonName: getPokemonNameWithAffix(pokemon) }), true)); + } + + if (!pokemon.isPlayer()) { + this.scene.applyModifiers(EnemyTurnHealModifier, false, pokemon); + this.scene.applyModifier(EnemyStatusEffectHealChanceModifier, false, pokemon); + } + + applyPostTurnAbAttrs(PostTurnAbAttr, pokemon); + + this.scene.applyModifiers(TurnStatusEffectModifier, pokemon.isPlayer(), pokemon); + + this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon); + + pokemon.battleSummonData.turnCount++; + }; + + this.executeForAll(handlePokemon); + + this.scene.arena.lapseTags(); + + if (this.scene.arena.weather && !this.scene.arena.weather.lapse()) { + this.scene.arena.trySetWeather(WeatherType.NONE, false); + } + + if (this.scene.arena.terrain && !this.scene.arena.terrain.lapse()) { + this.scene.arena.trySetTerrain(TerrainType.NONE, false); + } + + this.end(); + } +} diff --git a/src/phases/turn-init-phase.ts b/src/phases/turn-init-phase.ts new file mode 100644 index 00000000000..a999d57ca0f --- /dev/null +++ b/src/phases/turn-init-phase.ts @@ -0,0 +1,65 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex } from "#app/battle.js"; +import { TurnInitEvent } from "#app/events/battle-scene.js"; +import { PlayerPokemon } from "#app/field/pokemon.js"; +import i18next from "i18next"; +import { FieldPhase } from "./field-phase"; +import { ToggleDoublePositionPhase } from "./toggle-double-position-phase"; +import { CommandPhase } from "./command-phase"; +import { EnemyCommandPhase } from "./enemy-command-phase"; +import { GameOverPhase } from "./game-over-phase"; +import { TurnStartPhase } from "./turn-start-phase"; + +export class TurnInitPhase extends FieldPhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + this.scene.getPlayerField().forEach(p => { + // If this pokemon is in play and evolved into something illegal under the current challenge, force a switch + if (p.isOnField() && !p.isAllowedInBattle()) { + this.scene.queueMessage(i18next.t("challenges:illegalEvolution", { "pokemon": p.name }), null, true); + + const allowedPokemon = this.scene.getParty().filter(p => p.isAllowedInBattle()); + + if (!allowedPokemon.length) { + // If there are no longer any legal pokemon in the party, game over. + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new GameOverPhase(this.scene)); + } else if (allowedPokemon.length >= this.scene.currentBattle.getBattlerCount() || (this.scene.currentBattle.double && !allowedPokemon[0].isActive(true))) { + // If there is at least one pokemon in the back that is legal to switch in, force a switch. + p.switchOut(false); + } else { + // If there are no pokemon in the back but we're not game overing, just hide the pokemon. + // This should only happen in double battles. + p.leaveField(); + } + if (allowedPokemon.length === 1 && this.scene.currentBattle.double) { + this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true)); + } + } + }); + + //this.scene.pushPhase(new MoveAnimTestPhase(this.scene)); + this.scene.eventTarget.dispatchEvent(new TurnInitEvent()); + + this.scene.getField().forEach((pokemon, i) => { + if (pokemon?.isActive()) { + if (pokemon.isPlayer()) { + this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon); + } + + pokemon.resetTurnData(); + + this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY)); + } + }); + + this.scene.pushPhase(new TurnStartPhase(this.scene)); + + this.end(); + } +} diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts new file mode 100644 index 00000000000..1320cb6235c --- /dev/null +++ b/src/phases/turn-start-phase.ts @@ -0,0 +1,172 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr, ChangeMovePriorityAbAttr } from "#app/data/ability.js"; +import { allMoves, applyMoveAttrs, IncrementMovePriorityAttr, MoveHeaderAttr } from "#app/data/move.js"; +import { Abilities } from "#app/enums/abilities.js"; +import { Stat } from "#app/enums/stat.js"; +import { PokemonMove } from "#app/field/pokemon.js"; +import { BypassSpeedChanceModifier } from "#app/modifier/modifier.js"; +import { Command } from "#app/ui/command-ui-handler.js"; +import * as Utils from "#app/utils.js"; +import { AttemptCapturePhase } from "./attempt-capture-phase"; +import { AttemptRunPhase } from "./attempt-run-phase"; +import { BerryPhase } from "./berry-phase"; +import { FieldPhase } from "./field-phase"; +import { MoveHeaderPhase } from "./move-header-phase"; +import { MovePhase } from "./move-phase"; +import { PostTurnStatusEffectPhase } from "./post-turn-status-effect-phase"; +import { SwitchSummonPhase } from "./switch-summon-phase"; +import { TurnEndPhase } from "./turn-end-phase"; +import { WeatherEffectPhase } from "./weather-effect-phase"; + +export class TurnStartPhase extends FieldPhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + const field = this.scene.getField(); + const order = this.getOrder(); + + const battlerBypassSpeed = {}; + + this.scene.getField(true).filter(p => p.summonData).map(p => { + const bypassSpeed = new Utils.BooleanHolder(false); + const canCheckHeldItems = new Utils.BooleanHolder(true); + applyAbAttrs(BypassSpeedChanceAbAttr, p, null, bypassSpeed); + applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, bypassSpeed, canCheckHeldItems); + if (canCheckHeldItems.value) { + this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); + } + battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed; + }); + + const moveOrder = order.slice(0); + + moveOrder.sort((a, b) => { + const aCommand = this.scene.currentBattle.turnCommands[a]; + const bCommand = this.scene.currentBattle.turnCommands[b]; + + if (aCommand?.command !== bCommand?.command) { + if (aCommand?.command === Command.FIGHT) { + return 1; + } else if (bCommand?.command === Command.FIGHT) { + return -1; + } + } else if (aCommand?.command === Command.FIGHT) { + const aMove = allMoves[aCommand.move!.move];//TODO: is the bang correct here? + const bMove = allMoves[bCommand!.move!.move];//TODO: is the bang correct here? + + const aPriority = new Utils.IntegerHolder(aMove.priority); + const bPriority = new Utils.IntegerHolder(bMove.priority); + + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? + + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? + + if (aPriority.value !== bPriority.value) { + const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value); + const hasSpeedDifference = battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value; + if (bracketDifference === 0 && hasSpeedDifference) { + return battlerBypassSpeed[a].value ? -1 : 1; + } + return aPriority.value < bPriority.value ? 1 : -1; + } + } + + if (battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) { + return battlerBypassSpeed[a].value ? -1 : 1; + } + + const aIndex = order.indexOf(a); + const bIndex = order.indexOf(b); + + return aIndex < bIndex ? -1 : aIndex > bIndex ? 1 : 0; + }); + + let orderIndex = 0; + + for (const o of moveOrder) { + + const pokemon = field[o]; + const turnCommand = this.scene.currentBattle.turnCommands[o]; + + if (turnCommand?.skip) { + continue; + } + + switch (turnCommand?.command) { + case Command.FIGHT: + const queuedMove = turnCommand.move; + pokemon.turnData.order = orderIndex++; + if (!queuedMove) { + continue; + } + const move = pokemon.getMoveset().find(m => m?.moveId === queuedMove.move) || new PokemonMove(queuedMove.move); + if (move.getMove().hasAttr(MoveHeaderAttr)) { + this.scene.unshiftPhase(new MoveHeaderPhase(this.scene, pokemon, move)); + } + if (pokemon.isPlayer()) { + if (turnCommand.cursor === -1) { + this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here? + } else { + const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP);//TODO: is the bang correct here? + this.scene.pushPhase(playerPhase); + } + } else { + this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP));//TODO: is the bang correct here? + } + break; + case Command.BALL: + this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here? + break; + case Command.POKEMON: + this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));//TODO: is the bang correct here? + break; + case Command.RUN: + let runningPokemon = pokemon; + if (this.scene.currentBattle.double) { + const playerActivePokemon = field.filter(pokemon => { + if (!!pokemon) { + return pokemon.isPlayer() && pokemon.isActive(); + } else { + return; + } + }); + // if only one pokemon is alive, use that one + if (playerActivePokemon.length > 1) { + // find which active pokemon has faster speed + const fasterPokemon = playerActivePokemon[0].getStat(Stat.SPD) > playerActivePokemon[1].getStat(Stat.SPD) ? playerActivePokemon[0] : playerActivePokemon[1]; + // check if either active pokemon has the ability "Run Away" + const hasRunAway = playerActivePokemon.find(p => p.hasAbility(Abilities.RUN_AWAY)); + runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon; + } + } + this.scene.unshiftPhase(new AttemptRunPhase(this.scene, runningPokemon.getFieldIndex())); + break; + } + } + + + this.scene.pushPhase(new WeatherEffectPhase(this.scene)); + + for (const o of order) { + if (field[o].status && field[o].status.isPostTurn()) { + this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, o)); + } + } + + this.scene.pushPhase(new BerryPhase(this.scene)); + this.scene.pushPhase(new TurnEndPhase(this.scene)); + + /** + * this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front + * of the queue and dequeues to start the next phase + * this is important since stuff like SwitchSummon, AttemptRun, AttemptCapture Phases break the "flow" and should take precedence + */ + this.end(); + } +} diff --git a/src/phases/unavailable-phase.ts b/src/phases/unavailable-phase.ts new file mode 100644 index 00000000000..4757af5e15d --- /dev/null +++ b/src/phases/unavailable-phase.ts @@ -0,0 +1,17 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Mode } from "#app/ui/ui.js"; +import { LoginPhase } from "./login-phase"; + +export class UnavailablePhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + this.scene.ui.setMode(Mode.UNAVAILABLE, () => { + this.scene.unshiftPhase(new LoginPhase(this.scene, true)); + this.end(); + }); + } +} diff --git a/src/phases/unlock-phase.ts b/src/phases/unlock-phase.ts new file mode 100644 index 00000000000..ce06e2445ac --- /dev/null +++ b/src/phases/unlock-phase.ts @@ -0,0 +1,27 @@ +import BattleScene from "#app/battle-scene.js"; +import { Phase } from "#app/phase.js"; +import { Unlockables, getUnlockableName } from "#app/system/unlockables.js"; +import { Mode } from "#app/ui/ui.js"; +import i18next from "i18next"; + +export class UnlockPhase extends Phase { + private unlockable: Unlockables; + + constructor(scene: BattleScene, unlockable: Unlockables) { + super(scene); + + this.unlockable = unlockable; + } + + start(): void { + this.scene.time.delayedCall(2000, () => { + this.scene.gameData.unlocks[this.unlockable] = true; + this.scene.playSound("level_up_fanfare"); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.showText(i18next.t("battle:unlockedSomething", { unlockedThing: getUnlockableName(this.unlockable) }), null, () => { + this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); + this.end(); + }, null, true, 1500); + }); + } +} diff --git a/src/phases/victory-phase.ts b/src/phases/victory-phase.ts new file mode 100644 index 00000000000..b7587de4dbb --- /dev/null +++ b/src/phases/victory-phase.ts @@ -0,0 +1,151 @@ +import BattleScene from "#app/battle-scene.js"; +import { BattlerIndex, BattleType } from "#app/battle.js"; +import { modifierTypes } from "#app/modifier/modifier-type.js"; +import { ExpShareModifier, ExpBalanceModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier } from "#app/modifier/modifier.js"; +import * as Utils from "#app/utils.js"; +import Overrides from "#app/overrides"; +import { BattleEndPhase } from "./battle-end-phase"; +import { NewBattlePhase } from "./new-battle-phase"; +import { PokemonPhase } from "./pokemon-phase"; +import { AddEnemyBuffModifierPhase } from "./add-enemy-buff-modifier-phase"; +import { EggLapsePhase } from "./egg-lapse-phase"; +import { ExpPhase } from "./exp-phase"; +import { GameOverPhase } from "./game-over-phase"; +import { ModifierRewardPhase } from "./modifier-reward-phase"; +import { SelectModifierPhase } from "./select-modifier-phase"; +import { ShowPartyExpBarPhase } from "./show-party-exp-bar-phase"; +import { TrainerVictoryPhase } from "./trainer-victory-phase"; + +export class VictoryPhase extends PokemonPhase { + constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + super(scene, battlerIndex); + } + + start() { + super.start(); + + this.scene.gameData.gameStats.pokemonDefeated++; + + const participantIds = this.scene.currentBattle.playerParticipantIds; + const party = this.scene.getParty(); + const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier; + const expBalanceModifier = this.scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier; + const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier; + const nonFaintedPartyMembers = party.filter(p => p.hp); + const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.scene.getMaxExpLevel()); + const partyMemberExp: number[] = []; + + if (participantIds.size) { + let expValue = this.getPokemon().getExpValue(); + if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + expValue = Math.floor(expValue * 1.5); + } + for (const partyMember of nonFaintedPartyMembers) { + const pId = partyMember.id; + const participated = participantIds.has(pId); + if (participated) { + partyMember.addFriendship(2); + } + if (!expPartyMembers.includes(partyMember)) { + continue; + } + if (!participated && !expShareModifier) { + partyMemberExp.push(0); + continue; + } + let expMultiplier = 0; + if (participated) { + expMultiplier += (1 / participantIds.size); + if (participantIds.size > 1 && multipleParticipantExpBonusModifier) { + expMultiplier += multipleParticipantExpBonusModifier.getStackCount() * 0.2; + } + } else if (expShareModifier) { + expMultiplier += (expShareModifier.getStackCount() * 0.2) / participantIds.size; + } + if (partyMember.pokerus) { + expMultiplier *= 1.5; + } + if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) { + expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; + } + const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); + this.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); + partyMemberExp.push(Math.floor(pokemonExp.value)); + } + + if (expBalanceModifier) { + let totalLevel = 0; + let totalExp = 0; + expPartyMembers.forEach((expPartyMember, epm) => { + totalExp += partyMemberExp[epm]; + totalLevel += expPartyMember.level; + }); + + const medianLevel = Math.floor(totalLevel / expPartyMembers.length); + + const recipientExpPartyMemberIndexes: number[] = []; + expPartyMembers.forEach((expPartyMember, epm) => { + if (expPartyMember.level <= medianLevel) { + recipientExpPartyMemberIndexes.push(epm); + } + }); + + const splitExp = Math.floor(totalExp / recipientExpPartyMemberIndexes.length); + + expPartyMembers.forEach((_partyMember, pm) => { + partyMemberExp[pm] = Phaser.Math.Linear(partyMemberExp[pm], recipientExpPartyMemberIndexes.indexOf(pm) > -1 ? splitExp : 0, 0.2 * expBalanceModifier.getStackCount()); + }); + } + + for (let pm = 0; pm < expPartyMembers.length; pm++) { + const exp = partyMemberExp[pm]; + + if (exp) { + const partyMemberIndex = party.indexOf(expPartyMembers[pm]); + this.scene.unshiftPhase(expPartyMembers[pm].isOnField() ? new ExpPhase(this.scene, partyMemberIndex, exp) : new ShowPartyExpBarPhase(this.scene, partyMemberIndex, exp)); + } + } + } + + if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType ? !p?.isFainted(true) : p.isOnField())) { + this.scene.pushPhase(new BattleEndPhase(this.scene)); + if (this.scene.currentBattle.battleType === BattleType.TRAINER) { + this.scene.pushPhase(new TrainerVictoryPhase(this.scene)); + } + if (this.scene.gameMode.isEndless || !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) { + this.scene.pushPhase(new EggLapsePhase(this.scene)); + if (this.scene.currentBattle.waveIndex % 10) { + this.scene.pushPhase(new SelectModifierPhase(this.scene)); + } else if (this.scene.gameMode.isDaily) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_CHARM)); + if (this.scene.currentBattle.waveIndex > 10 && !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); + } + } else { + const superExpWave = !this.scene.gameMode.isEndless ? (this.scene.offsetGym ? 0 : 20) : 10; + if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex === 10) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_SHARE)); + } + if (this.scene.currentBattle.waveIndex <= 750 && (this.scene.currentBattle.waveIndex <= 500 || (this.scene.currentBattle.waveIndex % 30) === superExpWave)) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, (this.scene.currentBattle.waveIndex % 30) !== superExpWave || this.scene.currentBattle.waveIndex > 250 ? modifierTypes.EXP_CHARM : modifierTypes.SUPER_EXP_CHARM)); + } + if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50)) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); + } + if (this.scene.gameMode.isEndless && !(this.scene.currentBattle.waveIndex % 50)) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, !(this.scene.currentBattle.waveIndex % 250) ? modifierTypes.VOUCHER_PREMIUM : modifierTypes.VOUCHER_PLUS)); + this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene)); + } + } + this.scene.pushPhase(new NewBattlePhase(this.scene)); + } else { + this.scene.currentBattle.battleType = BattleType.CLEAR; + this.scene.score += this.scene.gameMode.getClearScoreBonus(); + this.scene.updateScoreText(); + this.scene.pushPhase(new GameOverPhase(this.scene, true)); + } + } + + this.end(); + } +} diff --git a/src/phases/weather-effect-phase.ts b/src/phases/weather-effect-phase.ts new file mode 100644 index 00000000000..6f5fbc0fce3 --- /dev/null +++ b/src/phases/weather-effect-phase.ts @@ -0,0 +1,67 @@ +import BattleScene from "#app/battle-scene.js"; +import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability.js"; +import { CommonAnim } from "#app/data/battle-anims.js"; +import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather.js"; +import { WeatherType } from "#app/enums/weather-type.js"; +import Pokemon, { HitResult } from "#app/field/pokemon.js"; +import * as Utils from "#app/utils.js"; +import { CommonAnimPhase } from "./common-anim-phase"; + +export class WeatherEffectPhase extends CommonAnimPhase { + public weather: Weather | null; + + constructor(scene: BattleScene) { + super(scene, undefined, undefined, CommonAnim.SUNNY + ((scene?.arena?.weather?.weatherType || WeatherType.NONE) - 1)); + this.weather = scene?.arena?.weather; + } + + start() { + // Update weather state with any changes that occurred during the turn + this.weather = this.scene?.arena?.weather; + + if (!this.weather) { + this.end(); + return; + } + + this.setAnimation(CommonAnim.SUNNY + (this.weather.weatherType - 1)); + + if (this.weather.isDamaging()) { + + const cancelled = new Utils.BooleanHolder(false); + + this.executeForAll((pokemon: Pokemon) => applyPreWeatherEffectAbAttrs(SuppressWeatherEffectAbAttr, pokemon, this.weather, cancelled)); + + if (!cancelled.value) { + const inflictDamage = (pokemon: Pokemon) => { + const cancelled = new Utils.BooleanHolder(false); + + applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather , cancelled); + applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + + if (cancelled.value) { + return; + } + + const damage = Math.ceil(pokemon.getMaxHp() / 16); + + this.scene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct? + pokemon.damageAndUpdate(damage, HitResult.EFFECTIVE, false, false, true); + }; + + this.executeForAll((pokemon: Pokemon) => { + const immune = !pokemon || !!pokemon.getTypes(true, true).filter(t => this.weather?.isTypeDamageImmune(t)).length; + if (!immune) { + inflictDamage(pokemon); + } + }); + } + } + + this.scene.ui.showText(getWeatherLapseMessage(this.weather.weatherType)!, null, () => { // TODO: is this bang correct? + this.executeForAll((pokemon: Pokemon) => applyPostWeatherLapseAbAttrs(PostWeatherLapseAbAttr, pokemon, this.weather)); + + super.start(); + }); + } +} diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 40f24fc8326..a9acd80fdee 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -27,7 +27,6 @@ import { Tutorial } from "../tutorial"; import { speciesEggMoves } from "../data/egg-moves"; import { allMoves } from "../data/move"; import { TrainerVariant } from "../field/trainer"; -import { OutdatedPhase, ReloadSessionPhase } from "#app/phases"; import { Variant, variantData } from "#app/data/variant"; import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad"; import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard"; @@ -43,6 +42,8 @@ import { Species } from "#enums/species"; import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import { WeatherType } from "#app/enums/weather-type.js"; import { TerrainType } from "#app/data/terrain.js"; +import { OutdatedPhase } from "#app/phases/outdated-phase.js"; +import { ReloadSessionPhase } from "#app/phases/reload-session-phase.js"; export const defaultStarterSpecies: Species[] = [ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 4d8097897e9..7263ae3a3de 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -8,13 +8,21 @@ import SettingsUiHandler from "#app/ui/settings/settings-ui-handler"; import { EaseType } from "#enums/ease-type"; import { MoneyFormat } from "#enums/money-format"; import { PlayerGender } from "#enums/player-gender"; +import { getIsInitialized, initI18n } from "#app/plugins/i18n.js"; + +function getTranslation(key: string): string { + if (!getIsInitialized()) { + initI18n(); + } + return i18next.t(key); +} const VOLUME_OPTIONS: SettingOption[] = new Array(11).fill(null).map((_, i) => i ? { value: (i * 10).toString(), label: (i * 10).toString(), } : { value: "Mute", - label: i18next.t("settings:mute") + label: getTranslation("settings:mute") }); const SHOP_OVERLAY_OPACITY_OPTIONS: SettingOption[] = new Array(9).fill(null).map((_, i) => { const value = ((i + 1) * 10).toString(); diff --git a/src/system/voucher.ts b/src/system/voucher.ts index 0c71e3c0286..2f94308d9c8 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -1,9 +1,10 @@ import BattleScene from "../battle-scene"; import i18next from "i18next"; -import { Achv, AchvTier, achvs, getAchievementDescription } from "./achv"; +import { AchvTier, achvs, getAchievementDescription } from "./achv"; import { PlayerGender } from "#enums/player-gender"; import { TrainerType } from "#enums/trainer-type"; import { ConditionFn } from "#app/@types/common.js"; +import { trainerConfigs } from "#app/data/trainer-config.js"; export enum VoucherType { REGULAR, @@ -88,42 +89,36 @@ export interface Vouchers { export const vouchers: Vouchers = {}; -const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ]; - export function initVouchers() { - import("../data/trainer-config").then(tc => { - const trainerConfigs = tc.trainerConfigs; + for (const achv of [achvs.CLASSIC_VICTORY]) { + const voucherType = achv.score >= 150 + ? VoucherType.GOLDEN + : achv.score >= 100 + ? VoucherType.PREMIUM + : achv.score >= 75 + ? VoucherType.PLUS + : VoucherType.REGULAR; + vouchers[achv.id] = new Voucher(voucherType, getAchievementDescription(achv.localizationKey)); + } - for (const achv of voucherAchvs) { - const voucherType = achv.score >= 150 - ? VoucherType.GOLDEN - : achv.score >= 100 - ? VoucherType.PREMIUM - : achv.score >= 75 - ? VoucherType.PLUS - : VoucherType.REGULAR; - vouchers[achv.id] = new Voucher(voucherType, getAchievementDescription(achv.localizationKey)); - } + const bossTrainerTypes = Object.keys(trainerConfigs) + .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL && trainerConfigs[tt].hasVoucher); - const bossTrainerTypes = Object.keys(trainerConfigs) - .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL && trainerConfigs[tt].hasVoucher); - - for (const trainerType of bossTrainerTypes) { - const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 - ? VoucherType.PLUS - : VoucherType.PREMIUM; - const key = TrainerType[trainerType]; - const trainerName = trainerConfigs[trainerType].name; - const trainer = trainerConfigs[trainerType]; - const title = trainer.title ? ` (${trainer.title})` : ""; - vouchers[key] = new Voucher( - voucherType, - `${i18next.t("voucher:defeatTrainer", { trainerName })} ${title}`, - ); - } - const voucherKeys = Object.keys(vouchers); - for (const k of voucherKeys) { - vouchers[k].id = k; - } - }); + for (const trainerType of bossTrainerTypes) { + const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 + ? VoucherType.PLUS + : VoucherType.PREMIUM; + const key = TrainerType[trainerType]; + const trainerName = trainerConfigs[trainerType].name; + const trainer = trainerConfigs[trainerType]; + const title = trainer.title ? ` (${trainer.title})` : ""; + vouchers[key] = new Voucher( + voucherType, + `${i18next.t("voucher:defeatTrainer", { trainerName })} ${title}`, + ); + } + const voucherKeys = Object.keys(vouchers); + for (const k of voucherKeys) { + vouchers[k].id = k; + } } diff --git a/src/test/abilities/ability_timing.test.ts b/src/test/abilities/ability_timing.test.ts index 3906233a7bf..c117c62d45b 100644 --- a/src/test/abilities/ability_timing.test.ts +++ b/src/test/abilities/ability_timing.test.ts @@ -1,4 +1,3 @@ -import { CommandPhase, MessagePhase, TurnInitPhase } from "#app/phases"; import i18next, { initI18n } from "#app/plugins/i18n"; import GameManager from "#test/utils/gameManager"; import { Mode } from "#app/ui/ui"; @@ -8,6 +7,9 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Ability Timing", () => { diff --git a/src/test/abilities/aura_break.test.ts b/src/test/abilities/aura_break.test.ts index a34475cb1ad..bca400bc0e3 100644 --- a/src/test/abilities/aura_break.test.ts +++ b/src/test/abilities/aura_break.test.ts @@ -1,5 +1,4 @@ import { allMoves } from "#app/data/move.js"; -import { MoveEffectPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -8,6 +7,7 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Aura Break", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/battery.test.ts b/src/test/abilities/battery.test.ts index 2345e63d987..766c1c30ecc 100644 --- a/src/test/abilities/battery.test.ts +++ b/src/test/abilities/battery.test.ts @@ -1,6 +1,5 @@ import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -8,6 +7,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Battery", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/battle_bond.test.ts b/src/test/abilities/battle_bond.test.ts index 1a5c71b4c15..c28a00e821d 100644 --- a/src/test/abilities/battle_bond.test.ts +++ b/src/test/abilities/battle_bond.test.ts @@ -1,6 +1,6 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/abilities/costar.test.ts b/src/test/abilities/costar.test.ts index ef3fb3a2ab0..9410ee55069 100644 --- a/src/test/abilities/costar.test.ts +++ b/src/test/abilities/costar.test.ts @@ -2,12 +2,13 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { Abilities } from "#app/enums/abilities.js"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; -import { CommandPhase, MessagePhase } from "#app/phases.js"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index 8b1b959bea8..969375c397e 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -4,10 +4,14 @@ import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { StatusEffect } from "#app/data/status-effect.js"; -import { CommandPhase, MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { SPLASH_ONLY } from "../utils/testUtils"; import { Mode } from "#app/ui/ui.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/dry_skin.test.ts b/src/test/abilities/dry_skin.test.ts index 20b85eab767..1e3860da985 100644 --- a/src/test/abilities/dry_skin.test.ts +++ b/src/test/abilities/dry_skin.test.ts @@ -1,5 +1,4 @@ import { Species } from "#app/enums/species.js"; -import { TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,7 @@ import { Moves } from "#enums/moves"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Dry Skin", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/flash_fire.test.ts b/src/test/abilities/flash_fire.test.ts index b77b271b754..28c59903b68 100644 --- a/src/test/abilities/flash_fire.test.ts +++ b/src/test/abilities/flash_fire.test.ts @@ -5,11 +5,12 @@ import { Moves } from "#enums/moves"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MovePhase, TurnEndPhase } from "#app/phases"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { StatusEffect } from "#app/data/status-effect.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { BattlerIndex } from "#app/battle.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Flash Fire", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts index 52ae323839d..d033604fe00 100644 --- a/src/test/abilities/gulp_missile.test.ts +++ b/src/test/abilities/gulp_missile.test.ts @@ -1,10 +1,4 @@ import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { - BerryPhase, - MoveEndPhase, - TurnEndPhase, - TurnStartPhase, -} from "#app/phases"; import GameManager from "#app/test/utils/gameManager"; import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -16,6 +10,10 @@ import { SPLASH_ONLY } from "../utils/testUtils"; import { BattleStat } from "#app/data/battle-stat.js"; import { StatusEffect } from "#app/enums/status-effect.js"; import Pokemon from "#app/field/pokemon.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Abilities - Gulp Missile", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/heatproof.test.ts b/src/test/abilities/heatproof.test.ts index 8249ba6996f..64a45c5023f 100644 --- a/src/test/abilities/heatproof.test.ts +++ b/src/test/abilities/heatproof.test.ts @@ -1,5 +1,5 @@ import { Species } from "#app/enums/species.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index dde310fda2a..8f5547a5518 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -1,7 +1,6 @@ import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; import { Stat } from "#app/enums/stat.js"; -import { DamagePhase, MoveEffectPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -9,6 +8,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Hustle", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/ice_face.test.ts b/src/test/abilities/ice_face.test.ts index cdf8d5928ee..905e0dfdaf7 100644 --- a/src/test/abilities/ice_face.test.ts +++ b/src/test/abilities/ice_face.test.ts @@ -1,5 +1,3 @@ -import { QuietFormChangePhase } from "#app/form-change-phase"; -import { MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -8,6 +6,11 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Abilities - Ice Face", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts index 2b4c1041bfe..842b33108a3 100644 --- a/src/test/abilities/intimidate.test.ts +++ b/src/test/abilities/intimidate.test.ts @@ -7,11 +7,16 @@ import { generateStarter, getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; import { Status, StatusEffect } from "#app/data/status-effect"; import { GameModes, getGameMode } from "#app/game-mode"; -import { CommandPhase, DamagePhase, EncounterPhase, EnemyCommandPhase, SelectStarterPhase, TurnInitPhase } from "#app/phases"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Abilities - Intimidate", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/intrepid_sword.test.ts b/src/test/abilities/intrepid_sword.test.ts index dcc91421165..c1c05b59997 100644 --- a/src/test/abilities/intrepid_sword.test.ts +++ b/src/test/abilities/intrepid_sword.test.ts @@ -1,10 +1,10 @@ import { BattleStat } from "#app/data/battle-stat"; -import { CommandPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; describe("Abilities - Intrepid Sword", () => { diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index 2581eac068d..d35cb8b6e2d 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -2,7 +2,6 @@ import { allMoves } from "#app/data/move.js"; import { Type } from "#app/data/type.js"; import { Weather, WeatherType } from "#app/data/weather.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; @@ -13,6 +12,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vi import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index c86d65ca453..c7404f83a54 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -2,7 +2,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Moves } from "#enums/moves"; import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag"; diff --git a/src/test/abilities/moxie.test.ts b/src/test/abilities/moxie.test.ts index f99068dea41..6550dcab526 100644 --- a/src/test/abilities/moxie.test.ts +++ b/src/test/abilities/moxie.test.ts @@ -1,6 +1,5 @@ import { BattleStat } from "#app/data/battle-stat"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, EnemyCommandPhase, VictoryPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -10,6 +9,9 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { VictoryPhase } from "#app/phases/victory-phase.js"; describe("Abilities - Moxie", () => { diff --git a/src/test/abilities/mycelium_might.test.ts b/src/test/abilities/mycelium_might.test.ts index d519eb67626..2fcdc28b279 100644 --- a/src/test/abilities/mycelium_might.test.ts +++ b/src/test/abilities/mycelium_might.test.ts @@ -1,4 +1,5 @@ -import { MovePhase, TurnEndPhase } from "#app/phases"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 182f780763c..ef0ad7785d2 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -2,7 +2,6 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { StatusEffect } from "#app/data/status-effect.js"; import { Type } from "#app/data/type.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BerryPhase, CommandPhase, DamagePhase, MoveEffectPhase, MoveEndPhase, TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -11,6 +10,12 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts index e3d52a720b3..cb6be666d5f 100644 --- a/src/test/abilities/pastel_veil.test.ts +++ b/src/test/abilities/pastel_veil.test.ts @@ -2,13 +2,14 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { CommandPhase, TurnEndPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { StatusEffect } from "#app/data/status-effect.js"; import { allAbilities } from "#app/data/ability.js"; import { Abilities } from "#app/enums/abilities.js"; import { BattlerIndex } from "#app/battle.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Pastel Veil", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/power_construct.test.ts b/src/test/abilities/power_construct.test.ts index dd8fd836e51..e6a319d229f 100644 --- a/src/test/abilities/power_construct.test.ts +++ b/src/test/abilities/power_construct.test.ts @@ -1,6 +1,6 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/abilities/power_spot.test.ts b/src/test/abilities/power_spot.test.ts index 368f8a48110..467fc677ac0 100644 --- a/src/test/abilities/power_spot.test.ts +++ b/src/test/abilities/power_spot.test.ts @@ -1,6 +1,5 @@ import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -8,6 +7,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Power Spot", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index 78768ce32db..ed63613945a 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -2,7 +2,6 @@ import { allMoves } from "#app/data/move.js"; import { Type } from "#app/data/type.js"; import { Weather, WeatherType } from "#app/data/weather.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; @@ -13,6 +12,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vi import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/quick_draw.test.ts b/src/test/abilities/quick_draw.test.ts index 75bb9ec6a0a..6e3416b0724 100644 --- a/src/test/abilities/quick_draw.test.ts +++ b/src/test/abilities/quick_draw.test.ts @@ -1,5 +1,4 @@ import { allAbilities, BypassSpeedChanceAbAttr } from "#app/data/ability"; -import { FaintPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import { FaintPhase } from "#app/phases/faint-phase.js"; describe("Abilities - Quick Draw", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/sand_veil.test.ts b/src/test/abilities/sand_veil.test.ts index 6aab362634a..010878db68d 100644 --- a/src/test/abilities/sand_veil.test.ts +++ b/src/test/abilities/sand_veil.test.ts @@ -1,7 +1,6 @@ import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { WeatherType } from "#app/data/weather.js"; -import { CommandPhase, MoveEffectPhase, MoveEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -9,6 +8,9 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/sap_sipper.test.ts b/src/test/abilities/sap_sipper.test.ts index 6fbe57978e9..dfb4ab7e976 100644 --- a/src/test/abilities/sap_sipper.test.ts +++ b/src/test/abilities/sap_sipper.test.ts @@ -1,6 +1,5 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { TerrainType } from "#app/data/terrain.js"; -import { MoveEndPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -9,6 +8,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; // See also: TypeImmunityAbAttr describe("Abilities - Sap Sipper", () => { diff --git a/src/test/abilities/schooling.test.ts b/src/test/abilities/schooling.test.ts index e55b7795006..62a7e98bc76 100644 --- a/src/test/abilities/schooling.test.ts +++ b/src/test/abilities/schooling.test.ts @@ -1,6 +1,6 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/abilities/screen_cleaner.test.ts b/src/test/abilities/screen_cleaner.test.ts index a73f56dd3eb..403efcce1c0 100644 --- a/src/test/abilities/screen_cleaner.test.ts +++ b/src/test/abilities/screen_cleaner.test.ts @@ -1,5 +1,4 @@ import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import { PostSummonPhase, TurnEndPhase, } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Screen Cleaner", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index d46587e45c7..5e4841f005a 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -1,6 +1,5 @@ import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, MoveEffectPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -12,6 +11,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { BattlerIndex } from "#app/battle.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Serene Grace", () => { diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 50a0f0b63fb..33b34124cc4 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -1,6 +1,7 @@ import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, MoveEffectPhase } from "#app/phases"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index f1534551e92..b40689a180a 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -1,6 +1,7 @@ import { applyAbAttrs, applyPreDefendAbAttrs, IgnoreMoveEffectsAbAttr, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, MoveEffectPhase } from "#app/phases"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; diff --git a/src/test/abilities/shields_down.test.ts b/src/test/abilities/shields_down.test.ts index 4d85e8aa47c..e07c12ebb63 100644 --- a/src/test/abilities/shields_down.test.ts +++ b/src/test/abilities/shields_down.test.ts @@ -1,6 +1,6 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/abilities/stall.test.ts b/src/test/abilities/stall.test.ts index 44519064300..5410d2e953e 100644 --- a/src/test/abilities/stall.test.ts +++ b/src/test/abilities/stall.test.ts @@ -1,4 +1,3 @@ -import { MovePhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -6,6 +5,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { MovePhase } from "#app/phases/move-phase.js"; describe("Abilities - Stall", () => { diff --git a/src/test/abilities/steely_spirit.test.ts b/src/test/abilities/steely_spirit.test.ts index 5d5514bc3a1..3ca1a55ebee 100644 --- a/src/test/abilities/steely_spirit.test.ts +++ b/src/test/abilities/steely_spirit.test.ts @@ -1,7 +1,6 @@ import { allAbilities } from "#app/data/ability.js"; import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; -import { MoveEffectPhase, SelectTargetPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -9,6 +8,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; describe("Abilities - Steely Spirit", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/sturdy.test.ts b/src/test/abilities/sturdy.test.ts index 4caa7b0bd14..602b2c04eb1 100644 --- a/src/test/abilities/sturdy.test.ts +++ b/src/test/abilities/sturdy.test.ts @@ -1,5 +1,4 @@ import { EnemyPokemon } from "#app/field/pokemon.js"; -import { DamagePhase, MoveEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts index d650455664f..8ab384ae59e 100644 --- a/src/test/abilities/sweet_veil.test.ts +++ b/src/test/abilities/sweet_veil.test.ts @@ -2,13 +2,15 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { CommandPhase, MovePhase, TurnEndPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Abilities } from "#app/enums/abilities.js"; import { BattlerIndex } from "#app/battle.js"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Sweet Veil", () => { let phaserGame: Phaser.Game; diff --git a/src/test/abilities/unseen_fist.test.ts b/src/test/abilities/unseen_fist.test.ts index a6cad8b03ce..7d47d73bb16 100644 --- a/src/test/abilities/unseen_fist.test.ts +++ b/src/test/abilities/unseen_fist.test.ts @@ -1,4 +1,3 @@ -import { TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -6,6 +5,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/volt_absorb.test.ts b/src/test/abilities/volt_absorb.test.ts index 985459e133b..0e3d5c9792f 100644 --- a/src/test/abilities/volt_absorb.test.ts +++ b/src/test/abilities/volt_absorb.test.ts @@ -1,5 +1,5 @@ import { BattleStat } from "#app/data/battle-stat.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/wind_power.test.ts b/src/test/abilities/wind_power.test.ts index 670544a89ef..24f01cceebc 100644 --- a/src/test/abilities/wind_power.test.ts +++ b/src/test/abilities/wind_power.test.ts @@ -1,5 +1,5 @@ import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/wind_rider.test.ts b/src/test/abilities/wind_rider.test.ts index e27349efe41..92c38507e4f 100644 --- a/src/test/abilities/wind_rider.test.ts +++ b/src/test/abilities/wind_rider.test.ts @@ -1,5 +1,5 @@ import { BattleStat } from "#app/data/battle-stat.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/wonder_skin.test.ts b/src/test/abilities/wonder_skin.test.ts index a2815152df6..d6e2b2443c4 100644 --- a/src/test/abilities/wonder_skin.test.ts +++ b/src/test/abilities/wonder_skin.test.ts @@ -1,6 +1,6 @@ import { allAbilities } from "#app/data/ability.js"; import { allMoves } from "#app/data/move.js"; -import { MoveEffectPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 1bc7a6af4ce..72fdc5442c5 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -1,7 +1,5 @@ import { Stat } from "#app/data/pokemon-stat"; import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase"; -import { CommandPhase, DamagePhase, EnemyCommandPhase, MessagePhase, PostSummonPhase, SwitchPhase, SwitchSummonPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -12,6 +10,17 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { BattlerIndex } from "#app/battle.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { SwitchPhase } from "#app/phases/switch-phase.js"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/abilities/zero_to_hero.test.ts b/src/test/abilities/zero_to_hero.test.ts index 7924b30eb76..ee6c07096a8 100644 --- a/src/test/abilities/zero_to_hero.test.ts +++ b/src/test/abilities/zero_to_hero.test.ts @@ -1,6 +1,6 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/form-change-phase.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/arena/arena_gravity.test.ts b/src/test/arena/arena_gravity.test.ts index 66d6994fb80..68c31258454 100644 --- a/src/test/arena/arena_gravity.test.ts +++ b/src/test/arena/arena_gravity.test.ts @@ -1,13 +1,14 @@ import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Arena - Gravity", () => { let phaserGame: Phaser.Game; diff --git a/src/test/arena/weather_fog.test.ts b/src/test/arena/weather_fog.test.ts index e5718b73a3c..350007ae943 100644 --- a/src/test/arena/weather_fog.test.ts +++ b/src/test/arena/weather_fog.test.ts @@ -1,7 +1,7 @@ import { allMoves } from "#app/data/move.js"; import { WeatherType } from "#app/data/weather.js"; import { Abilities } from "#app/enums/abilities.js"; -import { MoveEffectPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; diff --git a/src/test/arena/weather_strong_winds.test.ts b/src/test/arena/weather_strong_winds.test.ts index d9f626cfb83..79fba30c019 100644 --- a/src/test/arena/weather_strong_winds.test.ts +++ b/src/test/arena/weather_strong_winds.test.ts @@ -1,5 +1,4 @@ import { allMoves } from "#app/data/move.js"; -import { TurnStartPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Weather - Strong Winds", () => { let phaserGame: Phaser.Game; diff --git a/src/test/battle/battle-order.test.ts b/src/test/battle/battle-order.test.ts index 6aa919186b4..208b921b843 100644 --- a/src/test/battle/battle-order.test.ts +++ b/src/test/battle/battle-order.test.ts @@ -1,5 +1,4 @@ import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, EnemyCommandPhase, SelectTargetPhase, TurnStartPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -11,6 +10,10 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Battle order", () => { diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index a4713f90506..43d8ddce4b0 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -2,21 +2,6 @@ import { allSpecies } from "#app/data/pokemon-species"; import { TempBattleStat } from "#app/data/temp-battle-stat.js"; import { GameModes } from "#app/game-mode"; import { getGameMode } from "#app/game-mode.js"; -import { - BattleEndPhase, - CommandPhase, DamagePhase, - EncounterPhase, - EnemyCommandPhase, - LoginPhase, - NextEncounterPhase, - SelectGenderPhase, - SelectModifierPhase, - SelectStarterPhase, - SummonPhase, - SwitchPhase, - TitlePhase, - TurnInitPhase, VictoryPhase, -} from "#app/phases"; import GameManager from "#app/test/utils/gameManager"; import { generateStarter, getMovePosition, } from "#app/test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -28,6 +13,21 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { LoginPhase } from "#app/phases/login-phase.js"; +import { NextEncounterPhase } from "#app/phases/next-encounter-phase.js"; +import { SelectGenderPhase } from "#app/phases/select-gender-phase.js"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { SummonPhase } from "#app/phases/summon-phase.js"; +import { SwitchPhase } from "#app/phases/switch-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { VictoryPhase } from "#app/phases/victory-phase.js"; describe("Test Battle Phase", () => { let phaserGame: Phaser.Game; diff --git a/src/test/battle/double_battle.test.ts b/src/test/battle/double_battle.test.ts index 76b7defe33d..d2ee3812b3e 100644 --- a/src/test/battle/double_battle.test.ts +++ b/src/test/battle/double_battle.test.ts @@ -1,4 +1,3 @@ -import { BattleEndPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition, } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -7,6 +6,8 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; import { Status, StatusEffect } from "#app/data/status-effect.js"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Double Battles", () => { let phaserGame: Phaser.Game; diff --git a/src/test/battle/special_battle.test.ts b/src/test/battle/special_battle.test.ts index 6130df703f5..9b0fd1b3ab1 100644 --- a/src/test/battle/special_battle.test.ts +++ b/src/test/battle/special_battle.test.ts @@ -1,4 +1,4 @@ -import { CommandPhase } from "#app/phases"; +import { CommandPhase } from "#app/phases/command-phase.js"; import GameManager from "#test/utils/gameManager"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/battlerTags/octolock.test.ts b/src/test/battlerTags/octolock.test.ts index 369a84e21fa..a69b45cdfd2 100644 --- a/src/test/battlerTags/octolock.test.ts +++ b/src/test/battlerTags/octolock.test.ts @@ -2,9 +2,9 @@ import { describe, expect, it, vi } from "vitest"; import Pokemon from "#app/field/pokemon.js"; import BattleScene from "#app/battle-scene.js"; import { BattlerTag, BattlerTagLapseType, OctolockTag, TrappedTag } from "#app/data/battler-tags.js"; -import { StatChangePhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; vi.mock("#app/battle-scene.js"); diff --git a/src/test/battlerTags/stockpiling.test.ts b/src/test/battlerTags/stockpiling.test.ts index 005f1e1593c..1a39d11e1bd 100644 --- a/src/test/battlerTags/stockpiling.test.ts +++ b/src/test/battlerTags/stockpiling.test.ts @@ -2,9 +2,9 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import Pokemon, { PokemonSummonData } from "#app/field/pokemon.js"; import BattleScene from "#app/battle-scene.js"; import { StockpilingTag } from "#app/data/battler-tags.js"; -import { StatChangePhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import * as messages from "#app/messages.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; beforeEach(() => { vi.spyOn(messages, "getPokemonNameWithAffix").mockImplementation(() => ""); diff --git a/src/test/items/grip_claw.test.ts b/src/test/items/grip_claw.test.ts index 40ef81fed73..ecf144c96c5 100644 --- a/src/test/items/grip_claw.test.ts +++ b/src/test/items/grip_claw.test.ts @@ -4,11 +4,13 @@ import { Abilities } from "#app/enums/abilities.js"; import { BerryType } from "#app/enums/berry-type.js"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; -import { CommandPhase, MoveEndPhase, SelectTargetPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; const TIMEOUT = 20 * 1000; // 20 seconds diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 4abc470c6f0..1e46bda9f0f 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Moves } from "#enums/moves"; diff --git a/src/test/items/leftovers.test.ts b/src/test/items/leftovers.test.ts index e791c4426a1..1a1c95ad9e6 100644 --- a/src/test/items/leftovers.test.ts +++ b/src/test/items/leftovers.test.ts @@ -1,4 +1,3 @@ -import { DamagePhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -6,6 +5,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Items - Leftovers", () => { diff --git a/src/test/items/lock_capsule.test.ts b/src/test/items/lock_capsule.test.ts index 32103a6d780..0909e51ea2c 100644 --- a/src/test/items/lock_capsule.test.ts +++ b/src/test/items/lock_capsule.test.ts @@ -4,8 +4,8 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { Abilities } from "#app/enums/abilities.js"; import { Moves } from "#app/enums/moves.js"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { SelectModifierPhase } from "#app/phases.js"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; describe("Items - Lock Capsule", () => { let phaserGame: Phaser.Game; diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts index 4efc7ab9d05..fa605ca7129 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Moves } from "#enums/moves"; diff --git a/src/test/items/toxic_orb.test.ts b/src/test/items/toxic_orb.test.ts index 69f55cb2bbc..dc54a5a1c36 100644 --- a/src/test/items/toxic_orb.test.ts +++ b/src/test/items/toxic_orb.test.ts @@ -1,5 +1,4 @@ import { StatusEffect } from "#app/data/status-effect"; -import { CommandPhase, EnemyCommandPhase, MessagePhase, TurnEndPhase } from "#app/phases"; import i18next, { initI18n } from "#app/plugins/i18n"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; @@ -10,6 +9,10 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Items - Toxic orb", () => { diff --git a/src/test/moves/astonish.test.ts b/src/test/moves/astonish.test.ts index 358e4a9bec3..21a82f09d33 100644 --- a/src/test/moves/astonish.test.ts +++ b/src/test/moves/astonish.test.ts @@ -1,6 +1,5 @@ import { allMoves } from "#app/data/move.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BerryPhase, CommandPhase, MoveEndPhase, TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -8,6 +7,10 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/aurora_veil.test.ts b/src/test/moves/aurora_veil.test.ts index a10c9b6b60a..5429efec2bf 100644 --- a/src/test/moves/aurora_veil.test.ts +++ b/src/test/moves/aurora_veil.test.ts @@ -4,7 +4,7 @@ import { WeatherType } from "#app/data/weather.js"; import { Abilities } from "#app/enums/abilities.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { NumberHolder } from "#app/utils.js"; diff --git a/src/test/moves/baton_pass.test.ts b/src/test/moves/baton_pass.test.ts index 9f0cb3619b2..790eddbf45c 100644 --- a/src/test/moves/baton_pass.test.ts +++ b/src/test/moves/baton_pass.test.ts @@ -1,5 +1,4 @@ import { BattleStat } from "#app/data/battle-stat.js"; -import { PostSummonPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#app/test/utils/gameManager"; import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -7,6 +6,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Baton Pass", () => { diff --git a/src/test/moves/beak_blast.test.ts b/src/test/moves/beak_blast.test.ts index 61a022ac9eb..8938b4c7af8 100644 --- a/src/test/moves/beak_blast.test.ts +++ b/src/test/moves/beak_blast.test.ts @@ -5,9 +5,11 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BerryPhase, MovePhase, TurnEndPhase } from "#app/phases"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { StatusEffect } from "#app/enums/status-effect.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/beat_up.test.ts b/src/test/moves/beat_up.test.ts index a5e4b3cbd34..a0f168ea30f 100644 --- a/src/test/moves/beat_up.test.ts +++ b/src/test/moves/beat_up.test.ts @@ -5,8 +5,8 @@ import { Species } from "#app/enums/species.js"; import { Moves } from "#app/enums/moves.js"; import { Abilities } from "#app/enums/abilities.js"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { MoveEffectPhase } from "#app/phases.js"; import { StatusEffect } from "#app/enums/status-effect.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; const TIMEOUT = 20 * 1000; // 20 sec timeout diff --git a/src/test/moves/belly_drum.test.ts b/src/test/moves/belly_drum.test.ts index 74afc910faf..e579a4587ad 100644 --- a/src/test/moves/belly_drum.test.ts +++ b/src/test/moves/belly_drum.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/ceaseless_edge.test.ts b/src/test/moves/ceaseless_edge.test.ts index c5ce8375102..c8291a99b59 100644 --- a/src/test/moves/ceaseless_edge.test.ts +++ b/src/test/moves/ceaseless_edge.test.ts @@ -2,13 +2,14 @@ import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; import { allMoves } from "#app/data/move"; import { Abilities } from "#app/enums/abilities"; import { ArenaTagType } from "#app/enums/arena-tag-type"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/clangorous_soul.test.ts b/src/test/moves/clangorous_soul.test.ts index 5493466ba56..5b2e8b6e06d 100644 --- a/src/test/moves/clangorous_soul.test.ts +++ b/src/test/moves/clangorous_soul.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/crafty_shield.test.ts b/src/test/moves/crafty_shield.test.ts index de2829aacf6..c3e50bc52c2 100644 --- a/src/test/moves/crafty_shield.test.ts +++ b/src/test/moves/crafty_shield.test.ts @@ -5,9 +5,10 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase, CommandPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/double_team.test.ts b/src/test/moves/double_team.test.ts index 2153b856517..1c89d5b6350 100644 --- a/src/test/moves/double_team.test.ts +++ b/src/test/moves/double_team.test.ts @@ -1,6 +1,6 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { Abilities } from "#app/enums/abilities.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index 6ec7521f678..8a27f4006f4 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -3,7 +3,7 @@ import { Type } from "#app/data/type"; import { Species } from "#app/enums/species.js"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/dragon_tail.test.ts b/src/test/moves/dragon_tail.test.ts index 7374451e643..28c47a83454 100644 --- a/src/test/moves/dragon_tail.test.ts +++ b/src/test/moves/dragon_tail.test.ts @@ -1,6 +1,5 @@ import { allMoves } from "#app/data/move.js"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { BattleEndPhase, BerryPhase, TurnEndPhase} from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -9,6 +8,9 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vi import GameManager from "../utils/gameManager"; import { getMovePosition } from "../utils/gameManagerUtils"; import { BattlerIndex } from "#app/battle.js"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/dynamax_cannon.test.ts b/src/test/moves/dynamax_cannon.test.ts index 57846c1aef7..5e81241ef46 100644 --- a/src/test/moves/dynamax_cannon.test.ts +++ b/src/test/moves/dynamax_cannon.test.ts @@ -1,12 +1,14 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import { DamagePhase, MoveEffectPhase, TurnStartPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Moves - Dynamax Cannon", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/fillet_away.test.ts b/src/test/moves/fillet_away.test.ts index 6965ced46d9..fcad704ef29 100644 --- a/src/test/moves/fillet_away.test.ts +++ b/src/test/moves/fillet_away.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/test/moves/fissure.test.ts b/src/test/moves/fissure.test.ts index 979bc40646c..65d692a5cc1 100644 --- a/src/test/moves/fissure.test.ts +++ b/src/test/moves/fissure.test.ts @@ -1,7 +1,6 @@ import { BattleStat } from "#app/data/battle-stat"; import { Species } from "#app/enums/species.js"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { DamagePhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -9,6 +8,8 @@ import { Moves } from "#enums/moves"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Fissure", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/flame_burst.test.ts b/src/test/moves/flame_burst.test.ts index 0f9e311ca86..d6679f921df 100644 --- a/src/test/moves/flame_burst.test.ts +++ b/src/test/moves/flame_burst.test.ts @@ -2,12 +2,13 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { SelectTargetPhase, TurnEndPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#app/enums/abilities.js"; import { allAbilities } from "#app/data/ability.js"; import Pokemon from "#app/field/pokemon.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Flame Burst", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/flower_shield.test.ts b/src/test/moves/flower_shield.test.ts index 7ca5fb8bc62..9001e8ceacb 100644 --- a/src/test/moves/flower_shield.test.ts +++ b/src/test/moves/flower_shield.test.ts @@ -2,7 +2,7 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { SemiInvulnerableTag } from "#app/data/battler-tags.js"; import { Type } from "#app/data/type.js"; import { Biome } from "#app/enums/biome.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/focus_punch.test.ts b/src/test/moves/focus_punch.test.ts index f5cf85ffae0..385234f0b71 100644 --- a/src/test/moves/focus_punch.test.ts +++ b/src/test/moves/focus_punch.test.ts @@ -5,8 +5,12 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BerryPhase, MessagePhase, MoveHeaderPhase, SwitchSummonPhase, TurnStartPhase } from "#app/phases"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { MoveHeaderPhase } from "#app/phases/move-header-phase.js"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/follow_me.test.ts b/src/test/moves/follow_me.test.ts index 420dd7e0762..a0fff9afbf8 100644 --- a/src/test/moves/follow_me.test.ts +++ b/src/test/moves/follow_me.test.ts @@ -1,13 +1,15 @@ import { BattlerIndex } from "#app/battle.js"; import { Stat } from "#app/data/pokemon-stat"; import { Abilities } from "#app/enums/abilities.js"; -import { CommandPhase, SelectTargetPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/foresight.test.ts b/src/test/moves/foresight.test.ts index 3fef1569eba..91d3e3c37e0 100644 --- a/src/test/moves/foresight.test.ts +++ b/src/test/moves/foresight.test.ts @@ -5,7 +5,7 @@ import { Species } from "#app/enums/species.js"; import { SPLASH_ONLY } from "../utils/testUtils"; import { Moves } from "#app/enums/moves.js"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { MoveEffectPhase } from "#app/phases.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Moves - Foresight", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/freezy_frost.test.ts b/src/test/moves/freezy_frost.test.ts index 3ccd31bd29e..b4c30279c21 100644 --- a/src/test/moves/freezy_frost.test.ts +++ b/src/test/moves/freezy_frost.test.ts @@ -1,5 +1,4 @@ import { BattleStat } from "#app/data/battle-stat"; -import { MoveEndPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -9,6 +8,8 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; import { allMoves } from "#app/data/move.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Freezy Frost", () => { describe("integration tests", () => { diff --git a/src/test/moves/fusion_flare.test.ts b/src/test/moves/fusion_flare.test.ts index 9ae42e7977f..aa38357ddd3 100644 --- a/src/test/moves/fusion_flare.test.ts +++ b/src/test/moves/fusion_flare.test.ts @@ -1,11 +1,11 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { TurnStartPhase } from "#app/phases"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { StatusEffect } from "#app/data/status-effect"; import { Species } from "#enums/species"; import { Moves } from "#enums/moves"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Moves - Fusion Flare", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/fusion_flare_bolt.test.ts b/src/test/moves/fusion_flare_bolt.test.ts index c2214d5442b..1b95062ee81 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -1,13 +1,16 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { MoveEffectPhase, MovePhase, MoveEndPhase, DamagePhase } from "#app/phases"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Stat } from "#app/data/pokemon-stat"; import { allMoves } from "#app/data/move"; import { BattlerIndex } from "#app/battle"; import { Species } from "#enums/species"; import { Moves } from "#enums/moves"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; describe("Moves - Fusion Flare and Fusion Bolt", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts index b9c9d2199d3..f97ba1f0367 100644 --- a/src/test/moves/glaive_rush.test.ts +++ b/src/test/moves/glaive_rush.test.ts @@ -1,12 +1,13 @@ import { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; -import { DamagePhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Glaive Rush", () => { diff --git a/src/test/moves/growth.test.ts b/src/test/moves/growth.test.ts index bfa3cc54896..0c60bb723f4 100644 --- a/src/test/moves/growth.test.ts +++ b/src/test/moves/growth.test.ts @@ -1,6 +1,5 @@ import { BattleStat } from "#app/data/battle-stat"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, EnemyCommandPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -10,6 +9,9 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Growth", () => { diff --git a/src/test/moves/hard_press.test.ts b/src/test/moves/hard_press.test.ts index baf63a1ad23..255b9f1f4b1 100644 --- a/src/test/moves/hard_press.test.ts +++ b/src/test/moves/hard_press.test.ts @@ -1,5 +1,5 @@ import { allMoves } from "#app/data/move.js"; -import { MoveEffectPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/haze.test.ts b/src/test/moves/haze.test.ts index 092575b8000..d5e3efcbd9d 100644 --- a/src/test/moves/haze.test.ts +++ b/src/test/moves/haze.test.ts @@ -1,5 +1,4 @@ import { BattleStat } from "#app/data/battle-stat"; -import { MoveEndPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -8,6 +7,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Haze", () => { describe("integration tests", () => { diff --git a/src/test/moves/hyper_beam.test.ts b/src/test/moves/hyper_beam.test.ts index f33ce4f5478..ac8075081fb 100644 --- a/src/test/moves/hyper_beam.test.ts +++ b/src/test/moves/hyper_beam.test.ts @@ -3,11 +3,12 @@ import { Abilities } from "#app/enums/abilities.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; -import { BerryPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; // 20 sec timeout for all tests diff --git a/src/test/moves/light_screen.test.ts b/src/test/moves/light_screen.test.ts index 9de1f8c492b..4577ffc574a 100644 --- a/src/test/moves/light_screen.test.ts +++ b/src/test/moves/light_screen.test.ts @@ -3,7 +3,7 @@ import Move, { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { NumberHolder } from "#app/utils.js"; diff --git a/src/test/moves/lucky_chant.test.ts b/src/test/moves/lucky_chant.test.ts index 1232ce9ffc3..643a5eddb00 100644 --- a/src/test/moves/lucky_chant.test.ts +++ b/src/test/moves/lucky_chant.test.ts @@ -4,8 +4,9 @@ import { getMovePosition } from "../utils/gameManagerUtils"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; import { Abilities } from "#app/enums/abilities.js"; -import { BerryPhase, TurnEndPhase } from "#app/phases.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/magnet_rise.test.ts b/src/test/moves/magnet_rise.test.ts index 9b3c6c457e2..4ab32b5d048 100644 --- a/src/test/moves/magnet_rise.test.ts +++ b/src/test/moves/magnet_rise.test.ts @@ -1,9 +1,10 @@ -import { CommandPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Magnet Rise", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts index a4440401c4b..5b0a8c6d62a 100644 --- a/src/test/moves/make_it_rain.test.ts +++ b/src/test/moves/make_it_rain.test.ts @@ -1,5 +1,4 @@ import { BattleStat } from "#app/data/battle-stat.js"; -import { MoveEndPhase, StatChangePhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -8,6 +7,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/mat_block.test.ts b/src/test/moves/mat_block.test.ts index 3a4d23d1497..27a55cab289 100644 --- a/src/test/moves/mat_block.test.ts +++ b/src/test/moves/mat_block.test.ts @@ -5,8 +5,10 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase, CommandPhase, TurnEndPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts index 45de8b7e4fb..3e1e151e7d4 100644 --- a/src/test/moves/miracle_eye.test.ts +++ b/src/test/moves/miracle_eye.test.ts @@ -5,8 +5,8 @@ import { Species } from "#app/enums/species.js"; import { SPLASH_ONLY } from "../utils/testUtils"; import { Moves } from "#app/enums/moves.js"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { MoveEffectPhase } from "#app/phases.js"; import { BattlerIndex } from "#app/battle.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Moves - Miracle Eye", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/multi_target.test.ts b/src/test/moves/multi_target.test.ts index 4cb2dfb764d..6e8a7c99e9b 100644 --- a/src/test/moves/multi_target.test.ts +++ b/src/test/moves/multi_target.test.ts @@ -1,7 +1,7 @@ import { getMoveTargets } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; import { Species } from "#app/enums/species.js"; -import { TurnEndPhase } from "#app/phases.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { Moves } from "#enums/moves"; import Phaser from "phaser"; diff --git a/src/test/moves/octolock.test.ts b/src/test/moves/octolock.test.ts index 8988109f431..fcd68446eff 100644 --- a/src/test/moves/octolock.test.ts +++ b/src/test/moves/octolock.test.ts @@ -1,6 +1,5 @@ import { BattleStat } from "#app/data/battle-stat"; import { TrappedTag } from "#app/data/battler-tags.js"; -import { CommandPhase, MoveEndPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -9,6 +8,9 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Octolock", () => { describe("integration tests", () => { diff --git a/src/test/moves/parting_shot.test.ts b/src/test/moves/parting_shot.test.ts index b8b0faba4ce..32995d2d563 100644 --- a/src/test/moves/parting_shot.test.ts +++ b/src/test/moves/parting_shot.test.ts @@ -1,5 +1,4 @@ import { SPLASH_ONLY } from "../utils/testUtils"; -import { BerryPhase, MessagePhase, TurnInitPhase, FaintPhase } from "#app/phases"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -8,6 +7,10 @@ import { afterEach, beforeAll, beforeEach, describe, expect, test, it } from "vi import GameManager from "../utils/gameManager"; import { getMovePosition } from "../utils/gameManagerUtils"; import { BattleStat } from "#app/data/battle-stat"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { FaintPhase } from "#app/phases/faint-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/protect.test.ts b/src/test/moves/protect.test.ts index 34e208e0914..4d97ef5ce82 100644 --- a/src/test/moves/protect.test.ts +++ b/src/test/moves/protect.test.ts @@ -5,10 +5,10 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { allMoves } from "#app/data/move.js"; import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 7959927d63f..3020e4b47ac 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -1,6 +1,5 @@ import { Status, StatusEffect } from "#app/data/status-effect.js"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon.js"; -import { MoveEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -8,6 +7,7 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { BattlerIndex } from "#app/battle.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/quick_guard.test.ts b/src/test/moves/quick_guard.test.ts index 58165f3d916..8bf647f2027 100644 --- a/src/test/moves/quick_guard.test.ts +++ b/src/test/moves/quick_guard.test.ts @@ -5,8 +5,9 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase, CommandPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/rage_powder.test.ts b/src/test/moves/rage_powder.test.ts index 92cdcc9b4f7..17b687feead 100644 --- a/src/test/moves/rage_powder.test.ts +++ b/src/test/moves/rage_powder.test.ts @@ -1,5 +1,4 @@ import { BattlerIndex } from "#app/battle.js"; -import { CommandPhase, SelectTargetPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -7,6 +6,9 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/reflect.test.ts b/src/test/moves/reflect.test.ts index f5ea489a75e..79dd4f8202b 100644 --- a/src/test/moves/reflect.test.ts +++ b/src/test/moves/reflect.test.ts @@ -3,7 +3,7 @@ import Move, { allMoves } from "#app/data/move.js"; import { Abilities } from "#app/enums/abilities.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { NumberHolder } from "#app/utils.js"; diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts index 728fe1ecd45..1fc208c6724 100644 --- a/src/test/moves/rollout.test.ts +++ b/src/test/moves/rollout.test.ts @@ -1,5 +1,5 @@ import { allMoves } from "#app/data/move.js"; -import { CommandPhase } from "#app/phases"; +import { CommandPhase } from "#app/phases/command-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; diff --git a/src/test/moves/roost.test.ts b/src/test/moves/roost.test.ts index a9036dcb478..c40bb18cdb1 100644 --- a/src/test/moves/roost.test.ts +++ b/src/test/moves/roost.test.ts @@ -2,11 +2,12 @@ import { Abilities } from "#app/enums/abilities.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/shell_trap.test.ts b/src/test/moves/shell_trap.test.ts index b027541c252..c600b1ee1cc 100644 --- a/src/test/moves/shell_trap.test.ts +++ b/src/test/moves/shell_trap.test.ts @@ -6,9 +6,11 @@ import { Species } from "#app/enums/species.js"; import { allMoves } from "#app/data/move.js"; import { BattlerIndex } from "#app/battle.js"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase, MoveEndPhase, MovePhase } from "#app/phases.js"; import { SPLASH_ONLY } from "../utils/testUtils"; import { MoveResult } from "#app/field/pokemon.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts index bbbb3347580..ae3c676b893 100644 --- a/src/test/moves/spikes.test.ts +++ b/src/test/moves/spikes.test.ts @@ -1,4 +1,4 @@ -import { CommandPhase } from "#app/phases"; +import { CommandPhase } from "#app/phases/command-phase.js"; import GameManager from "#test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; diff --git a/src/test/moves/spit_up.test.ts b/src/test/moves/spit_up.test.ts index ec0a53028ff..51d84a5e151 100644 --- a/src/test/moves/spit_up.test.ts +++ b/src/test/moves/spit_up.test.ts @@ -3,7 +3,6 @@ import { StockpilingTag } from "#app/data/battler-tags.js"; import { allMoves } from "#app/data/move.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import { MovePhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -11,6 +10,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Spit Up", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/spotlight.test.ts b/src/test/moves/spotlight.test.ts index 0893ba975d7..40ab78471ae 100644 --- a/src/test/moves/spotlight.test.ts +++ b/src/test/moves/spotlight.test.ts @@ -1,12 +1,14 @@ import { BattlerIndex } from "#app/battle.js"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, SelectTargetPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/stockpile.test.ts b/src/test/moves/stockpile.test.ts index 375eeab3c95..0b208e20f81 100644 --- a/src/test/moves/stockpile.test.ts +++ b/src/test/moves/stockpile.test.ts @@ -1,7 +1,6 @@ import { BattleStat } from "#app/data/battle-stat"; import { StockpilingTag } from "#app/data/battler-tags.js"; import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import { CommandPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -10,6 +9,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Stockpile", () => { describe("integration tests", () => { diff --git a/src/test/moves/swallow.test.ts b/src/test/moves/swallow.test.ts index aed30445fd2..6a054393acc 100644 --- a/src/test/moves/swallow.test.ts +++ b/src/test/moves/swallow.test.ts @@ -2,7 +2,6 @@ import { BattleStat } from "#app/data/battle-stat"; import { StockpilingTag } from "#app/data/battler-tags.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import { MovePhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -10,6 +9,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Swallow", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/tackle.test.ts b/src/test/moves/tackle.test.ts index 512b23ae363..f442645baa9 100644 --- a/src/test/moves/tackle.test.ts +++ b/src/test/moves/tackle.test.ts @@ -1,5 +1,4 @@ import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase, EnemyCommandPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -8,6 +7,9 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Tackle", () => { diff --git a/src/test/moves/tail_whip.test.ts b/src/test/moves/tail_whip.test.ts index 7630b31f7de..ba4a7459094 100644 --- a/src/test/moves/tail_whip.test.ts +++ b/src/test/moves/tail_whip.test.ts @@ -1,5 +1,4 @@ import { BattleStat } from "#app/data/battle-stat"; -import { CommandPhase, EnemyCommandPhase, TurnInitPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; @@ -9,6 +8,9 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Tail whip", () => { diff --git a/src/test/moves/tailwind.test.ts b/src/test/moves/tailwind.test.ts index e32e10a4290..115a97f3be4 100644 --- a/src/test/moves/tailwind.test.ts +++ b/src/test/moves/tailwind.test.ts @@ -1,7 +1,7 @@ import { ArenaTagSide } from "#app/data/arena-tag.js"; import { Stat } from "#app/data/pokemon-stat.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import { TurnEndPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; diff --git a/src/test/moves/thousand_arrows.test.ts b/src/test/moves/thousand_arrows.test.ts index 84a71ee5256..d72f3ed3fac 100644 --- a/src/test/moves/thousand_arrows.test.ts +++ b/src/test/moves/thousand_arrows.test.ts @@ -1,12 +1,13 @@ import { Abilities } from "#app/enums/abilities.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BerryPhase, MoveEffectPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/moves/tidy_up.test.ts b/src/test/moves/tidy_up.test.ts index e35a438c562..64a63df08df 100644 --- a/src/test/moves/tidy_up.test.ts +++ b/src/test/moves/tidy_up.test.ts @@ -1,6 +1,5 @@ import { BattleStat } from "#app/data/battle-stat.js"; import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import { MoveEndPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -9,6 +8,8 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Tidy Up", () => { diff --git a/src/test/moves/u_turn.test.ts b/src/test/moves/u_turn.test.ts index 2c12a4da43b..b93f997c487 100644 --- a/src/test/moves/u_turn.test.ts +++ b/src/test/moves/u_turn.test.ts @@ -1,5 +1,4 @@ import { Abilities } from "#app/enums/abilities.js"; -import { SwitchPhase, TurnEndPhase } from "#app/phases"; import GameManager from "#app/test/utils/gameManager"; import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; @@ -8,6 +7,8 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { StatusEffect } from "#app/enums/status-effect.js"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { SwitchPhase } from "#app/phases/switch-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - U-turn", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/wide_guard.test.ts b/src/test/moves/wide_guard.test.ts index 94f382022c2..1f22428de4b 100644 --- a/src/test/moves/wide_guard.test.ts +++ b/src/test/moves/wide_guard.test.ts @@ -5,8 +5,9 @@ import { Species } from "#enums/species"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { getMovePosition } from "../utils/gameManagerUtils"; -import { BerryPhase, CommandPhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; diff --git a/src/test/phases/phases.test.ts b/src/test/phases/phases.test.ts index c61eb1d41b8..2ed1e48c706 100644 --- a/src/test/phases/phases.test.ts +++ b/src/test/phases/phases.test.ts @@ -1,9 +1,11 @@ import BattleScene from "#app/battle-scene.js"; -import { LoginPhase, TitlePhase, UnavailablePhase } from "#app/phases.js"; import { Mode } from "#app/ui/ui.js"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; +import { LoginPhase } from "#app/phases/login-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; +import { UnavailablePhase } from "#app/phases/unavailable-phase.js"; describe("Phases", () => { let phaserGame: Phaser.Game; diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index 020b26b7f66..dbbdb1999b9 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -1,7 +1,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { EncounterPhase, SelectStarterPhase, TitlePhase } from "#app/phases"; import { Mode } from "#app/ui/ui"; import { GameModes } from "#app/game-mode"; import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; @@ -14,6 +13,9 @@ import { Nature} from "#app/data/nature"; import { Button } from "#enums/buttons"; import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; describe("UI - Starter select", () => { diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index 9315971e484..21aed9b5b87 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -2,7 +2,6 @@ import { BerryType } from "#app/enums/berry-type"; import { Button } from "#app/enums/buttons"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import { BattleEndPhase, SelectModifierPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; @@ -11,6 +10,8 @@ import Phaser from "phaser"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; describe("UI - Transfer Items", () => { diff --git a/src/test/ui/type-hints.test.ts b/src/test/ui/type-hints.test.ts index eb0191812e8..f93260f15b7 100644 --- a/src/test/ui/type-hints.test.ts +++ b/src/test/ui/type-hints.test.ts @@ -1,7 +1,6 @@ import { Button } from "#app/enums/buttons.js"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import { CommandPhase } from "#app/phases"; import FightUiHandler from "#app/ui/fight-ui-handler.js"; import { Mode } from "#app/ui/ui.js"; import GameManager from "#test/utils/gameManager"; @@ -9,6 +8,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import MockText from "../utils/mocks/mocksContainer/mockText"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { CommandPhase } from "#app/phases/command-phase.js"; describe("UI - Type Hints", () => { let phaserGame: Phaser.Game; diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 6333179e3b2..d60cbd62836 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -1,7 +1,6 @@ import GameWrapper from "#test/utils/gameWrapper"; import { Mode } from "#app/ui/ui"; import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils"; -import { CommandPhase, EncounterPhase, FaintPhase, LoginPhase, MovePhase, NewBattlePhase, SelectStarterPhase, SelectTargetPhase, TitlePhase, TurnEndPhase, TurnInitPhase, TurnStartPhase } from "#app/phases"; import BattleScene from "#app/battle-scene.js"; import PhaseInterceptor from "#test/utils/phaseInterceptor"; import TextInterceptor from "#test/utils/TextInterceptor"; @@ -31,6 +30,18 @@ import { vi } from "vitest"; import { ClassicModeHelper } from "./helpers/classicModeHelper"; import { DailyModeHelper } from "./helpers/dailyModeHelper"; import { SettingsHelper } from "./helpers/settingsHelper"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { FaintPhase } from "#app/phases/faint-phase.js"; +import { LoginPhase } from "#app/phases/login-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { NewBattlePhase } from "#app/phases/new-battle-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; /** * Class to manage the game state and transitions between phases. diff --git a/src/test/utils/helpers/classicModeHelper.ts b/src/test/utils/helpers/classicModeHelper.ts index e6854d5bc79..cf59dd81183 100644 --- a/src/test/utils/helpers/classicModeHelper.ts +++ b/src/test/utils/helpers/classicModeHelper.ts @@ -1,7 +1,8 @@ import { Species } from "#app/enums/species.js"; import { GameModes, getGameMode } from "#app/game-mode.js"; import overrides from "#app/overrides.js"; -import { EncounterPhase, SelectStarterPhase } from "#app/phases.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; import { Mode } from "#app/ui/ui.js"; import { generateStarter } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; diff --git a/src/test/utils/helpers/dailyModeHelper.ts b/src/test/utils/helpers/dailyModeHelper.ts index c83a2e587d9..a143e212fcb 100644 --- a/src/test/utils/helpers/dailyModeHelper.ts +++ b/src/test/utils/helpers/dailyModeHelper.ts @@ -1,6 +1,7 @@ import { Button } from "#app/enums/buttons.js"; import overrides from "#app/overrides.js"; -import { EncounterPhase, TitlePhase } from "#app/phases.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler.js"; import { Mode } from "#app/ui/ui.js"; import { GameManagerHelper } from "./gameManagerHelper"; diff --git a/src/test/utils/helpers/moveHelper.ts b/src/test/utils/helpers/moveHelper.ts index 9438952aa92..3179e63a6d0 100644 --- a/src/test/utils/helpers/moveHelper.ts +++ b/src/test/utils/helpers/moveHelper.ts @@ -1,6 +1,6 @@ import { vi } from "vitest"; -import { MoveEffectPhase } from "#app/phases.js"; import { GameManagerHelper } from "./gameManagerHelper"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; /** * Helper to handle a Pokemon's move diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 5a8b4ae01b2..2304d726757 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -1,44 +1,42 @@ -import { - BattleEndPhase, - BerryPhase, - CheckSwitchPhase, - CommandPhase, - DamagePhase, - EggLapsePhase, - EncounterPhase, - EnemyCommandPhase, - FaintPhase, - LoginPhase, - MessagePhase, - MoveEffectPhase, - MoveEndPhase, - MovePhase, - NewBattlePhase, - NextEncounterPhase, - PartyHealPhase, - PostSummonPhase, - SelectGenderPhase, - SelectModifierPhase, - SelectStarterPhase, - SelectTargetPhase, - ShinySparklePhase, - ShowAbilityPhase, - StatChangePhase, - SummonPhase, - SwitchPhase, - SwitchSummonPhase, - TitlePhase, - ToggleDoublePositionPhase, - TurnEndPhase, - TurnInitPhase, - TurnStartPhase, - UnavailablePhase, - VictoryPhase -} from "#app/phases"; import UI, { Mode } from "#app/ui/ui"; import { Phase } from "#app/phase"; import ErrorInterceptor from "#app/test/utils/errorInterceptor"; -import { QuietFormChangePhase } from "#app/form-change-phase"; +import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; +import { BerryPhase } from "#app/phases/berry-phase.js"; +import { CheckSwitchPhase } from "#app/phases/check-switch-phase.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { DamagePhase } from "#app/phases/damage-phase.js"; +import { EggLapsePhase } from "#app/phases/egg-lapse-phase.js"; +import { EncounterPhase } from "#app/phases/encounter-phase.js"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; +import { FaintPhase } from "#app/phases/faint-phase.js"; +import { LoginPhase } from "#app/phases/login-phase.js"; +import { MessagePhase } from "#app/phases/message-phase.js"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import { MoveEndPhase } from "#app/phases/move-end-phase.js"; +import { MovePhase } from "#app/phases/move-phase.js"; +import { NewBattlePhase } from "#app/phases/new-battle-phase.js"; +import { NextEncounterPhase } from "#app/phases/next-encounter-phase.js"; +import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; +import { SelectGenderPhase } from "#app/phases/select-gender-phase.js"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase.js"; +import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; +import { StatChangePhase } from "#app/phases/stat-change-phase.js"; +import { SummonPhase } from "#app/phases/summon-phase.js"; +import { SwitchPhase } from "#app/phases/switch-phase.js"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; +import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase.js"; +import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; +import { UnavailablePhase } from "#app/phases/unavailable-phase.js"; +import { VictoryPhase } from "#app/phases/victory-phase.js"; +import { PartyHealPhase } from "#app/phases/party-heal-phase.js"; export default class PhaseInterceptor { public scene; diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index d8b3e5e3ee8..04691886d9c 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -1,4 +1,3 @@ -import { CommandPhase } from "../phases"; import BattleScene from "../battle-scene"; import { getPokeballName } from "../data/pokeball"; import { addTextObject, getTextStyleOptions, TextStyle } from "./text"; @@ -7,6 +6,7 @@ import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import {Button} from "#enums/buttons"; +import { CommandPhase } from "#app/phases/command-phase.js"; export default class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts index 12211fa71cc..73c47da41fe 100644 --- a/src/ui/challenges-select-ui-handler.ts +++ b/src/ui/challenges-select-ui-handler.ts @@ -5,12 +5,13 @@ import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import {Button} from "#enums/buttons"; import i18next from "i18next"; -import { SelectStarterPhase, TitlePhase } from "#app/phases.js"; import { Challenge } from "#app/data/challenge.js"; import * as Utils from "../utils"; import { Challenges } from "#app/enums/challenges.js"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { Color, ShadowColor } from "#app/enums/color.js"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; /** * Handles all the UI for choosing optional challenges. diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index 11814a25240..b22ea5d20fc 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -1,4 +1,3 @@ -import { CommandPhase } from "../phases"; import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import PartyUiHandler, { PartyUiMode } from "./party-ui-handler"; @@ -7,6 +6,7 @@ import UiHandler from "./ui-handler"; import i18next from "i18next"; import {Button} from "#enums/buttons"; import { getPokemonNameWithAffix } from "#app/messages.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; export enum Command { FIGHT = 0, diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index f567861e0b7..733873b974e 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -1,8 +1,8 @@ import BattleScene from "../battle-scene"; -import { EggHatchPhase } from "../egg-hatch-phase"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import {Button} from "#enums/buttons"; +import { EggHatchPhase } from "#app/phases/egg-hatch-phase.js"; export default class EggHatchSceneHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 4ade6ca5d20..71d137fbfd7 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -5,11 +5,11 @@ import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; -import { CommandPhase } from "../phases"; import { MoveCategory } from "#app/data/move.js"; import i18next from "i18next"; import {Button} from "#enums/buttons"; import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; export default class FightUiHandler extends UiHandler { public static readonly MOVES_CONTAINER_NAME = "moves"; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 5e1ca7ccbb0..66c777944d1 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,4 +1,3 @@ -import { CommandPhase, SelectModifierPhase } from "../phases"; import BattleScene from "../battle-scene"; import Pokemon, { MoveResult, PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; @@ -23,6 +22,8 @@ import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; +import { CommandPhase } from "#app/phases/command-phase.js"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; const defaultMessage = i18next.t("partyUiHandler:choosePokemon"); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 9f2df1f2329..67e870838a2 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -16,7 +16,6 @@ import { LevelMoves, pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "../ import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { Type } from "../data/type"; import { GameModes } from "../game-mode"; -import { SelectChallengePhase, TitlePhase } from "../phases"; import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterMoveset, StarterAttributes, StarterPreferences, StarterPrefs } from "../system/game-data"; import { Tutorial, handleTutorial } from "../tutorial"; import * as Utils from "../utils"; @@ -44,6 +43,8 @@ import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType } import { StarterContainer } from "./starter-container"; import { DropDownColumn, FilterBar } from "./filter-bar"; import { ScrollBar } from "./scroll-bar"; +import { SelectChallengePhase } from "#app/phases/select-challenge-phase.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; export type StarterSelectCallback = (starters: Starter[]) => void; From e39ebb68f2d79c99d4b73e73f7bb2863c09c1702 Mon Sep 17 00:00:00 2001 From: damocleas Date: Tue, 20 Aug 2024 00:59:23 -0400 Subject: [PATCH 30/63] [Balance] Dark Void 80% Accurate (#1836) * Dark Void 80% Accurate * updated comment --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index af3f49bea0d..acb61042e70 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -7474,7 +7474,7 @@ export function initMoves() { .attr(OpponentHighHpPowerAttr, 120), new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4) .attr(TrapAttr, BattlerTagType.MAGMA_STORM), - new StatusMove(Moves.DARK_VOID, Type.DARK, 50, 10, -1, 0, 4) + new StatusMove(Moves.DARK_VOID, Type.DARK, 80, 10, -1, 0, 4) //Accuracy from Generations 4-6 .attr(StatusEffectAttr, StatusEffect.SLEEP) .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.SEED_FLARE, Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, 40, 0, 4) From 7946382817a2c2582cd96960d96d5cbf4f887734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ricardo=20Fleury=20Oliveira?= Date: Tue, 20 Aug 2024 02:06:49 -0300 Subject: [PATCH 31/63] [Localization] Portuguese hotfix of dialogue.ts and more (#3658) * [Localization] Portuguese hotfix of dialogue.ts and more * menu fixes * fix wrong message key of curse --- src/locales/pt_BR/dialogue.ts | 1406 +++++++++++++++++++++++++ src/locales/pt_BR/menu.ts | 4 +- src/locales/pt_BR/modifier.ts | 2 +- src/locales/pt_BR/move-trigger.ts | 2 +- src/locales/pt_BR/party-ui-handler.ts | 2 +- src/locales/pt_BR/pokemon-form.ts | 24 +- 6 files changed, 1423 insertions(+), 17 deletions(-) diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index cb0c05fab45..969c6fc36a9 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -2779,6 +2779,90 @@ export const PGFdialogue: DialogueTranslationEntries = { 9: "Estou realmente cansando de batalhar… Deve haver algo novo para fazer…" } }, + "breeder": { + "encounter": { + 1: "Pokémon obedientes, Pokémon egoístas… Pokémon têm características únicas.", + 2: "Embora minha criação e comportamento sejam ruins, criei meus Pokémon bem.", + 3: "Hmm, você disciplina seus Pokémon? Mimar demais não é bom." + }, + "victory": { + 1: "É importante nutrir e treinar as características de cada Pokémon.", + 2: "Ao contrário do meu lado diabólico, esses são bons Pokémon.", + 3: "Muito elogio pode estragar tanto Pokémon quanto pessoas." + }, + "defeat": { + 1: "Você não deve ficar com raiva dos seus Pokémon, mesmo se perder uma batalha.", + 2: "Certo? Pokémon bons, né? Eu sou adequado para criar coisas.", + 3: "Não importa o quanto você ame seus Pokémon, ainda precisa discipliná-los quando se comportam mal." + } + }, + "breeder_female": { + "encounter": { + 1: "Pokémon nunca te traem. Eles retribuem todo o amor que você dá a eles.", + 2: "Quer uma dica para treinar bons Pokémon?", + 3: "Eu criei esses Pokémon muito especiais usando um método especial." + }, + "victory": { + 1: "Ugh… Não era para ser assim. Será que administrei a mistura errada?", + 2: "Como isso aconteceu com meus Pokémon… O que você está dando de comer aos seus Pokémon?", + 3: "Se eu perder, isso significa que eu estava só matando o tempo. Não machuca meu ego nem um pouco." + }, + "defeat": { + 1: "Isso prova que meus Pokémon aceitaram meu amor.", + 2: "O verdadeiro truque para treinar bons Pokémon é capturar bons Pokémon.", + 3: "Pokémon serão fortes ou fracos dependendo de como você os cria." + } + }, + "fisherman": { + "encounter": { + 1: "Anem! Você me fez perder uma fisgada!\nO que vai fazer sobre isso?", + 2: "Sai daqui! Você está assustando os Pokémon!", + 3: "Vamos ver se você consegue fisgar uma vitória!", + }, + "victory": { + 1: "Esqueça isso.", + 2: "Da próxima vez, eu vou pescar a vitória!", + 3: "Acho que subestimei a força das correntes dessa vez.", + }, + }, + "fisherman_female": { + "encounter": { + 1: "Uau! Peguei um grande!", + 2: "Linha lançada, pronta para pescar o sucesso!", + 3: "Pronta para fazer ondas!" + }, + "victory": { + 1: "Vou voltar com um anzol mais forte.", + 2: "Vou pescar a vitória na próxima vez.", + 3: "Estou só afiando meus anzóis para a revanche!" + }, + }, + "swimmer": { + "encounter": { + 1: "Hora de mergulhar!", + 2: "Vamos surfar nas ondas da vitória!", + 3: "Pronto para fazer um splash!", + }, + "victory": { + 1: "Molhado na derrota!", + 2: "Uma onda de derrota!", + 3: "De volta à praia, eu acho.", + }, + }, + "backpacker": { + "encounter": { + 1: "Prepare-se, vamos começar!", + 2: "Vamos ver se você consegue acompanhar!", + 3: "Prepare-se, desafiante!", + 4: "Passei 20 anos tentando me encontrar… Mas onde estou?" + }, + "victory": { + 1: "Dessa vez tropecei!", + 2: "Ah, acho que estou perdido.", + 3: "Caminho sem saída!", + 4: "Espere um segundo! Ei! Você não sabe quem eu sou?" + }, + }, "ace_trainer": { "encounter": { 1: "Você parece bastante confiante.", @@ -2799,6 +2883,14 @@ export const PGFdialogue: DialogueTranslationEntries = { 4: "Claro que sou forte e não perco. É importante ganhar com graça." } }, + "parasol_lady": { + "encounter": { + 1: "Hora de embelezar o campo de batalha com elegância e postura!", + }, + "victory": { + 1: "Minha elegância permanece inabalável!", + } + }, "twins": { "encounter": { 1: "Prepare-se, porque quando nos unimos, é o dobro do problema!", @@ -2816,6 +2908,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Dobro de sorrisos, dobro da dança da vitória!" } }, + "cyclist": { + "encounter": { + 1: "Prepare-se para comer poeira!", + 2: "Prepare-se, desafiante! Estou prestes a te deixar para trás!", + 3: "Pé no pedal, vamos ver se você consegue acompanhar!" + }, + "victory": { + 1: "As rodas podem estar paradas, mas a determinação continua a pedalar.", + 2: "Fui mais rápido!", + 3: "O caminho para a vitória tem muitas curvas e voltas para explorar." + }, + }, "black_belt": { "encounter": { 1: "Elogio sua coragem ao me desafiar! Pois eu sou o que tem o chute mais forte!", @@ -2826,6 +2930,100 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Hmmm… Se eu ia perder de qualquer maneira, esperava ficar totalmente destruído no processo." }, }, + "battle_girl": { + "encounter": { + 1: "Você não precisa tentar me impressionar. Você pode perder contra mim.", + }, + "victory": { + 1: "É difícil dizer adeus, mas estamos ficando sem tempo…", + }, + }, + "hiker": { + "encounter": { + 1: "Minha barriga de meia-idade me deu tanta gravidade quanto as montanhas que eu escalo!", + 2: "Herdei esse corpo ossudo dos meus pais… Sou como uma cadeia de montanhas viva…", + }, + "victory": { + 1: "Pelo menos não posso perder quando se trata de IMC!", + 2: "Não é suficiente… Nunca é suficiente. Meu colesterol ruim não está alto o suficiente…" + }, + }, + "ranger": { + "encounter": { + 1: "Quando estou cercado pela natureza, a maioria das outras coisas deixa de importar.", + 2: "Quando estou vivendo sem natureza na minha vida, às vezes sinto uma crise de ansiedade se aproximando." + }, + "victory": { + 1: "Não importa para a vastidão da natureza se eu ganhar ou perder…", + 2: "Algo assim é bastante trivial comparado aos sentimentos sufocantes da vida na cidade." + }, + "defeat": { + 1: "Ganhei a batalha. Mas a vitória não é nada comparada à vastidão da natureza…", + 2: "Tenho certeza de que como você se sente não é tão ruim se comparar aos meus ataques de ansiedade…" + } + }, + "scientist": { + "encounter": { + 1: "Minha pesquisa levará este mundo à paz e alegria.", + }, + "victory": { + 1: "Sou um gênio… Não devo perder para alguém como você…", + }, + }, + "school_kid": { + "encounter": { + 1: "Heehee. Estou confiante nos meus cálculos e análises.", + 2: "Estou ganhando o máximo de experiência que posso porque quero ser um Líder de Ginásio um dia." + }, + "victory": { + 1: "Aff… Cálculo e análise talvez não sejam páreo para o acaso…", + 2: "Até experiências difíceis e desafiadoras têm seu propósito, eu acho." + } + }, + "artist": { + "encounter": { + 1: "Eu costumava ser popular, mas agora estou acabado.", + }, + "victory": { + 1: "À medida que os tempos mudam, os valores também mudam. Percebi isso tarde demais.", + }, + }, + "guitarist": { + "encounter": { + 1: "Prepare-se para sentir o ritmo da derrota enquanto eu toco minha vitória!", + }, + "victory": { + 1: "Silenciado por agora, mas minha melodia de resiliência continuará a tocar.", + }, + }, + "worker": { + "encounter": { + 1: "Me incomoda que as pessoas sempre me entendam mal. Sou muito mais puro do que todos pensam.", + }, + "victory": { + 1: "Eu realmente não quero que minha pele queime, então quero ficar na sombra enquanto trabalho.", + }, + }, + "worker_female": { + "encounter": { + 1: `Me incomoda que as pessoas sempre me entendam mal. + $Sou muito mais pura do que todos pensam.` + }, + "victory": { + 1: "Eu realmente não quero que minha pele queime, então quero ficar na sombra enquanto trabalho." + }, + "defeat": { + 1: "Meu corpo e mente nem sempre estão necessariamente em sincronia." + } + }, + "worker_double": { + "encounter": { + 1: "Vou te mostrar que podemos te quebrar. Estamos treinando no campo!", + }, + "victory": { + 1: "Que estranho… Como isso pode ser… Não deveria ter sido superado.", + }, + }, "hex_maniac": { "encounter": { 1: "Normalmente, só escuto música clássica, mas se eu perder, acho que vou tentar um pouco de new age!", @@ -2840,6 +3038,32 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Não fique presa na tristeza ou frustração. Você pode usar seus rancores para se motivar." } }, + "psychic": { + "encounter": { + 1: "Oi! Concentre-se!", + }, + "victory": { + 1: "Perdi minha concentração!", + }, + }, + "officer": { + "encounter": { + 1: "Prepare-se, porque a justiça está prestes a ser servida!", + 2: "Pronto para defender a lei e servir a justiça no campo de batalha!" + }, + "victory": { + 1: "O peso da justiça parece mais pesado do que nunca…", + 2: "As sombras da derrota pairam no distrito." + } + }, + "beauty": { + "encounter": { + 1: "Minha última batalha… É assim que eu gostaria que víssemos esta partida…", + }, + "victory": { + 1: "Foi divertido… Vamos ter outra última batalha algum dia…", + }, + }, "baker": { "encounter": { 1: "Espero que esteja pronta para saborear a derrota!" @@ -2848,6 +3072,26 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Vou assar uma revanche." }, }, + "biker": { + "encounter": { + 1: "Hora de acelerar e te deixar na poeira!" + }, + "victory": { + 1: "Vou me ajustar para a próxima corrida." + }, + }, + "firebreather": { + "encounter": { + 1: "Minhas chamas irão te consumir!", + 2: "Minha alma está pegando fogo. Irei te mostrar como queima!", + 3: "Cola aqui e dá uma olhada!" + }, + "victory": { + 1: "Fui reduzido a cinzas…", + 2: "Uau! Isso foi quente!", + 3: "Ai! Queimei minha língua!" + }, + }, "sailor": { "encounter": { 1: "Mano, você vai andar na prancha se perder!", @@ -2860,6 +3104,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Estou achando que quem tá enjoado sou eu..." }, }, + "archer": { + "encounter": { + 1: "Antes de você ir mais longe, vamos ver como você se sai contra nós, Equipe Rocket!", + 2: "Eu tenho recebido relatórios de que suas habilidades não são insignificantes. Vamos ver se são verdadeiros.", + 3: "Eu sou Archer, um Admin da Equipe Rocket. E não tenho piedade dos inimigos da nossa organização." + }, + "victory": { + 1: "Que vexame!", + 2: "Com minhas habilidades atuais, eu não estava à altura da tarefa, afinal.", + 3: "M-me perdoe, Giovanni... Por ser derrotado por um mero treinador..." + }, + }, "ariana": { "encounter": { 1: "Pera aí! Não podemos deixar alguém solto por aí. Isso é prejudicial para o orgulho da Equipe Rocket, entende?", @@ -2872,6 +3128,30 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Aaaieeeee! Isso não pode estar acontecendo! Eu lutei muito, mas ainda perdi…" }, }, + "proton": { + "encounter": { + 1: "O que você quer? Se você interromper nosso trabalho, não espere misericórdia!", + 2: "O que temos aqui? Costumam me chamar de o cara mais assustador e cruel da Equipe Rocket… Eu recomendo fortemente que você não interfira nos nossos negócios!", + 3: "Eu sou Proton, um Admin da Equipe Rocket. Estou aqui para acabar com a sua intromissão!" + }, + "victory": { + 1: "A fortaleza caiu!", + 2: "Você pode ter vencido desta vez… Mas tudo o que fez foi aumentar a ira da Equipe Rocket…", + 3: "Fui derrotado… Mas não esquecerei disso!" + }, + }, + "petrel": { + "encounter": { + 1: "Muhahaha, estávamos esperando por você. Eu? Você não sabe quem eu sou? Sou eu, Giovanni. O majestoso Giovanni em pessoa! Wahahaha! ...Huh? Eu não pareço nada com Giovanni? Eu nem mesmo pareço com Giovanni? Como assim? Trabalhei tanto para imitá-lo!", + 2: "Eu sou Petrel, um Admin da Equipe Rocket. Não permitirei que você interfira em nossos planos!", + 3: "O Executivo da Rocket, Petrel, vai lidar com este intruso!" + }, + "victory": { + 1: "OK, OK. Vou te contar onde ele está.", + 2: "Eu... Eu não consegui fazer nada... Giovanni, por favor, me perdoe...", + 3: "Não, eu não posso deixar isso me afetar. Tenho que informar os outros…" + }, + }, "tabitha": { "encounter": { 1: "Hehehe! Então você veio até aqui! Mas você chegou tarde demais!", @@ -2884,6 +3164,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Ahya! Como isso pode ser? Para um Admin como eu perder para uma treinadora qualquer..." }, }, + "courtney": { + "encounter": { + 1: "A coisa... A coisa que você segura... É o que... É o que nós da Equipe Magma procuramos...", + 2: "... Bem então... Deletando...", + 3: "...Ha. ...Analisando... ...Hah♪" + }, + "victory": { + 1: "... ...Mudar...o mundo.", + 2: "Como antecipado. Não antecipado. Você. Bloqueio de alvo... concluído. Iniciando... experimento. Você. Para sempre. Aha... ♪", + 3: "... De novo? Isso não foi antecipado. ...Eu sabia. Você... é interessante! ...Haha. ♪" + }, + }, "shelly": { "encounter": { 1: "Ahahahaha! Você vai se meter nos assuntos da Equipe Aqua? Você é absolutamente destemida, simplesmente ignorante ou ambos! Você é tão fofa que chega a ser nojenta! Vou te derrubar", @@ -2920,6 +3212,30 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Derrotada... Este foi um erro caro." } }, + "jupiter": { + "encounter": { + 1: "Júpiter, Comandante da Equipe Galáctica, ao seu serviço.", + 2: "A resistência é inútil. A Equipe Galáctica prevalecerá!", + 3: "Você está tremendo... já está com medo?" + }, + "victory": { + 1: "De jeito nenhum... Eu perdi?!", + 2: "Impressionante, você tem coragem!", + 3: "Perder assim... Que embaraço." + } + }, + "saturn": { + "encounter": { + 1: "Eu sou Saturno, Comandante da Equipe Galáctica.", + 2: "Nossa missão é absoluta. Qualquer obstáculo será obliterado!", + 3: "É medo o que vejo em seus olhos?" + }, + "victory": { + 1: "Impossível... Derrotado por você?!", + 2: "Você provou ser um adversário digno.", + 3: "Derrotado... Isso é inaceitável." + } + }, "zinzolin": { "encounter": { 1: "Você poderia se tornar uma ameaça para a Equipe Plasma, então vamos eliminá-la aqui e agora!", @@ -2984,6 +3300,38 @@ export const PGFdialogue: DialogueTranslationEntries = { 5: "Você diz o que? Equipe Rocket tchau-tchau a vai-vai? Quebrado é diz você?" // Uso de gramática incorreta é proposital }, }, + "magma_grunt": { + "encounter": { + 1: "Se você se meter com a Equipe Magma, não teremos piedade!", + 2: "É melhor você não interferir em nossos planos! Estamos tornando o mundo um lugar melhor!", + 3: "Você está no caminho! A Equipe Magma não tem tempo para crianças como você!", + 4: "Espero que você tenha trazido marshmallows porque as coisas estão prestes a esquentar!", + 5: "Vamos usar o poder de um vulcão! Vai ser... explosivo! Entendeu? Heh heh!" + }, + "victory": { + 1: "Ahn? Eu perdi?!", + 2: "Não posso acreditar que perdi! Até pulei o almoço por isso.", + 3: "De jeito nenhum! Você é apenas uma criança!", + 4: "Urrrgh... Eu deveria ter me escondido em nosso esconderijo imediatamente...", + 5: "Você me venceu... Você acha que o chefe vai cortar meu salário por isso?" + }, + }, + "aqua_grunt": { + "encounter": { + 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!", + 2: "Grrr... Você tem coragem de se intrometer com a Equipe Aqua!", + 3: "Você está prestes a se molhar! E não apenas por causa dos meus Pokémon aquáticos!", + 4: "Nós, da Equipe Aqua, existimos para o bem de todos!", + 5: "Prepare-se para ser levado pelas ondas do meu... uh, Pokémon! Sim, meu Pokémon!" + }, + "victory": { + 1: "Tá de brincadeira!", + 2: "Arrgh, eu não contei que seria atrapalhado por uma criança intrometida!", + 3: "Eu perdi?! Acho que vou ter que nadar de volta para o esconderijo agora...", + 4: "Oh, cara, que desastre... O chefe vai ficar furioso...", + 5: "Você me venceu... Você acha que o chefe vai me fazer andar na prancha por isso?" + }, + }, "galactic_grunt": { "encounter": { 1: "Não mexa com a Equipe Galáctica!", @@ -3000,6 +3348,104 @@ export const PGFdialogue: DialogueTranslationEntries = { 5: "Nota para mim mesmo: praticar batalhas Pokémon, o mais rápido possível." }, }, + "plasma_grunt": { + "encounter": { + 1: "Não toleramos pessoas que pensam diferente de nós!", + 2: "Se eu ganhar de você, liberte seus Pokémon!", + 3: "Se você atrapalhar a Equipe Plasma, eu cuidarei de você!", + 4: "A Equipe Plasma vai libertar os Pokémon de humanos egoístas como você!", + 5: "Nossos penteados são de outro mundo... mas nossas habilidades de batalha? Você descobrirá em breve." + }, + "victory": { + 1: "Plasmaaaaaaaaa!", + 2: "Como eu pude perder...", + 3: "...Que Pokémon fraco, vou ter que roubar alguns melhores!", + 4: "Grandes planos são sempre interrompidos.", + 5: "Isso é ruim... Ruim ruim ruim ruim ruim ruim ruim! Ruim para a Equipe Plasma! Ou Plasruim, para abreviar!" + }, + }, + "flare_grunt": { + "encounter": { + 1: "Seus Pokémon não são páreo para a elegância da Equipe Flare.", + 2: "Espero que você tenha trazido seus óculos de sol, porque as coisas vão ficar brilhantes!", + 3: "A Equipe Flare vai purificar o mundo da imperfeição!", + 4: "Prepare-se para enfrentar o brilho da Equipe Flare!", + 5: "A moda é o mais importante para nós!" + }, + "victory": { + 1: "O futuro não parece brilhante para mim.", + 2: "Talvez haja mais na batalha do que eu pensei. De volta à prancheta.", + 3: "Gahh?! Eu perdi?!", + 4: "Mesmo na derrota, a elegância da Equipe Flare brilha.", + 5: "Você pode ter me vencido, mas quando eu perco, eu saio com estilo!" + }, + }, + "rocket_boss_giovanni_1": { + "encounter": { + 1: "Tenho que admitir, estou impressionado que tenha chegado até aqui!" + }, + "victory": { + 1: "QUÊ! Isso não é possível!" + }, + "defeat": { + 1: "Guarde minhas palavras.\nNão ser capaz de medir sua própria força mostra que você ainda é uma criança." + } + }, + "rocket_boss_giovanni_2": { + "encounter": { + 1: "Meus antigos associados precisam de mim... Você vai ficar no meu caminho?" + }, + "victory": { + 1: "Como isso é possível...?\nO precioso sonho da Equipe Rocket se tornou pouco mais que uma ilusão..." + }, + "defeat": { + 1: "A Equipe Rocket renascerá, e eu dominarei o mundo!" + } + }, + "magma_boss_maxie_1": { + "encounter": { + 1: "Eu vou te enterrar com minhas próprias mãos.\nEspero que você aprecie essa honra!" + }, + "victory": { + 1: "Ugh! Você é... bastante capaz...\nEu fiquei para trás, mas apenas por um triz..." + }, + "defeat": { + 1: "A Equipe Magma vai prevalecer!" + } + }, + "magma_boss_maxie_2": { + "encounter": { + 1: "Você é o último obstáculo entre mim e meus objetivos.\nPrepare-se para meu ataque final! Fuhahaha!" + }, + "victory": { + 1: "Isso... Isso não é... Ngh..." + }, + "defeat": { + 1: "E agora... Eu transformarei este planeta em uma terra ideal para a humanidade." + } + }, + "aqua_boss_archie_1": { + "encounter": { + 1: "Eu sou o líder da Equipe Aqua, então temo que esse seja o fim da linha para você." + }, + "victory": { + 1: "Vamos nos encontrar de novo em algum lugar. Eu vou ter certeza de lembrar desse rosto." + }, + "defeat": { + 1: "Brilhante! Nada vai parar minha equipe agora!" + } + }, + "aqua_boss_archie_2": { + "encounter": { + 1: "Estive esperando tanto tempo por este dia.\nEste é o verdadeiro poder da minha equipe!" + }, + "victory": { + 1: "Como eu suspeitava..." + }, + "defeat": { + 1: "Eu vou voltar tudo neste mundo ao seu estado puro e original!!" + } + }, "galactic_boss_cyrus_1": { "encounter": { 1: "Você foi compelida a vir aqui por tal sentimentalismo vazio\nEu farei você se arrepender de ter ouvido seu coração!" @@ -3011,6 +3457,78 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Eu criarei meu novo mundo..." } }, + "galactic_boss_cyrus_2": { + "encounter": { + 1: "Nos encontramos novamente. Parece que nossos destinos estão entrelaçados.\nMas aqui e agora, eu finalmente quebrarei esse vínculo!" + }, + "victory": { + 1: "Como? Como? COMO?!" + }, + "defeat": { + 1: "Até logo." + } + }, + "plasma_boss_ghetsis_1": { + "encounter": { + 1: "Ninguém pode me deter! Não importa quem seja ou o que faça!" + }, + "victory": { + 1: "Como isso é possível? Eu sou o criador da Equipe Plasma! Eu sou perfeito!" + }, + "defeat": { + 1: "Eu sou o governante perfeito de um novo mundo perfeito! Mwa ha ha!" + } + }, + "plasma_boss_ghetsis_2": { + "encounter": { + 1: "Vamos! Eu quero ver sua cara depois que você perder toda a esperança!" + }, + "victory": { + 1: "Meus cálculos... Não! Meus planos cuidadosos! O mundo deveria ser meu!" + }, + "defeat": { + 1: "Kyurem! Use Absofusion!" + } + }, + "flare_boss_lysandre_1": { + "encounter": { + 1: "Você está aqui para me deter? Mostre-me em batalha." + }, + "victory": { + 1: "Você está aqui para me deter. Mas eu peço que você espere." + }, + "defeat": { + 1: "Pokémon... não devem mais existir." + } + }, + "flare_boss_lysandre_2": { + "encounter": { + 1: "O futuro que você quer, ou o futuro que eu quero... Vamos ver qual é o mais merecedor, não é mesmo?" + }, + "victory": { + 1: "Uau!" + }, + "defeat": { + 1: "Tolos sem visão continuarão a poluir este belo mundo." + } + }, + "brock": { + "encounter": { + 1: "Minha especialidade em Pokémon do tipo Pedra vai te derrubar! Vamos lá!", + 2: "Minha vontade firme como pedra vai te sobrecarregar!", + 3: "Permita-me mostrar a verdadeira força dos meus Pokémon!" + }, + "victory": { + 1: "A força dos seus Pokémon superou minhas defesas de pedra!", + 2: "O mundo é enorme! Estou feliz por ter tido a chance de batalhar com você.", + 3: "Talvez eu deva voltar a perseguir meu sonho de ser Criador de Pokémon…" + }, + "defeat": { + 1: "A melhor defesa é um bom ataque!\nEssa é a minha maneira de fazer as coisas!", + 2: "Venha estudar rochas comigo da próxima vez para aprender melhor a combatê-las!", + 3: "Hah, todas as minhas viagens pelas regiões estão valendo a pena!" + } + }, "misty": { "encounter": { 1: "Minha política é um ataque total com Pokémon do tipo Água!", @@ -3045,6 +3563,77 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Uma batalha de Pokémon é guerra, e eu te mostrei combate em primeira mão!" } }, + "erika": { + "encounter": { + 1: "Ah, o tempo está adorável aqui…\nOh, uma batalha? Muito bem então.", + 2: "Minhas habilidades de batalha Pokémon rivalizam com minhas habilidades de arranjo de flores.", + 3: "Oh, espero que o aroma agradável dos meus Pokémon não me faça dormir de novo…", + 4: "Ver flores em um jardim é tão calmante." + }, + "victory": { + 1: "Oh! Eu concedo a derrota.", + 2: "Aquela partida foi muito agradável.", + 3: "Ah, parece que perdi…", + 4: "Oh, meu Deus." + }, + "defeat": { + 1: "Tinha medo de adormecer…", + 2: "Oh, meu Deus, parece que meus Pokémon de Grama te dominaram.", + 3: "Essa batalha foi uma experiência tão calmante.", + 4: "Oh… É só isso?" + } + }, + "janine": { + "encounter": { + 1: "Estou dominando a arte dos ataques venenosos.\nVou lutar com você hoje!", + 2: "Meu pai confia que posso me defender.\nVou provar que ele está certo!", + 3: "Minhas técnicas de ninja só perdem para as do meu pai!\nVocê consegue acompanhar?" + }, + "victory": { + 1: "Ainda preciso de treinamento… Entendi.", + 2: "Sua técnica de batalha superou a minha.", + 3: "Vou me aplicar de verdade e melhorar minhas habilidades." + }, + "defeat": { + 1: "Hehe… o veneno drenou todas as suas forças para lutar.", + 2: "Ha! Você não teve chance contra minhas habilidades superiores de ninja!", + 3: "A fé do meu pai em mim não foi mal colocada." + } + }, + "sabrina": { + "encounter": { + 1: "Através da minha habilidade psíquica, tive uma visão da sua chegada!", + 2: "Não gosto de lutar, mas se você quiser, vou mostrar meus poderes!", + 3: "Posso sentir grande ambição em você. Vou ver se não é infundada." + }, + "victory": { + 1: "Seu poder… Ele supera o que eu previa…", + 2: "Não consegui prever seu poder com precisão.", + 3: "Mesmo com meus imensos poderes psíquicos, não consigo sentir outro tão forte quanto você." + }, + "defeat": { + 1: "Essa vitória… É exatamente como previ nas minhas visões!", + 2: "Talvez fosse outra pessoa que eu sentisse um grande desejo…", + 3: "Aprimore suas habilidades antes de entrar em batalha precipitadamente.\nVocê nunca sabe o que o futuro pode reservar se fizer isso…" + } + }, + "blaine": { + "encounter": { + 1: "Hah! Espero que tenha trazido uma Cura de Queimadura!", + 2: "Meus Pokémon de Fogo vão incinerar todos os desafiantes!", + 3: "Prepare-se para brincar com fogo!" + }, + "victory": { + 1: "Queimei até não restar nada! Nem cinzas sobraram!", + 2: "Não acendi as chamas alto o suficiente?", + 3: "Estou completamente exausto… Mas isso faz minha motivação para melhorar queimar ainda mais!" + }, + "defeat": { + 1: "Meu inferno ardente não pode ser apagado!", + 2: "Meus Pokémon foram fortalecidos com o calor desta vitória!", + 3: "Hah! Minha paixão queima mais do que a sua!" + } + }, "giovanni": { "encounter": { 1: "Eu, o líder da Equipe Rocket, vou te fazer sentir um mundo de dor!", @@ -3062,6 +3651,23 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Espero que entenda o quão tolo foi me desafiar." } }, + "roxanne": { + "encounter": { + 1: "Você poderia gentilmente demonstrar como batalha?", + 2: "Você pode aprender muitas coisas batalhando com muitos treinadores.", + 3: "Oh, você me pegou estrategizando.\nGostaria de batalhar?" + }, + "victory": { + 1: "Oh, parece que perdi.\nEu entendo.", + 2: "Parece que ainda tenho muito mais a aprender quando se trata de batalhas.", + 3: "Vou levar o que aprendi aqui hoje a sério." + }, + "defeat": { + 1: "Aprendi muitas coisas com nossa batalha.\nEspero que você também tenha aprendido.", + 2: "Espero batalhar com você novamente.\nEspero que use o que aprendeu aqui.", + 3: "Venci devido a tudo o que aprendi." + } + }, "brawly": { "encounter": { 1: "Oh cara, uma desafiante!\nVamos ver o que você pode fazer!", @@ -3096,6 +3702,40 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Wahahahaha! Que batalha eletrizante!" } }, + "flannery": { + "encounter": { + 1: "Meus Pokémon de fogo estão prontos para queimar a concorrência!\nVamos nessa!", + 2: "Prepare-se para sentir o calor da minha determinação!\nNão vou segurar nada!", + 3: "Minhas habilidades vão incinerar você!\nPrepare-se para a batalha mais quente da sua vida!" + }, + "victory": { + 1: "Essa derrota só faz minha determinação queimar mais!", + 2: "Essa perda não apagará minhas chamas!\nEstarei de volta mais forte!", + 3: "Vou usar essa experiência para reacender meu espírito competitivo!" + }, + "defeat": { + 1: "Minhas chamas nunca se apagarão!\nSou muito apaixonada por isso!", + 2: "Você foi incrível!\nVamos fazer isso de novo algum dia!", + 3: "Que batalha ardente!\nMal posso esperar pela próxima!" + } + }, + "norman": { + "encounter": { + 1: "Você está pronto para enfrentar a força pura do meu time?\nVou te mostrar o poder do equilíbrio!", + 2: "Minha experiência em batalha vai fazer você suar!\nPrepare-se!", + 3: "Treinei meu time rigorosamente.\nVamos ver se você consegue igualar!" + }, + "victory": { + 1: "Parece que subestimei você.\nFoi uma batalha dura.", + 2: "Você é forte, mas ainda há muito para aprender.", + 3: "Essa derrota não abalará minha determinação.\nEstarei de volta mais forte!" + }, + "defeat": { + 1: "Você lutou bravamente!\nEspero batalhar com você novamente.", + 2: "Sua força é incrível!\nNão posso esperar pela nossa próxima batalha.", + 3: "Foi uma honra batalhar com você!\nAté a próxima!" + } + }, "winona": { "encounter": { 1: "Tenho sobrevoado os céus em busca de presas...\nE você é meu alvo!", @@ -3147,6 +3787,60 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Tudo graças ao meu treinamento rigoroso com Tate.\nPosso me sincronizar com meus Pokémon." } }, + "juan": { + "encounter": { + 1: "Agora não é hora de agir timidamente.\nVamos batalhar!", + 2: "Ahahaha, você será testemunha da minha arte com Pokémon de Água!", + 3: "Um tufão se aproxima!\nVocê será capaz de me testar?", + 4: "Por favor, você será testemunha da nossa arte.\nUma grande ilusão de água esculpida por meus Pokémon e por mim!" + }, + "victory": { + 1: "Você pode ser um gênio que pode enfrentar Wallace!", + 2: "Eu me concentrei na elegância enquanto você treinava.\nÉ natural que você me derrotasse.", + 3: "Ahahaha!\nMuito bem, você venceu desta vez.", + 4: "De você, sinto o brilho brilhante da habilidade que superará tudo." + }, + "defeat": { + 1: "Meus Pokémon e eu esculpimos uma ilusão de Água e saímos vitoriosos.", + 2: "Ahahaha, eu venci, e você perdeu.", + 3: "Posso emprestar meu traje? Pode te ajudar a batalhar!\nAhahaha, estou brincando!", + 4: "Eu sou o vencedor! O que quer dizer, você perdeu." + } + }, + "crasher_wake": { + "encounter": { + 1: "Crash! Crash! Cuidado!\nDemolidor Wake… está… aqui!", + 2: "Crash! Crash! Demolidor Wake!", + 3: "Sou a onda de poder que vai te lavar!" + }, + "victory": { + 1: "Isso coloca um sorriso no meu rosto!\nGuhahaha! Foi uma explosão!", + 2: "Hunwah! Acabou e terminou!\nComo vou dizer isso...\nQuero mais! Queria batalhar muito mais!", + 3: "O QUÊ?!" + }, + "defeat": { + 1: "Siiiiim! Isso mesmo!", + 2: "Eu venci, mas quero mais! Queria batalhar muito mais!", + 3: "Até logo!" + } + }, + "falkner": { + "encounter": { + 1: "Vou mostrar o verdadeiro poder dos magníficos Pokémon pássaros!", + 2: "Ventos, fiquem comigo!", + 3: "Pai! Espero que esteja vendo minha batalha de cima!" + }, + "victory": { + 1: "Eu entendo... Vou sair graciosamente.", + 2: "Uma derrota é uma derrota. Você é realmente forte.", + 3: "...Droga! Sim, eu perdi." + }, + "defeat": { + 1: "Pai! Venci com seus amados Pokémon pássaros...", + 2: "Pokémon pássaros são os melhores afinal!", + 3: "Sinto que estou alcançando meu pai!" + } + }, "nessa": { "encounter": { 1: "Não importa que tipo de plano sua mente refinada possa estar tramando, meu parceiro e eu vamos afundá-la.", @@ -3295,6 +3989,42 @@ export const PGFdialogue: DialogueTranslationEntries = { 6: "Eu sabia que venceria!" } }, + "crispin": { + "encounter": { + 1: "Quero vencer, então é exatamente isso que vou fazer!", + 2: "Eu batalho porque quero batalhar! E sabe de uma coisa? É assim que deve ser!" + }, + "victory": { + 1: "Queria vencer... mas perdi!", + 2: "Eu perdi... porque não consegui vencer!" + }, + "defeat": { + 1: "Ei, espere um segundo. Eu acabei de vencer? Acho que acabei de vencer! Que satisfação!", + 2: "Uou! Isso foi incrível!" + } + }, + "amarys": { + "encounter": { + 1: "Quero ser a pessoa a ajudar alguém em particular. Sendo assim, não posso me dar ao luxo de perder.\n... Nossa batalha começa agora." + }, + "victory": { + 1: "Eu sou... não o suficiente, eu vejo." + }, + "defeat": { + 1: "A vitória pertence a mim. Bem lutado." + } + }, + "lacey": { + "encounter": { + 1: "Vou enfrentar você com meu time usual como membro da Elite dos Quatro." + }, + "victory": { + 1: "Foi uma excelente batalha. Estou ansiosa para o próximo desafio." + }, + "defeat": { + 1: "Fufufu... Nada mal.\nDesafiantes que derrotam a Elite dos Quatro são dignos de notar." + } + }, "drayton": { "encounter": { 1: `Cara, eu amo cadeiras. Você não ama cadeiras? Que salva-vidas. @@ -3319,6 +4049,23 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Hohoho... De fato. Pequenas lâminas frágeis de grama conseguem quebrar até mesmo concreto." } }, + "viola": { + "encounter": { + 1: `Seja as lágrimas de frustração que seguem uma derrota ou o florescer da alegria que vem com a vitória… + $Ambos são ótimos temas para minha câmera! Fantástico! Isso vai ser simplesmente fantástico! + $Agora venha para cima de mim!`, + 2: "Minha lente está sempre focada na vitória – não vou deixar nada estragar esta foto!" + }, + "victory": { + 1: "Você e seus Pokémon me mostraram uma nova profundidade de campo! Fantástico! Simplesmente fantástico!", + 2: `O mundo que você vê através de uma lente, e o mundo que você vê com um Pokémon ao seu lado… + $O mesmo mundo pode parecer completamente diferente dependendo do seu ponto de vista.` + }, + "defeat": { + 1: "A foto do momento da minha vitória vai ser um verdadeiro sucesso!", + 2: "Sim! Tirei ótimas fotos!" + } + }, "candice": { "encounter": { 1: `Você quer desafiar a Candice? Com certeza! Eu estava esperando por alguém forte! @@ -3347,6 +4094,40 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Sim! Meus Pokémon e eu somos perfeitamente bons!" } }, + "aaron": { + "encounter": { + 1: "Ok! Deixe-me enfrentar você!" + }, + "victory": { + 1: "Batalhar é um assunto profundo e complexo..." + }, + "defeat": { + 1: "Vencer um membro da Elite dos Quatro não é fácil." + } + }, + "cress": { + "encounter": { + 1: "Isso mesmo! Serei eu e meus estimados tipos Água que você deve enfrentar na batalha!" + }, + "victory": { + 1: "Perder? Eu? Não acredito nisso." + }, + "defeat": { + 1: "Este é o resultado apropriado quando eu sou seu oponente." + } + }, + "allister": { + "encounter": { + 1: "Sou Allister.\nA-aqui... vou eu..." + }, + "victory": { + 1: `Quase perdi minha máscara de tanto choque... Isso foi… + $Uau. Posso ver sua habilidade pelo que ela é.`, + }, + "defeat": { + 1: "I-isso foi incrível!" + } + }, "clay": { "encounter": { 1: "Harrumph! Me deixou esperando, não foi, garota? Tudo bem, hora de ver o que você pode fazer!" @@ -3369,6 +4150,68 @@ export const PGFdialogue: DialogueTranslationEntries = { "defeat": { 1: "Volte para me ver novamente, ouviu?" } + }, "tulip": { + "encounter": { + 1: "Permita-me usar minhas habilidades para deixar seus lindos Pokémon ainda mais bonitos!" + }, + "victory": { + 1: "Sua força tem uma magia que não pode ser apagada." + }, + "defeat": { + 1: "Você sabe, na minha linha de trabalho, pessoas que carecem de talento em uma área ou outra frequentemente desaparecem rapidamente - nunca mais se ouve falar delas." + } + }, + "sidney": { + "encounter": { + 1: `Gostei desse olhar que você me deu. Acho que você vai ser um bom desafio. + $Isso é ótimo! Parece muito bom! Vamos nessa! + $Você e eu, vamos curtir uma batalha que só pode acontecer aqui!`, + }, + "victory": { + 1: "E aí, gostou? Eu perdi! Mas foi divertido, então não importa." + }, + "defeat": { + 1: "Sem ressentimentos, beleza?" + } + }, + "phoebe": { + "encounter": { + 1: `Enquanto treinava, adquiri a habilidade de me comunicar com Pokémon do tipo Fantasma. + $Sim, o vínculo que desenvolvi com os Pokémon é extremamente forte. + $Então, vamos lá, tente ver se você consegue até mesmo causar dano aos meus Pokémon!`, + }, + "victory": { + 1: "Ah, droga. Eu perdi." + }, + "defeat": { + 1: "Estou ansiosa para batalhar com você de novo algum dia!" + } + }, + "glacia": { + "encounter": { + 1: `Tudo o que vi foram desafios de Treinadores fracos e seus Pokémon. + $E você? Ficaria extremamente satisfeita se pudesse dar tudo de mim contra você!`, + }, + "victory": { + 1: `Você e seus Pokémon… Como seus espíritos queimam! + $O calor consumido é esmagador. + $Não é surpresa que minhas habilidades geladas falharam em te machucar.`, + }, + "defeat": { + 1: "Uma batalha intensamente apaixonada, sem dúvida." + } + }, + "drake": { + "encounter": { + 1: `Para nós, batalhar com Pokémon como parceiros, você sabe o que é necessário? Você sabe o que precisa? + $Se não souber, nunca prevalecerá contra mim!`, + }, + "victory": { + 1: "Excelente, deve-se dizer." + }, + "defeat": { + 1: "Dei meu máximo nessa batalha!" + } }, "wallace": { "encounter": { @@ -3420,6 +4263,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Estou encantada! Sim, encantada por poder esmagar você sob meu calcanhar." } }, + "hala": { + "encounter": { + 1: "O velho Hala está aqui para fazer você gritar!" + }, + "victory": { + 1: "Pude sentir o poder que você ganhou na sua jornada." + }, + "defeat": { + 1: "Haha! Que batalha deliciosa!" + } + }, "molayne": { "encounter": { 1: `Dei a posição de capitão ao meu primo Sophocles, mas estou confiante na minha habilidade. @@ -3443,6 +4297,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Nahahaha! Você realmente é algo mais, garota!" } }, + "bruno": { + "encounter": { + 1: "Nós vamos te triturar com nosso poder superior! Hoo hah!" + }, + "victory": { + 1: "Por quê? Como eu poderia perder?" + }, + "defeat": { + 1: "Você pode me desafiar o quanto quiser, mas os resultados nunca vão mudar!" + } + }, "bugsy": { "encounter": { 1: "Sou Bugsy! Eu nunca perco quando se trata de Pokémon do tipo Inseto!" @@ -3454,6 +4319,30 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Obrigado! Graças à nossa batalha, eu também pude fazer progressos na minha pesquisa!" } }, + "koga": { + "encounter": { + 1: "Fwahahahaha! Pokémon não são apenas sobre força bruta--você verá em breve!" + }, + "victory": { + 1: "Ah! Você provou seu valor!" + }, + "defeat": { + 1: "Você aprendeu a temer as técnicas do ninja?" + } + }, + "bertha": { + "encounter": { + 1: "Bem, você mostraria a esta velha senhora o quanto aprendeu?" + }, + "victory": { + 1: `Bem! Querida criança, devo dizer, isso foi muito impressionante. + $Seus Pokémon acreditaram em você e fizeram o melhor para te dar a vitória. + $Mesmo tendo perdido, me encontro com esse sorriso bobo!`, + }, + "defeat": { + 1: "Hahahahah! Parece que esta velha senhora ganhou!" + } + }, "lenora": { "encounter": { 1: "Bem, desafiadora, vou pesquisar como você batalha com os Pokémon que criou com tanto carinho!" @@ -3465,6 +4354,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ah ha ha! Se você perder, certifique-se de analisar o porquê e use esse conhecimento na próxima batalha!" } }, + "siebold": { + "encounter": { + 1: "Enquanto eu estiver vivo, continuarei em busca da culinária suprema... e dos oponentes mais fortes em batalha!" + }, + "victory": { + 1: "Guardarei minha memória de você e seus Pokémon para sempre em meu coração." + }, + "defeat": { + 1: `Nossa batalha Pokémon foi como alimento para minha alma. Isso vai me manter em frente. + $É assim que vou prestar meus respeitos a você por dar tudo de si na batalha!`, + } + }, "roxie": { "encounter": { 1: "Prepare-se! Vou arrancar algum senso de você!" @@ -3476,6 +4377,40 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ei, vamos lá! Seja séria! Você tem que dar mais de si!" } }, + "olivia": { + "encounter": { + 1: "Não precisa de introdução aqui. Hora de batalhar comigo, Olivia!" + }, + "victory": { + 1: "Realmente encantador… Tanto você quanto seus Pokémon…" + }, + "defeat": { + 1: "Mmm-hmm." + } + }, + "poppy": { + "encounter": { + 1: "Oooh! Você quer ter uma batalha Pokémon comigo?" + }, + "victory": { + 1: "Uagh?! Mmmuuuggghhh…" + }, + "defeat": { + 1: `Yaaay! Eu consegui! Eu der-ro-tei você! Você pode vir para… Para… Uma revanche? + $Venha para uma revanche quando quiser!`, + } + }, + "agatha": { + "encounter": { + 1: "Pokémon são para batalhas! Vou te mostrar como um verdadeiro Treinador batalha!" + }, + "victory": { + 1: "Oh meu! Você é algo especial, criança!" + }, + "defeat": { + 1: "Bahaha. É assim que uma batalha adequada é feita!" + } + }, "flint": { "encounter": { 1: "Espero que você esteja aquecida, porque aqui vem o Big Bang!" @@ -3487,6 +4422,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Huh? Isso é tudo? Acho que você precisa de um pouco mais de paixão." } }, + "grimsley": { + "encounter": { + 1: "O vencedor leva tudo, e não sobra nada para o perdedor." + }, + "victory": { + 1: "Quando se perde, perde-se tudo… A próxima coisa que vou procurar será a vitória, também!" + }, + "defeat": { + 1: "Se alguém vence, a pessoa que lutou contra essa pessoa perde." + } + }, "caitlin": { "encounter": { 1: `Sou eu que apareci quando a flor se abriu. Você que estava esperando… @@ -3501,6 +4447,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Aspiro a reivindicar a vitória com elegância e graça." } }, + "diantha": { + "encounter": { + 1: `Batalhar contra você e seus Pokémon, todos vocês cheios de esperança para o futuro… + $Honestamente, isso apenas me enche da energia que preciso para continuar enfrentando cada novo dia! Sim!`, + }, + "victory": { + 1: "Testemunhar os espíritos nobres de você e seus Pokémon em batalha realmente tocou meu coração…" + }, + "defeat": { + 1: "Oh, fantástico! O que achou? Minha equipe foi bem legal, né?" + } + }, "wikstrom": { "encounter": { 1: `Bem encontrado, jovem desafiadora! Verdadeiramente sou a lâmina famosa de aço endurecido, Duque Wikstrom! @@ -3525,6 +4483,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ehaha! Que vitória incrível!" } }, + "larry_elite": { + "encounter": { + 1: `Olá… Sou eu, Larry. + $Eu também sou membro da Elite dos Quatro, sim… Infelizmente para mim.`, + }, + "victory": { + 1: "Bem, isso tirou o vento debaixo das nossas asas…" + }, + "defeat": { + 1: "É hora de uma reunião com o chefe." + } + }, "lance": { "encounter": { 1: "Estive esperando por você. Permita-me testar suas habilidades.", @@ -3539,6 +4509,23 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Não é que você seja fraca. Não se incomode com isso." } }, + "karen": { + "encounter": { + 1: "Eu sou Karen. Você gostaria de um duelo com meus Pokémon do tipo Sombrio?", + 2: "Sou diferente daqueles que você já conheceu.", + 3: "Você montou uma equipe charmosa. Nossa batalha deve ser boa." + }, + "victory": { + 1: "Não! Eu não posso vencer. Como você ficou tão forte?", + 2: "Não me desviarei do meu caminho escolhido.", + 3: "O Campeão está ansioso para te conhecer." + }, + "defeat": { + 1: "Isso era o que eu esperava.", + 2: "Bem, isso foi relativamente divertido.", + 3: "Venha me visitar a qualquer momento." + } + }, "milo": { "encounter": { 1: `Parece que você entende bem os Pokémon. @@ -3552,6 +4539,20 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Isso realmente vai te deixar em choque e admiração." } }, + "lucian": { + "encounter": { + 1: `Só um momento, por favor. O livro que estou lendo está quase no clímax emocionante… + $O herói obteve uma espada mística e está prestes a enfrentar sua prova final… Ah, tanto faz. + $Já que você chegou tão longe, vou deixar isso de lado e batalhar com você. + $Deixe-me ver se você alcançará tanta glória quanto o herói do meu livro!`, + }, + "victory": { + 1: "Eu vejo… Parece que você me colocou em xeque-mate." + }, + "defeat": { + 1: "Tenho uma reputação a manter." + } + }, "drasna": { "encounter": { 1: `Você deve ser uma Treinadora forte. Sim, bastante forte… @@ -3564,6 +4565,29 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Como isso é possível?" } }, + "kahili": { + "encounter": { + 1: "Então, aqui está você… Por que não vemos para quem os ventos favorecem hoje, você… ou eu?" + }, + "victory": { + 1: "É frustrante para mim como membro da Elite dos Quatro, mas parece que sua força é real." + }, + "defeat": { + 1: "Essa foi uma jogada de mestre!" + } + }, + "hassel": { + "encounter": { + 1: "Prepare-se para aprender em primeira mão como é a respiração ardente de uma batalha feroz!" + }, + "victory": { + 1: `A sorte sorriu para mim desta vez, mas… + $Julgando pelo andamento da luta, quem sabe se serei tão sortudo na próxima vez.`, + }, + "defeat": { + 1: "Essa foi uma jogada de mestre!" + } + }, "blue": { "encounter": { 1: "Você deve ser muito boa para chegar tão longe." @@ -3575,6 +4599,39 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Viu? Meu poder é o que me trouxe até aqui." } }, + "piers": { + "encounter": { + 1: "Prepare-se para uma mosh pit comigo e minha galera! Spikemuth, é hora de roquear!" + }, + "victory": { + 1: "Eu e minha equipe demos o nosso melhor. Vamos nos encontrar novamente para uma batalha algum dia…" + }, + "defeat": { + 1: "Minha garganta está desgastada de tanto gritar… Mas essa foi uma batalha empolgante!" + } + }, + "red": { + "encounter": { + 1: "…!" + }, + "victory": { + 1: "…?" + }, + "defeat": { + 1: "…!" + } + }, + "jasmine": { + "encounter": { + 1: "Oh… Seus Pokémon são impressionantes. Acho que vou gostar disso." + }, + "victory": { + 1: "Você é realmente forte. Vou ter que me esforçar muito mais também." + }, + "defeat": { + 1: "Eu nunca esperei ganhar." + } + }, "lance_champion": { "encounter": { 1: "Ainda sou o Campeão. Não vou segurar nada." @@ -3586,6 +4643,96 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Defendi com sucesso meu Campeonato." } }, + "steven": { + "encounter": { + 1: `Diga-me… O que você viu na sua jornada com seus Pokémon? + $O que você sentiu, encontrando tantos outros Treinadores por aí? + $Viajar por esta terra rica… Isso despertou algo dentro de você? + $Quero que você venha até mim com tudo o que aprendeu. + $Meus Pokémon e eu responderemos com tudo o que sabemos!`, + }, + "victory": { + 1: "Então eu, o Campeão, caio em derrota…" + }, + "defeat": { + 1: "Esse tempo foi bem gasto! Obrigado!" + } + }, + "cynthia": { + "encounter": { + 1: "Eu, Cynthia, aceito seu desafio! Não haverá nenhuma trégua da minha parte!" + }, + "victory": { + 1: "Não importa o quão divertida a batalha seja, ela sempre terminará algum dia…" + }, + "defeat": { + 1: "Mesmo que você perca, nunca perca o amor pelos Pokémon." + } + }, + "iris": { + "encounter": { + 1: `Sabe de uma coisa? Estou realmente ansiosa para ter batalhas sérias com Treinadores fortes! + $Quero dizer, vamos lá! Os Treinadores que chegam aqui são Treinadores que desejam a vitória com todas as fibras do seu ser! + $E eles estão batalhando ao lado de Pokémon que passaram por inúmeras batalhas difíceis! + $Se eu batalhar com pessoas assim, não só eu ficarei mais forte, meus Pokémon também! + $E nós vamos nos conhecer ainda melhor! OK! Prepare-se! + $Sou Iris, a Campeã da Liga Pokémon, e vou te derrotar!`, + }, + "victory": { + 1: "Aghhhh… Eu dei o meu melhor, mas nós perdemos…" + }, + "defeat": { + 1: "Yay! Nós vencemos!" + } + }, + "hau": { + "encounter": { + 1: `Eu me pergunto se um Treinador batalha de maneira diferente dependendo se ele é de uma região quente ou fria. + $Vamos testar isso!`, + }, + "victory": { + 1: "Isso foi incrível! Acho que entendi um pouco melhor seu estilo agora!" + }, + "defeat": { + 1: "Cara, essa foi uma batalha e tanto!" + } + }, + "geeta": { + "encounter": { + 1: `Decidi entrar na batalha mais uma vez. + $Venha agora… Mostre-me os frutos do seu treinamento.`, + }, + "victory": { + 1: "Estou ansiosa para notícias de todas as suas conquistas!" + }, + "defeat": { + 1: "Qual o problema? Isso é tudo?" + } + }, + "nemona": { + "encounter": { + 1: "Yesss! Estou tão empolgada! Hora de soltar tudo!" + }, + "victory": { + 1: "Bem, isso foi ruim, mas ainda me diverti! Eu te pego na próxima!" + }, + "defeat": { + 1: "Bem, essa foi uma ótima batalha! Frutífera, com certeza." + } + }, + "leon": { + "encounter": { + 1: "Vamos ter um tempo absolutamente campeão!" + }, + "victory": { + 1: `Meu tempo como Campeão acabou… + $Mas que tempo campeão foi! + $Obrigado pela melhor batalha que já tive!`, + }, + "defeat": { + 1: "Um tempo absolutamente campeão, foi!" + } + }, "whitney": { "encounter": { 1: "Eai! Você não acha que os Pokémon são, tipo, super fofos?" @@ -3619,6 +4766,28 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Coma, meu adorável Vivillon!" } }, + "pryce": { + "encounter": { + 1: "A juventude sozinha não garante a vitória! Experiência é o que conta." + }, + "victory": { + 1: "Excelente! Isso foi perfeito. Tente não esquecer o que sente agora." + }, + "defeat": { + 1: "Exatamente como eu imaginei." + } + }, + "clair": { + "encounter": { + 1: "Você sabe quem eu sou? E ainda se atreve a me desafiar?" + }, + "victory": { + 1: "Eu me pergunto até onde você pode ir com seu nível de habilidade. Isso deve ser fascinante." + }, + "defeat": { + 1: "E é isso." + } + }, "maylene": { "encounter": { 1: `Vim desafiá-la agora e não vou segurar nada. @@ -3631,6 +4800,18 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Isso foi incrível." } }, + "fantina": { + "encounter": { + 1: `Você vai me desafiar, não é? Mas eu vou ganhar. + $É o que a Líder do Ginásio de Hearthome faz, não?`, + }, + "victory": { + 1: "Você é tão incrivelmente forte. Sei porque perdi." + }, + "defeat": { + 1: "Estou tão, tão, muito feliz!" + } + }, "byron": { "encounter": { 1: `Treinadora! Você é jovem, assim como meu filho, Roark. @@ -3644,6 +4825,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Gwahahaha! Como foram meus Pokémon robustos?!" } }, + "olympia": { + "encounter": { + 1: "Um costume antigo decidindo o destino de alguém. A batalha começa!" + }, + "victory": { + 1: "Crie seu próprio caminho. Não deixe nada te atrapalhar. Seu destino, seu futuro." + }, + "defeat": { + 1: "Nosso caminho está claro agora." + } + }, "volkner": { "encounter": { 1: `Já que você chegou tão longe, deve ser bastante forte… @@ -3659,6 +4851,108 @@ export const PGFdialogue: DialogueTranslationEntries = { $Isso não é o que eu queria!`, } }, + "burgh": { + "encounter": { + 1: `M'hm… Se eu ganhar esta batalha, sinto que posso desenhar um quadro diferente de qualquer outro. + $OK! Posso ouvir minha musa da batalha claramente. Vamos direto ao ponto!`, + 2: `Claro, estou realmente orgulhoso de todos os meus Pokémon! + $Bem agora… Vamos direto ao ponto!` + }, + "victory": { + 1: "Acabou? Minha musa me abandonou?", + 2: "Hmm… Acabou! Você é incrível!" + }, + "defeat": { + 1: "Uau… É bonito de alguma forma, não é…", + 2: `Às vezes ouço as pessoas dizerem que foi uma vitória feia. + $Acho que se você está dando o seu melhor, qualquer vitória é bonita.` + } + }, + "elesa": { + "encounter": { + 1: `C'est fini! Quando tenho certeza disso, sinto um choque elétrico percorrer meu corpo! + $Quero sentir essa sensação, então agora meus amados Pokémon vão fazer sua cabeça girar!`, + }, + "victory": { + 1: "Eu queria fazer sua cabeça girar, mas você me surpreendeu." + }, + "defeat": { + 1: "Isso foi insatisfatório de alguma forma… Você dará tudo de si na próxima vez?" + } + }, + "skyla": { + "encounter": { + 1: `Finalmente é hora do confronto! Isso significa a batalha Pokémon que decide quem está no topo, certo? + $Eu amo estar no topo! Porque você pode ver para sempre e sempre de lugares altos! + $Então, que tal nós nos divertirmos?`, + }, + "victory": { + 1: "Ser seu oponente na batalha é uma nova fonte de força para mim. Obrigada!" + }, + "defeat": { + 1: "Ganhar ou perder, você sempre ganha algo com uma batalha, certo?" + } + }, + "brycen": { + "encounter": { + 1: `Há também força em estar com outras pessoas e Pokémon. + $Receber o apoio deles te fortalece. Vou te mostrar esse poder!`, + }, + "victory": { + 1: "A maravilhosa combinação de você e seus Pokémon! Que amizade linda!" + }, + "defeat": { + 1: "Condições extremas realmente testam e treinam você!" + } + }, + "drayden": { + "encounter": { + 1: `O que eu quero encontrar é um jovem Treinador que possa me mostrar um futuro brilhante. + $Vamos batalhar com tudo o que temos: sua habilidade, minha experiência e o amor com que criamos nossos Pokémon!`, + }, + "victory": { + 1: "Esse sentimento intenso que me invade após uma derrota… Não sei como descrevê-lo." + }, + "defeat": { + 1: "Harrumph! Sei que sua habilidade é maior que isso!" + } + }, + "grant": { + "encounter": { + 1: `Só há uma coisa que desejo. + $Que, superando um ao outro, encontremos um caminho para alturas ainda maiores.`, + }, + "victory": { + 1: "Você é uma parede que não consigo superar!" + }, + "defeat": { + 1: `Não desista. + $Isso é tudo o que realmente importa. + $As lições mais importantes da vida são simples.`, + } + }, + "korrina": { + "encounter": { + 1: "Hora da grande aparição de Lady Korrina!" + }, + "victory": { + 1: "É o seu próprio ser que permite que seus Pokémon evoluam!" + }, + "defeat": { + 1: "Que batalha explosiva!" + } + }, + "clemont": { + "encounter": { + 1: "Oh! Estou feliz por termos nos encontrado!" + }, + "victory": { + 1: "Sua paixão pela batalha me inspira!" + }, + "defeat": { + 1: "Parece que minha Máquina Treinadora-Crescer-Forte, Mach 2 está realmente funcionando!" + } + }, "valerie": { "encounter": { 1: `Oh, se não é uma jovem Treinadora… É adorável conhecê-la assim. @@ -3732,6 +5026,42 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Bom trabalho, eu suponho." } }, + "gordie": { + "encounter": { + 1: "Então, vamos acabar com isso." + }, + "victory": { + 1: "Eu só quero me enterrar em um buraco… Bem, acho que seria mais como cair daqui." + }, + "defeat": { + 1: "Batalhe como sempre faz, a vitória seguirá!" + } + }, + "marnie": { + "encounter": { + 1: `A verdade é que, quando tudo está dito e feito… Eu realmente só quero me tornar Campeã por mim mesma! + $Então, não leve para o pessoal quando eu chutar seu traseiro!`, + }, + "victory": { + 1: "OK, então eu perdi… Mas consegui ver muitos dos pontos bons de você e seus Pokémon!" + }, + "defeat": { + 1: "Espero que você tenha gostado das nossas táticas de batalha." + } + }, + "raihan": { + "encounter": { + 1: "Vou derrotar o Campeão, vencer todo o torneio e provar ao mundo o quão forte o grande Raihan realmente é!" + }, + "victory": { + 1: `Eu pareço bem mesmo quando perco. + $É uma verdadeira maldição. + $Acho que é hora de mais uma selfie!`, + }, + "defeat": { + 1: "Vamos tirar uma selfie para lembrar disso." + } + }, "brassius": { "encounter": { 1: "Pressuponho que você está pronta? Que nossa obra de arte colaborativa comece!" @@ -3757,6 +5087,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Seus olhos são MEUS!" } }, + "larry": { + "encounter": { + 1: "Quando tudo está dito e feito, a simplicidade é mais forte." + }, + "victory": { + 1: "Uma porção de derrota, hein?" + }, + "defeat": { + 1: "Vou encerrar o dia." + } + }, "ryme": { "encounter": { 1: "Vamos lá, baby! Me agite até os ossos!" @@ -3768,6 +5109,31 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Até mais, baby!" } }, + "grusha": { + "encounter": { + 1: "Tudo o que preciso fazer é garantir que o poder do meu Pokémon te arrependa até os ossos!" + }, + "victory": { + 1: "Sua paixão ardente... Eu meio que gosto, para ser honesto." + }, + "defeat": { + 1: "As coisas não esquentaram para você." + } + }, + "marnie_elite": { + "encounter": { + 1: "Você chegou até aqui, hein? Vamos ver se você pode lidar com meus Pokémon!", + 2: "Vou dar o meu melhor, mas não pense que vou pegar leve com você!" + }, + "victory": { + 1: "Não acredito que perdi... Mas você mereceu essa vitória. Bem feito!", + 2: "Parece que ainda tenho muito a aprender. Porém, grande batalha!" + }, + "defeat": { + 1: "Você lutou bem, mas eu tenho a vantagem! Melhor sorte na próxima vez!", + 2: "Parece que meu treinamento valeu a pena. Obrigado pela batalha!" + } + }, "nessa_elite": { "encounter": { 1: "As marés estão mudando a meu favor. Pronta para ser levada pela corrente?", @@ -3782,6 +5148,20 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Você lutou bem, mas o poder do oceano é imparável!" } }, + "bea_elite": { + "encounter": { + 1: "Prepare-se! Meu espírito de luta brilha intensamente!", + 2: "Vamos ver se você consegue acompanhar meu ritmo implacável!" + }, + "victory": { + 1: "Sua força... É impressionante. Você realmente merece essa vitória.", + 2: "Nunca senti essa intensidade antes. Trabalho incrível!" + }, + "defeat": { + 1: "Outra vitória para meu rigoroso regime de treinamento! Bem feito!", + 2: "Você tem força, mas eu treinei mais. Grande batalha!" + } + }, "allister_elite": { "encounter": { 1: "As sombras caem... Você está pronta para enfrentar seus medos?", @@ -3810,6 +5190,32 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Você foi pega na minha tempestade! Melhor sorte na próxima vez!" } }, + "alder": { + "encounter": { + 1: "Se prepare para uma batalha contra o Treinador mais forte de Unova!" + }, + "victory": { + 1: "Muito bem! Você certamente é um talento incomparável." + }, + "defeat": { + 1: `Um vento fresco sopra em meu coração... + $Que esforço extraordinário!` + } + }, + "kieran": { + "encounter": { + 1: `Através do trabalho duro, eu me torno cada vez mais forte! + $Eu não perco.` + }, + "victory": { + 1: `Eu não acredito... + $Que batalha divertida e emocionante!` + }, + "defeat": { + 1: `Uau, que batalha! + $Hora de você treinar ainda mais.` + } + }, "rival": { "encounter": { 1: `@c{smile}Eai, estava procurando você! Sabia que você estava ansiosa para começar, mas esperava pelo menos um tchau… diff --git a/src/locales/pt_BR/menu.ts b/src/locales/pt_BR/menu.ts index 927ccce518b..87be5d8bed0 100644 --- a/src/locales/pt_BR/menu.ts +++ b/src/locales/pt_BR/menu.ts @@ -35,11 +35,11 @@ export const menu: SimpleTranslationEntries = { "sessionSuccess": "Sessão carregada com sucesso.", "failedToLoadSession": "Não foi possível carregar os dados da sua sessão.\nEles podem estar corrompidos.", "boyOrGirl": "Você é um menino ou uma menina?", - "evolving": "Que?\n{{pokemonName}} tá evoluindo!", + "evolving": "Quê?\n{{pokemonName}} tá evoluindo!", "stoppedEvolving": "{{pokemonName}} parou de evoluir.", "pauseEvolutionsQuestion": "Gostaria de pausar evoluções para {{pokemonName}}?\nEvoluções podem ser religadas na tela de equipe.", "evolutionsPaused": "Evoluções foram paradas para {{pokemonName}}.", - "evolutionDone": "Parabéns!\nSeu {{pokemonName}} evolui para {{evolvedPokemonName}}!", + "evolutionDone": "Parabéns!\nSeu {{pokemonName}} evoluiu para {{evolvedPokemonName}}!", "dailyRankings": "Classificação Diária", "weeklyRankings": "Classificação Semanal", "noRankings": "Sem Classificação", diff --git a/src/locales/pt_BR/modifier.ts b/src/locales/pt_BR/modifier.ts index 168665205c3..eadd5c5667a 100644 --- a/src/locales/pt_BR/modifier.ts +++ b/src/locales/pt_BR/modifier.ts @@ -4,7 +4,7 @@ export const modifier: SimpleTranslationEntries = { "surviveDamageApply": "{{pokemonNameWithAffix}} aguentou o tranco\nusando sua {{typeName}}!", "turnHealApply": "{{pokemonNameWithAffix}} restaurou um pouco de PS usando\nsuas {{typeName}}!", "hitHealApply": "{{pokemonNameWithAffix}} restaurou um pouco de PS usando\nsua {{typeName}}!", - "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} foi revivido\npor sua {{typeName}}!", + "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} foi reanimado\npor sua {{typeName}}!", "pokemonResetNegativeStatStageApply": "Os atributos diminuídos de {{pokemonNameWithAffix}} foram\nrestaurados por seu(sua) {{typeName}}!", "moneyInterestApply": "Você recebeu um juros de ₽{{moneyAmount}}\nde sua {{typeName}}!", "turnHeldItemTransferApply": "{{itemName}} de {{pokemonNameWithAffix}} foi absorvido(a)\npelo {{typeName}} de {{pokemonName}}!", diff --git a/src/locales/pt_BR/move-trigger.ts b/src/locales/pt_BR/move-trigger.ts index 042d539338e..620f867ae9a 100644 --- a/src/locales/pt_BR/move-trigger.ts +++ b/src/locales/pt_BR/move-trigger.ts @@ -26,7 +26,7 @@ export const moveTriggers: SimpleTranslationEntries = { "soothingAromaWaftedThroughArea": "Um aroma suave se espalhou pelo ambiente!", "sprangUp": "{{pokemonName}} se levantou!", "choseDoomDesireAsDestiny": "{{pokemonName}} escolheu\no Desejo da Perdição como seu destino!", - "vanishedInstantly": "{{pokemonName}} desapareceu/nde repente!", + "vanishedInstantly": "{{pokemonName}} desapareceu\nde repente!", "tookTargetIntoSky": "{{pokemonName}} levou {{targetName}}\npara o céu!", "becameCloakedInFreezingLight": "{{pokemonName}} ficou envolto/nem uma luz congelante!", "becameCloakedInFreezingAir": "{{pokemonName}} ficou envolto/nem ar congelante!", diff --git a/src/locales/pt_BR/party-ui-handler.ts b/src/locales/pt_BR/party-ui-handler.ts index 08132b4bfc0..1f3e0fbe242 100644 --- a/src/locales/pt_BR/party-ui-handler.ts +++ b/src/locales/pt_BR/party-ui-handler.ts @@ -15,7 +15,7 @@ export const partyUiHandler: SimpleTranslationEntries = { "ALL": "Tudo", "PASS_BATON": "Passar Bastão", "UNPAUSE_EVOLUTION": "Ativar Evolução", - "REVIVE": "Reviver", + "REVIVE": "Reanimar", "RENAME": "Renomear", "choosePokemon": "Escolha um Pokémon.", diff --git a/src/locales/pt_BR/pokemon-form.ts b/src/locales/pt_BR/pokemon-form.ts index 062fc165ae0..dbe63fb7864 100644 --- a/src/locales/pt_BR/pokemon-form.ts +++ b/src/locales/pt_BR/pokemon-form.ts @@ -29,7 +29,7 @@ export const pokemonForm: SimpleTranslationEntries = { "pikachuPartner": "Parceiro", "eeveePartner": "Parceiro", // 2G - "pichuSpiky": "Spiky", + "pichuSpiky": "Orelha Espetada", "unownA": "A", "unownB": "B", "unownC": "C", @@ -74,8 +74,8 @@ export const pokemonForm: SimpleTranslationEntries = { "rotomFrost": "Congelante", "rotomFan": "Ventilador", "rotomMow": "Corte", - "giratinaAltered": "Altered", - "shayminLand": "Land", + "giratinaAltered": "Alterado", + "shayminLand": "Terrestre", // 5G "basculinRedStriped": "Listras Vermelhas", "basculinBlueStriped": "Listras Azuis", @@ -84,11 +84,11 @@ export const pokemonForm: SimpleTranslationEntries = { "deerlingSummer": "Verão", "deerlingAutumn": "Outono", "deerlingWinter": "Inverno", - "tornadusIncarnate": "Incarnate", - "thundurusIncarnate": "Incarnate", - "landorusIncarnate": "Incarnate", - "keldeoOrdinary": "Ordinary", - "meloettaAria": "Aria", + "tornadusIncarnate": "Materializado", + "thundurusIncarnate": "Materializado", + "landorusIncarnate": "Materializado", + "keldeoOrdinary": "Comum", + "meloettaAria": "Ária", // 6G "froakieBattleBond": "Vínculo de Batalha", "scatterbugMeadow": "Prado", @@ -165,11 +165,11 @@ export const pokemonForm: SimpleTranslationEntries = { "eiscueNoIce": "Descongelado", "indeedeeMale": "Macho", "indeedeeFemale": "Fêmea", - "morpekoFullBelly": "Full Belly", - "zacianHeroOfManyBattles": "Hero Of Many Battles", - "zamazentaHeroOfManyBattles": "Hero Of Many Battles", + "morpekoFullBelly": "Saciado", + "zacianHeroOfManyBattles": "Herói Veterano", + "zamazentaHeroOfManyBattles": "Herói Veterano", "zarudeDada": "Papa", - "enamorusIncarnate": "Incarnate", + "enamorusIncarnate": "Materializado", // 9G "squawkabillyGreenPlumage": "Plumas Verdes", "squawkabillyBluePlumage": "Plumas Azuis", From 3a9d24c49a54e18732a42a68f2760fc03816624c Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:44:37 -0700 Subject: [PATCH 32/63] [Bug] Fix Jaw Lock leaving the user trapped after the target faints (#3450) * Fix Jaw Lock not removing TRAPPED tag after enemy faints * Create tests for Jaw Lock * Fix overrides import * Clean up implementation + tests * minor style change to phases * Update src/data/move.ts Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> * Jaw Lock no longer overlaps its trapping effect * Friendship ended with JAW_LOCK tag type Now TRAPPED is my new best friend --------- Co-authored-by: EmberCM Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --- src/data/move.ts | 36 ++++++- src/test/moves/jaw_lock.test.ts | 172 ++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 src/test/moves/jaw_lock.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index acb61042e70..51ba4058140 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4438,6 +4438,39 @@ export class GulpMissileTagAttr extends MoveEffectAttr { } } +/** + * Attribute to implement Jaw Lock's linked trapping effect between the user and target + * @extends AddBattlerTagAttr + */ +export class JawLockAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.TRAPPED); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.canApply(user, target, move, args)) { + return false; + } + + // If either the user or the target already has the tag, do not apply + if (user.getTag(TrappedTag) || target.getTag(TrappedTag)) { + return false; + } + + const moveChance = this.getMoveChance(user, target, move, this.selfTarget); + if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) { + /** + * Add the tag to both the user and the target. + * The target's tag source is considered to be the user and vice versa + */ + return target.addTag(BattlerTagType.TRAPPED, 1, move.id, user.id) + && user.addTag(BattlerTagType.TRAPPED, 1, move.id, target.id); + } + + return false; + } +} + export class CurseAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean { @@ -8313,8 +8346,7 @@ export function initMoves() { .attr(HighCritAttr) .attr(BypassRedirectAttr), new AttackMove(Moves.JAW_LOCK, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8) - .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, false, true) - .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1, 1, false, true) + .attr(JawLockAttr) .bitingMove(), new SelfStatusMove(Moves.STUFF_CHEEKS, Type.NORMAL, -1, 10, -1, 0, 8) // TODO: Stuff Cheeks should not be selectable when the user does not have a berry, see wiki .attr(EatBerryAttr) diff --git a/src/test/moves/jaw_lock.test.ts b/src/test/moves/jaw_lock.test.ts new file mode 100644 index 00000000000..4fe996588e4 --- /dev/null +++ b/src/test/moves/jaw_lock.test.ts @@ -0,0 +1,172 @@ +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import GameManager from "#app/test/utils/gameManager"; +import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "#app/test/utils/testUtils"; +import { BattlerIndex } from "#app/battle"; +import { FaintPhase } from "#app/phases/faint-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { BerryPhase } from "#app/phases/berry-phase"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Jaw Lock", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.INSOMNIA) + .enemyMoveset(SPLASH_ONLY) + .moveset([Moves.JAW_LOCK, Moves.SPLASH]) + .startingLevel(100) + .enemyLevel(100) + .disableCrits(); + }); + + it( + "should trap the move's user and target", + async () => { + await game.startBattle([ Species.BULBASAUR ]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + + await game.phaseInterceptor.to(MoveEffectPhase, false); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + + await game.phaseInterceptor.to(TurnEndPhase); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeDefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeDefined(); + }, TIMEOUT + ); + + it( + "should not trap either pokemon if the target faints", + async () => { + game.override.enemyLevel(1); + await game.startBattle([ Species.BULBASAUR ]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + + await game.phaseInterceptor.to(MoveEffectPhase, false); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + + await game.phaseInterceptor.to(FaintPhase); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + }, TIMEOUT + ); + + it( + "should only trap the user until the target faints", + async () => { + await game.startBattle([ Species.BULBASAUR ]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeDefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeDefined(); + + await game.phaseInterceptor.to(TurnEndPhase); + + await game.doKillOpponents(); + + expect(leadPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + }, TIMEOUT + ); + + it( + "should not trap other targets after the first target is trapped", + async () => { + game.override.battleType("double"); + + await game.startBattle([ Species.CHARMANDER, Species.BULBASAUR ]); + + const playerPokemon = game.scene.getPlayerField(); + const enemyPokemon = game.scene.getEnemyField(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.doSelectTarget(BattlerIndex.ENEMY); + + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(playerPokemon[0].getTag(BattlerTagType.TRAPPED)).toBeDefined(); + expect(enemyPokemon[0].getTag(BattlerTagType.TRAPPED)).toBeDefined(); + + await game.toNextTurn(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.doSelectTarget(BattlerIndex.ENEMY_2); + + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(enemyPokemon[1].getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(playerPokemon[0].getTag(BattlerTagType.TRAPPED)).toBeDefined(); + expect(playerPokemon[0].getTag(BattlerTagType.TRAPPED)?.sourceId).toBe(enemyPokemon[0].id); + }, TIMEOUT + ); + + it( + "should not trap either pokemon if the target is protected", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.PROTECT)); + + await game.startBattle([ Species.BULBASAUR ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + + await game.phaseInterceptor.to(BerryPhase, false); + + expect(playerPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + }, TIMEOUT + ); +}); From 6defc8c8f93664e0822793f4d1882bb8e307c34a Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:28:10 -0700 Subject: [PATCH 33/63] Fix Rollout test (#3660) --- src/test/moves/rollout.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts index 1fc208c6724..cad65768a1c 100644 --- a/src/test/moves/rollout.test.ts +++ b/src/test/moves/rollout.test.ts @@ -1,13 +1,13 @@ import { allMoves } from "#app/data/move.js"; import { CommandPhase } from "#app/phases/command-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Rollout", () => { let phaserGame: Phaser.Game; @@ -29,9 +29,9 @@ describe("Moves - Rollout", () => { game.override.disableCrits(); game.override.battleType("single"); game.override.starterSpecies(Species.RATTATA); - game.override.ability(Abilities.NONE); + game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.BIDOOF); - game.override.enemyAbility(Abilities.NONE); + game.override.enemyAbility(Abilities.BALL_FETCH); game.override.startingLevel(100); game.override.enemyLevel(100); game.override.enemyMoveset(SPLASH_ONLY); From f162c6af89cb8069c23abca70b7623e969e4cf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:06:01 +0200 Subject: [PATCH 34/63] Update ability-trigger.ts (IT) (#3546) * Update ability-trigger.ts (IT) * Update ability-trigger.ts --- src/locales/it/ability-trigger.ts | 68 +++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/locales/it/ability-trigger.ts b/src/locales/it/ability-trigger.ts index 95db5cbf26c..c834fa28fbe 100644 --- a/src/locales/it/ability-trigger.ts +++ b/src/locales/it/ability-trigger.ts @@ -25,39 +25,39 @@ export const abilityTriggers: SimpleTranslationEntries = { "postAttackStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{defenderName}}!", "postDefendStealHeldItem": "{{pokemonNameWithAffix}} ruba\n{{stolenItemType}} di {{attackerName}}!", "copyFaintedAllyAbility": "L'abilità {{abilityName}} di {{pokemonNameWithAffix}} è passata all'alleato!", - "intimidateImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}} prevented it from being Intimidated!", - "postSummonAllyHeal": "{{pokemonNameWithAffix}} drank down all the\nmatcha that {{pokemonName}} made!", - "postSummonClearAllyStats": "{{pokemonNameWithAffix}}'s stat changes\nwere removed!", - "postSummonTransform": "{{pokemonNameWithAffix}} transformed\ninto {{targetName}}!", - "protectStat": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents lowering its {{statName}}!", - "statusEffectImmunityWithName": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{statusEffectName}}!", - "statusEffectImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents status problems!", - "battlerTagImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{battlerTagName}}!", - "forewarn": "{{pokemonNameWithAffix}} was forewarned about {{moveName}}!", - "frisk": "{{pokemonNameWithAffix}} frisked {{opponentName}}'s {{opponentAbilityName}}!", - "postWeatherLapseHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", - "postWeatherLapseDamage": "{{pokemonNameWithAffix}} is hurt\nby its {{abilityName}}!", - "postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}} harvested one {{berryName}}!", - "postTurnHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", - "fetchBall": "{{pokemonNameWithAffix}} found a\n{{pokeballName}}!", - "healFromBerryUse": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP!", - "arenaTrap": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents switching!", - "postBattleLoot": "{{pokemonNameWithAffix}} picked up\n{{itemName}}!", - "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", - "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", - "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", - "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", - "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", - "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", - "postSummonTeravolt": "{{pokemonNameWithAffix}} is radiating a bursting aura!", - "postSummonDarkAura": "{{pokemonNameWithAffix}} is radiating a Dark Aura!", - "postSummonFairyAura": "{{pokemonNameWithAffix}} is radiating a Fairy Aura!", - "postSummonNeutralizingGas": "{{pokemonNameWithAffix}}'s Neutralizing Gas filled the area!", - "postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} has two Abilities!", - "postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} has two Abilities!", - "postSummonVesselOfRuin": "{{pokemonNameWithAffix}}'s Vessel of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonSwordOfRuin": "{{pokemonNameWithAffix}}'s Sword of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonTabletsOfRuin": "{{pokemonNameWithAffix}}'s Tablets of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonBeadsOfRuin": "{{pokemonNameWithAffix}}'s Beads of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", + "intimidateImmunity": "{{abilityName}} impedisce a {{pokemonNameWithAffix}} di\nessere intimidito!", + "postSummonAllyHeal": "{{pokemonNameWithAffix}} beve il\ntè che {{pokemonName}} gli ha preparato!", + "postSummonClearAllyStats": "Le statistiche di {{pokemonNameWithAffix}}\ntornano alla normalità!", + "postSummonTransform": "{{pokemonNameWithAffix}} assume le sembianze\ndi {{targetName}}!", + "protectStat": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene la riduzione del/della suo/a {{statName}}!", + "statusEffectImmunityWithName": "{{abilityName}} di {{pokemonNameWithAffix}}\nnon gli fa subire il/lo/la {{statusEffectName}}!", + "statusEffectImmunity": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene i problemi di stato!", + "battlerTagImmunity": "{{abilityName}} di {{pokemonNameWithAffix}}\npreviene {{battlerTagName}}!", + "forewarn": "{{pokemonNameWithAffix}} è stato messo in guardia da {{moveName}}!", + "frisk": "{{pokemonNameWithAffix}} perquisice {{opponentName}}\ne trova la sua abilità, {{opponentAbilityName}}!", + "postWeatherLapseHeal": "{{pokemonNameWithAffix}} recupera alcuni PS\ncon {{abilityName}}!", + "postWeatherLapseDamage": "{{pokemonNameWithAffix}} subisce danni\na causa della sua abilità, {{abilityName}}!", + "postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}} raccoglie una {{berryName}}!", + "postTurnHeal": "{{pokemonNameWithAffix}} recupera alcuni PS\ncon {{abilityName}}!", + "fetchBall": "{{pokemonNameWithAffix}} ha trovato una\n{{pokeballName}}!", + "healFromBerryUse": "{{abilityName}} di {{pokemonNameWithAffix}}\nristabilisce parte dei PS!", + "arenaTrap": "L’abilità {{abilityName}} di {{pokemonNameWithAffix}}\nimpedisce la sostituzione!", + "postBattleLoot": "{{pokemonNameWithAffix}} ha raccolto\nil/l'/lo/la {{itemName}}!", + "postFaintContactDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", + "postFaintHpDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", + "postSummonPressure": "{{pokemonNameWithAffix}} fa pressione!", + "postSummonMoldBreaker": "{{pokemonNameWithAffix}} ha l’abilità Rompiforma!", + "postSummonAnticipation": "{{pokemonNameWithAffix}} rabbrividisce!", + "postSummonTurboblaze": "{{pokemonNameWithAffix}} emana un’aura infuocata!", + "postSummonTeravolt": "{{pokemonNameWithAffix}} emana un’aura repulsiva!", + "postSummonDarkAura": "L’abilità Auratetra di {{pokemonNameWithAffix}} è attiva.", + "postSummonFairyAura": "L’abilità Aurafolletto di {{pokemonNameWithAffix}} è attiva.", + "postSummonNeutralizingGas": "Il Gas Reagente di {{pokemonNameWithAffix}}\nsi diffonde tutt’intorno!", + "postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} ha due abilità!", + "postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} ha due abilità!", + "postSummonVesselOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Vaso Nefasto di {{pokemonNameWithAffix}}!", + "postSummonSwordOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Spada Nefasta di {{pokemonNameWithAffix}}!", + "postSummonTabletsOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Amuleto Nefasto di {{pokemonNameWithAffix}}!", + "postSummonBeadsOfRuin": "La/l'{{statName}} dei Pokémon intorno si indebolisce a causa\ndell'abilità Monile Nefasto di {{pokemonNameWithAffix}}!", "preventBerryUse": "{{pokemonNameWithAffix}} non riesce a\nmangiare le bacche per l'agitazione!", } as const; From 677331221883a5d2bb8370a988fd4be8abc36ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:06:18 +0200 Subject: [PATCH 35/63] Update achv.ts (IT) (#3558) --- src/locales/it/achv.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/it/achv.ts b/src/locales/it/achv.ts index 91222b81579..756d95e6431 100644 --- a/src/locales/it/achv.ts +++ b/src/locales/it/achv.ts @@ -170,8 +170,8 @@ export const PGMachv: AchievementTranslationEntries = { description: "Vinci in modalità classica", }, "UNEVOLVED_CLASSIC_VICTORY": { - name: "Bring Your Child To Work Day", - description: "Beat the game in Classic Mode with at least one unevolved party member." + name: "Alternanza scuola-lavoro", + description: "Completa la modalità classica con almeno un membro della squadra non evoluto completamente." }, "MONO_GEN_ONE": { @@ -269,8 +269,8 @@ export const PGMachv: AchievementTranslationEntries = { name: "Follettini e follettine", }, "FRESH_START": { - name: "First Try!", - description: "Complete the Fresh Start challenge." + name: "Buona la prima!", + description: "Completa la modalità sfida 'Un nuovo inizio'." } } as const; From 767d802b942595008b6683efc7b1c3c8410bc662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:06:34 +0200 Subject: [PATCH 36/63] Update challenges.ts (IT) (#3559) --- src/locales/it/challenges.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/it/challenges.ts b/src/locales/it/challenges.ts index 784791f5425..dde5bd0d4e7 100644 --- a/src/locales/it/challenges.ts +++ b/src/locales/it/challenges.ts @@ -2,7 +2,7 @@ import { TranslationEntries } from "#app/interfaces/locales"; export const challenges: TranslationEntries = { "title": "Modificatori delle sfide", - "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!", + "illegalEvolution": "{{pokemon}} non è più utilizzabile\nsecondo le regole della sfida!", "singleGeneration": { "name": "Mono gen", "desc": "Puoi usare solo Pokémon di {{gen}} generazione.", @@ -23,8 +23,8 @@ export const challenges: TranslationEntries = { "desc_default": "Puoi usare solo Pokémon del tipo selezionato." }, "freshStart": { - "name": "Fresh Start", - "desc": "You can only use the original starters, and only as if you had just started PokéRogue.", + "name": "Un nuovo inizio", + "desc": "Puoi usare solo gli starter originali, e come se avessi appena cominciato Pokérogue.", "value.0": "Off", "value.1": "On", } From 2dc9900522dc8d9015dfc580d47a892e1543700a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:06:44 +0200 Subject: [PATCH 37/63] Update battle.ts (IT) (#3560) --- src/locales/it/battle.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts index bd7227eacb6..347a9968e96 100644 --- a/src/locales/it/battle.ts +++ b/src/locales/it/battle.ts @@ -74,22 +74,22 @@ export const battle: SimpleTranslationEntries = { "fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!", "statsAnd": "e", "stats": "statistiche", - "statRose_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a!", - "statRose_other": "{{pokemonNameWithAffix}}'s {{stats}} rose!", - "statSharplyRose_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a molto!", - "statSharplyRose_other": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!", - "statRoseDrastically_one": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a drasticamente!", - "statRoseDrastically_other": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!", - "statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}'s {{stats}} non può aumentare più di così!", - "statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!", - "statFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a!", - "statFell_other": "{{pokemonNameWithAffix}}'s {{stats}} fell!", - "statHarshlyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a molto!", - "statHarshlyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!", - "statSeverelyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a drasticamente!", - "statSeverelyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!", - "statWontGoAnyLower_one": "{{pokemonNameWithAffix}}'s {{stats}} non può diminuire più di così!", - "statWontGoAnyLower_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!", + "statRose_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata!", + "statRose_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate!", + "statSharplyRose_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata molto!", + "statSharplyRose_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate molto!", + "statRoseDrastically_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è aumentata drasticamente!", + "statRoseDrastically_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono aumentate drasticamente!", + "statWontGoAnyHigher_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} non può aumentare di più!", + "statWontGoAnyHigher_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} non possono aumentare di più!", + "statFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita!", + "statFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite!", + "statHarshlyFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita molto!", + "statHarshlyFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite molto!", + "statSeverelyFell_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} è diminuita drasticamente!", + "statSeverelyFell_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} sono diminuite drasticamente!", + "statWontGoAnyLower_one": "La statistica {{stats}} di {{pokemonNameWithAffix}} non può diminuire di più!", + "statWontGoAnyLower_other": "Le statistiche {{stats}} di {{pokemonNameWithAffix}} non possono diminuire di più!", "transformedIntoType": "{{pokemonName}} diventa\ndi tipo {{type}} type!", "retryBattle": "Vuoi riprovare dall'inizio della lotta?", "unlockedSomething": "{{unlockedThing}}\nè stato/a sbloccato/a.", From 548f7fce6f16c4d19fea6ca0afbf8bbede176786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:07:00 +0200 Subject: [PATCH 38/63] Update battler-tags.ts (IT) (#3561) --- src/locales/it/battler-tags.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/locales/it/battler-tags.ts b/src/locales/it/battler-tags.ts index 7dd3ebc6fb1..518e9194521 100644 --- a/src/locales/it/battler-tags.ts +++ b/src/locales/it/battler-tags.ts @@ -1,14 +1,14 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const battlerTags: SimpleTranslationEntries = { - "trappedDesc": "trapping", - "flinchedDesc": "flinching", - "confusedDesc": "confusion", - "infatuatedDesc": "infatuation", - "seedDesc": "seeding", - "nightmareDesc": "nightmares", - "ingrainDesc": "roots", - "drowsyDesc": "drowsiness", + "trappedDesc": "intrappolando", + "flinchedDesc": "tentennando", + "confusedDesc": "confuso", + "infatuatedDesc": "infatuato", + "seedDesc": "pieno di semi", + "nightmareDesc": "incubi", + "ingrainDesc": "radici", + "drowsyDesc": "assonnato", "rechargingLapse": "{{pokemonNameWithAffix}} deve\nricaricarsi!", "trappedOnAdd": "{{pokemonNameWithAffix}} non può\npiù fuggire!", "trappedOnRemove": "{{pokemonNameWithAffix}} è stato liberato\nda {{moveName}}", From 742b5432aaded32c5383c37bd740fa24fdf09d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:07:15 +0200 Subject: [PATCH 39/63] Update menu-ui-handler.ts (IT) (#3562) --- src/locales/it/menu-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/it/menu-ui-handler.ts b/src/locales/it/menu-ui-handler.ts index 0cfea8d67b7..3454de24f87 100644 --- a/src/locales/it/menu-ui-handler.ts +++ b/src/locales/it/menu-ui-handler.ts @@ -25,5 +25,5 @@ export const menuUiHandler: SimpleTranslationEntries = { "unlinkGoogle": "Scollega Google", "cancel": "Annulla", "losingProgressionWarning": "Perderai tutti i progressi dall'inizio della battaglia. Confermi?", - "noEggs": "You are not hatching\nany eggs at the moment!" + "noEggs": "Non stai schiudendo\nuova al momento!" } as const; From 3e44c4552c570a09ffa9f2e9b166b8d4ed2a3359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:07:25 +0200 Subject: [PATCH 40/63] Update menu.ts (IT) (#3563) --- src/locales/it/menu.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index 9766708f7ae..3787ceb0e70 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -17,7 +17,7 @@ export const menu: SimpleTranslationEntries = { "username": "Nome utente", "password": "Password", "login": "Accedi", - "orUse": "Or use", + "orUse": "O usa", "register": "Registrati", "emptyUsername": "Nome utente mancante!", "invalidLoginUsername": "Nome utente non valido!", @@ -39,9 +39,9 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classifica settimanale", "noRankings": "Nessuna classifica", "positionIcon": "#", - "usernameScoreboard": "Username", - "score": "Score", - "wave": "Wave", + "usernameScoreboard": "Nome utente", + "score": "Punteggio", + "wave": "Onda", "loading": "Caricamento…", "loadingAsset": "Caricamento asset: {{assetName}}", "playersOnline": "Giocatori online", From 9ecebb942c649346ed5d53a9e8d9bffbcddc075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:07:39 +0200 Subject: [PATCH 41/63] Update modifier-type.ts (IT) (#3564) --- src/locales/it/modifier-type.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/it/modifier-type.ts b/src/locales/it/modifier-type.ts index 6f054e4e566..0b166d268a5 100644 --- a/src/locales/it/modifier-type.ts +++ b/src/locales/it/modifier-type.ts @@ -101,7 +101,7 @@ export const modifierType: ModifierTypeTranslationEntries = { }, "TmModifierTypeWithInfo": { name: "MT{{moveId}} - {{moveName}}", - description: "Insegna {{moveName}} a un Pokémon\n(Hold C or Shift for more info).", + description: "Insegna {{moveName}} a un Pokémon\n(Tieni premuto C o Shift per maggiori informazioni).", }, "EvolutionItemModifierType": { description: "Fa evolvere determinate specie di Pokémon.", @@ -153,7 +153,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "REVIVER_SEED": { name: "Revitalseme", description: "Il possessore recupera 1/2 di PS in caso di KO causato da un colpo diretto." }, - "WHITE_HERB": { name: "Erbachiara", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." }, + "WHITE_HERB": { name: "Erbachiara", description: "Strumento da dare a un Pokémon. Ripristina le statistiche ridotte in lotta." }, "ETHER": { name: "Etere" }, "MAX_ETHER": { name: "Etere max" }, From 0ff94d832e2049fc18831ce41182a05c03994a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:07:55 +0200 Subject: [PATCH 42/63] Update modifier.ts (IT) (#3565) * Update modifier.ts (IT) * Update src/locales/it/modifier.ts Co-authored-by: Enoch --------- Co-authored-by: Enoch --- src/locales/it/modifier.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/locales/it/modifier.ts b/src/locales/it/modifier.ts index 810524a9e5e..94512efef0d 100644 --- a/src/locales/it/modifier.ts +++ b/src/locales/it/modifier.ts @@ -1,14 +1,14 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const modifier: SimpleTranslationEntries = { - "surviveDamageApply": "{{pokemonNameWithAffix}} hung on\nusing its {{typeName}}!", - "turnHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", - "hitHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", - "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} was revived\nby its {{typeName}}!", - "pokemonResetNegativeStatStageApply": "{{pokemonNameWithAffix}}'s lowered stats were restored\nby its {{typeName}}!", - "moneyInterestApply": "You received interest of ₽{{moneyAmount}}\nfrom the {{typeName}}!", - "turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was absorbed\nby {{pokemonName}}'s {{typeName}}!", - "contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was snatched\nby {{pokemonName}}'s {{typeName}}!", - "enemyTurnHealApply": "{{pokemonNameWithAffix}}\nrestored some HP!", + "surviveDamageApply": "{{pokemonNameWithAffix}} resiste\ngrazie al/alla suo/a {{typeName}}!", + "turnHealApply": "{{pokemonNameWithAffix}} recupera alcuni PS con\nil/la suo/a {{typeName}}!", + "hitHealApply": "{{pokemonNameWithAffix}} recupera alcuni PS con\nil/la suo/a {{typeName}}!", + "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} torna in forze\ngrazie al/alla suo/a {{typeName}}!", + "pokemonResetNegativeStatStageApply": "La riduzione alle statistiche di {{pokemonNameWithAffix}}\nviene annullata grazie al/alla suo/a {{typeName}}!", + "moneyInterestApply": "Ricevi un interesse pari a {{moneyAmount}}₽\ngrazie al/allo/a {{typeName}}!", + "turnHeldItemTransferApply": "Il/l'/lo/la {{itemName}} di {{pokemonNameWithAffix}} è stato assorbito\ndal {{typeName}} di {{pokemonName}}!", + "contactHeldItemTransferApply": "Il/l'/lo/la {{itemName}} di {{pokemonNameWithAffix}} è stato rubato\nda {{pokemonName}} con {{typeName}}!", + "enemyTurnHealApply": "{{pokemonNameWithAffix}}\nristabilisce parte dei PS!", "bypassSpeedChanceApply": "{{pokemonName}} agisce più rapidamente del normale grazie al suo {{itemName}}!", } as const; From 98df8a39bf94f9a44d94b933681c3b2fe11c86d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:08:14 +0200 Subject: [PATCH 43/63] Update move-trigger.ts (IT) (#3572) --- src/locales/it/move-trigger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/it/move-trigger.ts b/src/locales/it/move-trigger.ts index 198fc269785..92ce6a76a74 100644 --- a/src/locales/it/move-trigger.ts +++ b/src/locales/it/move-trigger.ts @@ -57,10 +57,10 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}} riceve i benefici\neffetti di Curardore!", "invertStats": "Le modifiche alle statistiche di {{pokemonName}}\nvengono invertite!", "resetStats": "Tutte le modifiche alle statistiche sono state annullate!", - "statEliminated": "All stat changes were eliminated!", + "statEliminated": "Tutte le modifiche alle statistiche sono state annullate!", "faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.", "copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!", "suppressAbilities": "L’abilità di {{pokemonName}}\nperde ogni efficacia!", "swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!", - "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", + "exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!", } as const; From e9d17f0605a3498f91e672e1283c80b6d1200ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2?= <123510358+NicusPulcis@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:08:34 +0200 Subject: [PATCH 44/63] Update move.ts (IT) (#3575) --- src/locales/it/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/it/move.ts b/src/locales/it/move.ts index a2c99218cec..1c510d4df6d 100644 --- a/src/locales/it/move.ts +++ b/src/locales/it/move.ts @@ -2915,7 +2915,7 @@ export const move: MoveTranslationEntries = { }, zippyZap: { name: "Sprintaboom", - effect: "The user attacks the target with bursts of electricity at high speed. This move always goes first and raises the user's evasiveness.", + effect: "Un attacco elettrico ad altissima velocità. Questa mossa ha priorità alta e aumenta l'elusione dell'utilizzatore.", }, splishySplash: { name: "Surfasplash", From 0aedf63685b8e6230eca92217c220b118d0478d6 Mon Sep 17 00:00:00 2001 From: Pancakes Date: Wed, 21 Aug 2024 14:03:46 -0400 Subject: [PATCH 45/63] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..180c7af1240 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: patapancakes From 6b21a777a1edc2bf37a7fcac50e49e0f450d9857 Mon Sep 17 00:00:00 2001 From: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:27:25 -0400 Subject: [PATCH 46/63] [Sprite] Index Rookidee, remove stray pixel (#3653) * [Sprite] Index front static Rookidee * [Sprite] Index front exp Rookidee * [Sprite] Index back static Rookidee * [Sprite] Index shiny front static Rookidee * [Sprite] Index back exp Rookidee * [Sprite] Index shiny back static Rookidee * [Sprite] Index shiny back static Rookidee * [Sprite] Index shiny back exp Rookidee --- public/images/pokemon/back/821.png | Bin 1108 -> 474 bytes public/images/pokemon/back/shiny/821.png | Bin 1083 -> 474 bytes public/images/pokemon/exp/821.png | Bin 23268 -> 8520 bytes public/images/pokemon/exp/back/821.png | Bin 3863 -> 1624 bytes public/images/pokemon/exp/back/shiny/821.png | Bin 3822 -> 1624 bytes public/images/pokemon/exp/shiny/821.png | Bin 22683 -> 8516 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/pokemon/back/821.png b/public/images/pokemon/back/821.png index a102a0491de588b7e17475116581c10076cbe5f0..24e0edd705dd1f82587ff097beeb1bd3d82253cb 100644 GIT binary patch delta 459 zcmV;+0W|*92-*XX8Gi!+003ZT+XVms00DDSM?wIu&K&6g001OVOjJbx000OG2p}2~ zF)1BDH6&0_I43JdG(mD~U1Y44G)ZTxmz$o!Z6-_r000bhQchC<|NsC0|NsC0|Ns99 z#84&x00B%%L_t(YiS5(dvV$ND1yHwQBK80O_vC^gBG9Mv)PKx$+Tz+60heW7Sf`@; zv(LOuNLF9*orphHOxS0h=u>LOD{Oq^uQsmY;q>*?q8Xv@>518VhvTVjHACY;tyb)d zN#VwIH^AZv++q)`#mcBaxeD!6*N(Jl$~pZL5*Di;dnWdhTV!Q#l~AuM+B8#Z zd1j;@Xxlclvp4WOgN$Lu|z z)x+*JkV7MDTnKVg6TRe{Yhc)it0RQqKjzrD9BfJ8kVNyHqLbNAeHGMea>A{|A$W2W z5N+!cj+C=xUtiCs8Y$W5$hopGU#!r0>wopX^#_JX7Knh30Q~>}002ovPDHLkV1md_ B*vS9@ delta 1098 zcmV-Q1hxCx1JnqR8Gi-<0039HD>ncD00DDSM?wIu&K&6g00a(6L_t(&f$f;jYZE~f z$G?$+Lm?=|M%oIktt84u=%uBRV&kcQf%MX%hu|T25WMNx+{A;DL&-rgm(qWrJ();x zi@gXYwgxU#h+7W20x*T!(-%BS7J~|%9>FqNd0HQGs zz44TzT{NcggL)NvMp^X3+nU8`yG{&zaAXP_+raQ-#@Dtto0bgf`8GCo`_=*iVg`F0Oxl`Ub$e!h`}&&_UFw z=@#f@DvQ8+;y3)hR7~_K@ zQ%&_YD6}2eo~=er$Cvt1)H>PMCI|= zfgkSR_FYXHlv8~rcmUWl%1EZN79iPyS1;x;I5LId$&6(UAJnU!RY$g^IRPL&VDQq~ zj>veI3`_&=t`xAlQo!(JrfCuy2o9Tt)1VMspg1BGN^CH@As_1zPj!YpM)0)PXGvfy=v)sEkgN6AVN^3ijF4Ht46+O=h zM4p5uYSi>52UJARa>UyeMP95KI)?g1QU;K-W0#y26?>IA`??LRuJ6M%&4}25Ow)`U zMIZEY6J^6Mg7)kk)T@D`zGsw?yqp$o&kcyOK!0o14es~PHJnS_Zn`J0^L9mnG)*%C z_-sIAv{hXOGs=!m(Dk>i=K@}is?)<6RKx?cu;o+rA2p#jFA~Ma zNzC4__`(Cu4%p=dOllh(u)+h@=&Lw1d%vOtD=SoR8N@C(_#n_gh~RSD350CO0dg(~ zbZBCX@w;;wo*ug-er`65F&^}TsI1VxWPcr=mjNIr;N(}XCr|VAG62~@*+xa7gD=eI z0LTsi^vYFOEbbWtE4$)#LwQ(1_-H+dr2;R|FmXz)KNzrb@X59FEd?4I5+Q8 Q(f|Me07*qoM6N<$f{SnuLOD{Oq^uQsmY;q>*?q8Xv@>518VhvTVjHACY;tyb)d zN#VwIH^AZv++q)`#mcBaxeD!6*N(Jl$~pZL5*Di;dnWdhTV!Q#l~AuM+B8#Z zd1j;@Xxlclvp4WOgN$Lu|z z)x+*JkV7MDTnKVg6TRe{Yhc)it0RQqKjzrD9BfJ8kVNyHqLbNAeHGMea>A{|A$W2W z5N+!cj+C=xUtiCs8Y$W5$hopGU#!r0>wopX^#@)u7qIlxg_8gP002ovPDHLkV1f`% B-1z_i delta 1073 zcmV-11kU@~1G@;28Gi-<0039HD>ncD00DDSM?wIu&K&6g00Z?&L_t(&f$f-2XcIvc z#=qDe=3FT1LDXCWKbAb z{^|qn-qoZ|Ic*FC4*;dLeXLGfO+d1NzJX`R4#hB29BW#~cBSrHb=+(IcuZ{8&+*;8 zZ877$GB9;Gl`mr|U&c&v?D$-{r6V#EH0V^mEZX=%yW6@oG5Hwtvk>qR#u#6nw#4+& zAT$td)qhj@vbdfp*dp6r$`ov5hhnf&(U!jDnF#`xS+3m4VSaWFyL;P_UdM4FnS#v; zL>`0&T3^{}F`y%YmNVX|DDz^?&|_#&CS?G5cHEL@MJHZo%*}ca4vuPY94FFJ$K~hf zAQN&nRp7K#EG??RWswOtfPWi)x$+h7o~E?m!-{rO$8jP+zy?G? zuio#Vw6?D_LH{4Ts0es@Evs(Mup%CyjV+(54>|W*1^{sQyHEW8RNc_JZ-SI5*x|r| zzwp!%&@eERc_Lzp@7^}GF#+y|20D1GB^VhR0P+tWHXYwc-V`QHsx9#2njct?O~R|P z4S$4utd(nireI_FP02G>UOJzu8=!VN@`46Bd>)r;z8^f$o&k61Q_0AS#PXXG?mo%} z!UJjpZutR|jC`Ju;eqDt>lnKGD60i4%P6=E;+7YD7-+yCxO}Vvp%^ki=E6W56Jv}| z-XG`Ju3i^EuNcM{5Bot>mhmrH6O)et0Dtqd5ODG#`&v86ITdJolF zO`IbG0K{7h#l_M|%+JnACg<9QHwvy&ES&_l1&D|ceKU{nt)XmVs~#F2S>H08BrMofXlTSlJU6K*haQ|zmle!kt(40 rpcvo;KkU0fbYQybs;jQL`hWBXW4T3_A_@eU00000NkvXXu0mjfTde!l diff --git a/public/images/pokemon/exp/821.png b/public/images/pokemon/exp/821.png index e4a73a66140a2698346f09bd0a87a4c360176ec2..8bb00063bcb6029da354c9826f76c309e610e6c4 100644 GIT binary patch literal 8520 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 ci}syVySzomPEyIYM|Ws%Al-Ej-`~CK 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 diff --git a/public/images/pokemon/exp/back/821.png b/public/images/pokemon/exp/back/821.png index 80d88dce2f943ebb39e261fdc69a561a7dd6aea7..13aa5c24e83d65a509243a9e0b685f5379f75fa7 100644 GIT binary patch delta 1618 zcmV-Y2Cey*9@q?!8Gi!+000i>FSq~z00DDSM?wIu&K&6g001OVOjJbx000OG2p}2~ zF)1BDH6&0_I43JdG(mD~U1Y44G)ZTxmz$o!Z6-_r000bhQchC<|NsC0|NsC0|Ns99 z#84&x00qiPL_t(&fz_Igma8fZh0UoGT7CcbJthGOpb)_6y?=)_KTap?odCA-Etci~ z+u+Y{hNpd#KYm(Do#7QB>WbVl`{>rR%K_=B|#7dwc=u2Tu`-DQ+@%?$#J` zTS?PoOm`i9gMUM>b6g#1t5Ql|PBOFQOgT+lo4)9)LZEKoq+V@HLzf7JBo`l^x{7nt z7s7BNbtDh2moDRsk@0?-sw_F2=0zpys zHog?1pm3#lXxaL~mhc;6c)#C}Wf`KKtbfcpn0(Jlk_Dq=j#g%Q+%M5M?_jm{%lOZE zha@sL0~ErGakkpBv5XhKUaz*V0~LNTKpnm$_4#~WrO<^+ExgB8ls=!J1Z`g(KH+@iQ=lg}J!m|PDvt=o5{7UbhR(NnW-$GjHb1Jd(tFDoS z1GF-&DUsAE*HGyUuL&KU;T*u0PG@*UC=3)ywa2V8ydv~o*HtboGM(X7q1|5?KDjx3 zCuO=wMzb& zz$%&S*Kkf}1&`sJ&I%sFIZIy!PvM+GtATS;(lCs3a@R%$=xGQ!diwKQ{E8=i5yU~3 zK!00q-j^}`8N*0TASFB`AdU@~hHSFkNBJ?$uTE|daZbb`wCQDAu2lEH0bjVX)gvvN zMvq}&6E+bb48?CF^_Cn=NSIP$93p^2_R2D^&bg4~VQl~KXAl;E6oH{Y?AU+R{K{`e z0)_$1=>V?w4}WG>9!R+o*rBT6q#?3@Du1C0?z_ntgQem*sDT{;I4z_(*9DX?84G}; zdqV*!hv!;}QrbA8lnYyeKMkDY0UX_e36OF*I>WpI@C&(QA;(LR{@k>Lh(sWTt{_P% zkO~y$_%2zB4|o|Ji2fE1<`2!$b>Q!)nsM%pk=x-pQt;zGxZdA>Z*gmVgCgMaNJ z537I*NSU}08DohUu0reX8c11q6rMPz$$lEfeLyP04do02OvUvADNTQX({AyQYhw+h z+Q4p+O}>IEO$>8qtbmkht#s0#n)Ah+RhG(wI7d|wfZe^?V>lkvi}4L45TD zk($4cr~3c1tqsD`=gco2gVF)tJO)Md=RY_Gr8vwNk3p66=PSpcavt)fV^E4;S;Fo4 z=jWR6hF?u`GaE*_z*lqJ%z%-u@zoqQ%WeG`A3bus`Mkwf+YmNO&NYcG4S%UybqUw_ z>g>>o%>WffQm%YKV;4VF{T`ygS7X>rHj!R3aphxNKk+f5jjxOkcv5P_NE_3->=>7p zYTzp)HuK9cVkDt;$%@V}QVU<1u$jkKE)JKUvgqo{b4?X|Wx!@U#zjAncYstY!ALcH zWx-|(q+l*!r1Icbfsrcs%71d00?tEqGH0yBOEj_0b*lKv#IGRmD+fX8;uzPZ@eRJR z`Rd9~CBr$cJA7rvb-IEZnseoQgF*)QmBL7-b6grF_ z^me(2BRz<(dO6Zl_^OX1J&Lca9O+qnW#>o_;;S)^G>@+?w7UDv`TlPE3j?x(_wIT$ QDgXcg07*qoM6N<$f}HLILjV8( literal 3863 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 QuK)l507*qoM6N<$f}PL{Hvj+t literal 3822 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 diff --git a/public/images/pokemon/exp/shiny/821.png b/public/images/pokemon/exp/shiny/821.png index 5c03c17c7931d3b8a25b058ee21823d8d89bcb6f..6f6cf7f2991c80006cdef1790edb8af343aad46e 100644 GIT binary patch literal 8516 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

(Db}CwiNaC+#Wt-uM~4X;hg|muRVs`8 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 A;s5{u From 3a167610cf04b389e3a0326133e11c721a440789 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:40:55 -0700 Subject: [PATCH 47/63] [Bug] Fix: Gravity tag removes flying type during damage calculation (#3670) * add `hasTag` to arena * fix flying type damage calculation for grounded states Before the grounded state would make e.g. electric moves no more very-effective. This is invalid Co-authored-by: Tristan D Gant * add tests for gravity v. ground v. electric * Update src/test/arena/arena_gravity.test.ts fix typo Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> * use `arena` instead of this.scene.arena * use `const arena = this.scene.arean` instead of destructoring * Apply suggestions from code review Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> * fix es-lint --------- Co-authored-by: Tristan D Gant Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> --- src/field/arena.ts | 4 ++ src/field/pokemon.ts | 18 +++--- src/test/arena/arena_gravity.test.ts | 91 ++++++++++++++++++++++++---- 3 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/field/arena.ts b/src/field/arena.ts index eb3770d61d5..2ef6ce7dab3 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -584,6 +584,10 @@ export class Arena { return this.getTagOnSide(tagType, ArenaTagSide.BOTH); } + hasTag(tagType: ArenaTagType) : boolean { + return !!this.getTag(tagType); + } + getTagOnSide(tagType: ArenaTagType | Constructor, side: ArenaTagSide): ArenaTag | undefined { return typeof(tagType) === "string" ? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side)) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6a445a83b4e..b3a96a5f1fc 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -978,12 +978,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // this.scene potentially can be undefined for a fainted pokemon in doubles // use optional chaining to avoid runtime errors - if (forDefend && (this.getTag(GroundedTag) || this.scene?.arena.getTag(ArenaTagType.GRAVITY))) { - const flyingIndex = types.indexOf(Type.FLYING); - if (flyingIndex > -1) { - types.splice(flyingIndex, 1); - } - } if (!types.length) { // become UNKNOWN if no types are present types.push(Type.UNKNOWN); @@ -1272,6 +1266,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.isTerastallized() ? 2 : 1; } const types = this.getTypes(true, true); + const arena = this.scene.arena; + + // Handle flying v ground type immunity without removing flying type so effective types are still effective + // Related to https://github.com/pagefaultgames/pokerogue/issues/524 + if (moveType === Type.GROUND && (this.isGrounded() || arena.hasTag(ArenaTagType.GRAVITY))) { + const flyingIndex = types.indexOf(Type.FLYING); + if (flyingIndex > -1) { + types.splice(flyingIndex, 1); + } + } let multiplier = types.map(defType => { if (source) { @@ -1293,7 +1297,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier; // Handle strong winds lowering effectiveness of types super effective against pure flying - if (!ignoreStrongWinds && this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) { + if (!ignoreStrongWinds && arena.weather?.weatherType === WeatherType.STRONG_WINDS && !arena.weather.isEffectSuppressed(this.scene) && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) { multiplier /= 2; if (!simulated) { this.scene.queueMessage(i18next.t("weather:strongWindsEffectMessage")); diff --git a/src/test/arena/arena_gravity.test.ts b/src/test/arena/arena_gravity.test.ts index 68c31258454..8fad4dde83d 100644 --- a/src/test/arena/arena_gravity.test.ts +++ b/src/test/arena/arena_gravity.test.ts @@ -1,14 +1,15 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; describe("Arena - Gravity", () => { let phaserGame: Phaser.Game; @@ -26,14 +27,17 @@ describe("Arena - Gravity", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); - game.override.moveset([Moves.TACKLE, Moves.GRAVITY, Moves.FISSURE]); - game.override.ability(Abilities.UNNERVE); - game.override.enemyAbility(Abilities.BALL_FETCH); - game.override.enemySpecies(Species.SHUCKLE); - game.override.enemyMoveset(new Array(4).fill(Moves.SPLASH)); + game.override + .battleType("single") + .moveset([Moves.TACKLE, Moves.GRAVITY, Moves.FISSURE]) + .ability(Abilities.UNNERVE) + .enemyAbility(Abilities.BALL_FETCH) + .enemySpecies(Species.SHUCKLE) + .enemyMoveset(SPLASH_ONLY); }); + // Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move) + it("non-OHKO move accuracy is multiplied by 1.67", async () => { const moveToCheck = allMoves[Moves.TACKLE]; @@ -77,4 +81,65 @@ describe("Arena - Gravity", () => { expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(30); }); + + describe("Against flying types", () => { + it("can be hit by ground-type moves now", async () => { + game.override + .startingLevel(5) + .enemyLevel(5) + .enemySpecies(Species.PIDGEOT) + .moveset([Moves.GRAVITY, Moves.EARTHQUAKE]); + + await game.startBattle([Species.PIKACHU]); + + const pidgeot = game.scene.getEnemyPokemon()!; + vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); + + // Try earthquake on 1st turn (fails!); + game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(0); + + // Setup Gravity on 2nd turn + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); + + // Use ground move on 3rd turn + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(1); + }); + + it("keeps super-effective moves super-effective after using gravity", async () => { + game.override + .startingLevel(5) + .enemyLevel(5) + .enemySpecies(Species.PIDGEOT) + .moveset([Moves.GRAVITY, Moves.THUNDERBOLT]); + + await game.startBattle([Species.PIKACHU]); + + const pidgeot = game.scene.getEnemyPokemon()!; + vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); + + // Setup Gravity on 1st turn + game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); + + // Use electric move on 2nd turn + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(2); + }); + }); }); From 0241a0a086f07f5bed54c4e3cf986d5ea43fd83c Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:49:22 +0200 Subject: [PATCH 48/63] Translated missing DE files (#3650) --- src/locales/de/battler-tags.ts | 2 +- src/locales/de/starter-select-ui-handler.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/de/battler-tags.ts b/src/locales/de/battler-tags.ts index 27d5f14c597..da0150836b0 100644 --- a/src/locales/de/battler-tags.ts +++ b/src/locales/de/battler-tags.ts @@ -69,5 +69,5 @@ export const battlerTags: SimpleTranslationEntries = { "saltCuredLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!", "cursedOnAdd": "{{pokemonNameWithAffix}} nimmt einen Teil seiner KP und legt einen Fluch auf {{pokemonName}}!", "cursedLapse": "{{pokemonNameWithAffix}} wurde durch den Fluch verletzt!", - "stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!", + "stockpilingOnAdd": "{{pokemonNameWithAffix}} hortet {{stockpiledCount}}!", } as const; diff --git a/src/locales/de/starter-select-ui-handler.ts b/src/locales/de/starter-select-ui-handler.ts index 284152bbd33..c96af29a3c0 100644 --- a/src/locales/de/starter-select-ui-handler.ts +++ b/src/locales/de/starter-select-ui-handler.ts @@ -7,7 +7,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; */ export const starterSelectUiHandler: SimpleTranslationEntries = { "confirmStartTeam": "Mit diesen Pokémon losziehen?", - "confirmExit": "Do you want to exit?", + "confirmExit": "Willst du zurück?", "invalidParty": "Das ist kein gültiges Team!", "gen1": "I", "gen2": "II", @@ -28,8 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "DVs anzeigen/verbergen", "manageMoves": "Attacken ändern", "manageNature": "Wesen ändern", - "addToFavorites": "Add to Favorites", - "removeFromFavorites": "Remove from Favorites", + "addToFavorites": "Zu Favoriten hinzufügen", + "removeFromFavorites": "Von Favoriten entfernen", "useCandies": "Bonbons verwenden", "selectNature": "Wähle das neue Wesen.", "selectMoveSwapOut": "Wähle die zu ersetzende Attacke.", From 1487d7f51cb359d741a5ad3b3d5184ef0506a8f3 Mon Sep 17 00:00:00 2001 From: cgyu7 <149552611+cgyu7@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:33:33 -0500 Subject: [PATCH 49/63] [Move] Some more implementation for Tera Blast (#3469) * terablast updated * terablast update * terablast * fix trailing spaces * fixed misspelling in a comment * split tera blast dmg calc and type calc into different classes * terablastpowerattr update removed dupe code and added user terastallized check to conditional * Update src/data/move.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/move.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * removed spaces and added missing semicolon * added tsdocs for tera blast * deleted extra spaces * tsdoc update Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * tsdoc update Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * tsdoc update Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Add files via upload * Update src/test/moves/tera_blast.test.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/test/moves/tera_blast.test.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/test/moves/tera_blast.test.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/test/moves/tera_blast.test.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/test/moves/tera_blast.test.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * remove trailing spaces * The style police are here * Fixed conflict resolution issues --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: innerthunder --- src/data/move.ts | 51 +++++++++++++- src/test/moves/tera_blast.test.ts | 106 ++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/test/moves/tera_blast.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 51ba4058140..3a2903cb7c6 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3784,6 +3784,30 @@ export class TeraBlastCategoryAttr extends VariableMoveCategoryAttr { } } +/** + * Increases the power of Tera Blast if the user is Terastallized into Stellar type + * @extends VariablePowerAttr + */ +export class TeraBlastPowerAttr extends VariablePowerAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + /** + * @param user {@linkcode Pokemon} Pokemon using the move + * @param target {@linkcode Pokemon} N/A + * @param move {@linkcode Move} {@linkcode Move.TERA_BLAST} + * @param {any[]} args N/A + * @returns true or false + */ + const power = args[0] as Utils.NumberHolder; + if (user.isTerastallized() && move.type === Type.STELLAR) { + //200 instead of 100 to reflect lack of stellar being 2x dmg on any type + power.value = 200; + return true; + } + + return false; + } +} + /** * Change the move category to status when used on the ally * @extends VariableMoveCategoryAttr @@ -4037,6 +4061,28 @@ export class HiddenPowerTypeAttr extends VariableMoveTypeAttr { } } +/** + * Changes the type of Tera Blast to match the user's tera type + * @extends VariableMoveTypeAttr + */ +export class TeraBlastTypeAttr extends VariableMoveTypeAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + /** + * @param user {@linkcode Pokemon} the user's type is checked + * @param target {@linkcode Pokemon} N/A + * @param move {@linkcode Move} {@linkcode Move.TeraBlastTypeAttr} + * @param {any[]} args N/A + * @returns true or false + */ + if (user.isTerastallized()) { + move.type = user.getTeraType(); //changes move type to tera type + return true; + } + + return false; + } +} + export class MatchUserTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const userTypes = user.getTypes(true); @@ -8791,7 +8837,10 @@ export function initMoves() { End Unused */ new AttackMove(Moves.TERA_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9) .attr(TeraBlastCategoryAttr) - .unimplemented(), + .attr(TeraBlastTypeAttr) + .attr(TeraBlastPowerAttr) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1, true, (user, target, move) => user.isTerastallized() && user.isOfType(Type.STELLAR)) + .partial(), new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9) .attr(ProtectAttr, BattlerTagType.SILK_TRAP), new AttackMove(Moves.AXE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, 30, 0, 9) diff --git a/src/test/moves/tera_blast.test.ts b/src/test/moves/tera_blast.test.ts new file mode 100644 index 00000000000..0bd2ad24e23 --- /dev/null +++ b/src/test/moves/tera_blast.test.ts @@ -0,0 +1,106 @@ +import { allMoves } from "#app/data/move"; +import GameManager from "#test/utils/gameManager"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { Abilities } from "#app/enums/abilities"; +import { SPLASH_ONLY } from "../utils/testUtils"; +import { Type } from "#app/data/type"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { Stat } from "#app/enums/stat"; +import { BattlerIndex } from "#app/battle"; +import { HitResult } from "#app/field/pokemon"; + +describe("Moves - Tera Blast", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + const moveToCheck = allMoves[Moves.TERA_BLAST]; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .disableCrits() + .starterSpecies(Species.FEEBAS) + .moveset([Moves.TERA_BLAST]) + .ability(Abilities.BALL_FETCH) + .startingHeldItems([{name: "TERA_SHARD", type: Type.FIRE}]) + .enemySpecies(Species.MAGIKARP) + .enemyMoveset(SPLASH_ONLY) + .enemyAbility(Abilities.BALL_FETCH) + .enemyLevel(20); + + vi.spyOn(moveToCheck, "calculateBattlePower"); + }); + + it("changes type to match user's tera type", async() => { + game.override + .enemySpecies(Species.FURRET) + .startingHeldItems([{name: "TERA_SHARD", type: Type.FIGHTING}]); + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + vi.spyOn(enemyPokemon, "apply"); + + game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); + }, 20000); + + it("increases power if user is Stellar tera type", async() => { + game.override.startingHeldItems([{name: "TERA_SHARD", type: Type.STELLAR}]); + const stellarTypeMultiplier = 2; + const stellarTypeDmgBonus = 20; + const basePower = moveToCheck.power; + + await game.startBattle(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(moveToCheck.calculateBattlePower).toHaveReturnedWith((basePower + stellarTypeDmgBonus) * stellarTypeMultiplier); + }, 20000); + + // Currently abilities are bugged and can't see when a move's category is changed + it.skip("uses the higher stat of the user's Atk and SpAtk for damage calculation", async() => { + game.override.enemyAbility(Abilities.TOXIC_DEBRIS); + await game.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + playerPokemon.stats[Stat.ATK] = 100; + playerPokemon.stats[Stat.SPATK] = 1; + + game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); + }, 20000); + + it("causes stat drops if user is Stellar tera type", async() => { + game.override.startingHeldItems([{name: "TERA_SHARD", type: Type.STELLAR}]); + await game.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEndPhase"); + + expect(playerPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(-1); + expect(playerPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-1); + }, 20000); +}); From 7bea5eb86e79c7295ab2103466ae93e75a578702 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:31:08 -0700 Subject: [PATCH 50/63] Revert "W Event (Classic and Translations) (#3583)" (#3685) This reverts commit 96302a9a5500428ce454566b4eb68c1db1cb8a49. --- src/data/trainer-config.ts | 4 ++-- src/locales/ca_ES/dialogue.ts | 10 ++++------ src/locales/de/dialogue.ts | 10 ++++------ src/locales/en/dialogue.ts | 14 ++++++-------- src/locales/es/dialogue.ts | 10 ++++------ src/locales/fr/dialogue.ts | 22 +++++++++------------- src/locales/it/dialogue.ts | 10 ++++------ src/locales/ja/dialogue.ts | 10 ++++------ src/locales/ko/dialogue.ts | 10 ++++------ src/locales/pt_BR/dialogue.ts | 28 ++++++++++++---------------- src/locales/zh_CN/dialogue.ts | 8 ++++---- src/locales/zh_TW/dialogue.ts | 8 ++++---- 12 files changed, 61 insertions(+), 83 deletions(-) diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 2d54a79441d..5f47ce42a62 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -1577,11 +1577,11 @@ export const trainerConfigs: TrainerConfigs = { })), [TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL) - .setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE, () => modifierTypes.SHINY_CHARM, () => modifierTypes.ABILITY_CHARM) + .setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.CHIKORITA, Species.CYNDAQUIL, Species.TOTODILE, Species.TREECKO, Species.TORCHIC, Species.MUDKIP, Species.TURTWIG, Species.CHIMCHAR, Species.PIPLUP, Species.SNIVY, Species.TEPIG, Species.OSHAWOTT, Species.CHESPIN, Species.FENNEKIN, Species.FROAKIE, Species.ROWLET, Species.LITTEN, Species.POPPLIO, Species.GROOKEY, Species.SCORBUNNY, Species.SOBBLE, Species.SPRIGATITO, Species.FUECOCO, Species.QUAXLY], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEY, Species.HOOTHOOT, Species.TAILLOW, Species.STARLY, Species.PIDOVE, Species.FLETCHLING, Species.PIKIPEK, Species.ROOKIDEE, Species.WATTREL], TrainerSlot.TRAINER, true)), [TrainerType.RIVAL_2]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setMoneyMultiplier(1.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL_2) - .setModifierRewardFuncs(() => modifierTypes.EXP_SHARE, () => modifierTypes.SHINY_CHARM) + .setModifierRewardFuncs(() => modifierTypes.EXP_SHARE) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.IVYSAUR, Species.CHARMELEON, Species.WARTORTLE, Species.BAYLEEF, Species.QUILAVA, Species.CROCONAW, Species.GROVYLE, Species.COMBUSKEN, Species.MARSHTOMP, Species.GROTLE, Species.MONFERNO, Species.PRINPLUP, Species.SERVINE, Species.PIGNITE, Species.DEWOTT, Species.QUILLADIN, Species.BRAIXEN, Species.FROGADIER, Species.DARTRIX, Species.TORRACAT, Species.BRIONNE, Species.THWACKEY, Species.RABOOT, Species.DRIZZILE, Species.FLORAGATO, Species.CROCALOR, Species.QUAXWELL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PIDGEOTTO, Species.HOOTHOOT, Species.TAILLOW, Species.STARAVIA, Species.TRANQUILL, Species.FLETCHINDER, Species.TRUMBEAK, Species.CORVISQUIRE, Species.WATTREL], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)), diff --git a/src/locales/ca_ES/dialogue.ts b/src/locales/ca_ES/dialogue.ts index 6db337517da..e783ea14006 100644 --- a/src/locales/ca_ES/dialogue.ts +++ b/src/locales/ca_ES/dialogue.ts @@ -2573,8 +2573,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{serious_smile_fists}Good luck out there!` }, }, "rival_female": { @@ -2588,8 +2587,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{smile_wave}Do your best like always! I believe in you!` }, }, "rival_2": { @@ -2605,7 +2603,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care, and enjoy the event!` + $@c{smile}Anyway, take care!` }, }, "rival_2_female": { @@ -2621,7 +2619,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Aw well. That just means I'll have to train even harder for next time! $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it, and enjoy the event!` + $@c{smile_wave}Keep at it!` }, "defeat": { 1: "It's OK to lose sometimes…" diff --git a/src/locales/de/dialogue.ts b/src/locales/de/dialogue.ts index 4c964db6dc3..a84060143fc 100644 --- a/src/locales/de/dialogue.ts +++ b/src/locales/de/dialogue.ts @@ -2641,8 +2641,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Vielleicht war es einfach etwas Glück, aber…\nWer weiß, vielleicht schaffst du es irgendwann $ja wirklich ganz groß raus zu kommen. $Übrigens, der Professor hat mich gebeten dir diese Items zu geben. Die sehen wirklich cool aus. - $@c{serious_smile_fists}Viel Glück da draußen! - $@c{smile}Oh-und genieße das Event!` + $@c{serious_smile_fists}Viel Glück da draußen!` }, }, "rival_female": { @@ -2657,8 +2656,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Du hast gerade erst angefangen und bist schon so stark?!@d{96} @c{angry}Du hast sowas von betrogen, oder? $@c{smile_wave_wink}Ich mach nur Spaß!@d{64} @c{smile_eclosed}Ich habe ehrlich verloren… Ich habe das Gefühl, dass du es dort draußen weit bringen wirst. $@c{smile}Übrigens, der Professor hat mich gebeten dir diese Items zu geben. Ich hoffe sie sind hilfreich! - $@c{smile_wave}Gib wie immer dein Bestes! Ich glaube an dich! - $@c{smile}Oh-und genieße das Event!` + $@c{smile_wave}Gib wie immer dein Bestes! Ich glaube an dich!` }, }, "rival_2": { @@ -2676,7 +2674,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Nicht, dass du wirklich Hilfe benötigen würdest, aber ich habe hier noch eins von diesen Dingern herumliegen. $Du kannst es haben.\n $@c{serious_smile_fists}Erwarte aber nicht, dass ich dir noch mehr gebe!\nIch kann meinen Rivalen doch keine Vorteile verschaffen. - $@c{smile}Egal, pass auf dich auf und genieße das Event!` + $@c{smile}Egal, pass auf dich auf!` }, }, "rival_2_female": { @@ -2692,7 +2690,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Na gut. Das bedeutet ich muss noch härter tranieren! $@c{smile_wave}Ich habe noch eins von diesen Dingern!\n@c{smile_wave_wink}Kein Grund mir zu danken~. $@c{angry_mopen}Das ist aber das Letzte! Du bekommst ab jett keine Geschenke mehr von mir! - $@c{smile_wave}Bleib stark und genieße das Event!` + $@c{smile_wave}Bleib stark!` }, "defeat": { 1: "Es ist Ok manchmal zu verlieren…" diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index 1180e202f3c..715f245e518 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -2574,8 +2574,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{serious_smile_fists}Good luck out there!` }, }, "rival_female": { @@ -2589,8 +2588,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{smile_wave}Do your best like always! I believe in you!` }, }, "rival_2": { @@ -2604,9 +2602,9 @@ export const PGMdialogue: DialogueTranslationEntries = { "victory": { 1: `@c{neutral_eclosed}Oh. I guess I was overconfident. $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n - $@c{smile}Oh, not that you really need the help, but I had an extra one of each of these lying around and figured you might want them.\n + $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care, and enjoy the event!` + $@c{smile}Anyway, take care!` }, }, "rival_2_female": { @@ -2620,9 +2618,9 @@ export const PGMdialogue: DialogueTranslationEntries = { "victory": { 1: `@c{neutral}I… wasn't supposed to lose that time… $@c{smile}Aw well. That just means I'll have to train even harder for next time! - $@c{smile_wave}I also got you another two of these!\n@c{smile_wave_wink}No need to thank me~. + $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it, and enjoy the event!` + $@c{smile_wave}Keep at it!` }, "defeat": { 1: "It's OK to lose sometimes…" diff --git a/src/locales/es/dialogue.ts b/src/locales/es/dialogue.ts index 07e51458a29..187127d1d39 100644 --- a/src/locales/es/dialogue.ts +++ b/src/locales/es/dialogue.ts @@ -2569,8 +2569,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{serious_smile_fists}Good luck out there!` }, }, "rival_female": { @@ -2584,8 +2583,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{smile_wave}Do your best like always! I believe in you!` }, }, "rival_2": { @@ -2601,7 +2599,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care, and enjoy the event!` + $@c{smile}Anyway, take care!` }, }, "rival_2_female": { @@ -2617,7 +2615,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Aw well. That just means I'll have to train even harder for next time! $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it, and enjoy the event!` + $@c{smile_wave}Keep at it!` }, "defeat": { 1: "It's OK to lose sometimes…" diff --git a/src/locales/fr/dialogue.ts b/src/locales/fr/dialogue.ts index 49dc6124fbf..8a8707dc4e5 100644 --- a/src/locales/fr/dialogue.ts +++ b/src/locales/fr/dialogue.ts @@ -2372,8 +2372,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wah… Tu m’as vraiment lavé.\nT’es vraiment un débutant ? $@c{smile}T’as peut-être eu de la chance, mais…\nPeut-être que t’arriveras jusqu’au bout du chemin. $D’ailleurs, le prof m’a demandé de te filer ces objets.\nIls ont l’air sympas. - $@c{serious_smile_fists}Bonne chance à toi ! - $@c{smile}Oh, et profite bien de l’évènement !` + $@c{serious_smile_fists}Bonne chance à toi !` }, }, "rival_female": { @@ -2387,8 +2386,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Tu viens de commencer et t’es déjà si fort ?!@d{96}\n@c{angry}T’as triché non ? Avoue ! $@c{smile_wave_wink}J’déconne !@d{64} @c{smile_eclosed}J’ai perdu dans les règles…\nJ’ai le sentiment que tu vas très bien t’en sortir. $@c{smile}D’ailleurs, le prof veut que je te donne ces quelques objets. Ils te seront utiles, pour sûr ! - $@c{smile_wave}Fais de ton mieux, comme toujours !\nJe crois fort en toi ! - $@c{smile}Oh, et profite bien de l’évènement !` + $@c{smile_wave}Fais de ton mieux, comme toujours !\nJe crois fort en toi !` }, }, "rival_2": { @@ -2404,7 +2402,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Pas grave, c’est OK. Je me doutais que ça arriverait.\n@c{serious_mopen_fists}Je vais juste devoir encore plus m’entrainer !\n $@c{smile}Ah, et pas que t’aies réellement besoin d’aide, mais j’ai ça en trop sur moi qui pourrait t’intéresser.\n $@c{serious_smile_fists}Mais n’espère plus en avoir d’autres !\nJe peux pas passer mon temps à aider mon adversaire. - $@c{smile}Bref, prends soin de toi et profite bien de l’évènement !` + $@c{smile}Bref, prends soin de toi !` }, }, "rival_2_female": { @@ -2419,8 +2417,8 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{neutral}Je… J’étais pas encore supposée perdre… $@c{smile}Bon. Ça veut juste dire que je vais devoir encore plus m’entrainer ! $@c{smile_wave}J’ai aussi ça en rab pour toi !\n@c{smile_wave_wink}Inutile de me remercier ~. - $@c{angry_mopen}C’étaient les derniers, terminé les cadeaux après ceux-là ! - $@c{smile_wave}Allez, tiens le coup et profite bien de l’évènement !` + $@c{angry_mopen}C’était le dernier, terminé les cadeaux après celui-là ! + $@c{smile_wave}Allez, tiens le coup !` }, "defeat": { 1: "Je suppose que c’est parfois normal de perdre…" @@ -5053,8 +5051,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wah… Tu m’as vraiment lavé.\nT’es vraiment une débutante ? $@c{smile}T’as peut-être eu de la chance, mais…\nPeut-être que t’arriveras jusqu’au bout du chemin. $D’ailleurs, le prof m’a demandé de te filer ces objets.\nIls ont l’air sympas. - $@c{serious_smile_fists}Bonne chance à toi ! - $@c{smile}Oh, et profite bien de l’évènement !` + $@c{serious_smile_fists}Bonne chance à toi !` }, }, "rival_female": { @@ -5068,8 +5065,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: `@c{shock}Tu viens de commencer et t’es déjà si forte ?!@d{96}\n@c{angry}T’as triché non ? Avoue ! $@c{smile_wave_wink}J’déconne !@d{64} @c{smile_eclosed}J’ai perdu dans les règles…\nJ’ai le sentiment que tu vas très bien t’en sortir. $@c{smile}D’ailleurs, le prof veut que je te donne ces quelques objets. Ils te seront utiles, pour sûr ! - $@c{smile_wave}Fais de ton mieux, comme toujours !\nJe crois fort en toi ! - $@c{smile}Oh, et profite bien de l’évènement !` + $@c{smile_wave}Fais de ton mieux, comme toujours !\nJe crois fort en toi !` }, }, "rival_2": { @@ -5085,7 +5081,7 @@ export const PGFdialogue: DialogueTranslationEntries = { $@c{smile}Pas grave, c’est OK. Je me doutais que ça arriverait.\n@c{serious_mopen_fists}Je vais juste devoir encore plus m’entrainer !\n $@c{smile}Ah, et pas que t’aies réellement besoin d’aide, mais j’ai ça en trop sur moi qui pourrait t’intéresser.\n $@c{serious_smile_fists}Mais n’espère plus en avoir d’autres !\nJe peux pas passer mon temps à aider mon adversaire. - $@c{smile}Bref, prends soin de toi et profite bien de l’évènement !` + $@c{smile}Bref, prends soin de toi !` }, }, "rival_2_female": { @@ -5101,7 +5097,7 @@ export const PGFdialogue: DialogueTranslationEntries = { $@c{smile}Bon. Ça veut juste dire que je vais devoir encore plus m’entrainer ! $@c{smile_wave}J’ai aussi ça en rab pour toi !\n@c{smile_wave_wink}Inutile de me remercier ~. $@c{angry_mopen}C’était le dernier, terminé les cadeaux après celui-là ! - $@c{smile_wave}Allez, tiens le coup et profite bien de l’évènement !` + $@c{smile_wave}Allez, tiens le coup !` }, "defeat": { 1: "Je suppose que c’est parfois normal de perdre…" diff --git a/src/locales/it/dialogue.ts b/src/locales/it/dialogue.ts index f692b9b848a..1089db4e6f8 100644 --- a/src/locales/it/dialogue.ts +++ b/src/locales/it/dialogue.ts @@ -2569,8 +2569,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{serious_smile_fists}Good luck out there!` }, }, "rival_female": { @@ -2584,8 +2583,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{smile_wave}Do your best like always! I believe in you!` }, }, "rival_2": { @@ -2601,7 +2599,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care, and enjoy the event!` + $@c{smile}Anyway, take care!` }, }, "rival_2_female": { @@ -2617,7 +2615,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Aw well. That just means I'll have to train even harder for next time! $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it, and enjoy the event!` + $@c{smile_wave}Keep at it!` }, "defeat": { 1: "It's OK to lose sometimes…" diff --git a/src/locales/ja/dialogue.ts b/src/locales/ja/dialogue.ts index 6db337517da..e783ea14006 100644 --- a/src/locales/ja/dialogue.ts +++ b/src/locales/ja/dialogue.ts @@ -2573,8 +2573,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. $By the way, the professor asked me to give you these items. They look pretty cool. - $@c{serious_smile_fists}Good luck out there! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{serious_smile_fists}Good luck out there!` }, }, "rival_female": { @@ -2588,8 +2587,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $@c{smile_wave}Do your best like always! I believe in you! - $@c{smile}Oh- and I hope you enjoy the event!` + $@c{smile_wave}Do your best like always! I believe in you!` }, }, "rival_2": { @@ -2605,7 +2603,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. - $@c{smile}Anyway, take care, and enjoy the event!` + $@c{smile}Anyway, take care!` }, }, "rival_2_female": { @@ -2621,7 +2619,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Aw well. That just means I'll have to train even harder for next time! $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! - $@c{smile_wave}Keep at it, and enjoy the event!` + $@c{smile_wave}Keep at it!` }, "defeat": { 1: "It's OK to lose sometimes…" diff --git a/src/locales/ko/dialogue.ts b/src/locales/ko/dialogue.ts index ce6af0e43e7..ed0b498abbc 100644 --- a/src/locales/ko/dialogue.ts +++ b/src/locales/ko/dialogue.ts @@ -2569,8 +2569,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}와… 정말 깔끔하게 당했네.\n초보자 맞아? $@c{smile}운이 따른 건지도 모르겠지만…\n그래도 정말 꿈을 이룰 지도. $그나저나, 박사님께서 이걸 전해달라고 하시더라.\n좋아 보이던데. - $@c{serious_smile_fists}아무튼, 힘 내는거야! - $@c{smile}아- 그리고 이벤트 즐겁게 보내!` + $@c{serious_smile_fists}아무튼, 힘 내는거야!` }, }, "rival_female": { @@ -2584,8 +2583,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}왜 벌써 이렇게 센 건데?!@d{96}\n@c{angry}아니면 뭔가 속임수, 그런 거? $@c{smile_wave_wink}농담, 농담!@d{64} @c{smile_eclosed}내가 진 거 맞아…\n너 정말 앞으로도 잘 하겠는데. $@c{smile}아 그래, 박사님께서 전해달라던 물건.\n도움이 되면 좋겠어! - $@c{smile_wave}항상 최선을 다 하라구! 믿고 있을게! - $@c{smile}아- 그리고 이벤트 즐겁게 보내!` + $@c{smile_wave}항상 최선을 다 하라구! 믿고 있을게!` }, }, "rival_2": { @@ -2601,7 +2599,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}그래, 또 지고 말았네.\n@c{serious_mopen_fists}좀 더 열심히 훈련을 해야겠어!\n $@c{smile}너한테 도움이 필요할 것 같지는 않지만, 이거.\n남는 게 있어서 말이야. $@c{serious_smile_fists}물론 이번이 마지막이야, 알겠지?\n공평하게 하지 않으면 그게 내 핑계거리가 되고 말거야. - $@c{smile}이제 갈게. 앞으로도 조심하고, 이벤트도 즐겁게 보내!` + $@c{smile}이제 갈게. 앞으로도 조심하고!` }, }, "rival_2_female": { @@ -2617,7 +2615,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}으, 그래. 더 열심히 훈련하면 되겠지! $@c{smile_wave}이것도 하나 더 챙겨왔으니 받아!\n@c{smile_wave_wink}감사 인사는 됐다구~. $@c{angry_mopen}하지만, 마지막이야!\n또 이렇게 공짜로 나눠주진 않을 테니까! - $@c{smile_wave}그럼! 이벤트 잘 즐기고!` + $@c{smile_wave}그럼!` }, "defeat": { 1: "가끔은 지는 것도 괜찮아…" diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index 969c6fc36a9..076ca00d951 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -2541,8 +2541,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Caramba… Você me limpou.\nVocê é mesmo um novato? $@c{smile}Talvez tenha sido um pouco de sorte, mas…\nQuem sabe você consiga chegar até o fim. $Aliás, o professor me pediu para te dar esses itens. Eles parecem bem legais. - $@c{serious_smile_fists}Boa sorte lá fora! - $@c{smile}Ah- e eu espero que você aproveite o evento!` + $@c{serious_smile_fists}Boa sorte lá fora!` }, }, "rival_female": { @@ -2556,8 +2555,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `@c{shock}Você acabou de começar e já está tão forte?!@d{96}\n@c{angry}Você trapaceou, não foi? $@c{smile_wave_wink}Brincadeirinha!@d{64} @c{smile_eclosed}Eu perdi de forma justa… Tenho a sensação de que você vai se sair muito bem lá fora. $@c{smile}Aliás, o professor pediu para eu te dar alguns itens. Espero que sejam úteis! - $@c{smile_wave}Dê o seu melhor, como sempre! Eu acredito em você! - $@c{smile}Ah- e eu espero que você aproveite o evento!` + $@c{smile_wave}Dê o seu melhor, como sempre! Eu acredito em você!` }, }, "rival_2": { @@ -2573,7 +2571,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{smile}Tudo bem, no entanto. Eu imaginei que isso poderia acontecer.\n@c{serious_mopen_fists}Isso só significa que preciso me esforçar mais para a próxima vez!\n $@c{smile}Ah, não que você precise realmente de ajuda, mas eu tinha um extra desses itens e pensei que você poderia querer. $@c{serious_smile_fists}Não espere outro depois deste!\nNão posso continuar dando vantagem ao meu oponente. - $@c{smile}Enfim, cuide-se, e aproveite o evento!` + $@c{smile}Enfim, cuide-se!` }, }, "rival_2_female": { @@ -2587,9 +2585,9 @@ export const PGMdialogue: DialogueTranslationEntries = { "victory": { 1: `@c{neutral}Eu… não era para eu perder dessa vez… $@c{smile}Ah bem. Isso só significa que vou ter que treinar ainda mais para a próxima vez! - $@c{smile_wave}Também consegui mais dois desses para você!\n@c{smile_wave_wink}Não precisa me agradecer~. - $@c{angry_mopen}Estes são os últimos, hein! Você não vai ganhar mais nenhum presente de mim depois desse! - $@c{smile_wave}Continue assim, e aproveite o evento!` + $@c{smile_wave}Também consegui mais um desses para você!\n@c{smile_wave_wink}Não precisa me agradecer~. + $@c{angry_mopen}Este é o último, hein! Você não vai ganhar mais nenhum presente de mim depois desse! + $@c{smile_wave}Continue assim!` }, "defeat": { 1: "Está tudo bem perder às vezes…" @@ -5227,8 +5225,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: `@c{shock}Caramba… Você me limpou.\nVocê é mesmo uma novata? $@c{smile}Talvez tenha sido um pouco de sorte, mas…\nQuem sabe você consiga chegar até o fim. $Aliás, o professor me pediu para te dar esses itens. Eles parecem bem legais. - $@c{serious_smile_fists}Boa sorte lá fora! - $@c{smile}Ah- e eu espero que você aproveite o evento!` + $@c{serious_smile_fists}Boa sorte lá fora!` }, }, "rival_female": { @@ -5242,8 +5239,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: `@c{shock}Você acabou de começar e já está tão forte?!@d{96}\n@c{angry}Você trapaceou, não foi? $@c{smile_wave_wink}Brincadeirinha!@d{64} @c{smile_eclosed}Eu perdi de forma justa… Tenho a sensação de que você vai se sair muito bem lá fora. $@c{smile}Aliás, o professor pediu para eu te dar alguns itens. Espero que sejam úteis! - $@c{smile_wave}Dê o seu melhor, como sempre! Eu acredito em você! - $@c{smile}Ah- e eu espero que você aproveite o evento!` + $@c{smile_wave}Dê o seu melhor, como sempre! Eu acredito em você!` }, }, "rival_2": { @@ -5259,7 +5255,7 @@ export const PGFdialogue: DialogueTranslationEntries = { $@c{smile}Tudo bem, no entanto. Eu imaginei que isso poderia acontecer.\n@c{serious_mopen_fists}Isso só significa que preciso me esforçar mais para a próxima vez!\n $@c{smile}Ah, não que você precise realmente de ajuda, mas eu tinha um extra desses itens e pensei que você poderia querer. $@c{serious_smile_fists}Não espere outro depois deste!\nNão posso continuar dando vantagem ao meu oponente. - $@c{smile}Enfim, cuide-se, e aproveite o evento!` + $@c{smile}Enfim, cuide-se!` }, }, "rival_2_female": { @@ -5273,9 +5269,9 @@ export const PGFdialogue: DialogueTranslationEntries = { "victory": { 1: `@c{neutral}Eu… não era para eu perder dessa vez… $@c{smile}Ah bem. Isso só significa que vou ter que treinar ainda mais para a próxima vez! - $@c{smile_wave}Também consegui mais dois desses para você!\n@c{smile_wave_wink}Não precisa me agradecer~. - $@c{angry_mopen}Estes são os últimos, hein! Você não vai ganhar mais nenhum presente de mim depois desse! - $@c{smile_wave}Continue assim, e aproveite o evento!` + $@c{smile_wave}Também consegui mais um desses para você!\n@c{smile_wave_wink}Não precisa me agradecer~. + $@c{angry_mopen}Este é o último, hein! Você não vai ganhar mais nenhum presente de mim depois desse! + $@c{smile_wave}Continue assim!` }, "defeat": { 1: "Está tudo bem perder às vezes…" diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index 29afb56c40e..20d1d0d6040 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -2463,7 +2463,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile}嘿,我在找你呢!我知道你急着上路,\n但至少说个再见吧…$@c{smile_eclosed}所以你终于要开始追逐梦想了?\n我几乎不敢相信。$@c{serious_smile_fists}来都来了,来一场对战怎么样?\n毕竟,我想看看你是不是准备周全了。$@c{serious_mopen_fists}不要手下留情,我想让你全力以赴!", }, "victory": { - 1: "@c{shock}哇…你彻底击败了我。\n你是真初学者吗?$@c{smile}也许是靠点运气,但是…\n谁知道,你可能真的能一路走下去。$顺便说一下,博士让我给你这些东西。它们看起来可牛了。$@c{serious_smile_fists}祝你好运!$@c{smile}哦!我希望你能喜欢这次的活动! ", + 1: "@c{shock}哇…你彻底击败了我。\n你是真初学者吗?$@c{smile}也许是靠点运气,但是…\n谁知道,你可能真的能一路走下去。$顺便说一下,博士让我给你这些东西。它们看起来可牛了。$@c{serious_smile_fists}祝你好运!", }, }, "rival_female": { @@ -2471,7 +2471,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile_wave}你在这儿啊!我到处找你呢!$@c{angry_mopen}你忘了和你最好的朋友说再见了吗?$@c{smile_ehalf}你要去追逐梦想了,对吧?\n从今天开始,是不是…$@c{smile}不管怎样,忘了我的事就原谅你吧,\n但有个条件。@c{smile_wave_wink}你必须和我对战!$@c{angry_mopen}全力以赴!\n你也不想让你的冒险在开始之前就结束了,对吧?", }, "victory": { - 1: "@c{shock}你刚开始就已经这么强了?!@d{96}$@c{angry}你是不是开了?$@c{smile_wave_wink}只是开个玩笑啦!@d{64} @c{smile_eclosed}我输地心服口服了…\n我感觉你出去挺有天赋的。$@c{smile}顺便说一下,博士想让我给你一些东西。\n希望它们能帮上忙!$@c{smile_wave}像往常一样尽力而为!\n我相信你!$@c{smile}哦!我希望你能喜欢这次的活动! ", + 1: "@c{shock}你刚开始就已经这么强了?!@d{96}$@c{angry}你是不是开了?$@c{smile_wave_wink}只是开个玩笑啦!@d{64} @c{smile_eclosed}我输地心服口服了…\n我感觉你出去挺有天赋的。$@c{smile}顺便说一下,博士想让我给你一些东西。\n希望它们能帮上忙!$@c{smile_wave}像往常一样尽力而为!\n我相信你!", }, }, "rival_2": { @@ -2479,7 +2479,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile}嘿,你也在这里吗?$@c{smile_eclosed}一路过关斩将,是吧?$@c{serious_mopen_fists}我知道看起来好像我尾随着你来到这里,\n怎么可能啦。$@c{serious_smile_fists}说真的,自从你在老家打败我后,\n我就一直很渴望再比一场。$我自己也进行了很多训练,\n所以这次我肯定会好好打一场。$@c{serious_mopen_fists}不要手下留情,就像以前一样!$让我们开始吧!", }, "victory": { - 1: "@c{neutral_eclosed}哦。我过于自信了。$@c{smile}不过没关系。我猜到可能会这样。$@c{serious_mopen_fists}这只意味着我下次需要更努力!$$@c{smile}呃,不是特意帮你,我正好有多余的这个,\n我觉得你可能想要。$$@c{serious_smile_fists}不过这次之后别指望再有了!$我不能一直给我的对手优势。$@c{smile}反正,保重,要享受活动哦!", + 1: "@c{neutral_eclosed}哦。我过于自信了。$@c{smile}不过没关系。我猜到可能会这样。$@c{serious_mopen_fists}这只意味着我下次需要更努力!$$@c{smile}呃,不是特意帮你,我正好有多余的这个,\n我觉得你可能想要。$$@c{serious_smile_fists}不过这次之后别指望再有了!$我不能一直给我的对手优势。$@c{smile}反正,保重!", }, }, "rival_2_female": { @@ -2487,7 +2487,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile_wave}哦,真巧,在这里遇见你。\n看来你还没输过嘛。@c{angry_mopen}哈……好家伙!$@c{angry_mopen}我知道你在想什么,\n不,我才不会跟踪你什么呢。 @c{smile_eclosed}我只是碰巧在附近。$@c{smile_ehalf}我为你感到高兴,但我只想让你知道\n有时输了是可以接受的。$@c{smile}我们从错误中学到的东西\n往往比我们一直成功时学到的还要多。$@c{angry_mopen}无论如何,我为了我们的复赛已经努力训练了\n所以你最好全力以赴!", }, "victory": { - 1: "@c{neutral}我……没打算会输来着……$@c{smile}嗷……好吧。看来我要再更加努力训练了!$@c{smile_wave}我还给你带了个这个$@c{smile_wave_wink}不用谢我哦~.$@c{angry_mopen}不过,这是最后一个啦!\n你可别想再从我这赚小便宜了~$@c{smile_wave}要保重哦,要享受活动哦!", + 1: "@c{neutral}我……没打算会输来着……$@c{smile}嗷……好吧。看来我要再更加努力训练了!$@c{smile_wave}我还给你带了个这个$@c{smile_wave_wink}不用谢我哦~.$@c{angry_mopen}不过,这是最后一个啦!\n你可别想再从我这赚小便宜了~$@c{smile_wave}要保重哦!", }, "defeat": { 1: "输了有时候也不要紧的…", diff --git a/src/locales/zh_TW/dialogue.ts b/src/locales/zh_TW/dialogue.ts index 06ccc745a49..cfe43317bb7 100644 --- a/src/locales/zh_TW/dialogue.ts +++ b/src/locales/zh_TW/dialogue.ts @@ -2463,7 +2463,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile}嘿,我在找你呢!我知道你急著上路,\n但至少說個再見吧…$@c{smile_eclosed}所以你終於要開始追逐夢想了?\n我幾乎不敢相信。$@c{serious_smile_fists}來都來了,來一場對戰怎麼樣?\n畢竟,我想看看你是不是準備周全了。$@c{serious_mopen_fists}不要手下留情,我想讓你全力以赴!", }, "victory": { - 1: "@c{shock}哇…你徹底擊敗了我。\n你是真初學者嗎?$@c{smile}也許是靠點運氣,但是…\n誰知道,你可能真的能一路走下去。$順便說一下,博士讓我給你這些東西。它們看起來可牛了。$@c{serious_smile_fists}祝你好运!$@c{smile}哦!我希望你能喜歡這次的活動!", + 1: "@c{shock}哇…你徹底擊敗了我。\n你是真初學者嗎?$@c{smile}也許是靠點運氣,但是…\n誰知道,你可能真的能一路走下去。$順便說一下,博士讓我給你這些東西。它們看起來可牛了。$@c{serious_smile_fists}祝你好运!", }, }, "rival_female": { @@ -2471,7 +2471,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile_wave}你在這兒啊!我到處找你呢!$@c{angry_mopen}你忘了和你最好的朋友說再見了嗎?$@c{smile_ehalf}你要去追逐夢想了,對吧?\n從今天開始,是不是…$@c{smile}不管怎樣,忘了我的事就原諒你吧,\n但有個條件。@c{smile_wave_wink}你必須和我對戰!$@c{angry_mopen}全力以赴!\n你也不想讓你的冒險在開始之前就結束了,對吧?", }, "victory": { - 1: "@c{shock}你剛開始就已經這麼強了?!@d{96}$@c{angry}你是不是開了?$@c{smile_wave_wink}只是開個玩笑啦!@d{64} @c{smile_eclosed}我輸地心服口服了…\n我感覺你出去挺有天賦的。$@c{smile}順便說一下,博士想讓我給你一些東西。\n希望它們能幫上忙!$@c{smile_wave}像往常一樣盡力而為!\n我相信你!$@c{smile}哦!我希望你能喜歡這次的活動!", + 1: "@c{shock}你剛開始就已經這麼強了?!@d{96}$@c{angry}你是不是開了?$@c{smile_wave_wink}只是開個玩笑啦!@d{64} @c{smile_eclosed}我輸地心服口服了…\n我感覺你出去挺有天賦的。$@c{smile}順便說一下,博士想讓我給你一些東西。\n希望它們能幫上忙!$@c{smile_wave}像往常一樣盡力而為!\n我相信你!", }, }, "rival_2": { @@ -2479,7 +2479,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile}嘿,你也在這裡嗎?$@c{smile_eclosed}一路過關斬將,是吧?$@c{serious_mopen_fists}我知道看起來好像我尾隨著你來到這裡,\n怎麼可能啦。$@c{serious_smile_fists}說真的,自從你在老家打敗我後,\n我就一直很渴望再比一場。$我自己也進行了很多訓練,\n所以這次我肯定會好好打一場。$@c{serious_mopen_fists}不要手下留情,就像以前一樣!$讓我們開始吧!", }, "victory": { - 1: "@c{neutral_eclosed}哦。我過於自信了。$@c{smile}不過沒關係。我猜到可能會這樣。$@c{serious_mopen_fists}這只意味著我下次需要更努力!$$@c{smile}呃,不是特意幫你,我正好有多餘的這個,\n我覺得你可能想要。$$@c{serious_smile_fists}不過這次之後別指望再有了!$我不能一直給我的對手優勢。$@c{smile}反正,保重, 要享受活動哦!", + 1: "@c{neutral_eclosed}哦。我過於自信了。$@c{smile}不過沒關係。我猜到可能會這樣。$@c{serious_mopen_fists}這只意味著我下次需要更努力!$$@c{smile}呃,不是特意幫你,我正好有多餘的這個,\n我覺得你可能想要。$$@c{serious_smile_fists}不過這次之後別指望再有了!$我不能一直給我的對手優勢。$@c{smile}反正,保重!", }, }, "rival_2_female": { @@ -2487,7 +2487,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "@c{smile_wave}哦,真巧,在這裡遇見你。\n看來你還沒輸過嘛。@c{angry_mopen}哈……好傢伙!$@c{angry_mopen}我知道你在想什麼,\n不,我才不會跟蹤你什麼呢。 @c{smile_eclosed}我只是碰巧在附近。$@c{smile_ehalf}我為你感到高興,但我只想讓你知道\n有時輸了是可以接受的。$@c{smile}我們從錯誤中學到的東西\n往往比我們一直成功時學到的還要多。$@c{angry_mopen}無論如何,我為了我們的複賽已經努力訓練了\n所以你最好全力以赴!", }, "victory": { - 1: "@c{neutral}我……沒打算會輸來著……$@c{smile}嗷……好吧。看來我要再更加努力訓練了!$@c{smile_wave}我還給你帶了個這個$@c{smile_wave_wink}不用謝我哦~.$@c{angry_mopen}不過,這是最後一個啦!\n 你可別想再從我這賺小便宜了~$@c{smile_wave}要保重哦,要享受活動哦!", + 1: "@c{neutral}我……沒打算會輸來著……$@c{smile}嗷……好吧。看來我要再更加努力訓練了!$@c{smile_wave}我還給你帶了個這個$@c{smile_wave_wink}不用謝我哦~.$@c{angry_mopen}不過,這是最後一個啦!\n 你可別想再從我這賺小便宜了~$@c{smile_wave}要保重哦!", }, "defeat": { 1: "輸了有時候也不要緊的…", From 051d38e0a2f6b61340a25e2f68b1333b5b412b11 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:29:21 -0700 Subject: [PATCH 51/63] [Enhancement] Add support for simulated calls to Abilities (#3529) * Adds simulated tag support to all abilities * Fix compiler errors in ability.ts Most things are still on fire :cry: * Fix errors left over after merge * Another pass through simulated ability call logic * Fix leftover errors from merge resolution * Another gh pages issue :pikamad: * Simulated call fixes based on Kev's feedback * RIP phases.ts --------- Co-authored-by: Xavion3 --- src/battle-scene.ts | 6 +- src/data/ability.ts | 979 ++++++++++++-------- src/data/arena-tag.ts | 2 +- src/data/berry.ts | 14 +- src/data/move.ts | 26 +- src/data/terrain.ts | 2 +- src/field/pokemon.ts | 80 +- src/phases/attempt-run-phase.ts | 2 +- src/phases/command-phase.ts | 2 +- src/phases/encounter-phase.ts | 2 +- src/phases/enemy-command-phase.ts | 2 +- src/phases/move-effect-phase.ts | 2 +- src/phases/move-phase.ts | 2 +- src/phases/post-turn-status-effect-phase.ts | 2 +- src/phases/stat-change-phase.ts | 4 +- src/phases/turn-start-phase.ts | 8 +- src/test/abilities/sand_veil.test.ts | 2 +- src/test/abilities/serene_grace.test.ts | 4 +- src/test/abilities/sheer_force.test.ts | 16 +- src/test/abilities/shield_dust.test.ts | 4 +- 20 files changed, 677 insertions(+), 484 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index b72e79c866d..aad0d355e38 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1100,7 +1100,7 @@ export default class BattleScene extends SceneBase { } else if (trainerConfigs[trainerType].hasDouble) { const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); - playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); + playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance)); doubleTrainer = !Utils.randSeedInt(doubleChance.value); // Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance if (trainerConfigs[trainerType].trainerTypeDouble && ![ TrainerType.TATE, TrainerType.LIZA ].includes(trainerType)) { @@ -1116,7 +1116,7 @@ export default class BattleScene extends SceneBase { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); - playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); + playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance)); newDouble = !Utils.randSeedInt(doubleChance.value); } else if (newBattleType === BattleType.TRAINER) { newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; @@ -2136,7 +2136,7 @@ export default class BattleScene extends SceneBase { pushMovePhase(movePhase: MovePhase, priorityOverride?: integer): void { const movePriority = new Utils.IntegerHolder(priorityOverride !== undefined ? priorityOverride : movePhase.move.getMove().priority); - applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, movePhase.move.getMove(), movePriority); + applyAbAttrs(ChangeMovePriorityAbAttr, movePhase.pokemon, null, false, movePhase.move.getMove(), movePriority); const lowerPriorityPhase = this.phaseQueue.find(p => p instanceof MovePhase && p.move.getMove().priority < movePriority.value); if (lowerPriorityPhase) { this.phaseQueue.splice(this.phaseQueue.indexOf(lowerPriorityPhase), 0, movePhase); diff --git a/src/data/ability.ts b/src/data/ability.ts index 8e020849a17..27a11eb0b9a 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -135,7 +135,7 @@ export abstract class AbAttr { this.showAbility = showAbility; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { return false; } @@ -154,7 +154,7 @@ export abstract class AbAttr { } export class BlockRecoilDamageAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -170,7 +170,7 @@ export class DoubleBattleChanceAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const doubleChance = (args[0] as Utils.IntegerHolder); doubleChance.value = Math.max(doubleChance.value / 2, 1); return true; @@ -178,7 +178,7 @@ export class DoubleBattleChanceAbAttr extends AbAttr { } export class PostBattleInitAbAttr extends AbAttr { - applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { return false; } } @@ -192,9 +192,9 @@ export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr { this.formFunc = formFunc; } - applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); - if (formIndex !== pokemon.formIndex) { + if (formIndex !== pokemon.formIndex && !simulated) { return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); } @@ -217,22 +217,24 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { this.selfTarget = !!selfTarget; } - applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const statChangePhases: StatChangePhase[] = []; - if (this.selfTarget) { - statChangePhases.push(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); - } else { - for (const opponent of pokemon.getOpponents()) { - statChangePhases.push(new StatChangePhase(pokemon.scene, opponent.getBattlerIndex(), false, this.stats, this.levels)); + if (!simulated) { + if (this.selfTarget) { + statChangePhases.push(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + } else { + for (const opponent of pokemon.getOpponents()) { + statChangePhases.push(new StatChangePhase(pokemon.scene, opponent.getBattlerIndex(), false, this.stats, this.levels)); + } } - } - for (const statChangePhase of statChangePhases) { - if (!this.selfTarget && !statChangePhase.getPokemon()?.summonData) { - pokemon.scene.pushPhase(statChangePhase); - } else { // TODO: This causes the ability bar to be shown at the wrong time - pokemon.scene.unshiftPhase(statChangePhase); + for (const statChangePhase of statChangePhases) { + if (!this.selfTarget && !statChangePhase.getPokemon()?.summonData) { + pokemon.scene.pushPhase(statChangePhase); + } else { // TODO: This causes the ability bar to be shown at the wrong time + pokemon.scene.unshiftPhase(statChangePhase); + } } } @@ -243,17 +245,17 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move) => boolean; export class PreDefendAbAttr extends AbAttr { - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { return false; } } export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (pokemon.isFullHp() && - pokemon.getMaxHp() > 1 && //Checks if pokemon has wonder_guard (which forces 1hp) - (args[0] as Utils.NumberHolder).value >= pokemon.hp) { //Damage >= hp - return pokemon.addTag(BattlerTagType.STURDY, 1); + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (pokemon.isFullHp() + && pokemon.getMaxHp() > 1 //Checks if pokemon has wonder_guard (which forces 1hp) + && (args[0] as Utils.NumberHolder).value >= pokemon.hp) { //Damage >= hp + return simulated || pokemon.addTag(BattlerTagType.STURDY, 1); } return false; @@ -261,7 +263,7 @@ export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { } export class BlockItemTheftAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -276,7 +278,7 @@ export class BlockItemTheftAbAttr extends AbAttr { } export class StabBoostAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if ((args[0] as Utils.NumberHolder).value > 1) { (args[0] as Utils.NumberHolder).value += 0.5; return true; @@ -297,7 +299,7 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr { this.damageMultiplier = damageMultiplier; } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { (args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * this.damageMultiplier); @@ -341,7 +343,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr { * @param args [0] {@linkcode Utils.NumberHolder} gets set to 0 if move is immuned by an ability. * @param args [1] - Whether the move is simulated. */ - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { // Field moves should ignore immunity if ([ MoveTarget.BOTH_SIDES, MoveTarget.ENEMY_SIDE, MoveTarget.USER_SIDE ].includes(move.moveTarget)) { return false; @@ -368,9 +370,9 @@ export class AttackTypeImmunityAbAttr extends TypeImmunityAbAttr { * Type immunity abilities that do not give additional benefits (HP recovery, stat boosts, etc) are not immune to status moves of the type * Example: Levitate */ - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (move.category !== MoveCategory.STATUS) { - return super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); + return super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } return false; } @@ -381,17 +383,14 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr { super(immuneType); } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); if (ret) { - if (!pokemon.isFullHp()) { - const simulated = args.length > 1 && args[1]; - if (!simulated) { - const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; - pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); - } + if (!pokemon.isFullHp() && !simulated) { + const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; + pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } return true; } @@ -411,12 +410,11 @@ class TypeImmunityStatChangeAbAttr extends TypeImmunityAbAttr { this.levels = levels; } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); if (ret) { cancelled.value = true; - const simulated = args.length > 1 && args[1]; if (!simulated) { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); } @@ -437,12 +435,11 @@ class TypeImmunityAddBattlerTagAbAttr extends TypeImmunityAbAttr { this.turnCount = turnCount; } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); if (ret) { cancelled.value = true; - const simulated = args.length > 1 && args[1]; if (!simulated) { pokemon.addTag(this.tagType, this.turnCount, undefined, pokemon.id); } @@ -457,7 +454,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { super(null, condition); } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (move instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.type, attacker) < 2) { cancelled.value = true; (args[0] as Utils.NumberHolder).value = 0; @@ -476,7 +473,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { } export class PostDefendAbAttr extends AbAttr { - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { return false; } } @@ -500,12 +497,16 @@ export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr { * @param {any[]} args - n/a * @returns Whether the effects of the ability are applied. */ - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { const battlerTag = pokemon.getTag(GulpMissileTag); if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) { return false; } + if (simulated) { + return true; + } + const cancelled = new Utils.BooleanHolder(false); applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled); @@ -525,12 +526,12 @@ export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr { } export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { const attackPriority = new Utils.IntegerHolder(move.priority); - applyMoveAttrs(IncrementMovePriorityAttr,attacker,null,move,attackPriority); - applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, move, attackPriority); + applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, attackPriority); + applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, simulated, move, attackPriority); - if (move.moveTarget===MoveTarget.USER || move.moveTarget===MoveTarget.NEAR_ALLY) { + if (move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) { return false; } @@ -544,7 +545,7 @@ export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { } export class PostStatChangeAbAttr extends AbAttr { - applyPostStatChange(pokemon: Pokemon, statsChanged: BattleStat[], levelChanged: integer, selfTarget: boolean, args: any[]): boolean | Promise { + applyPostStatChange(pokemon: Pokemon, simulated: boolean, statsChanged: BattleStat[], levelChanged: integer, selfTarget: boolean, args: any[]): boolean | Promise { return false; } } @@ -558,7 +559,7 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr { this.immuneCondition = immuneCondition; } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.immuneCondition(pokemon, attacker, move)) { cancelled.value = true; return true; @@ -579,7 +580,7 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr { * @extends PreDefendAbAttr */ export class WonderSkinAbAttr extends PreDefendAbAttr { - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { const moveAccuracy = args[0] as Utils.NumberHolder; if (move.category === MoveCategory.STATUS && moveAccuracy.value >= 50) { moveAccuracy.value = 50; @@ -600,13 +601,10 @@ export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr { this.levels = levels; } - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); - if (ret) { - const simulated = args.length > 1 && args[1]; - if (!simulated) { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); - } + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); + if (ret && !simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); } return ret; @@ -630,9 +628,11 @@ export class ReverseDrainAbAttr extends PostDefendAbAttr { * @args N/A * @returns true if healing should be reversed on a healing move, false otherwise. */ - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.hasAttr(HitHealAttr)) { - pokemon.scene.queueMessage(i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(attacker) })); + if (!simulated) { + pokemon.scene.queueMessage(i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(attacker) })); + } return true; } return false; @@ -656,8 +656,12 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr { this.allOthers = allOthers; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { + if (simulated) { + return true; + } + if (this.allOthers) { const otherPokemon = pokemon.getAlly() ? pokemon.getOpponents().concat([ pokemon.getAlly() ]) : pokemon.getOpponents(); for (const other of otherPokemon) { @@ -690,13 +694,15 @@ export class PostDefendHpGatedStatChangeAbAttr extends PostDefendAbAttr { this.selfTarget = selfTarget; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { const hpGateFlat: integer = Math.ceil(pokemon.getMaxHp() * this.hpGate); const lastAttackReceived = pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1]; const damageReceived = lastAttackReceived?.damage || 0; if (this.condition(pokemon, attacker, move) && (pokemon.hp <= hpGateFlat && (pokemon.hp + damageReceived) > hpGateFlat)) { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, this.stats, this.levels)); + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, this.stats, this.levels)); + } return true; } @@ -715,11 +721,13 @@ export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr { this.tagType = tagType; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { const tag = pokemon.scene.arena.getTag(this.tagType) as ArenaTrapTag; if (!pokemon.scene.arena.getTag(this.tagType) || tag.layers < tag.maxLayers) { - pokemon.scene.arena.addTag(this.tagType, 0, undefined, pokemon.id, pokemon.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER); + if (!simulated) { + pokemon.scene.arena.addTag(this.tagType, 0, undefined, pokemon.id, pokemon.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER); + } return true; } } @@ -737,9 +745,9 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr { this.tagType = tagType; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { - if (!pokemon.getTag(this.tagType)) { + if (!pokemon.getTag(this.tagType) && !simulated) { pokemon.addTag(this.tagType, undefined, undefined, pokemon.id); pokemon.scene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name })); } @@ -750,8 +758,11 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr { } export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr { - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (hitResult < HitResult.NO_EFFECT) { + if (simulated) { + return true; + } const type = move.type; const pokemonTypes = pokemon.getTypes(true); if (pokemonTypes.length !== 1 || pokemonTypes[0] !== type) { @@ -781,9 +792,13 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr { this.terrainType = terrainType; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (hitResult < HitResult.NO_EFFECT) { - return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + if (simulated) { + return pokemon.scene.arena.terrain?.terrainType !== (this.terrainType || undefined); + } else { + return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + } } return false; @@ -801,10 +816,14 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr { this.effects = effects; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.status && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance)) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; - return attacker.trySetStatus(effect, true, pokemon); + if (simulated) { + return attacker.canSetStatus(effect, true, false, pokemon); + } else { + return attacker.trySetStatus(effect, true, pokemon); + } } return false; @@ -816,11 +835,11 @@ export class EffectSporeAbAttr extends PostDefendContactApplyStatusEffectAbAttr super(10, StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP); } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (attacker.hasAbility(Abilities.OVERCOAT) || attacker.isOfType(Type.GRASS)) { return false; } - return super.applyPostDefend(pokemon, passive, attacker, move, hitResult, args); + return super.applyPostDefend(pokemon, passive, simulated, attacker, move, hitResult, args); } } @@ -837,9 +856,13 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr { this.turnCount = turnCount; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance) { - return attacker.addTag(this.tagType, this.turnCount, move.id, attacker.id); + if (simulated) { + return attacker.canAddTag(this.tagType); + } else { + return attacker.addTag(this.tagType, this.turnCount, move.id, attacker.id); + } } return false; @@ -857,8 +880,10 @@ export class PostDefendCritStatChangeAbAttr extends PostDefendAbAttr { this.levels = levels; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); + } return true; } @@ -877,8 +902,8 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { this.damageRatio = damageRatio; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + if (!simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.turnData.damageTaken += Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)); return true; @@ -910,13 +935,15 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr { this.turns = turns; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { if (pokemon.getTag(BattlerTagType.PERISH_SONG) || attacker.getTag(BattlerTagType.PERISH_SONG)) { return false; } else { - attacker.addTag(BattlerTagType.PERISH_SONG, this.turns); - pokemon.addTag(BattlerTagType.PERISH_SONG, this.turns); + if (!simulated) { + attacker.addTag(BattlerTagType.PERISH_SONG, this.turns); + pokemon.addTag(BattlerTagType.PERISH_SONG, this.turns); + } return true; } } @@ -939,11 +966,14 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr { this.condition = condition ?? null; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (this.condition !== null && !this.condition(pokemon, attacker, move)) { return false; } if (!pokemon.scene.arena.weather?.isImmutable()) { + if (simulated) { + return pokemon.scene.arena.weather?.weatherType !== this.weatherType; + } return pokemon.scene.arena.trySetWeather(this.weatherType, true); } @@ -956,11 +986,13 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr { super(); } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnswappableAbilityAbAttr)) { - const tempAbilityId = attacker.getAbility().id; - attacker.summonData.ability = pokemon.getAbility().id; - pokemon.summonData.ability = tempAbilityId; + if (!simulated) { + const tempAbilityId = attacker.getAbility().id; + attacker.summonData.ability = pokemon.getAbility().id; + pokemon.summonData.ability = tempAbilityId; + } return true; } @@ -980,9 +1012,11 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr { this.ability = ability; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr)) { - attacker.summonData.ability = this.ability; + if (!simulated) { + attacker.summonData.ability = this.ability; + } return true; } @@ -1009,9 +1043,13 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr { this.chance = chance; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (!attacker.summonData.disabledMove) { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) && !attacker.isMax()) { + if (simulated) { + return true; + } + this.attacker = attacker; this.move = move; @@ -1044,9 +1082,11 @@ export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr { this.levels = levels; } - applyPostStatChange(pokemon: Pokemon, statsChanged: BattleStat[], levelsChanged: integer, selfTarget: boolean, args: any[]): boolean { + applyPostStatChange(pokemon: Pokemon, simulated: boolean, statsChanged: BattleStat[], levelsChanged: integer, selfTarget: boolean, args: any[]): boolean { if (this.condition(pokemon, statsChanged, levelsChanged) && !selfTarget) { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (pokemon).getBattlerIndex(), true, this.statsToChange, this.levels)); + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (pokemon).getBattlerIndex(), true, this.statsToChange, this.levels)); + } return true; } @@ -1055,7 +1095,7 @@ export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr { } export class PreAttackAbAttr extends AbAttr { - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean | Promise { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean | Promise { return false; } } @@ -1076,7 +1116,7 @@ export class MoveEffectChanceMultiplierAbAttr extends AbAttr { * @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. Has to be higher than or equal to 0. * [1]: {@linkcode Moves } Move used by the ability user. */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { // Disable showAbility during getTargetBenefitScore this.showAbility = args[4]; if ((args[0] as Utils.NumberHolder).value <= 0 || (args[1] as Move).id === Moves.ORDER_UP) { @@ -1099,7 +1139,7 @@ export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr { /** * @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. */ - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if ((args[0] as Utils.NumberHolder).value <= 0) { return false; @@ -1112,14 +1152,14 @@ export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr { } export class VariableMovePowerAbAttr extends PreAttackAbAttr { - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { //const power = args[0] as Utils.NumberHolder; return false; } } export class FieldPreventExplosiveMovesAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { cancelled.value = true; return true; } @@ -1156,7 +1196,7 @@ export class FieldMultiplyBattleStatAbAttr extends AbAttr { * @param args {any[]} unused * @returns true if this changed the checked stat, false otherwise. */ - applyFieldBattleStat(pokemon: Pokemon, passive: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): boolean { + applyFieldBattleStat(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): boolean { if (!this.canStack && hasApplied.value) { return false; } @@ -1180,7 +1220,7 @@ export class MoveTypeChangeAttr extends PreAttackAbAttr { super(true); } - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { if (this.condition && this.condition(pokemon, defender, move)) { move.type = this.newType; if (args[0] && args[0] instanceof Utils.NumberHolder) { @@ -1201,7 +1241,7 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr { super(true); } - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { if ( !pokemon.isTerastallized() && move.id !== Moves.STRUGGLE && @@ -1229,9 +1269,11 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr { } if (pokemon.getTypes().some((t) => t !== moveCopy.type)) { - this.moveType = moveCopy.type; - pokemon.summonData.types = [moveCopy.type]; - pokemon.updateInfo(); + if (!simulated) { + this.moveType = moveCopy.type; + pokemon.summonData.types = [moveCopy.type]; + pokemon.updateInfo(); + } return true; } @@ -1307,7 +1349,7 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr { * @param {Utils.NumberHolder} args\[2\] the damage multiplier for the current strike * @returns */ - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { const numTargets = args[0] as integer; const hitCount = args[1] as Utils.IntegerHolder; const multiplier = args[2] as Utils.NumberHolder; @@ -1352,7 +1394,7 @@ export class DamageBoostAbAttr extends PreAttackAbAttr { * @param args Utils.NumberHolder as damage * @returns true if the function succeeds */ - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { if (this.condition(pokemon, defender, move)) { const power = args[0] as Utils.NumberHolder; power.value = Math.floor(power.value * this.damageMultiplier); @@ -1373,7 +1415,7 @@ export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr { this.powerMultiplier = powerMultiplier; } - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean { if (this.condition(pokemon, defender, move)) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; @@ -1420,7 +1462,7 @@ export class VariableMovePowerBoostAbAttr extends VariableMovePowerAbAttr { /** * @override */ - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move, args: any[]): boolean { const multiplier = this.mult(pokemon, defender, move); if (multiplier !== 1) { (args[0] as Utils.NumberHolder).value *= multiplier; @@ -1449,7 +1491,7 @@ export class FieldMovePowerBoostAbAttr extends AbAttr { this.powerMultiplier = powerMultiplier; } - applyPreAttack(pokemon: Pokemon | null, passive: boolean | null, defender: Pokemon | null, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon | null, passive: boolean | null, simulated: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean { if (this.condition(pokemon, defender, move)) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; @@ -1513,7 +1555,7 @@ export class BattleStatMultiplierAbAttr extends AbAttr { this.condition = condition ?? null; } - applyBattleStat(pokemon: Pokemon, passive: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise { + applyBattleStat(pokemon: Pokemon, passive: boolean, simulated: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise { const move = (args[0] as Move); if (battleStat === this.battleStat && (!this.condition || this.condition(pokemon, null, move))) { statValue.value *= this.multiplier; @@ -1539,11 +1581,11 @@ export class PostAttackAbAttr extends AbAttr { * applying the effect of any inherited class. This can be changed by providing a different {@link attackCondition} to the constructor. See {@link ConfusionOnStatusEffectAbAttr} * for an example of an effect that does not require a damaging move. */ - applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { + applyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { // When attackRequired is true, we require the move to be an attack move and to deal damage before checking secondary requirements. // If attackRequired is false, we always defer to the secondary requirements. if (this.attackCondition(pokemon, defender, move)) { - return this.applyPostAttackAfterMoveTypeCheck(pokemon, passive, defender, move, hitResult, args); + return this.applyPostAttackAfterMoveTypeCheck(pokemon, passive, simulated, defender, move, hitResult, args); } else { return false; } @@ -1552,7 +1594,7 @@ export class PostAttackAbAttr extends AbAttr { /** * This method is only called after {@link applyPostAttack} has already been applied. Use this for handling checks specific to the ability in question. */ - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { return false; } } @@ -1566,9 +1608,9 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { this.stealCondition = stealCondition ?? null; } - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { return new Promise(resolve => { - if (hitResult < HitResult.NO_EFFECT && (!this.stealCondition || this.stealCondition(pokemon, defender, move))) { + if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.stealCondition || this.stealCondition(pokemon, defender, move))) { const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferrable); if (heldItems.length) { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; @@ -1581,7 +1623,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { return; } } - resolve(false); + resolve(simulated); }); } @@ -1604,14 +1646,14 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr { this.effects = effects; } - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { /**Status inflicted by abilities post attacking are also considered additional effects.*/ - if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) { + if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !simulated && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; return attacker.trySetStatus(effect, true, pokemon); } - return false; + return simulated; } } @@ -1635,11 +1677,11 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr { this.effects = effects; } - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { /**Battler tags inflicted by abilities post attacking are also considered additional effects.*/ if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; - return attacker.addTag(effect); + return simulated || attacker.addTag(effect); } return false; @@ -1655,9 +1697,9 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { this.condition = condition ?? null; } - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { return new Promise(resolve => { - if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) { + if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) { const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferrable); if (heldItems.length) { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; @@ -1670,7 +1712,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { return; } } - resolve(false); + resolve(simulated); }); } @@ -1681,7 +1723,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { } export class PostVictoryAbAttr extends AbAttr { - applyPostVictory(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { return false; } } @@ -1697,12 +1739,13 @@ class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr { this.levels = levels; } - applyPostVictory(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat; - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], this.levels)); - + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], this.levels)); + } return true; } } @@ -1716,10 +1759,12 @@ export class PostVictoryFormChangeAbAttr extends PostVictoryAbAttr { this.formFunc = formFunc; } - applyPostVictory(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) { - pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + if (!simulated) { + pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + } return true; } @@ -1728,7 +1773,7 @@ export class PostVictoryFormChangeAbAttr extends PostVictoryAbAttr { } export class PostKnockOutAbAttr extends AbAttr { - applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { + applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { return false; } } @@ -1744,12 +1789,13 @@ export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr { this.levels = levels; } - applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { + applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat; - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], this.levels)); - + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], this.levels)); + } return true; } } @@ -1759,10 +1805,12 @@ export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr { super(); } - applyPostKnockOut(pokemon: Pokemon, passive: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { + applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise { if (pokemon.isPlayer() === knockedOut.isPlayer() && !knockedOut.getAbility().hasAttr(UncopiableAbilityAbAttr)) { - pokemon.summonData.ability = knockedOut.getAbility().id; - pokemon.scene.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name })); + if (!simulated) { + pokemon.summonData.ability = knockedOut.getAbility().id; + pokemon.scene.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name })); + } return true; } @@ -1775,7 +1823,7 @@ export class IgnoreOpponentStatChangesAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]) { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]) { (args[0] as Utils.IntegerHolder).value = 0; return true; @@ -1798,7 +1846,7 @@ export class IgnoreOpponentEvasionAbAttr extends AbAttr { * @param args [0] {@linkcode Utils.IntegerHolder} of BattleStat.EVA * @returns if evasion level was successfully considered as 0 */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]) { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]) { (args[0] as Utils.IntegerHolder).value = 0; return true; } @@ -1809,7 +1857,7 @@ export class IntimidateImmunityAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -1834,8 +1882,10 @@ export class PostIntimidateStatChangeAbAttr extends AbAttr { this.overwrites = !!overwrites; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { - pokemon.scene.pushPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, this.stats, this.levels)); + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (!simulated) { + pokemon.scene.pushPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, this.stats, this.levels)); + } cancelled.value = this.overwrites; return true; } @@ -1853,7 +1903,7 @@ export class PostSummonAbAttr extends AbAttr { * @param args Set of unique arguments needed by this attribute * @returns true if application of the ability succeeds */ - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { return false; } } @@ -1872,9 +1922,11 @@ export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr { this.arenaTags = arenaTags; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { - for (const arenaTag of this.arenaTags) { - pokemon.scene.arena.removeTag(arenaTag); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { + if (!simulated) { + for (const arenaTag of this.arenaTags) { + pokemon.scene.arena.removeTag(arenaTag); + } } return true; } @@ -1889,8 +1941,10 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr { this.messageFunc = messageFunc; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - pokemon.scene.queueMessage(this.messageFunc(pokemon)); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (!simulated) { + pokemon.scene.queueMessage(this.messageFunc(pokemon)); + } return true; } @@ -1906,8 +1960,10 @@ export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr { this.message = message; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - pokemon.scene.queueMessage(this.message); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (!simulated) { + pokemon.scene.queueMessage(this.message); + } return true; } @@ -1924,8 +1980,12 @@ export class PostSummonAddBattlerTagAbAttr extends PostSummonAbAttr { this.turnCount = turnCount; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - return pokemon.addTag(this.tagType, this.turnCount); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (simulated) { + return pokemon.canAddTag(this.tagType); + } else { + return pokemon.addTag(this.tagType, this.turnCount); + } } } @@ -1946,7 +2006,11 @@ export class PostSummonStatChangeAbAttr extends PostSummonAbAttr { this.intimidate = !!intimidate; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (simulated) { + return true; + } + queueShowAbility(pokemon, passive); // TODO: Better solution than manually showing the ability here if (this.selfTarget) { // we unshift the StatChangePhase to put it right after the showAbility and not at the end of the @@ -1957,8 +2021,8 @@ export class PostSummonStatChangeAbAttr extends PostSummonAbAttr { for (const opponent of pokemon.getOpponents()) { const cancelled = new Utils.BooleanHolder(false); if (this.intimidate) { - applyAbAttrs(IntimidateImmunityAbAttr, opponent, cancelled); - applyAbAttrs(PostIntimidateStatChangeAbAttr, opponent, cancelled); + applyAbAttrs(IntimidateImmunityAbAttr, opponent, cancelled, simulated); + applyAbAttrs(PostIntimidateStatChangeAbAttr, opponent, cancelled, simulated); } if (!cancelled.value) { const statChangePhase = new StatChangePhase(pokemon.scene, opponent.getBattlerIndex(), false, this.stats, this.levels); @@ -1980,11 +2044,14 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr { this.showAnim = showAnim; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const target = pokemon.getAlly(); if (target?.isActive(true)) { - target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / this.healRatio), 1), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); + if (!simulated) { + target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() / this.healRatio), 1), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); + } + return true; } @@ -2005,14 +2072,16 @@ export class PostSummonClearAllyStatsAbAttr extends PostSummonAbAttr { super(); } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const target = pokemon.getAlly(); if (target?.isActive(true)) { - for (let s = 0; s < target.summonData.battleStats.length; s++) { - target.summonData.battleStats[s] = 0; - } + if (!simulated) { + for (let s = 0; s < target.summonData.battleStats.length; s++) { + target.summonData.battleStats[s] = 0; + } - target.scene.queueMessage(i18next.t("abilityTriggers:postSummonClearAllyStats", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); + target.scene.queueMessage(i18next.t("abilityTriggers:postSummonClearAllyStats", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); + } return true; } @@ -2043,7 +2112,7 @@ export class DownloadAbAttr extends PostSummonAbAttr { * @param {any[]} args N/A * @returns Returns true if ability is used successful, false if not. */ - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { this.enemyDef = 0; this.enemySpDef = 0; this.enemyCountTally = 0; @@ -2063,7 +2132,9 @@ export class DownloadAbAttr extends PostSummonAbAttr { } if (this.enemyDef > 0 && this.enemySpDef > 0) { // only activate if there's actually an enemy to download from - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, this.stats, 1)); + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, this.stats, 1)); + } return true; } @@ -2080,11 +2151,15 @@ export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr { this.weatherType = weatherType; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { if ((this.weatherType === WeatherType.HEAVY_RAIN || this.weatherType === WeatherType.HARSH_SUN || this.weatherType === WeatherType.STRONG_WINDS) || !pokemon.scene.arena.weather?.isImmutable()) { - return pokemon.scene.arena.trySetWeather(this.weatherType, true); + if (simulated) { + return pokemon.scene.arena.weather?.weatherType !== this.weatherType; + } else { + return pokemon.scene.arena.trySetWeather(this.weatherType, true); + } } return false; @@ -2100,8 +2175,12 @@ export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr { this.terrainType = terrainType; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (simulated) { + return pokemon.scene.arena.terrain?.terrainType !== this.terrainType; + } else { + return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + } } } @@ -2114,10 +2193,10 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr { this.formFunc = formFunc; } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) { - return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + return simulated || pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); } return false; @@ -2129,7 +2208,7 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr { private target: Pokemon; private targetAbilityName: string; - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const targets = pokemon.getOpponents(); if (!targets.length) { return false; @@ -2150,11 +2229,13 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr { return false; } - this.target = target!; - this.targetAbilityName = allAbilities[target!.getAbility().id].name; - pokemon.summonData.ability = target!.getAbility().id; - setAbilityRevealed(target!); - pokemon.updateInfo(); + if (!simulated) { + this.target = target!; + this.targetAbilityName = allAbilities[target!.getAbility().id].name; + pokemon.summonData.ability = target!.getAbility().id; + setAbilityRevealed(target!); + pokemon.updateInfo(); + } return true; } @@ -2191,7 +2272,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt * @param args - n/a * @returns A boolean or a promise that resolves to a boolean indicating the result of the ability application. */ - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { const party = pokemon instanceof PlayerPokemon ? pokemon.scene.getPlayerField() : pokemon.scene.getEnemyField(); const allowedParty = party.filter(p => p.isAllowedInBattle()); @@ -2199,14 +2280,15 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt return false; } - for (const pokemon of allowedParty) { - if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) { - pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); - pokemon.resetStatus(false); - pokemon.updateInfo(); + if (!simulated) { + for (const pokemon of allowedParty) { + if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) { + pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); + pokemon.resetStatus(false); + pokemon.updateInfo(); + } } } - return true; } } @@ -2214,7 +2296,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt /** Attempt to copy the stat changes on an ally pokemon */ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { if (!pokemon.scene.currentBattle.double) { return false; } @@ -2224,8 +2306,10 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { return false; } - pokemon.summonData.battleStats = ally.summonData.battleStats; - pokemon.updateInfo(); + if (!simulated) { + pokemon.summonData.battleStats = ally.summonData.battleStats; + pokemon.updateInfo(); + } return true; } @@ -2243,10 +2327,10 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { super(true); } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const targets = pokemon.getOpponents(); - if (!targets.length) { - return false; + if (simulated || !targets.length) { + return simulated; } let target: Pokemon; @@ -2282,16 +2366,19 @@ export class PreSwitchOutAbAttr extends AbAttr { super(true); } - applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { return false; } } export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr { - applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { if (pokemon.status) { - pokemon.resetStatus(); - pokemon.updateInfo(); + if (!simulated) { + pokemon.resetStatus(); + pokemon.updateInfo(); + } + return true; } @@ -2310,7 +2397,7 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr { * @param args N/A * @returns {boolean} Returns true if the weather clears, otherwise false. */ - applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { const weatherType = pokemon.scene.arena.weather?.weatherType; let turnOffWeather = false; @@ -2336,6 +2423,10 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr { break; } + if (simulated) { + return turnOffWeather; + } + if (turnOffWeather) { pokemon.scene.arena.trySetWeather(WeatherType.NONE, false); return true; @@ -2346,11 +2437,14 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr { } export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { - applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { if (!pokemon.isFullHp()) { - const healAmount = Math.floor(pokemon.getMaxHp() * 0.33); - pokemon.heal(healAmount); - pokemon.updateInfo(); + if (!simulated) { + const healAmount = Math.floor(pokemon.getMaxHp() * 0.33); + pokemon.heal(healAmount); + pokemon.updateInfo(); + } + return true; } @@ -2379,10 +2473,12 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr { * @param args N/A * @returns true if the form change was successful */ - applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) { - pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + if (!simulated) { + pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + } return true; } @@ -2392,7 +2488,7 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr { } export class PreStatChangeAbAttr extends AbAttr { - applyPreStatChange(pokemon: Pokemon | null, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreStatChange(pokemon: Pokemon | null, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2406,7 +2502,7 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr { this.protectedStat = protectedStat; } - applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreStatChange(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) { cancelled.value = true; return true; @@ -2450,16 +2546,20 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr { * @param args [0] {@linkcode StatusEffect} applied by move * @returns true if defender is confused */ - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (this.effects.indexOf(args[0]) > -1 && !defender.isFainted()) { - return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedInt(3,2), move.id, defender.id); + if (simulated) { + return defender.canAddTag(BattlerTagType.CONFUSED); + } else { + return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedInt(3,2), move.id, defender.id); + } } return false; } } export class PreSetStatusAbAttr extends AbAttr { - applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2489,7 +2589,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr { * @param args - n/a * @returns A boolean indicating the result of the status application. */ - applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.immuneEffects.length < 1 || this.immuneEffects.includes(effect)) { cancelled.value = true; return true; @@ -2525,7 +2625,7 @@ export class StatusEffectImmunityAbAttr extends PreSetStatusEffectImmunityAbAttr export class UserFieldStatusEffectImmunityAbAttr extends PreSetStatusEffectImmunityAbAttr { } export class PreApplyBattlerTagAbAttr extends AbAttr { - applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2543,10 +2643,12 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr { this.immuneTagType = immuneTagType; } - applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (tag.tagType === this.immuneTagType) { cancelled.value = true; - this.battlerTag = tag; + if (!simulated) { + this.battlerTag = tag; + } return true; } @@ -2575,14 +2677,14 @@ export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr { export class UserFieldBattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr { } export class BlockCritAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.BooleanHolder).value = true; return true; } } export class BonusCritAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.BooleanHolder).value = true; return true; } @@ -2597,7 +2699,7 @@ export class MultCritAbAttr extends AbAttr { this.multAmount = multAmount; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const critMult = args[0] as Utils.NumberHolder; if (critMult.value > 1) { critMult.value *= this.multAmount; @@ -2628,7 +2730,7 @@ export class ConditionalCritAbAttr extends AbAttr { * [1] {@linkcode Pokemon} Target. * [2] {@linkcode Move} used by ability user. */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const target = (args[1] as Pokemon); const move = (args[2] as Move); if (!this.condition(pokemon,target,move)) { @@ -2641,7 +2743,7 @@ export class ConditionalCritAbAttr extends AbAttr { } export class BlockNonDirectDamageAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -2669,7 +2771,7 @@ export class BlockStatusDamageAbAttr extends AbAttr { * @param {any[]} args N/A * @returns Returns true if status damage is blocked */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (pokemon.status && this.effects.includes(pokemon.status.effect)) { cancelled.value = true; return true; @@ -2679,7 +2781,7 @@ export class BlockStatusDamageAbAttr extends AbAttr { } export class BlockOneHitKOAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -2705,7 +2807,7 @@ export class ChangeMovePriorityAbAttr extends AbAttr { this.changeAmount = changeAmount; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!this.moveFunc(pokemon, args[0] as Move)) { return false; } @@ -2718,7 +2820,7 @@ export class ChangeMovePriorityAbAttr extends AbAttr { export class IgnoreContactAbAttr extends AbAttr { } export class PreWeatherEffectAbAttr extends AbAttr { - applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather | null, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreWeatherEffect(pokemon: Pokemon, passive: Boolean, simulated: boolean, weather: Weather | null, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2734,7 +2836,7 @@ export class BlockWeatherDamageAttr extends PreWeatherDamageAbAttr { this.weatherTypes = weatherTypes; } - applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!this.weatherTypes.length || this.weatherTypes.indexOf(weather?.weatherType) > -1) { cancelled.value = true; } @@ -2752,7 +2854,7 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr { this.affectsImmutable = !!affectsImmutable; } - applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.affectsImmutable || weather.isImmutable()) { cancelled.value = true; return true; @@ -2859,7 +2961,7 @@ export class ForewarnAbAttr extends PostSummonAbAttr { super(true); } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { let maxPowerSeen = 0; let maxMove = ""; let movePower = 0; @@ -2883,7 +2985,9 @@ export class ForewarnAbAttr extends PostSummonAbAttr { } } } - pokemon.scene.queueMessage(i18next.t("abilityTriggers:forewarn", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: maxMove })); + if (!simulated) { + pokemon.scene.queueMessage(i18next.t("abilityTriggers:forewarn", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: maxMove })); + } return true; } } @@ -2893,17 +2997,19 @@ export class FriskAbAttr extends PostSummonAbAttr { super(true); } - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - for (const opponent of pokemon.getOpponents()) { - pokemon.scene.queueMessage(i18next.t("abilityTriggers:frisk", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), opponentName: opponent.name, opponentAbilityName: opponent.getAbility().name })); - setAbilityRevealed(opponent); + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (!simulated) { + for (const opponent of pokemon.getOpponents()) { + pokemon.scene.queueMessage(i18next.t("abilityTriggers:frisk", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), opponentName: opponent.name, opponentAbilityName: opponent.getAbility().name })); + setAbilityRevealed(opponent); + } } return true; } } export class PostWeatherChangeAbAttr extends AbAttr { - applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { + applyPostWeatherChange(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: WeatherType, args: any[]): boolean { return false; } } @@ -2921,13 +3027,17 @@ export class PostWeatherChangeAddBattlerTagAttr extends PostWeatherChangeAbAttr this.weatherTypes = weatherTypes; } - applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { + applyPostWeatherChange(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: WeatherType, args: any[]): boolean { console.log(this.weatherTypes.find(w => weather === w), WeatherType[weather]); if (!this.weatherTypes.find(w => weather === w)) { return false; } - return pokemon.addTag(this.tagType, this.turnCount); + if (simulated) { + return pokemon.canAddTag(this.tagType); + } else { + return pokemon.addTag(this.tagType, this.turnCount); + } } } @@ -2940,7 +3050,7 @@ export class PostWeatherLapseAbAttr extends AbAttr { this.weatherTypes = weatherTypes; } - applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather | null, args: any[]): boolean | Promise { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather | null, args: any[]): boolean | Promise { return false; } @@ -2958,12 +3068,14 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr { this.healFactor = healFactor; } - applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): boolean { if (!pokemon.isFullHp()) { const scene = pokemon.scene; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; - scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / (16 / this.healFactor)), 1), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + if (!simulated) { + scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() / (16 / this.healFactor)), 1), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + } return true; } @@ -2980,20 +3092,24 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { this.damageFactor = damageFactor; } - applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): boolean { const scene = pokemon.scene; if (pokemon.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { return false; } - const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; - scene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName })); - pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER); + + if (!simulated) { + const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; + scene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName })); + pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER); + } + return true; } } export class PostTerrainChangeAbAttr extends AbAttr { - applyPostTerrainChange(pokemon: Pokemon, passive: boolean, terrain: TerrainType, args: any[]): boolean { + applyPostTerrainChange(pokemon: Pokemon, passive: boolean, simulated: boolean, terrain: TerrainType, args: any[]): boolean { return false; } } @@ -3011,12 +3127,16 @@ export class PostTerrainChangeAddBattlerTagAttr extends PostTerrainChangeAbAttr this.terrainTypes = terrainTypes; } - applyPostTerrainChange(pokemon: Pokemon, passive: boolean, terrain: TerrainType, args: any[]): boolean { + applyPostTerrainChange(pokemon: Pokemon, passive: boolean, simulated: boolean, terrain: TerrainType, args: any[]): boolean { if (!this.terrainTypes.find(t => t === terrain)) { return false; } - return pokemon.addTag(this.tagType, this.turnCount); + if (simulated) { + return pokemon.canAddTag(this.tagType); + } else { + return pokemon.addTag(this.tagType, this.turnCount); + } } } @@ -3028,7 +3148,7 @@ function getTerrainCondition(...terrainTypes: TerrainType[]): AbAttrCondition { } export class PostTurnAbAttr extends AbAttr { - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { return false; } } @@ -3054,13 +3174,15 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { * @param {any[]} args N/A * @returns Returns true if healed from status, false if not */ - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { if (pokemon.status && this.effects.includes(pokemon.status.effect)) { if (!pokemon.isFullHp()) { - const scene = pokemon.scene; - const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; - scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 8), 1), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); + if (!simulated) { + const scene = pokemon.scene; + const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; + scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() / 8), 1), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); + } return true; } } @@ -3081,17 +3203,19 @@ export class PostTurnResetStatusAbAttr extends PostTurnAbAttr { this.allyTarget = allyTarget; } - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { if (this.allyTarget) { this.target = pokemon.getAlly(); } else { this.target = pokemon; } if (this.target?.status) { + if (!simulated) { + this.target.scene.queueMessage(getStatusEffectHealText(this.target.status?.effect, getPokemonNameWithAffix(this.target))); + this.target.resetStatus(false); + this.target.updateInfo(); + } - this.target.scene.queueMessage(getStatusEffectHealText(this.target.status?.effect, getPokemonNameWithAffix(this.target))); - this.target.resetStatus(false); - this.target.updateInfo(); return true; } @@ -3116,7 +3240,7 @@ export class PostTurnLootAbAttr extends PostTurnAbAttr { super(); } - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const pass = Phaser.Math.RND.realInRange(0, 1); // Clamp procChance to [0, 1]. Skip if didn't proc (less than pass) if (Math.max(Math.min(this.procChance(pokemon), 1), 0) < pass) { @@ -3124,7 +3248,7 @@ export class PostTurnLootAbAttr extends PostTurnAbAttr { } if (this.itemType === "EATEN_BERRIES") { - return this.createEatenBerry(pokemon); + return this.createEatenBerry(pokemon, simulated); } else { return false; } @@ -3133,15 +3257,20 @@ export class PostTurnLootAbAttr extends PostTurnAbAttr { /** * Create a new berry chosen randomly from the berries the pokemon ate this battle * @param pokemon The pokemon with this ability + * @param simulated whether the associated ability call is simulated * @returns whether a new berry was created */ - createEatenBerry(pokemon: Pokemon): boolean { + createEatenBerry(pokemon: Pokemon, simulated: boolean): boolean { const berriesEaten = pokemon.battleData.berriesEaten; if (!berriesEaten.length) { return false; } + if (simulated) { + return true; + } + const randomIdx = Utils.randSeedInt(berriesEaten.length); const chosenBerryType = berriesEaten[randomIdx]; const chosenBerry = new BerryModifierType(chosenBerryType); @@ -3175,17 +3304,17 @@ export class MoodyAbAttr extends PostTurnAbAttr { super(true); } - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const selectableStats = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD]; const increaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] < 6); let decreaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] > -6); - if (increaseStatArray.length > 0) { + if (!simulated && increaseStatArray.length > 0) { const increaseStat = increaseStatArray[Utils.randInt(increaseStatArray.length)]; decreaseStatArray = decreaseStatArray.filter(s => s !== increaseStat); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2)); } - if (decreaseStatArray.length > 0) { + if (!simulated && decreaseStatArray.length > 0) { const decreaseStat = selectableStats[Utils.randInt(selectableStats.length)]; pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1)); } @@ -3206,19 +3335,24 @@ export class PostTurnStatChangeAbAttr extends PostTurnAbAttr { this.levels = levels; } - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + } return true; } } export class PostTurnHealAbAttr extends PostTurnAbAttr { - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { if (!pokemon.isFullHp()) { - const scene = pokemon.scene; - const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; - scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + if (!simulated) { + const scene = pokemon.scene; + const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; + scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + } + return true; } @@ -3235,10 +3369,13 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr { this.formFunc = formFunc; } - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) { - pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + if (!simulated) { + pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); + } + return true; } @@ -3256,15 +3393,18 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr { * Deals damage to all sleeping opponents equal to 1/8 of their max hp (min 1) * @param {Pokemon} pokemon Pokemon that has this ability * @param {boolean} passive N/A + * @param {boolean} simulated true if applying in a simulated call. * @param {any[]} args N/A * @returns {boolean} true if any opponents are sleeping */ - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { let hadEffect: boolean = false; for (const opp of pokemon.getOpponents()) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - opp.damageAndUpdate(Math.floor(Math.max(1, opp.getMaxHp() / 8)), HitResult.OTHER); - pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", {pokemonName: getPokemonNameWithAffix(opp)})); + if (!simulated) { + opp.damageAndUpdate(Math.floor(Math.max(1, opp.getMaxHp() / 8)), HitResult.OTHER); + pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", {pokemonName: getPokemonNameWithAffix(opp)})); + } hadEffect = true; } @@ -3289,7 +3429,10 @@ export class FetchBallAbAttr extends PostTurnAbAttr { * @param args N/A * @returns true if player has used a pokeball and this pokemon is owned by the player */ - applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (simulated) { + return false; + } const lastUsed = pokemon.scene.currentBattle.lastUsedPokeball; if (lastUsed !== null && !!pokemon.isPlayer) { pokemon.scene.pokeballCounts[lastUsed]++; @@ -3312,9 +3455,13 @@ export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr { this.weatherType = weatherType; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!pokemon.scene.arena.weather?.isImmutable()) { - return pokemon.scene.arena.trySetWeather(this.weatherType, true); + if (simulated) { + return pokemon.scene.arena.weather?.weatherType !== this.weatherType; + } else { + return pokemon.scene.arena.trySetWeather(this.weatherType, true); + } } return false; @@ -3330,8 +3477,12 @@ export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr { this.terrainType = terrainType; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { - return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (simulated) { + return pokemon.scene.arena.terrain?.terrainType !== this.terrainType; + } else { + return pokemon.scene.arena.trySetTerrain(this.terrainType, true); + } } } @@ -3340,7 +3491,7 @@ export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr { * @extends AbAttr */ export class PostMoveUsedAbAttr extends AbAttr { - applyPostMoveUsed(pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], args: any[]): boolean | Promise { + applyPostMoveUsed(pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise { return false; } } @@ -3361,20 +3512,22 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { * * @return true if the Dancer ability was resolved */ - applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], args: any[]): boolean | Promise { + applyPostMoveUsed(dancer: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean, args: any[]): boolean | Promise { // List of tags that prevent the Dancer from replicating the move const forbiddenTags = [BattlerTagType.FLYING, BattlerTagType.UNDERWATER, BattlerTagType.UNDERGROUND, BattlerTagType.HIDDEN]; // The move to replicate cannot come from the Dancer if (source.getBattlerIndex() !== dancer.getBattlerIndex() && !dancer.summonData.tags.some(tag => forbiddenTags.includes(tag.tagType))) { - // If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance - if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) { - const target = this.getTarget(dancer, source, targets); - dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true)); - } else if (move.getMove() instanceof SelfStatusMove) { - // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself - dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true)); + if (!simulated) { + // If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance + if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) { + const target = this.getTarget(dancer, source, targets); + dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true)); + } else if (move.getMove() instanceof SelfStatusMove) { + // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself + dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true)); + } } return true; } @@ -3405,7 +3558,7 @@ export class StatChangeMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value *= this.multiplier; return true; @@ -3413,8 +3566,10 @@ export class StatChangeMultiplierAbAttr extends AbAttr { } export class StatChangeCopyAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, (args[0] as BattleStat[]), (args[1] as integer), true, false, false)); + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, (args[0] as BattleStat[]), (args[1] as integer), true, false, false)); + } return true; } } @@ -3424,7 +3579,7 @@ export class BypassBurnDamageReductionAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -3448,7 +3603,7 @@ export class ReduceBurnDamageAbAttr extends AbAttr { * @param args `[0]` {@linkcode Utils.NumberHolder} The damage value being modified * @returns `true` */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.NumberHolder).value = Math.max(Math.floor((args[0] as Utils.NumberHolder).value * this.multiplier), 1); return true; @@ -3456,7 +3611,7 @@ export class ReduceBurnDamageAbAttr extends AbAttr { } export class DoubleBerryEffectAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.NumberHolder).value *= 2; return true; @@ -3464,7 +3619,7 @@ export class DoubleBerryEffectAbAttr extends AbAttr { } export class PreventBerryUseAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -3487,24 +3642,25 @@ export class HealFromBerryUseAbAttr extends AbAttr { this.healPercent = Math.max(Math.min(healPercent, 1), 0); } - apply(pokemon: Pokemon, passive: boolean, ...args: [Utils.BooleanHolder, any[]]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, ...args: [Utils.BooleanHolder, any[]]): boolean { const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility(); - pokemon.scene.unshiftPhase( - new PokemonHealPhase( - pokemon.scene, - pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() * this.healPercent), 1), - i18next.t("abilityTriggers:healFromBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), - true - ) - ); - + if (!simulated) { + pokemon.scene.unshiftPhase( + new PokemonHealPhase( + pokemon.scene, + pokemon.getBattlerIndex(), + Math.max(Math.floor(pokemon.getMaxHp() * this.healPercent), 1), + i18next.t("abilityTriggers:healFromBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), + true + ) + ); + } return true; } } export class RunSuccessAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value = 256; return true; @@ -3527,7 +3683,7 @@ export class CheckTrappedAbAttr extends AbAttr { this.arenaTrapCondition = condition; } - applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean | Promise { + applyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean | Promise { return false; } } @@ -3552,7 +3708,7 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { * @param args N/A * @returns if enemy Pokemon is trapped or not */ - applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean { + applyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean { if (this.arenaTrapCondition(pokemon, otherPokemon)) { if (otherPokemon.getTypes(true).includes(Type.GHOST) || (otherPokemon.getTypes(true).includes(Type.STELLAR) && otherPokemon.getTypes().includes(Type.GHOST))) { trapped.value = false; @@ -3574,7 +3730,7 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { } export class MaxMultiHitAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value = 0; return true; @@ -3586,15 +3742,15 @@ export class PostBattleAbAttr extends AbAttr { super(true); } - applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { return false; } } export class PostBattleLootAbAttr extends PostBattleAbAttr { - applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot; - if (postBattleLoot.length) { + if (!simulated && postBattleLoot.length) { const randItem = Utils.randSeedItem(postBattleLoot); //@ts-ignore - TODO see below if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { // TODO: fix. This is a promise!? @@ -3609,7 +3765,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { } export class PostFaintAbAttr extends AbAttr { - applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { return false; } } @@ -3628,7 +3784,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr { * @param args N/A * @returns {boolean} Returns true if the weather clears, otherwise false. */ - applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { const weatherType = pokemon.scene.arena.weather?.weatherType; let turnOffWeather = false; @@ -3654,6 +3810,10 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr { break; } + if (simulated) { + return turnOffWeather; + } + if (turnOffWeather) { pokemon.scene.arena.trySetWeather(WeatherType.NONE, false); return true; @@ -3672,15 +3832,17 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { this.damageRatio = damageRatio; } - applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { const cancelled = new Utils.BooleanHolder(false); - pokemon.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled)); + pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated)); if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { return false; } - attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); - attacker.turnData.damageTaken += Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)); + if (!simulated) { + attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); + attacker.turnData.damageTaken += Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)); + } return true; } @@ -3700,10 +3862,12 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr { super (); } - applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - const damage = pokemon.turnData.attacksReceived[0].damage; - attacker.damageAndUpdate((damage), HitResult.OTHER); - attacker.turnData.damageTaken += damage; + applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + if (!simulated) { + const damage = pokemon.turnData.attacksReceived[0].damage; + attacker.damageAndUpdate((damage), HitResult.OTHER); + attacker.turnData.damageTaken += damage; + } return true; } @@ -3713,7 +3877,7 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr { } export class RedirectMoveAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.canRedirect(args[0] as Moves)) { const target = args[1] as Utils.IntegerHolder; const newTarget = pokemon.getBattlerIndex(); @@ -3756,7 +3920,7 @@ export class ReduceStatusEffectDurationAbAttr extends AbAttr { this.statusEffect = statusEffect; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (args[0] === this.statusEffect) { (args[1] as Utils.IntegerHolder).value = Math.floor((args[1] as Utils.IntegerHolder).value / 2); return true; @@ -3785,8 +3949,10 @@ export class FlinchStatChangeAbAttr extends FlinchEffectAbAttr { this.levels = levels; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (!simulated) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); + } return true; } } @@ -3794,7 +3960,7 @@ export class FlinchStatChangeAbAttr extends FlinchEffectAbAttr { export class IncreasePpAbAttr extends AbAttr { } export class ForceSwitchOutImmunityAbAttr extends AbAttr { - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -3805,7 +3971,7 @@ export class ReduceBerryUseThresholdAbAttr extends AbAttr { super(); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const hpRatio = pokemon.getHpRatio(); if (args[0].value < hpRatio) { @@ -3826,7 +3992,7 @@ export class WeightMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.NumberHolder).value *= this.multiplier; return true; @@ -3838,7 +4004,7 @@ export class SyncEncounterNatureAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Pokemon).setNature(pokemon.getNature()); return true; @@ -3854,7 +4020,7 @@ export class MoveAbilityBypassAbAttr extends AbAttr { this.moveIgnoreFunc = moveIgnoreFunc || ((pokemon, move) => true); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.moveIgnoreFunc(pokemon, (args[0] as Move))) { cancelled.value = true; return true; @@ -3868,7 +4034,7 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const ability = (args[0] as Ability); if (!ability.hasAttr(UnsuppressableAbilityAbAttr) && !ability.hasAttr(SuppressFieldAbilitiesAbAttr)) { cancelled.value = true; @@ -3923,7 +4089,7 @@ export class IgnoreTypeImmunityAbAttr extends AbAttr { this.allowedMoveTypes = allowedMoveTypes; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.defenderType === (args[1] as Type) && this.allowedMoveTypes.includes(args[0] as Type)) { cancelled.value = true; return true; @@ -3946,7 +4112,7 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr { this.defenderType = defenderType; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.statusEffect.includes(args[0] as StatusEffect) && this.defenderType.includes(args[1] as Type)) { cancelled.value = true; return true; @@ -3973,8 +4139,10 @@ export class MoneyAbAttr extends PostBattleAbAttr { * @param args N/A * @returns true */ - applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - pokemon.scene.currentBattle.moneyScattered += pokemon.scene.getWaveMoneyAmount(0.2); + applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + if (!simulated) { + pokemon.scene.currentBattle.moneyScattered += pokemon.scene.getWaveMoneyAmount(0.2); + } return true; } } @@ -4013,11 +4181,11 @@ export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAtt * @param {any[]} args - Additional arguments. * @returns {boolean} - Returns true if the stat change was applied, otherwise false. */ - applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const side = pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; if (pokemon.scene.arena.getTagOnSide(this.tagType, side)) { - return super.applyPostSummon(pokemon, passive, args); + return super.applyPostSummon(pokemon, passive, simulated, args); } return false; } @@ -4055,12 +4223,14 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { * @param {any[]} args Additional arguments. * @returns {boolean} Whether the immunity was applied. */ - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { - (args[0] as Utils.NumberHolder).value = this.multiplier; - pokemon.removeTag(this.tagType); - if (this.recoilDamageFunc) { - pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), HitResult.OTHER); + if (!simulated) { + (args[0] as Utils.NumberHolder).value = this.multiplier; + pokemon.removeTag(this.tagType); + if (this.recoilDamageFunc) { + pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), HitResult.OTHER); + } } return true; } @@ -4104,7 +4274,10 @@ export class BypassSpeedChanceAbAttr extends AbAttr { * @param {any[]} args [0] {@linkcode Utils.BooleanHolder} set to true when the ability activated * @returns {boolean} - whether the ability was activated. */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + if (simulated) { + return false; + } const bypassSpeed = args[0] as Utils.BooleanHolder; if (!bypassSpeed.value && pokemon.randSeedInt(100) < this.chance) { @@ -4147,7 +4320,7 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr { * @argument {boolean} bypassSpeed - determines if a Pokemon is able to bypass speed at the moment * @argument {boolean} canCheckHeldItems - determines if a Pokemon has access to Quick Claw's effects or not */ - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const bypassSpeed = args[0] as Utils.BooleanHolder; const canCheckHeldItems = args[1] as Utils.BooleanHolder; @@ -4169,7 +4342,7 @@ async function applyAbAttrsInternal( applyFunc: AbAttrApplyFunc, args: any[], showAbilityInstant: boolean = false, - isQuiet: boolean = false, + quiet: boolean = false, messages: string[] = [], ) { for (const passive of [false, true]) { @@ -4196,11 +4369,11 @@ async function applyAbAttrsInternal( if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) { pokemon.summonData.abilitiesApplied.push(ability.id); } - if (pokemon.battleData && !pokemon.battleData.abilitiesApplied.includes(ability.id)) { + if (pokemon.battleData && !quiet && !pokemon.battleData.abilitiesApplied.includes(ability.id)) { pokemon.battleData.abilitiesApplied.push(ability.id); } - if (attr.showAbility && !isQuiet) { + if (attr.showAbility && !quiet) { if (showAbilityInstant) { pokemon.scene.abilityBar.showAbility(pokemon, passive); } else { @@ -4208,12 +4381,12 @@ async function applyAbAttrsInternal( } } - const message = attr.getTriggerMessage(pokemon, ability.name, args); - if (message) { - if (!isQuiet) { + if (!quiet) { + const message = attr.getTriggerMessage(pokemon, ability.name, args); + if (message) { pokemon.scene.queueMessage(message); + messages.push(message); } - messages.push(message); } } } @@ -4222,34 +4395,33 @@ async function applyAbAttrsInternal( } } -export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args); +export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder | null, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, simulated, cancelled, args), args, false, simulated); } export function applyPostBattleInitAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, args), args); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, simulated, args), args, false, simulated); } export function applyPreDefendAbAttrs(attrType: Constructor, - pokemon: Pokemon, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise { - const simulated = args.length > 1 && args[1]; - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, simulated); + pokemon: Pokemon, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args), args, false, simulated); } export function applyPostDefendAbAttrs(attrType: Constructor, - pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args); + pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult | null, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated); } export function applyPostMoveUsedAbAttrs(attrType: Constructor, - pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, args), args); + pokemon: Pokemon, move: PokemonMove, source: Pokemon, targets: BattlerIndex[], simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostMoveUsed(pokemon, move, source, targets, simulated, args), args, false, simulated); } export function applyBattleStatMultiplierAbAttrs(attrType: Constructor, - pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args); + pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, simulated, battleStat, statValue, args), args, false, simulated); } /** @@ -4263,99 +4435,98 @@ export function applyBattleStatMultiplierAbAttrs(attrType: Constructor, - pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, stat, statValue, checkedPokemon, hasApplied, args), args); + pokemon: Pokemon, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyFieldBattleStat(pokemon, passive, simulated, stat, statValue, checkedPokemon, hasApplied, args), args, false, simulated); } export function applyPreAttackAbAttrs(attrType: Constructor, - pokemon: Pokemon, defender: Pokemon | null, move: Move, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args); + pokemon: Pokemon, defender: Pokemon | null, move: Move, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, simulated, defender, move, args), args, false, simulated); } export function applyPostAttackAbAttrs(attrType: Constructor, - pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args); + pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult | null, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, simulated, defender, move, hitResult, args), args, false, simulated); } export function applyPostKnockOutAbAttrs(attrType: Constructor, - pokemon: Pokemon, knockedOut: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, knockedOut, args), args); + pokemon: Pokemon, knockedOut: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, simulated, knockedOut, args), args, false, simulated); } export function applyPostVictoryAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, args), args); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, simulated, args), args, false, simulated); } export function applyPostSummonAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, args), args); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, false, simulated); } export function applyPreSwitchOutAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, true); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, simulated, args), args, true, simulated); } export function applyPreStatChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon | null, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args); + pokemon: Pokemon | null, stat: BattleStat, cancelled: Utils.BooleanHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, simulated, stat, cancelled, args), args, false, simulated); } export function applyPostStatChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, stats, levels, selfTarget, args), args); + pokemon: Pokemon, stats: BattleStat[], levels: integer, selfTarget: boolean, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostStatChange(pokemon, simulated, stats, levels, selfTarget, args), args, false, simulated); } export function applyPreSetStatusAbAttrs(attrType: Constructor, - pokemon: Pokemon, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - const simulated = args.length > 1 && args[1]; - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, !simulated); + pokemon: Pokemon, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, simulated, effect, cancelled, args), args, false, simulated); } export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor, - pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, tag, cancelled, args), args); + pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, simulated, tag, cancelled, args), args, false, simulated); } export function applyPreWeatherEffectAbAttrs(attrType: Constructor, - pokemon: Pokemon, weather: Weather | null, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, true); + pokemon: Pokemon, weather: Weather | null, cancelled: Utils.BooleanHolder, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, simulated, weather, cancelled, args), args, true, simulated); } export function applyPostTurnAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, args), args); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, simulated, args), args, false, simulated); } export function applyPostWeatherChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon, weather: WeatherType, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, weather, args), args); + pokemon: Pokemon, weather: WeatherType, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, simulated, weather, args), args, false, simulated); } export function applyPostWeatherLapseAbAttrs(attrType: Constructor, - pokemon: Pokemon, weather: Weather | null, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args); + pokemon: Pokemon, weather: Weather | null, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, simulated, weather, args), args, false, simulated); } export function applyPostTerrainChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon, terrain: TerrainType, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, terrain, args), args); + pokemon: Pokemon, terrain: TerrainType, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, simulated, terrain, args), args, false, simulated); } export function applyCheckTrappedAbAttrs(attrType: Constructor, - pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, isQuiet: boolean, messages: string[], ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, false, isQuiet, messages); + pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, messages: string[], simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, simulated, trapped, otherPokemon, args), args, false, simulated, messages); } export function applyPostBattleAbAttrs(attrType: Constructor, - pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, args), args); + pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, simulated, args), args, false, simulated); } export function applyPostFaintAbAttrs(attrType: Constructor, - pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args); + pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, simulated: boolean = false, ...args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated); } function queueShowAbility(pokemon: Pokemon, passive: boolean): void { diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 3394df827fb..026003d0b61 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -269,7 +269,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (arena, moveId) => { if (effectPhase instanceof MoveEffectPhase) { const attacker = effectPhase.getUserPokemon()!; applyMoveAttrs(IncrementMovePriorityAttr, attacker, null, move, priority); - applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, move, priority); + applyAbAttrs(ChangeMovePriorityAbAttr, attacker, null, false, move, priority); } return priority.value > 0; }; diff --git a/src/data/berry.ts b/src/data/berry.ts index e962219ca46..ff82a683e5a 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -36,25 +36,25 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { return (pokemon: Pokemon) => { const threshold = new Utils.NumberHolder(0.25); const battleStat = (berryType - BerryType.LIECHI) as BattleStat; - applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold); + applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6; }; case BerryType.LANSAT: return (pokemon: Pokemon) => { const threshold = new Utils.NumberHolder(0.25); - applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold); + applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); }; case BerryType.STARF: return (pokemon: Pokemon) => { const threshold = new Utils.NumberHolder(0.25); - applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold); + applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return pokemon.getHpRatio() < 0.25; }; case BerryType.LEPPA: return (pokemon: Pokemon) => { const threshold = new Utils.NumberHolder(0.25); - applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold); + applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return !!pokemon.getMoveset().find(m => !m?.getPpRatio()); }; } @@ -71,7 +71,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { pokemon.battleData.berriesEaten.push(berryType); } const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4)); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, hpHealed); + applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true)); }; @@ -97,7 +97,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { } const battleStat = (berryType - BerryType.LIECHI) as BattleStat; const statLevels = new Utils.NumberHolder(1); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels); + applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value)); }; case BerryType.LANSAT: @@ -113,7 +113,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { pokemon.battleData.berriesEaten.push(berryType); } const statLevels = new Utils.NumberHolder(2); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels); + applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value)); }; case BerryType.LEPPA: diff --git a/src/data/move.ts b/src/data/move.ts index 3a2903cb7c6..682ab0739d5 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -590,7 +590,7 @@ export default class Move implements Localizable { case MoveFlags.IGNORE_ABILITIES: if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) { const abilityEffectsIgnored = new Utils.BooleanHolder(false); - applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, this); + applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this); if (abilityEffectsIgnored.value) { return true; } @@ -686,11 +686,11 @@ export default class Move implements Localizable { * @param target {@linkcode Pokemon} The Pokémon being targeted by the move. * @returns The calculated accuracy of the move. */ - calculateBattleAccuracy(user: Pokemon, target: Pokemon) { + calculateBattleAccuracy(user: Pokemon, target: Pokemon, simulated: boolean = false) { const moveAccuracy = new Utils.NumberHolder(this.accuracy); applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy); - applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, moveAccuracy); + applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, simulated, moveAccuracy); if (moveAccuracy.value === -1) { return moveAccuracy.value; @@ -724,7 +724,7 @@ export default class Move implements Localizable { * @param target {@linkcode Pokemon} The Pokémon being targeted by the move. * @returns The calculated power of the move. */ - calculateBattlePower(source: Pokemon, target: Pokemon): number { + calculateBattlePower(source: Pokemon, target: Pokemon, simulated: boolean = false): number { if (this.category === MoveCategory.STATUS) { return -1; } @@ -732,17 +732,17 @@ export default class Move implements Localizable { const power = new Utils.NumberHolder(this.power); const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1); - applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, typeChangeMovePowerMultiplier); + applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, simulated, typeChangeMovePowerMultiplier); const sourceTeraType = source.getTeraType(); if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !source.scene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) { power.value = 60; } - applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, power); + applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, simulated, power); if (source.getAlly()) { - applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, power); + applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, source.getAlly(), target, this, simulated, power); } const fieldAuras = new Set( @@ -752,11 +752,11 @@ export default class Move implements Localizable { ); for (const aura of fieldAuras) { // The only relevant values are `move` and the `power` holder - aura.applyPreAttack(null, null, null, this, [power]); + aura.applyPreAttack(null, null, simulated, null, this, [power]); } const alliedField: Pokemon[] = source instanceof PlayerPokemon ? source.scene.getPlayerField() : source.scene.getEnemyField(); - alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, power)); + alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power)); power.value *= typeChangeMovePowerMultiplier.value; @@ -984,9 +984,9 @@ export class MoveEffectAttr extends MoveAttr { */ getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): integer { const moveChance = new Utils.NumberHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, moveChance, move, target, selfEffect, showAbility); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, moveChance, move, target, selfEffect, showAbility); if (!selfEffect) { - applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, moveChance); + applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, target, user, null, null, false, moveChance); } return moveChance.value; } @@ -1883,7 +1883,7 @@ export class MultiHitAttr extends MoveAttr { { const rand = user.randSeedInt(16); const hitValue = new Utils.IntegerHolder(rand); - applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue); + applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue); if (hitValue.value >= 10) { return 2; } else if (hitValue.value >= 4) { @@ -1954,7 +1954,7 @@ export class StatusEffectAttr extends MoveEffectAttr { } if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0)) && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) { - applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, this.effect); + applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect); return true; } } diff --git a/src/data/terrain.ts b/src/data/terrain.ts index e29344ffea2..d4789078af7 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -59,7 +59,7 @@ export class Terrain { case TerrainType.PSYCHIC: if (!move.hasAttr(ProtectAttr)) { const priority = new Utils.IntegerHolder(move.priority); - applyAbAttrs(ChangeMovePriorityAbAttr, user, null, move, priority); + applyAbAttrs(ChangeMovePriorityAbAttr, user, null, false, move, priority); // Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain return priority.value > 0 && user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()); } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b3a96a5f1fc..999ebb3cb21 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -694,7 +694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { break; } } - applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, statLevel); + applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, false, statLevel); if (move) { applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel); } @@ -1122,10 +1122,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const suppressed = new Utils.BooleanHolder(false); this.scene.getField(true).filter(p => p !== this).map(p => { if (p.getAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility()) { - p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, suppressed, [ability])); + p.getAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, false, false, suppressed, [ability])); } if (p.getPassiveAbility().hasAttr(SuppressFieldAbilitiesAbAttr) && p.canApplyAbility(true)) { - p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, suppressed, [ability])); + p.getPassiveAbility().getAttrs(SuppressFieldAbilitiesAbAttr).map(a => a.apply(this, true, false, suppressed, [ability])); } }); if (suppressed.value) { @@ -1177,7 +1177,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getWeight(): number { const weight = new Utils.NumberHolder(this.species.weight); // This will trigger the ability overlay so only call this function when necessary - applyAbAttrs(WeightMultiplierAbAttr, this, null, weight); + applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight); return weight.value; } @@ -1237,10 +1237,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const cancelled = new Utils.BooleanHolder(false); applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier); if (!typeless && !ignoreAbility) { - applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); + applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier); } if (!cancelled.value && !ignoreAbility) { - applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); + applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, true, typeMultiplier); } return (!cancelled.value ? Number(typeMultiplier.value) : 0) as TypeDamageMultiplier; @@ -1281,7 +1281,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (source) { const ignoreImmunity = new Utils.BooleanHolder(false); if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) { - applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, moveType, defType); + applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, false, moveType, defType); } if (ignoreImmunity.value) { return 1; @@ -1922,9 +1922,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]); const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]); - applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, userAccuracyLevel); - applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, targetEvasionLevel); - applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, targetEvasionLevel); + applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, false, userAccuracyLevel); + applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, false, targetEvasionLevel); + applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, false, targetEvasionLevel); applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel); this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel); @@ -1939,7 +1939,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { : 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6)); } - applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, sourceMove); + applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, false, sourceMove); const evasionMultiplier = new Utils.NumberHolder(1); applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier); @@ -1949,6 +1949,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return accuracyMultiplier.value; } + /** + * Apply the results of a move to this pokemon + * @param {Pokemon} source The pokemon using the move + * @param {PokemonMove} battlerMove The move being used + * @returns {HitResult} The result of the attack + */ apply(source: Pokemon, move: Move): HitResult { let result: HitResult; const damage = new Utils.NumberHolder(0); @@ -1984,12 +1990,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const sourceTeraType = source.getTeraType(); if (!typeless) { - applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier); + applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); applyMoveAttrs(NeutralDamageAgainstFlyingTypeMultiplierAttr, source, this, move, typeMultiplier); } if (!cancelled.value) { - applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier); - defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier)); + applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); + defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier)); } if (cancelled.value) { @@ -2012,7 +2018,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const critOnly = new Utils.BooleanHolder(false); const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT); applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly); - applyAbAttrs(ConditionalCritAbAttr, source, null, critOnly, this, move); + applyAbAttrs(ConditionalCritAbAttr, source, null, false, critOnly, this, move); if (critOnly.value || critAlways) { isCritical = true; } else { @@ -2022,7 +2028,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel); const bonusCrit = new Utils.BooleanHolder(false); //@ts-ignore - if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus. + if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus. if (bonusCrit.value) { critLevel.value += 1; } @@ -2040,7 +2046,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (isCritical) { const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide); const blockCrit = new Utils.BooleanHolder(false); - applyAbAttrs(BlockCritAbAttr, this, null, blockCrit); + applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit); if (noCritTag || blockCrit.value) { isCritical = false; } @@ -2048,7 +2054,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical)); const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical)); const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); - applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier); + applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier); const screenMultiplier = new Utils.NumberHolder(1); if (!isCritical) { this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier); @@ -2063,7 +2069,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { stabMultiplier.value += 0.5; } - applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier); + applyAbAttrs(StabBoostAbAttr, source, null, false, stabMultiplier); if (sourceTeraType !== Type.UNKNOWN && matchesSourceType) { stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25); @@ -2081,7 +2087,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { numTargets = effectPhase.getTargets().length; } const twoStrikeMultiplier = new Utils.NumberHolder(1); - applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier); + applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, false, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier); if (!isTypeImmune) { const levelMultiplier = (2 * source.level / 5 + 2); @@ -2100,14 +2106,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) { if (!move.hasAttr(BypassBurnDamageReductionAttr)) { const burnDamageReductionCancelled = new Utils.BooleanHolder(false); - applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled); + applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled, false); if (!burnDamageReductionCancelled.value) { damage.value = Math.floor(damage.value / 2); } } } - applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, damage); + applyPreAttackAbAttrs(DamageBoostAbAttr, source, this, move, false, damage); /** * For each {@link HitsTagAttr} the move has, doubles the damage of the move if: @@ -2165,7 +2171,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage); } - applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, damage); + applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, false, damage); } // This attribute may modify damage arbitrarily, so be careful about changing its order of application. @@ -2178,7 +2184,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (damage.value) { if (this.isFullHp()) { - applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, damage); + applyPreDefendAbAttrs(PreDefendFullHpEndureAbAttr, this, source, move, cancelled, false, damage); } else if (!this.isPlayer() && damage.value >= this.hp) { this.scene.applyModifiers(EnemyEndureChanceModifier, false, this); } @@ -2245,11 +2251,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { break; case MoveCategory.STATUS: if (!typeless) { - applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier); + applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); } if (!cancelled.value) { - applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier); - defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, typeMultiplier)); + applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, false, typeMultiplier); + defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, move, cancelled, false, typeMultiplier)); } if (!typeMultiplier.value) { this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) })); @@ -2341,6 +2347,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!)); } + canAddTag(tagType: BattlerTagType): boolean { + if (this.getTag(tagType)) { + return false; + } + + const stubTag = new BattlerTag(tagType, 0, 0); + + const cancelled = new Utils.BooleanHolder(false); + applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, stubTag, cancelled, true); + + const userField = this.getAlliedField(); + userField.forEach(pokemon => applyPreApplyBattlerTagAbAttrs(UserFieldBattlerTagImmunityAbAttr, pokemon, stubTag, cancelled, true)); + + return !cancelled.value; + } + addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean { const existingTag = this.getTag(tagType); if (existingTag) { @@ -2727,7 +2749,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity const cancelImmunity = new Utils.BooleanHolder(false); if (sourcePokemon) { - applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, effect, defType); + applyAbAttrs(IgnoreTypeStatusEffectImmunityAbAttr, sourcePokemon, cancelImmunity, false, effect, defType); if (cancelImmunity.value) { return false; } @@ -2799,7 +2821,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (effect === StatusEffect.SLEEP) { statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4)); - applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, statusCureTurn); + applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, false, effect, statusCureTurn); this.setFrameRate(4); diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts index 9781ca6d360..17625c57fc6 100644 --- a/src/phases/attempt-run-phase.ts +++ b/src/phases/attempt-run-phase.ts @@ -23,7 +23,7 @@ export class AttemptRunPhase extends PokemonPhase { const enemySpeed = enemyField.reduce((total: integer, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), 0) / enemyField.length; const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256); - applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance); + applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance); if (playerPokemon.randSeedInt(256) < escapeChance.value) { this.scene.playSound("flee"); diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 5d466e5d3b6..68ede826d95 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -189,7 +189,7 @@ export class CommandPhase extends FieldPhase { const batonPass = isSwitch && args[0] as boolean; const trappedAbMessages: string[] = []; if (!batonPass) { - enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, true, trappedAbMessages)); + enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon, trappedAbMessages, true)); } if (batonPass || (!trapTag && !trapped.value)) { this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 739bb1d93f1..dfa198c8339 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -67,7 +67,7 @@ export class EncounterPhase extends BattlePhase { battle.enemyParty[e].ivs = new Array(6).fill(31); } this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => { - applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]); + applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, false, battle.enemyParty[e]); }); } } diff --git a/src/phases/enemy-command-phase.ts b/src/phases/enemy-command-phase.ts index d7f553681c2..0b62fcbe813 100644 --- a/src/phases/enemy-command-phase.ts +++ b/src/phases/enemy-command-phase.ts @@ -47,7 +47,7 @@ export class EnemyCommandPhase extends FieldPhase { const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag; const trapped = new Utils.BooleanHolder(false); - opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, true, [])); + opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon, [], true)); if (!trapTag && !trapped.value) { const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true); diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index a5ac913cc5d..12018656458 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -74,7 +74,7 @@ export class MoveEffectPhase extends PokemonPhase { // Assume single target for multi hit applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); // If Parental Bond is applicable, double the hit count - applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0)); + applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, false, targets.length, hitCount, new Utils.IntegerHolder(0)); // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index b9656df856b..2aed0bb9495 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -90,7 +90,7 @@ export class MovePhase extends BattlePhase { : null; if (moveTarget) { const oldTarget = moveTarget.value; - this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, this.move.moveId, moveTarget)); + this.scene.getField(true).filter(p => p !== this.pokemon).forEach(p => applyAbAttrs(RedirectMoveAbAttr, p, null, false, this.move.moveId, moveTarget)); this.pokemon.getOpponents().forEach(p => { const redirectTag = p.getTag(CenterOfAttentionTag) as CenterOfAttentionTag; if (redirectTag && (!redirectTag.powder || (!this.pokemon.isOfType(Type.GRASS) && !this.pokemon.hasAbility(Abilities.OVERCOAT)))) { diff --git a/src/phases/post-turn-status-effect-phase.ts b/src/phases/post-turn-status-effect-phase.ts index 8b533f2e90a..47db32303a5 100644 --- a/src/phases/post-turn-status-effect-phase.ts +++ b/src/phases/post-turn-status-effect-phase.ts @@ -34,7 +34,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase { break; case StatusEffect.BURN: damage.value = Math.max(pokemon.getMaxHp() >> 4, 1); - applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, damage); + applyAbAttrs(ReduceBurnDamageAbAttr, pokemon, null, false, damage); break; } if (damage.value) { diff --git a/src/phases/stat-change-phase.ts b/src/phases/stat-change-phase.ts index 3469cc62942..fec3da9bc9a 100644 --- a/src/phases/stat-change-phase.ts +++ b/src/phases/stat-change-phase.ts @@ -68,7 +68,7 @@ export class StatChangePhase extends PokemonPhase { const levels = new Utils.IntegerHolder(this.levels); if (!this.ignoreAbilities) { - applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, levels); + applyAbAttrs(StatChangeMultiplierAbAttr, pokemon, null, false, levels); } const battleStats = this.getPokemon().summonData.battleStats; @@ -90,7 +90,7 @@ export class StatChangePhase extends PokemonPhase { if (levels.value > 0 && this.canBeCopied) { for (const opponent of pokemon.getOpponents()) { - applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value); + applyAbAttrs(StatChangeCopyAbAttr, opponent, null, false, this.stats, levels.value); } } diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 1320cb6235c..e4064fc784a 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -34,8 +34,8 @@ export class TurnStartPhase extends FieldPhase { this.scene.getField(true).filter(p => p.summonData).map(p => { const bypassSpeed = new Utils.BooleanHolder(false); const canCheckHeldItems = new Utils.BooleanHolder(true); - applyAbAttrs(BypassSpeedChanceAbAttr, p, null, bypassSpeed); - applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, bypassSpeed, canCheckHeldItems); + applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed); + applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems); if (canCheckHeldItems.value) { this.scene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); } @@ -64,8 +64,8 @@ export class TurnStartPhase extends FieldPhase { applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? - applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, false, aMove, aPriority); //TODO: is the bang correct here? + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, false, bMove, bPriority); //TODO: is the bang correct here? if (aPriority.value !== bPriority.value) { const bracketDifference = Math.ceil(aPriority.value) - Math.ceil(bPriority.value); diff --git a/src/test/abilities/sand_veil.test.ts b/src/test/abilities/sand_veil.test.ts index 010878db68d..3c5f97bd653 100644 --- a/src/test/abilities/sand_veil.test.ts +++ b/src/test/abilities/sand_veil.test.ts @@ -52,7 +52,7 @@ describe("Abilities - Sand Veil", () => { const sandVeilAttr = allAbilities[Abilities.SAND_VEIL].getAttrs(BattleStatMultiplierAbAttr)[0]; vi.spyOn(sandVeilAttr, "applyBattleStat").mockImplementation( - (pokemon, passive, battleStat, statValue, args) => { + (pokemon, passive, simulated, battleStat, statValue, args) => { if (battleStat === BattleStat.EVA && game.scene.arena.weather?.weatherType === WeatherType.SANDSTORM) { statValue.value *= -1; // will make all attacks miss return true; diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index 5e4841f005a..b126bb5eb7a 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -67,7 +67,7 @@ describe("Abilities - Serene Grace", () => { const chance = new Utils.IntegerHolder(move.chance); console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); expect(chance.value).toBe(30); }, 20000); @@ -99,7 +99,7 @@ describe("Abilities - Serene Grace", () => { expect(move.id).toBe(Moves.AIR_SLASH); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); expect(chance.value).toBe(60); }, 20000); diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 33b34124cc4..564e2040af4 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -69,8 +69,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); expect(chance.value).toBe(0); expect(power.value).toBe(move.power * 5461/4096); @@ -108,8 +108,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); expect(chance.value).toBe(-1); expect(power.value).toBe(move.power); @@ -147,8 +147,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); expect(chance.value).toBe(-1); expect(power.value).toBe(move.power); @@ -191,8 +191,8 @@ describe("Abilities - Sheer Force", () => { const target = phase.getTarget()!; const opponentType = target.getTypes()[0]; - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, chance, move, target, false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, chance, move, target, false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, false, power); applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move)); expect(chance.value).toBe(0); diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index b40689a180a..fe6c941752c 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -67,8 +67,8 @@ describe("Abilities - Shield Dust", () => { expect(move.id).toBe(Moves.AIR_SLASH); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); - applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null!, null!, chance); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getTarget(), false); + applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null, null, false, chance); expect(chance.value).toBe(0); }, 20000); From 34bf932722e4109502ae6cbabf4758984b11e148 Mon Sep 17 00:00:00 2001 From: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:48:39 -0400 Subject: [PATCH 52/63] [Sprite] Trim exp Rellor palette (#3674) * [Sprite] Trim exp Rellor palette * [Sprite] Trim Rellor exp Palette * [Sprite] Trim Rellor exp palette --- public/images/pokemon/exp/953.png | Bin 2164 -> 1296 bytes public/images/pokemon/variant/exp/953.json | 66 ++++----------------- 2 files changed, 11 insertions(+), 55 deletions(-) diff --git a/public/images/pokemon/exp/953.png b/public/images/pokemon/exp/953.png index fb4255a112b02fc6462c0420bcc33a808bae7ac9..8a6ca2e7eff12603d14fac0859f03e4abe10f72f 100644 GIT binary patch delta 1276 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 dh0k}s^9z@YZ|Wo1v{?WE002ovPDHLkV1igW Date: Thu, 22 Aug 2024 12:32:03 +0900 Subject: [PATCH 53/63] =?UTF-8?q?[Enhancement]=20Support=20for=20special?= =?UTF-8?q?=20characters(=E2=99=AA.=E2=98=85,=E2=99=A5,=E2=99=A3)=20in=20g?= =?UTF-8?q?ame=20font=20(issue#3180)=20(#3535)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added specialCharacters: "♪.★,♥,♣" * did refactoring...maybe * added note --- public/fonts/PokePT_Wansung.woff2 | Bin 37032 -> 37456 bytes src/plugins/i18n.ts | 10 ++++++++++ 2 files changed, 10 insertions(+) diff --git a/public/fonts/PokePT_Wansung.woff2 b/public/fonts/PokePT_Wansung.woff2 index 02b299ef7a05091853c64ad10d0fa26587826163..15aab3eb4f4de725cb1692f3ac3f7cab7b61635a 100644 GIT binary patch literal 37456 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�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 JUI+g>=P&CqKM()_ literal 37032 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%0Agl%=;JD^L$>;y9DO2Y=Uw}0d}1z8N&=qb7) zQw2D#g{$5HR~2ET{{eIu-bT~^;5r+Y#aj0zBs$uuVWSj>*vo80@h(BG;VlFPRkYR3 zFz!1Eh(CZ#>_yG+Xon^k0`?>P3(~ubyGWmxX1x8Xr(U_}J`W1f6T`W#C!^2I$gzh4*J8%5oz8L`c zF$U;$wUe{cyD{M2Ur_x++=QmU0YZ4N1O06?14QaS82-Vbko?y!Ck9S0>}C4{pr(od zlaVLSC1gbdl!iIV-ya|czldiu=<}qcA2k~M~ z-m|y=6@q>I;yySm;Qw!;_nnO3-$i+_KlI$6fkQunH`4R~BqEX!&u-@?B`zZ-E!p4n z-J6zunL)Kwzt@+M|A>&s`e%<1J@=M?!`{zcKW5=85X_#3r$7v8{<#D5IN(M4;3_gz zQ18Ot2~_$sFo-PpJ8-=CKO@JxPVV0zOt6XLB)?lE-Nfjsh5&kbk>P>w<88w|(=9hh zst>TD7ohmMPpkU<(qxDR_??#^m3OnQCkIPYVLI+tkpEYJ>(2s8%5I#4_kRO!Qyry> z{`c^v^MA-BAYeX_0pQPvr|AWO z|2y5igC+l+j)RL3NPYH1BID%IR**o~1Y8OF3|X^pz8M5 zE=99-=R0fNRV0m97tp|D3DN6+pT|Oo>cV5gO5VUbKWcO-L&O+~*DPvgsBs;*@Z$Ob zN>nN|%5Otn<#2<3vGo7iyY^_P@;L5M6d|$R29b`rrXNE~~XpieyXW zF&lL{j!JDh)=Fh&v!M`2c1g?#<#FWLLQ{G5&`g`x(U6HIduQg({oT=Q?v&ZHchC3> z=lY)S{O<4f`+gqZ-%so+Zm%v=5v?1%=Q(#+zWBjw{TsJd`9LR<#pXPv%k5@6+jHB} zZ2cIPfn~P_iGvO6QY{?xq5ScyhaDPX7@L+^vRaZUv)m2Av>#1uf z3P#YK>6|!PFJ)w;#2ZbW1#(cI8bBk$MqpXk1{jcC%}!fv(aWw4Dw`Tcj8)C(B{0V(&W`ey&5Y+0MC#}Qu7dSi*pbjbQ< z4|BWpV3)_c=as{2I{bWv_h-h;_A%4u;FWwg%y&+b5Vkmo$j&}a>^{5bG#e!l{M)xV5O6Z?e z>9_hFNiY$}2UD};Rv4Hn;+^Gp)A zZDP_C-kkseK^p3PvWc;e?`A}9a@^emcl~}#h3*+>&y03Sj8l`LQeJ z2X){%WRKkZ!mkDW_tBbbj=}`5VOj`4iEY85MPV#{y&Gm1DetCl$J(^cvhZy?!njAz z;6vx(P%rt-%l1s`pyNCM>nG|{AQm#*BE)U{$YoElI2>Nr54_tRx;YhuO*?`X&4I^_ z@w3>|@k1qRpiZS_u*>@$kiTbY-w3uNvBOKvh8Y*Hq#OG*Bo#b=>%!L2{VTJ<1oprO zmLrzgxF51VP3pRijg}}NkZK?WJY@==vPDc5&O8A?x}K;cP!fV&kZy=#ioC#qquYS6 znIP;65OyU9s{q0(BVlVm*ghm|?6ek$i-&Yo@s%zCPw7r@N@VerZ|wA9e5JbpU+L=L zE8ThcN>>wK=`O-ox(4`4R}Nq4F2Ps2O881w4`1m@0WZ`kBr$w01-z0Q-3d;#48GQy z6!1!JHpEU#0k0%SR|+Cv zk{n&B!Yj$ql`6dN8{Owm`(%;xkaRU!ftNkt4&2!9fg8IJxUrhRjYaO%2zF5vH1igR zfUq_o>{bvq5`X=&u_+iRd3iegD=S{PxUI J(;VohzX8yaY3Kj| diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 33f00d22555..b786787f83e 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -26,6 +26,7 @@ const unicodeRanges = { kana: "U+3040-30FF", CJKCommon: "U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3400-4DBF,U+F900-FAFF,U+FE30-FE4F", CJKIdeograph: "U+4E00-9FFF", + specialCharacters: "U+266A,U+2605,U+2665,U+2663" //♪.★,♥,♣ }; const rangesByLanguage = { korean: [unicodeRanges.CJKCommon, unicodeRanges.hangul].join(","), @@ -34,6 +35,15 @@ const rangesByLanguage = { }; const fonts: Array = [ + // unicode (special character from PokePT) + { + face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: unicodeRanges.specialCharacters }), + }, + { + face: new FontFace("pkmnems", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: unicodeRanges.specialCharacters }), + extraOptions: { sizeAdjust: "133%" }, + }, + // unicode (korean) { face: new FontFace("emerald", "url(./fonts/PokePT_Wansung.woff2)", { unicodeRange: rangesByLanguage.korean }), }, From 61d659d8bb26a204fafa71f85674335ef84167af Mon Sep 17 00:00:00 2001 From: Lugiad Date: Thu, 22 Aug 2024 05:57:46 +0200 Subject: [PATCH 54/63] [Localization] Localizable owned money symbol on battle UI (#3646) Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Enoch Co-authored-by: frutescens --- src/battle-scene.ts | 2 +- src/locales/ca_ES/battle-scene.ts | 5 +++++ src/locales/ca_ES/config.ts | 2 ++ src/locales/de/battle-scene.ts | 6 ++++++ src/locales/de/config.ts | 2 ++ src/locales/en/battle-scene.ts | 5 +++++ src/locales/en/config.ts | 2 ++ src/locales/es/battle-scene.ts | 5 +++++ src/locales/es/config.ts | 2 ++ src/locales/fr/battle-scene.ts | 5 +++++ src/locales/fr/config.ts | 2 ++ src/locales/it/battle-scene.ts | 5 +++++ src/locales/it/config.ts | 2 ++ src/locales/ja/battle-scene.ts | 5 +++++ src/locales/ja/config.ts | 2 ++ src/locales/ko/battle-scene.ts | 5 +++++ src/locales/ko/config.ts | 2 ++ src/locales/pt_BR/battle-scene.ts | 5 +++++ src/locales/pt_BR/config.ts | 2 ++ src/locales/zh_CN/battle-scene.ts | 5 +++++ src/locales/zh_CN/config.ts | 2 ++ src/locales/zh_TW/battle-scene.ts | 5 +++++ src/locales/zh_TW/config.ts | 2 ++ 23 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/locales/ca_ES/battle-scene.ts create mode 100644 src/locales/de/battle-scene.ts create mode 100644 src/locales/en/battle-scene.ts create mode 100644 src/locales/es/battle-scene.ts create mode 100644 src/locales/fr/battle-scene.ts create mode 100644 src/locales/it/battle-scene.ts create mode 100644 src/locales/ja/battle-scene.ts create mode 100644 src/locales/ko/battle-scene.ts create mode 100644 src/locales/pt_BR/battle-scene.ts create mode 100644 src/locales/zh_CN/battle-scene.ts create mode 100644 src/locales/zh_TW/battle-scene.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index aad0d355e38..af63f0b0a39 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1518,7 +1518,7 @@ export default class BattleScene extends SceneBase { return; } const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); - this.moneyText.setText(`₽${formattedMoney}`); + this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney })); this.fieldUI.moveAbove(this.moneyText, this.luckText); if (forceVisible) { this.moneyText.setVisible(true); diff --git a/src/locales/ca_ES/battle-scene.ts b/src/locales/ca_ES/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/ca_ES/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/ca_ES/config.ts b/src/locales/ca_ES/config.ts index 831ab5d99f5..36aee87fc75 100644 --- a/src/locales/ca_ES/config.ts +++ b/src/locales/ca_ES/config.ts @@ -6,6 +6,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const caESConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/de/battle-scene.ts b/src/locales/de/battle-scene.ts new file mode 100644 index 00000000000..bfa96445f6c --- /dev/null +++ b/src/locales/de/battle-scene.ts @@ -0,0 +1,6 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "{{formattedMoney}} ₽" + +} as const; diff --git a/src/locales/de/config.ts b/src/locales/de/config.ts index d0779c9eec4..080c9ecc598 100644 --- a/src/locales/de/config.ts +++ b/src/locales/de/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const deConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/en/battle-scene.ts b/src/locales/en/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/en/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/en/config.ts b/src/locales/en/config.ts index a98dd750fbe..d456b0540cc 100644 --- a/src/locales/en/config.ts +++ b/src/locales/en/config.ts @@ -6,6 +6,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const enConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/es/battle-scene.ts b/src/locales/es/battle-scene.ts new file mode 100644 index 00000000000..995ca744302 --- /dev/null +++ b/src/locales/es/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "{{formattedMoney}} ₽" +} as const; diff --git a/src/locales/es/config.ts b/src/locales/es/config.ts index ce9ad19aac3..6c038188da2 100644 --- a/src/locales/es/config.ts +++ b/src/locales/es/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const esConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/fr/battle-scene.ts b/src/locales/fr/battle-scene.ts new file mode 100644 index 00000000000..995ca744302 --- /dev/null +++ b/src/locales/fr/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "{{formattedMoney}} ₽" +} as const; diff --git a/src/locales/fr/config.ts b/src/locales/fr/config.ts index 246ae9a073f..a2ab67eefe0 100644 --- a/src/locales/fr/config.ts +++ b/src/locales/fr/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const frConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/it/battle-scene.ts b/src/locales/it/battle-scene.ts new file mode 100644 index 00000000000..995ca744302 --- /dev/null +++ b/src/locales/it/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "{{formattedMoney}} ₽" +} as const; diff --git a/src/locales/it/config.ts b/src/locales/it/config.ts index ceb52665796..d6265061a9f 100644 --- a/src/locales/it/config.ts +++ b/src/locales/it/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const itConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/ja/battle-scene.ts b/src/locales/ja/battle-scene.ts new file mode 100644 index 00000000000..d2f074416e1 --- /dev/null +++ b/src/locales/ja/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "{{formattedMoney}}円" +} as const; diff --git a/src/locales/ja/config.ts b/src/locales/ja/config.ts index 6af79547a04..61be36c08df 100644 --- a/src/locales/ja/config.ts +++ b/src/locales/ja/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -61,6 +62,7 @@ export const jaConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/ko/battle-scene.ts b/src/locales/ko/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/ko/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/ko/config.ts b/src/locales/ko/config.ts index 114950a4d35..2bc60f04bef 100644 --- a/src/locales/ko/config.ts +++ b/src/locales/ko/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const koConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/pt_BR/battle-scene.ts b/src/locales/pt_BR/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/pt_BR/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/pt_BR/config.ts b/src/locales/pt_BR/config.ts index b48fcfdc8d8..9ebb4867ae4 100644 --- a/src/locales/pt_BR/config.ts +++ b/src/locales/pt_BR/config.ts @@ -4,6 +4,7 @@ import { PGFachv, PGMachv } from "./achv"; import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const ptBrConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/zh_CN/battle-scene.ts b/src/locales/zh_CN/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/zh_CN/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/zh_CN/config.ts b/src/locales/zh_CN/config.ts index 24c8b870ffa..99b4e56ffc2 100644 --- a/src/locales/zh_CN/config.ts +++ b/src/locales/zh_CN/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const zhCnConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, diff --git a/src/locales/zh_TW/battle-scene.ts b/src/locales/zh_TW/battle-scene.ts new file mode 100644 index 00000000000..573e1791724 --- /dev/null +++ b/src/locales/zh_TW/battle-scene.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleScene: SimpleTranslationEntries = { + "moneyOwned": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/zh_TW/config.ts b/src/locales/zh_TW/config.ts index 004ed1da1ab..269ea3003b9 100644 --- a/src/locales/zh_TW/config.ts +++ b/src/locales/zh_TW/config.ts @@ -4,6 +4,7 @@ import { arenaFlyout } from "./arena-flyout"; import { arenaTag } from "./arena-tag"; import { PGFachv, PGMachv } from "./achv"; import { battle } from "./battle"; +import { battleScene } from "./battle-scene"; import { battleInfo } from "./battle-info"; import { battleMessageUiHandler } from "./battle-message-ui-handler"; import { battlerTags } from "./battler-tags"; @@ -60,6 +61,7 @@ export const zhTwConfig = { arenaFlyout: arenaFlyout, arenaTag: arenaTag, battle: battle, + battleScene: battleScene, battleInfo: battleInfo, battleMessageUiHandler: battleMessageUiHandler, battlePokemonForm: battlePokemonForm, From b1d4037a57c01d794a49c0f0a5d299918e153ac6 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:39:11 +0900 Subject: [PATCH 55/63] [Bug] Fix some damage formulas processed with ceil instead of floor (#3557) * fix damage calculations. add test code * define toIntValue function to replace every repeatitive min floor function. * revert unnecessary minimum boundary * update function name `toIntValue` -> `toDmgValue`. update comments. * add missing updates for changing function name * Update src/utils.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * remove redundant comment * update import code for test with phase --------- Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> --- src/data/ability.ts | 34 +++++------ src/data/arena-tag.ts | 6 +- src/data/battler-tags.ts | 18 +++--- src/data/berry.ts | 2 +- src/data/move.ts | 31 +++++----- src/field/pokemon.ts | 10 +-- src/modifier/modifier.ts | 6 +- src/test/abilities/disguise.test.ts | 7 ++- src/test/abilities/heatproof.test.ts | 3 +- src/test/abilities/parental_bond.test.ts | 5 +- src/test/battle/damage_calculation.test.ts | 71 ++++++++++++++++++++++ src/test/moves/belly_drum.test.ts | 7 ++- src/test/moves/clangorous_soul.test.ts | 7 ++- src/test/moves/fillet_away.test.ts | 7 ++- src/test/moves/tackle.test.ts | 2 +- src/utils.ts | 14 +++++ 16 files changed, 161 insertions(+), 69 deletions(-) create mode 100644 src/test/battle/damage_calculation.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 27a11eb0b9a..284a9cb4e91 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -301,7 +301,7 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr { applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.condition(pokemon, attacker, move)) { - (args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * this.damageMultiplier); + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue((args[0] as Utils.NumberHolder).value * this.damageMultiplier); return true; } @@ -390,7 +390,7 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr { if (!pokemon.isFullHp() && !simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + Utils.toDmgValue(pokemon.getMaxHp() / 4), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } return true; } @@ -904,8 +904,8 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { if (!simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); - attacker.turnData.damageTaken += Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)); + attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); + attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); return true; } @@ -2049,7 +2049,7 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr { if (target?.isActive(true)) { if (!simulated) { target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / this.healRatio), 1), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); + Utils.toDmgValue(pokemon.getMaxHp() / this.healRatio), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); } return true; @@ -2440,7 +2440,7 @@ export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { if (!pokemon.isFullHp()) { if (!simulated) { - const healAmount = Math.floor(pokemon.getMaxHp() * 0.33); + const healAmount = Utils.toDmgValue(pokemon.getMaxHp() * 0.33); pokemon.heal(healAmount); pokemon.updateInfo(); } @@ -3074,7 +3074,7 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; if (!simulated) { scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / (16 / this.healFactor)), 1), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } return true; } @@ -3101,7 +3101,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { if (!simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; scene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName })); - pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER); + pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER); } return true; @@ -3181,7 +3181,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { const scene = pokemon.scene; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 8), 1), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); + Utils.toDmgValue(pokemon.getMaxHp() / 8), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); } return true; } @@ -3350,7 +3350,7 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr { const scene = pokemon.scene; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + Utils.toDmgValue(pokemon.getMaxHp() / 16), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } return true; @@ -3402,7 +3402,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr { for (const opp of pokemon.getOpponents()) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if (!simulated) { - opp.damageAndUpdate(Math.floor(Math.max(1, opp.getMaxHp() / 8)), HitResult.OTHER); + opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER); pokemon.scene.queueMessage(i18next.t("abilityTriggers:badDreams", {pokemonName: getPokemonNameWithAffix(opp)})); } hadEffect = true; @@ -3604,7 +3604,7 @@ export class ReduceBurnDamageAbAttr extends AbAttr { * @returns `true` */ apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Math.max(Math.floor((args[0] as Utils.NumberHolder).value * this.multiplier), 1); + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue((args[0] as Utils.NumberHolder).value * this.multiplier); return true; } @@ -3649,7 +3649,7 @@ export class HealFromBerryUseAbAttr extends AbAttr { new PokemonHealPhase( pokemon.scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() * this.healPercent), 1), + Utils.toDmgValue(pokemon.getMaxHp() * this.healPercent), i18next.t("abilityTriggers:healFromBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true ) @@ -3840,8 +3840,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { return false; } if (!simulated) { - attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); - attacker.turnData.damageTaken += Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)); + attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); + attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); } return true; } @@ -3922,7 +3922,7 @@ export class ReduceStatusEffectDurationAbAttr extends AbAttr { apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (args[0] === this.statusEffect) { - (args[1] as Utils.IntegerHolder).value = Math.floor((args[1] as Utils.IntegerHolder).value / 2); + (args[1] as Utils.IntegerHolder).value = Utils.toDmgValue((args[1] as Utils.IntegerHolder).value / 2); return true; } @@ -5211,7 +5211,7 @@ export function initAbilities() { .conditionalAttr(pokemon => pokemon.formIndex === 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.DISGUISE, 0, false) .attr(FormBlockDamageAbAttr, (target, user, move) => !!target.getTag(BattlerTagType.DISGUISE) && target.getAttackTypeEffectiveness(move.type, user) > 0, 0, BattlerTagType.DISGUISE, (pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }), - (pokemon) => Math.floor(pokemon.getMaxHp() / 8)) + (pokemon) => Utils.toDmgValue(pokemon.getMaxHp() / 8)) .attr(PostBattleInitFormChangeAbAttr, () => 0) .bypassFaint() .ignorable(), diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 026003d0b61..a60ea5c2981 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -427,7 +427,7 @@ class WishTag extends ArenaTag { if (user) { this.battlerIndex = user.getBattlerIndex(); this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) }); - this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1); + this.healHp = Utils.toDmgValue(user.getMaxHp() / 2); } else { console.warn("Failed to get source for WishTag onAdd"); } @@ -585,7 +585,7 @@ class SpikesTag extends ArenaTrapTag { if (!cancelled.value) { const damageHpRatio = 1 / (10 - 2 * this.layers); - const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio); + const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio); pokemon.scene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); pokemon.damageAndUpdate(damage, HitResult.OTHER); @@ -745,7 +745,7 @@ class StealthRockTag extends ArenaTrapTag { const damageHpRatio = this.getDamageHpRatio(pokemon); if (damageHpRatio) { - const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio); + const damage = Utils.toDmgValue(pokemon.getMaxHp() * damageHpRatio); pokemon.scene.queueMessage(i18next.t("arenaTag:stealthRockActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); pokemon.damageAndUpdate(damage, HitResult.OTHER); if (pokemon.turnData) { diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ede8d029327..8c05d296e76 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -347,7 +347,7 @@ export class ConfusedTag extends BattlerTag { if (pokemon.randSeedInt(3) === 0) { const atk = pokemon.getBattleStat(Stat.ATK); const def = pokemon.getBattleStat(Stat.DEF); - const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); + const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); pokemon.damageAndUpdate(damage); pokemon.battleData.hitCount++; @@ -524,7 +524,7 @@ export class SeedTag extends BattlerTag { if (!cancelled.value) { pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED)); - const damage = pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 8), 1)); + const damage = pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8)); const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, source.getBattlerIndex(), !reverseDrain ? damage : damage * -1, @@ -570,7 +570,7 @@ export class NightmareTag extends BattlerTag { applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); if (!cancelled.value) { - pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 4)); + pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4)); } } @@ -714,7 +714,7 @@ export class IngrainTag extends TrappedTag { new PokemonHealPhase( pokemon.scene, pokemon.getBattlerIndex(), - Math.floor(pokemon.getMaxHp() / 16), + Utils.toDmgValue(pokemon.getMaxHp() / 16), i18next.t("battlerTags:ingrainLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), true ) @@ -777,7 +777,7 @@ export class AquaRingTag extends BattlerTag { new PokemonHealPhase( pokemon.scene, pokemon.getBattlerIndex(), - Math.floor(pokemon.getMaxHp() / 16), + Utils.toDmgValue(pokemon.getMaxHp() / 16), i18next.t("battlerTags:aquaRingLapse", { moveName: this.getMoveName(), pokemonName: getPokemonNameWithAffix(pokemon) @@ -883,7 +883,7 @@ export abstract class DamagingTrapTag extends TrappedTag { applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); if (!cancelled.value) { - pokemon.damageAndUpdate(Math.ceil(pokemon.getMaxHp() / 8)); + pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 8)); } } @@ -1067,7 +1067,7 @@ export class ContactDamageProtectedTag extends ProtectedTag { if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { const attacker = effectPhase.getPokemon(); if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); + attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); } } } @@ -1541,7 +1541,7 @@ export class SaltCuredTag extends BattlerTag { if (!cancelled.value) { const pokemonSteelOrWater = pokemon.isOfType(Type.STEEL) || pokemon.isOfType(Type.WATER); - pokemon.damageAndUpdate(Math.max(Math.floor(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), 1)); + pokemon.damageAndUpdate(Utils.toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8)); pokemon.scene.queueMessage( i18next.t("battlerTags:saltCuredLapse", { @@ -1587,7 +1587,7 @@ export class CursedTag extends BattlerTag { applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); if (!cancelled.value) { - pokemon.damageAndUpdate(Math.max(Math.floor(pokemon.getMaxHp() / 4), 1)); + pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / 4)); pokemon.scene.queueMessage(i18next.t("battlerTags:cursedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); } } diff --git a/src/data/berry.ts b/src/data/berry.ts index ff82a683e5a..d0c9c311e16 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -70,7 +70,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } - const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4)); + const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4)); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true)); diff --git a/src/data/move.ts b/src/data/move.ts index 682ab0739d5..b1b82009f3e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1162,7 +1162,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value = Math.max(Math.floor(target.hp / 2), 1); + (args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(target.hp / 2); return true; } @@ -1208,7 +1208,7 @@ export class CounterDamageAttr extends FixedDamageAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const damage = user.turnData.attacksReceived.filter(ar => this.moveFilter(allMoves[ar.move])).reduce((total: integer, ar: AttackMoveResult) => total + ar.damage, 0); - (args[0] as Utils.IntegerHolder).value = Math.floor(Math.max(damage * this.multiplier, 1)); + (args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(damage * this.multiplier); return true; } @@ -1234,7 +1234,7 @@ export class RandomLevelDamageAttr extends FixedDamageAttr { } getDamage(user: Pokemon, target: Pokemon, move: Move): number { - return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1); + return Utils.toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01)); } } @@ -1293,8 +1293,9 @@ export class RecoilAttr extends MoveEffectAttr { return false; } - const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio), - user.turnData.damageDealt ? 1 : 0); + const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio; + const minValue = user.turnData.damageDealt ? 1 : 0; + const recoilDamage = Utils.toDmgValue(damageValue, minValue); if (!recoilDamage) { return false; } @@ -1415,7 +1416,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr { // Check to see if the Pokemon has an ability that blocks non-direct damage applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); if (!cancelled.value) { - user.damageAndUpdate(Math.ceil(user.getMaxHp()/2), HitResult.OTHER, false, true, true); + user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp()/2), HitResult.OTHER, false, true, true); user.scene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", {pokemonName: getPokemonNameWithAffix(user)})); // Queue recoil message } return true; @@ -1466,7 +1467,7 @@ export class HealAttr extends MoveEffectAttr { */ addHealPhase(target: Pokemon, healRatio: number) { target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), - Math.max(Math.floor(target.getMaxHp() * healRatio), 1), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim)); + Utils.toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", {pokemonName: getPokemonNameWithAffix(target)}), true, !this.showAnim)); } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { @@ -1750,7 +1751,7 @@ export class HitHealAttr extends MoveEffectAttr { message = i18next.t("battle:drainMessage", {pokemonName: getPokemonNameWithAffix(target)}); } else { // Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc. - healAmount = Math.max(Math.floor(user.turnData.currDamageDealt * this.healRatio), 1); + healAmount = Utils.toDmgValue(user.turnData.currDamageDealt * this.healRatio); message = i18next.t("battle:regainHealth", {pokemonName: getPokemonNameWithAffix(user)}); } if (reverseDrain) { @@ -2710,7 +2711,7 @@ export class CutHpStatBoostAttr extends StatChangeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { - user.damageAndUpdate(Math.floor(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true); + user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true); user.updateInfo().then(() => { const ret = super.apply(user, target, move, args); if (this.messageCallback) { @@ -3190,7 +3191,7 @@ export class CompareWeightPowerAttr extends VariablePowerAttr { export class HpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Math.max(Math.floor(150 * user.getHpRatio()), 1); + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(150 * user.getHpRatio()); return true; } @@ -3218,7 +3219,7 @@ export class OpponentHighHpPowerAttr extends VariablePowerAttr { * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Math.max(Math.floor(this.maxBasePower * target.getHpRatio()), 1); + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.maxBasePower * target.getHpRatio()); return true; } @@ -3412,7 +3413,7 @@ export class PresentPowerAttr extends VariablePowerAttr { // If this move is multi-hit, disable all other hits user.stopMultiHit(); target.scene.unshiftPhase(new PokemonHealPhase(target.scene, target.getBattlerIndex(), - Math.max(Math.floor(target.getMaxHp() / 4), 1), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true)); + Utils.toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", {pokemonName: getPokemonNameWithAffix(target)}), true)); } return true; @@ -4232,9 +4233,9 @@ const crashDamageFunc = (user: Pokemon, move: Move) => { return false; } - user.damageAndUpdate(Math.floor(user.getMaxHp() / 2), HitResult.OTHER, false, true); + user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true); user.scene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", {pokemonName: getPokemonNameWithAffix(user)})); - user.turnData.damageTaken += Math.floor(user.getMaxHp() / 2); + user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2); return true; }; @@ -4944,7 +4945,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr { const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)]; const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id); pokemon.resetStatus(); - pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp())); + pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); user.scene.queueMessage(`${getPokemonNameWithAffix(pokemon)} was revived!`,0,true); if (user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) { diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 999ebb3cb21..030297a2126 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2092,7 +2092,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!isTypeImmune) { const levelMultiplier = (2 * source.level / 5 + 2); const randomMultiplier = ((this.scene.randBattleSeedInt(16) + 85) / 100); - damage.value = Math.ceil((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2) + damage.value = Utils.toDmgValue((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier.value @@ -2108,7 +2108,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const burnDamageReductionCancelled = new Utils.BooleanHolder(false); applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled, false); if (!burnDamageReductionCancelled.value) { - damage.value = Math.floor(damage.value / 2); + damage.value = Utils.toDmgValue(damage.value / 2); } } } @@ -2129,7 +2129,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && move.type === Type.DRAGON) { - damage.value = Math.floor(damage.value / 2); + damage.value = Utils.toDmgValue(damage.value / 2); } const fixedDamage = new Utils.IntegerHolder(0); @@ -3455,7 +3455,7 @@ export class PlayerPokemon extends Pokemon { pokemon.resetTurnData(); pokemon.resetStatus(); - pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp())); + pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); this.scene.queueMessage(`${pokemon.name} was revived!`,0,true); if (this.scene.currentBattle.double && this.scene.getParty().length > 1) { @@ -4382,7 +4382,7 @@ export class PokemonMove { } getMovePp(): integer { - return this.getMove().pp + this.ppUp * Math.max(Math.floor(this.getMove().pp / 5), 1); + return this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5); } getPpRatio(): number { diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 8a6598f5849..99f4540f493 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1160,7 +1160,7 @@ export class TurnHealModifier extends PokemonHeldItemModifier { if (!pokemon.isFullHp()) { const scene = pokemon.scene; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 16) * this.stackCount, 1), i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); + Utils.toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); return true; } @@ -1251,7 +1251,7 @@ export class HitHealModifier extends PokemonHeldItemModifier { if (pokemon.turnData.damageDealt && !pokemon.isFullHp()) { const scene = pokemon.scene; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.turnData.damageDealt / 8) * this.stackCount, 1), i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); + Utils.toDmgValue(pokemon.turnData.damageDealt / 8) * this.stackCount, i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); } return true; @@ -1386,7 +1386,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { const pokemon = args[0] as Pokemon; pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 2), 1), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); + Utils.toDmgValue(pokemon.getMaxHp() / 2), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); pokemon.resetStatus(true, false, true); return true; diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index 969375c397e..a22c4cb55d5 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -6,6 +6,7 @@ import { Species } from "#enums/species"; import { StatusEffect } from "#app/data/status-effect.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { SPLASH_ONLY } from "../utils/testUtils"; +import { toDmgValue } from "#app/utils"; import { Mode } from "#app/ui/ui.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { MoveEndPhase } from "#app/phases/move-end-phase.js"; @@ -47,7 +48,7 @@ describe("Abilities - Disguise", () => { const mimikyu = game.scene.getEnemyPokemon()!; const maxHp = mimikyu.getMaxHp(); - const disguiseDamage = Math.floor(maxHp / 8); + const disguiseDamage = toDmgValue(maxHp / 8); expect(mimikyu.formIndex).toBe(disguisedForm); @@ -80,7 +81,7 @@ describe("Abilities - Disguise", () => { const mimikyu = game.scene.getEnemyPokemon()!; const maxHp = mimikyu.getMaxHp(); - const disguiseDamage = Math.floor(maxHp / 8); + const disguiseDamage = toDmgValue(maxHp / 8); expect(mimikyu.formIndex).toBe(disguisedForm); @@ -121,7 +122,7 @@ describe("Abilities - Disguise", () => { const mimikyu = game.scene.getPlayerPokemon()!; const maxHp = mimikyu.getMaxHp(); - const disguiseDamage = Math.floor(maxHp / 8); + const disguiseDamage = toDmgValue(maxHp / 8); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); diff --git a/src/test/abilities/heatproof.test.ts b/src/test/abilities/heatproof.test.ts index 64a45c5023f..ee6c0bb6ec9 100644 --- a/src/test/abilities/heatproof.test.ts +++ b/src/test/abilities/heatproof.test.ts @@ -8,6 +8,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; import { StatusEffect } from "#app/enums/status-effect.js"; +import { toDmgValue } from "#app/utils"; describe("Abilities - Heatproof", () => { let phaserGame: Phaser.Game; @@ -72,6 +73,6 @@ describe("Abilities - Heatproof", () => { await game.toNextTurn(); // Normal burn damage is /16 - expect(enemy.hp).toBe(enemy.getMaxHp() - Math.floor(enemy.getMaxHp() / 32)); + expect(enemy.hp).toBe(enemy.getMaxHp() - toDmgValue(enemy.getMaxHp() / 32)); }); }); diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index ef0ad7785d2..d14d5871ef7 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -16,6 +16,7 @@ import { DamagePhase } from "#app/phases/damage-phase.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { MoveEndPhase } from "#app/phases/move-end-phase.js"; import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { toDmgValue } from "#app/utils"; const TIMEOUT = 20 * 1000; @@ -73,7 +74,7 @@ describe("Abilities - Parental Bond", () => { const secondStrikeDamage = enemyStartingHp - enemyPokemon.hp; expect(leadPokemon.turnData.hitCount).toBe(2); - expect(secondStrikeDamage).toBe(Math.ceil(0.25 * firstStrikeDamage)); + expect(secondStrikeDamage).toBe(toDmgValue(0.25 * firstStrikeDamage)); }, TIMEOUT ); @@ -303,7 +304,7 @@ describe("Abilities - Parental Bond", () => { // This test will time out if the user faints await game.phaseInterceptor.to(BerryPhase, false); - expect(leadPokemon.hp).toBe(Math.floor(leadPokemon.getMaxHp()/2)); + expect(leadPokemon.hp).toBe(toDmgValue(leadPokemon.getMaxHp()/2)); }, TIMEOUT ); diff --git a/src/test/battle/damage_calculation.test.ts b/src/test/battle/damage_calculation.test.ts new file mode 100644 index 00000000000..9b13a266d33 --- /dev/null +++ b/src/test/battle/damage_calculation.test.ts @@ -0,0 +1,71 @@ +import { DamagePhase } from "#app/phases/damage-phase.js"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { ArenaTagType } from "#enums/arena-tag-type"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { toDmgValue } from "#app/utils"; + +describe("Round Down and Minimun 1 test in Damage Calculation", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override.battleType("single"); + game.override.startingLevel(10); + }); + + it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => { + game.override.enemySpecies(Species.GASTLY); + game.override.enemyMoveset(SPLASH_ONLY); + game.override.starterSpecies(Species.SHEDINJA); + game.override.moveset([Moves.JUMP_KICK]); + game.override.ability(Abilities.WONDER_GUARD); + + await game.startBattle(); + + const shedinja = game.scene.getPlayerPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.JUMP_KICK)); + + await game.phaseInterceptor.to(DamagePhase); + + expect(shedinja.hp).toBe(shedinja.getMaxHp() - 1); + }); + + + it("Charizard with odd HP survives Stealth Rock damage twice", async () => { + game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0); + game.override.seed("Charizard Stealth Rock test"); + game.override.enemySpecies(Species.CHARIZARD); + game.override.enemyAbility(Abilities.BLAZE); + game.override.starterSpecies(Species.PIKACHU); + game.override.enemyLevel(100); + + await game.startBattle(); + + const charizard = game.scene.getEnemyPokemon()!; + + const maxHp = charizard.getMaxHp(); + const damage_prediction = toDmgValue(charizard.getMaxHp() / 2); + const currentHp = charizard.hp; + const expectedHP = maxHp - damage_prediction; + + expect(currentHp).toBe(expectedHP); + }); +}); diff --git a/src/test/moves/belly_drum.test.ts b/src/test/moves/belly_drum.test.ts index e579a4587ad..229314c96e6 100644 --- a/src/test/moves/belly_drum.test.ts +++ b/src/test/moves/belly_drum.test.ts @@ -6,6 +6,7 @@ import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { BattleStat } from "#app/data/battle-stat"; +import { toDmgValue } from "#app/utils"; const TIMEOUT = 20 * 1000; // RATIO : HP Cost of Move @@ -44,7 +45,7 @@ describe("Moves - BELLY DRUM", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); await game.phaseInterceptor.to(TurnEndPhase); @@ -59,7 +60,7 @@ describe("Moves - BELLY DRUM", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); // Here - BattleStat.ATK -> -3 and BattleStat.SPATK -> 6 leadPokemon.summonData.battleStats[BattleStat.ATK] = -3; @@ -95,7 +96,7 @@ describe("Moves - BELLY DRUM", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); diff --git a/src/test/moves/clangorous_soul.test.ts b/src/test/moves/clangorous_soul.test.ts index 5b2e8b6e06d..afab4c2e9be 100644 --- a/src/test/moves/clangorous_soul.test.ts +++ b/src/test/moves/clangorous_soul.test.ts @@ -7,6 +7,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { BattleStat } from "#app/data/battle-stat"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { toDmgValue } from "#app/utils"; const TIMEOUT = 20 * 1000; /** HP Cost of Move */ @@ -45,7 +46,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); await game.phaseInterceptor.to(TurnEndPhase); @@ -64,7 +65,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); //Here - BattleStat.SPD -> 0 and BattleStat.SPDEF -> 4 leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; @@ -113,7 +114,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); diff --git a/src/test/moves/fillet_away.test.ts b/src/test/moves/fillet_away.test.ts index fcad704ef29..fc87d600eb5 100644 --- a/src/test/moves/fillet_away.test.ts +++ b/src/test/moves/fillet_away.test.ts @@ -7,6 +7,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { BattleStat } from "#app/data/battle-stat"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { toDmgValue } from "#app/utils"; const TIMEOUT = 20 * 1000; /** HP Cost of Move */ @@ -45,7 +46,7 @@ describe("Moves - FILLET AWAY", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); await game.phaseInterceptor.to(TurnEndPhase); @@ -62,7 +63,7 @@ describe("Moves - FILLET AWAY", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); //Here - BattleStat.SPD -> 0 and BattleStat.SPATK -> 3 leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; @@ -103,7 +104,7 @@ describe("Moves - FILLET AWAY", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); + const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); diff --git a/src/test/moves/tackle.test.ts b/src/test/moves/tackle.test.ts index f442645baa9..3da8bc6f978 100644 --- a/src/test/moves/tackle.test.ts +++ b/src/test/moves/tackle.test.ts @@ -78,6 +78,6 @@ describe("Moves - Tackle", () => { await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); const hpLost = hpOpponent - game.scene.currentBattle.enemyParty[0].hp; expect(hpLost).toBeGreaterThan(0); - expect(hpLost).toBe(4); + expect(hpLost).toBeLessThan(4); }, 20000); }); diff --git a/src/utils.ts b/src/utils.ts index c51ac2b5b0b..a9bbc93d684 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -560,3 +560,17 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar: boole export function isNullOrUndefined(object: any): boolean { return null === object || undefined === object; } + +/** + * This function is used in the context of a Pokémon battle game to calculate the actual integer damage value from a float result. + * Many damage calculation formulas involve various parameters and result in float values. + * The actual damage applied to a Pokémon's HP must be an integer. + * This function helps in ensuring that by flooring the float value and enforcing a minimum damage value. + * + * @param value - The float value to convert. + * @param minValue - The minimum integer value to return. Defaults to 1. + * @returns The converted value as an integer. + */ +export function toDmgValue(value: number, minValue: number = 1) { + return Math.max(Math.floor(value), minValue); +} From 10f1a96ed6b3977e7f30ff90a7f9c770ff44fab5 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 22 Aug 2024 05:04:26 -0700 Subject: [PATCH 56/63] Increase Target Select UI Opacitiy (#3683) Co-authored-by: frutescens --- src/ui/target-select-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index 42c7fef5660..6ca580dc2b2 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -118,7 +118,7 @@ export default class TargetSelectUiHandler extends UiHandler { this.targetFlashTween = this.scene.tweens.add({ targets: this.targetsHighlighted, - key: { start: 0.55, to: 1 }, + key: { start: 1, to: 0.25 }, loop: -1, loopDelay: 150, duration: Utils.fixedInt(450), From 828897316e089ba390bc5fd3503e9175c7f45e8e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Thu, 22 Aug 2024 06:49:33 -0700 Subject: [PATCH 57/63] [Test] Replace `doAttack()` with `move.select()` in tests (#3567) * Consolidate `doSelectTarget()` into `doAttack()` * Fix ternary * Add error message to aid in debugging tests * Update docs * [Test] Change `doAttack()` to `selectMove()` * Add `select()` to `src/test/utils/helpers/moveHelper.ts` * Replace instances of `game.selectMove()` with `game.move.select()` * Fix imports * Replace `selectMove()` with `move.select()` helper Fix broken tests for Pastel Veil and Sweet Veil * Update tsdocs --- src/test/abilities/ability_timing.test.ts | 10 +- src/test/abilities/aura_break.test.ts | 15 ++- src/test/abilities/battery.test.ts | 25 ++-- src/test/abilities/battle_bond.test.ts | 9 +- src/test/abilities/costar.test.ts | 25 ++-- src/test/abilities/disguise.test.ts | 41 +++---- src/test/abilities/dry_skin.test.ts | 29 +++-- src/test/abilities/flash_fire.test.ts | 43 ++++--- src/test/abilities/gulp_missile.test.ts | 47 ++++--- src/test/abilities/heatproof.test.ts | 19 ++- src/test/abilities/hustle.test.ts | 23 ++-- src/test/abilities/hyper_cutter.test.ts | 11 +- src/test/abilities/ice_face.test.ts | 37 +++--- src/test/abilities/intimidate.test.ts | 71 +++-------- src/test/abilities/intrepid_sword.test.ts | 4 +- src/test/abilities/libero.test.ts | 49 ++++---- src/test/abilities/magic_guard.test.ts | 69 +++++------ src/test/abilities/moxie.test.ts | 22 +--- src/test/abilities/mycelium_might.test.ts | 27 ++-- src/test/abilities/parental_bond.test.ts | 95 +++++++------- src/test/abilities/pastel_veil.test.ts | 66 +++++----- src/test/abilities/power_construct.test.ts | 9 +- src/test/abilities/power_spot.test.ts | 25 ++-- src/test/abilities/protean.test.ts | 49 ++++---- src/test/abilities/quick_draw.test.ts | 11 +- src/test/abilities/sand_spit.test.ts | 13 +- src/test/abilities/sand_veil.test.ts | 19 ++- src/test/abilities/sap_sipper.test.ts | 35 +++--- src/test/abilities/schooling.test.ts | 9 +- src/test/abilities/screen_cleaner.test.ts | 15 ++- src/test/abilities/serene_grace.test.ts | 32 ++--- src/test/abilities/sheer_force.test.ts | 58 +++------ src/test/abilities/shield_dust.test.ts | 22 +--- src/test/abilities/shields_down.test.ts | 9 +- src/test/abilities/stall.test.ts | 23 ++-- src/test/abilities/steely_spirit.test.ts | 34 ++--- src/test/abilities/sturdy.test.ts | 17 ++- src/test/abilities/sweet_veil.test.ts | 53 ++++---- src/test/abilities/unseen_fist.test.ts | 7 +- src/test/abilities/volt_absorb.test.ts | 9 +- src/test/abilities/wind_power.test.ts | 17 ++- src/test/abilities/wind_rider.test.ts | 19 ++- src/test/abilities/wonder_skin.test.ts | 17 ++- src/test/abilities/zen_mode.test.ts | 55 +++------ src/test/abilities/zero_to_hero.test.ts | 13 +- src/test/account.spec.ts | 2 +- src/test/achievements/achievement.test.ts | 4 +- src/test/arena/arena_gravity.test.ts | 19 ++- src/test/arena/weather_fog.test.ts | 13 +- src/test/arena/weather_strong_winds.test.ts | 15 ++- src/test/battle-scene.test.ts | 2 +- src/test/battle-stat.spec.ts | 2 +- src/test/battle/battle-order.test.ts | 112 +++-------------- src/test/battle/battle.test.ts | 116 ++++++++---------- src/test/battle/damage_calculation.test.ts | 11 +- src/test/battle/double_battle.test.ts | 17 ++- src/test/battle/error-handling.test.ts | 10 +- src/test/battle/special_battle.test.ts | 4 +- src/test/battlerTags/octolock.test.ts | 12 +- src/test/battlerTags/stockpiling.test.ts | 12 +- src/test/eggs/egg.test.ts | 18 +-- src/test/evolution.test.ts | 6 +- src/test/evolutions/evolutions.test.ts | 8 +- src/test/field/pokemon.test.ts | 2 +- src/test/final_boss.test.ts | 6 +- src/test/game-mode.test.ts | 4 +- src/test/imports.test.ts | 2 +- src/test/inputs/inputs.test.ts | 8 +- src/test/internals.test.ts | 8 +- src/test/items/eviolite.test.ts | 2 +- src/test/items/exp_booster.test.ts | 6 +- src/test/items/grip_claw.test.ts | 33 ++--- src/test/items/leek.test.ts | 28 ++--- src/test/items/leftovers.test.ts | 13 +- src/test/items/light_ball.test.ts | 2 +- src/test/items/lock_capsule.test.ts | 15 ++- src/test/items/metal_powder.test.ts | 2 +- src/test/items/quick_powder.test.ts | 2 +- src/test/items/scope_lens.test.ts | 16 +-- src/test/items/thick_club.test.ts | 2 +- src/test/items/toxic_orb.test.ts | 24 +--- src/test/localization/battle-stat.test.ts | 41 +++---- src/test/localization/french.test.ts | 10 +- src/test/localization/status-effect.test.ts | 4 +- src/test/localization/terrain.test.ts | 4 +- src/test/moves/astonish.test.ts | 19 ++- src/test/moves/aurora_veil.test.ts | 41 +++---- src/test/moves/baton_pass.test.ts | 19 ++- src/test/moves/beak_blast.test.ts | 31 +++-- src/test/moves/beat_up.test.ts | 23 ++-- src/test/moves/belly_drum.test.ts | 29 +++-- src/test/moves/ceaseless_edge.test.ts | 29 +++-- src/test/moves/clangorous_soul.test.ts | 35 +++--- src/test/moves/crafty_shield.test.ts | 31 +++-- src/test/moves/double_team.test.ts | 11 +- src/test/moves/dragon_rage.test.ts | 23 ++-- src/test/moves/dragon_tail.test.ts | 61 +++------ src/test/moves/dynamax_cannon.test.ts | 49 ++++---- src/test/moves/fillet_away.test.ts | 29 +++-- src/test/moves/fissure.test.ts | 17 ++- src/test/moves/flame_burst.test.ts | 52 ++++---- src/test/moves/flower_shield.test.ts | 25 ++-- src/test/moves/focus_punch.test.ts | 27 ++-- src/test/moves/follow_me.test.ts | 90 ++++---------- src/test/moves/foresight.test.ts | 23 ++-- src/test/moves/freezy_frost.test.ts | 21 ++-- src/test/moves/fusion_bolt.test.ts | 19 ++- src/test/moves/fusion_flare.test.ts | 19 ++- src/test/moves/fusion_flare_bolt.test.ts | 108 +++++++--------- src/test/moves/gastro_acid.test.ts | 29 ++--- src/test/moves/glaive_rush.test.ts | 49 ++++---- src/test/moves/growth.test.ts | 22 +--- src/test/moves/hard_press.test.ts | 17 ++- src/test/moves/haze.test.ts | 19 ++- src/test/moves/hyper_beam.test.ts | 19 ++- src/test/moves/jaw_lock.test.ts | 47 ++++--- src/test/moves/light_screen.test.ts | 33 +++-- src/test/moves/lucky_chant.test.ts | 29 +++-- src/test/moves/magnet_rise.test.ts | 14 +-- src/test/moves/make_it_rain.test.ts | 25 ++-- src/test/moves/mat_block.test.ts | 31 +++-- src/test/moves/miracle_eye.test.ts | 19 ++- src/test/moves/multi_target.test.ts | 23 ++-- src/test/moves/octolock.test.ts | 19 ++- src/test/moves/parting_shot.test.ts | 37 +++--- src/test/moves/protect.test.ts | 23 ++-- src/test/moves/purify.test.ts | 15 ++- src/test/moves/quick_guard.test.ts | 25 ++-- src/test/moves/rage_powder.test.ts | 53 ++------ src/test/moves/reflect.test.ts | 33 +++-- src/test/moves/rollout.test.ts | 10 +- src/test/moves/roost.test.ts | 19 ++- src/test/moves/shell_trap.test.ts | 37 +++--- src/test/moves/spikes.test.ts | 38 +++--- src/test/moves/spit_up.test.ts | 28 ++--- src/test/moves/spotlight.test.ts | 51 ++------ src/test/moves/stockpile.test.ts | 19 ++- src/test/moves/swallow.test.ts | 26 ++-- src/test/moves/tackle.test.ts | 32 ++--- src/test/moves/tail_whip.test.ts | 22 +--- src/test/moves/tailwind.test.ts | 27 ++-- src/test/moves/tera_blast.test.ts | 39 +++--- src/test/moves/thousand_arrows.test.ts | 27 ++-- src/test/moves/tidy_up.test.ts | 47 ++++--- src/test/moves/u_turn.test.ts | 21 ++-- src/test/moves/wide_guard.test.ts | 29 +++-- src/test/phases/phases.test.ts | 14 +-- src/test/settingMenu/helpers/inGameManip.ts | 2 +- src/test/settingMenu/helpers/menuManip.ts | 4 +- .../settingMenu/rebinding_setting.test.ts | 14 +-- src/test/sprites/pokemonSprite.test.ts | 6 +- src/test/ui/starter-select.test.ts | 28 ++--- src/test/ui/transfer-item.test.ts | 10 +- src/test/ui/type-hints.test.ts | 8 +- src/test/utils/gameManager.ts | 107 +++++++--------- src/test/utils/gameManagerUtils.ts | 10 +- src/test/utils/gameWrapper.ts | 35 +++--- src/test/utils/helpers/classicModeHelper.ts | 12 +- src/test/utils/helpers/dailyModeHelper.ts | 12 +- src/test/utils/helpers/moveHelper.ts | 29 ++++- src/test/utils/inputsHandler.ts | 8 +- src/test/utils/misc.test.ts | 6 +- src/test/utils/mocks/mockTextureManager.ts | 10 +- .../utils/mocks/mocksContainer/mockSprite.ts | 2 +- .../utils/mocks/mocksContainer/mockTexture.ts | 2 +- src/test/utils/phaseInterceptor.ts | 74 +++++------ src/test/vitest.setup.ts | 4 +- 167 files changed, 1827 insertions(+), 2378 deletions(-) diff --git a/src/test/abilities/ability_timing.test.ts b/src/test/abilities/ability_timing.test.ts index c117c62d45b..3238f880992 100644 --- a/src/test/abilities/ability_timing.test.ts +++ b/src/test/abilities/ability_timing.test.ts @@ -1,15 +1,15 @@ +import { CommandPhase } from "#app/phases/command-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import i18next, { initI18n } from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Ability Timing", () => { diff --git a/src/test/abilities/aura_break.test.ts b/src/test/abilities/aura_break.test.ts index bca400bc0e3..7de300c157a 100644 --- a/src/test/abilities/aura_break.test.ts +++ b/src/test/abilities/aura_break.test.ts @@ -1,19 +1,18 @@ -import { allMoves } from "#app/data/move.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Aura Break", () => { let phaserGame: Phaser.Game; let game: GameManager; - const auraBreakMultiplier = 9/16 * 4/3; + const auraBreakMultiplier = 9 / 16 * 4 / 3; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -42,7 +41,7 @@ describe("Abilities - Aura Break", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.MOONBLAST)); + game.move.select(Moves.MOONBLAST); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier)); @@ -56,7 +55,7 @@ describe("Abilities - Aura Break", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DARK_PULSE)); + game.move.select(Moves.DARK_PULSE); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(expect.closeTo(basePower * auraBreakMultiplier)); diff --git a/src/test/abilities/battery.test.ts b/src/test/abilities/battery.test.ts index 766c1c30ecc..020866509d6 100644 --- a/src/test/abilities/battery.test.ts +++ b/src/test/abilities/battery.test.ts @@ -1,14 +1,13 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Battery", () => { let phaserGame: Phaser.Game; @@ -43,8 +42,8 @@ describe("Abilities - Battery", () => { await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.DAZZLING_GLEAM); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * batteryMultiplier); @@ -58,8 +57,8 @@ describe("Abilities - Battery", () => { await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); - game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.BREAKING_SWIPE); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); @@ -73,8 +72,8 @@ describe("Abilities - Battery", () => { await game.startBattle([Species.CHARJABUG, Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.DAZZLING_GLEAM); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); diff --git a/src/test/abilities/battle_bond.test.ts b/src/test/abilities/battle_bond.test.ts index c28a00e821d..71e9438db8f 100644 --- a/src/test/abilities/battle_bond.test.ts +++ b/src/test/abilities/battle_bond.test.ts @@ -1,11 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; @@ -53,7 +52,7 @@ describe("Abilities - BATTLE BOND", () => { greninja!.status = new Status(StatusEffect.FAINT); expect(greninja!.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); diff --git a/src/test/abilities/costar.test.ts b/src/test/abilities/costar.test.ts index 9410ee55069..9a4baeef1fb 100644 --- a/src/test/abilities/costar.test.ts +++ b/src/test/abilities/costar.test.ts @@ -1,14 +1,13 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; +import { BattleStat } from "#app/data/battle-stat"; +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; const TIMEOUT = 20 * 1000; @@ -44,15 +43,15 @@ describe("Abilities - COSTAR", () => { let [leftPokemon, rightPokemon] = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.NASTY_PLOT)); + game.move.select(Moves.NASTY_PLOT); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.toNextTurn(); expect(leftPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(+2); expect(rightPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(CommandPhase); game.doSwitchPokemon(2); await game.phaseInterceptor.to(MessagePhase); @@ -76,7 +75,7 @@ describe("Abilities - COSTAR", () => { expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2); expect(leftPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-2); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(CommandPhase); game.doSwitchPokemon(2); await game.phaseInterceptor.to(MessagePhase); diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index a22c4cb55d5..58087b408a5 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -1,18 +1,17 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { StatusEffect } from "#app/data/status-effect"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { Mode } from "#app/ui/ui"; +import { toDmgValue } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { StatusEffect } from "#app/data/status-effect.js"; -import { BattleStat } from "#app/data/battle-stat.js"; +import GameManager from "#test/utils/gameManager"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { toDmgValue } from "#app/utils"; -import { Mode } from "#app/ui/ui.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; @@ -52,7 +51,7 @@ describe("Abilities - Disguise", () => { expect(mimikyu.formIndex).toBe(disguisedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK)); + game.move.select(Moves.SHADOW_SNEAK); await game.phaseInterceptor.to(MoveEndPhase); @@ -67,7 +66,7 @@ describe("Abilities - Disguise", () => { expect(mimikyu.formIndex).toBe(disguisedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.VACUUM_WAVE)); + game.move.select(Moves.VACUUM_WAVE); await game.phaseInterceptor.to(MoveEndPhase); @@ -85,7 +84,7 @@ describe("Abilities - Disguise", () => { expect(mimikyu.formIndex).toBe(disguisedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES)); + game.move.select(Moves.SURGING_STRIKES); // First hit await game.phaseInterceptor.to(MoveEffectPhase); @@ -104,7 +103,7 @@ describe("Abilities - Disguise", () => { const mimikyu = game.scene.getEnemyPokemon()!; expect(mimikyu.hp).toBe(mimikyu.getMaxHp()); - game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_THREAD)); + game.move.select(Moves.TOXIC_THREAD); await game.phaseInterceptor.to(TurnEndPhase); @@ -124,7 +123,7 @@ describe("Abilities - Disguise", () => { const maxHp = mimikyu.getMaxHp(); const disguiseDamage = toDmgValue(maxHp / 8); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -149,7 +148,7 @@ describe("Abilities - Disguise", () => { const mimikyu = game.scene.getParty()[1]!; expect(mimikyu.formIndex).toBe(bustedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.toNextWave(); @@ -169,7 +168,7 @@ describe("Abilities - Disguise", () => { expect(mimikyu.formIndex).toBe(bustedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.toNextWave(); @@ -189,11 +188,11 @@ describe("Abilities - Disguise", () => { expect(mimikyu1.formIndex).toBe(bustedForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.killPokemon(mimikyu1); game.doSelectPartyPokemon(1); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { // TODO: Make tests run in set mode instead of switch mode game.setMode(Mode.MESSAGE); diff --git a/src/test/abilities/dry_skin.test.ts b/src/test/abilities/dry_skin.test.ts index 1e3860da985..b337e4d96f7 100644 --- a/src/test/abilities/dry_skin.test.ts +++ b/src/test/abilities/dry_skin.test.ts @@ -1,12 +1,11 @@ -import { Species } from "#app/enums/species.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Species } from "#app/enums/species"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Dry Skin", () => { let phaserGame: Phaser.Game; @@ -43,13 +42,13 @@ describe("Abilities - Dry Skin", () => { // first turn let previousEnemyHp = enemy.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.SUNNY_DAY)); + game.move.select(Moves.SUNNY_DAY); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeLessThan(previousEnemyHp); // second turn previousEnemyHp = enemy.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeLessThan(previousEnemyHp); }); @@ -66,13 +65,13 @@ describe("Abilities - Dry Skin", () => { // first turn let previousEnemyHp = enemy.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.RAIN_DANCE)); + game.move.select(Moves.RAIN_DANCE); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeGreaterThan(previousEnemyHp); // second turn previousEnemyHp = enemy.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeGreaterThan(previousEnemyHp); }); @@ -87,7 +86,7 @@ describe("Abilities - Dry Skin", () => { enemy.hp = initialHP; // first turn - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); + game.move.select(Moves.FLAMETHROWER); await game.phaseInterceptor.to(TurnEndPhase); const fireDamageTakenWithDrySkin = initialHP - enemy.hp; @@ -96,7 +95,7 @@ describe("Abilities - Dry Skin", () => { game.override.enemyAbility(Abilities.NONE); // second turn - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); + game.move.select(Moves.FLAMETHROWER); await game.phaseInterceptor.to(TurnEndPhase); const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp; @@ -113,7 +112,7 @@ describe("Abilities - Dry Skin", () => { enemy.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); + game.move.select(Moves.WATER_GUN); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeGreaterThan(1); }); @@ -129,7 +128,7 @@ describe("Abilities - Dry Skin", () => { enemy.hp = 1; game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); + game.move.select(Moves.WATER_GUN); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBe(1); }); @@ -145,14 +144,14 @@ describe("Abilities - Dry Skin", () => { enemy.hp = 1; // first turn - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_SHURIKEN)); + game.move.select(Moves.WATER_SHURIKEN); await game.phaseInterceptor.to(TurnEndPhase); const healthGainedFromWaterShuriken = enemy.hp - 1; enemy.hp = 1; // second turn - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); + game.move.select(Moves.WATER_GUN); await game.phaseInterceptor.to(TurnEndPhase); const healthGainedFromWaterGun = enemy.hp - 1; diff --git a/src/test/abilities/flash_fire.test.ts b/src/test/abilities/flash_fire.test.ts index 28c59903b68..de40873998f 100644 --- a/src/test/abilities/flash_fire.test.ts +++ b/src/test/abilities/flash_fire.test.ts @@ -1,16 +1,15 @@ -import { Species } from "#app/enums/species.js"; -import GameManager from "#test/utils/gameManager"; +import { BattlerIndex } from "#app/battle"; +import { StatusEffect } from "#app/data/status-effect"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { Species } from "#app/enums/species"; +import { MovePhase } from "#app/phases/move-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { StatusEffect } from "#app/data/status-effect.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BattlerIndex } from "#app/battle.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Flash Fire", () => { let phaserGame: Phaser.Game; @@ -38,35 +37,35 @@ describe("Abilities - Flash Fire", () => { }); - it("immune to Fire-type moves", async() => { + it("immune to Fire-type moves", async () => { game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY); await game.startBattle([Species.BLISSEY]); const blissey = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(blissey.hp).toBe(blissey.getMaxHp()); }, 20000); - it("not activate if the Pokémon is protected from the Fire-type move", async() => { + it("not activate if the Pokémon is protected from the Fire-type move", async () => { game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.PROTECT]); await game.startBattle([Species.BLISSEY]); const blissey = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(TurnEndPhase); expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined(); }, 20000); - it("activated by Will-O-Wisp", async() => { + it("activated by Will-O-Wisp", async () => { game.override.enemyMoveset(Array(4).fill(Moves.WILL_O_WISP)).moveset(SPLASH_ONLY); await game.startBattle([Species.BLISSEY]); const blissey = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.move.forceHit(); await game.phaseInterceptor.to(MovePhase, false); await game.move.forceHit(); @@ -75,25 +74,25 @@ describe("Abilities - Flash Fire", () => { expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined(); }, 20000); - it("activated after being frozen", async() => { + it("activated after being frozen", async () => { game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY); game.override.statusEffect(StatusEffect.FREEZE); await game.startBattle([Species.BLISSEY]); const blissey = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(blissey!.getTag(BattlerTagType.FIRE_BOOST)).toBeDefined(); }, 20000); - it("not passing with baton pass", async() => { + it("not passing with baton pass", async () => { game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.BATON_PASS]); await game.startBattle([Species.BLISSEY, Species.CHANSEY]); // ensure use baton pass after enemy moved - game.doAttack(getMovePosition(game.scene, 0, Moves.BATON_PASS)); + game.move.select(Moves.BATON_PASS); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); game.doSelectPartyPokemon(1); @@ -104,7 +103,7 @@ describe("Abilities - Flash Fire", () => { expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined(); }, 20000); - it("boosts Fire-type move when the ability is activated", async() => { + it("boosts Fire-type move when the ability is activated", async () => { game.override.enemyMoveset(Array(4).fill(Moves.FIRE_PLEDGE)).moveset([Moves.EMBER, Moves.SPLASH]); game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE); await game.startBattle([Species.BLISSEY]); @@ -113,7 +112,7 @@ describe("Abilities - Flash Fire", () => { blissey.hp = initialHP; // first turn - game.doAttack(getMovePosition(game.scene, 0, Moves.EMBER)); + game.move.select(Moves.EMBER); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(TurnEndPhase); const originalDmg = initialHP - blissey.hp; @@ -122,7 +121,7 @@ describe("Abilities - Flash Fire", () => { blissey.hp = initialHP; // second turn - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); const flashFireDmg = initialHP - blissey.hp; diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts index d033604fe00..a451d290906 100644 --- a/src/test/abilities/gulp_missile.test.ts +++ b/src/test/abilities/gulp_missile.test.ts @@ -1,19 +1,18 @@ -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { BattleStat } from "#app/data/battle-stat"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { StatusEffect } from "#app/enums/status-effect"; +import Pokemon from "#app/field/pokemon"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import GameManager from "#app/test/utils/gameManager"; -import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { StatusEffect } from "#app/enums/status-effect.js"; -import Pokemon from "#app/field/pokemon.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Abilities - Gulp Missile", () => { let phaserGame: Phaser.Game; @@ -30,7 +29,7 @@ describe("Abilities - Gulp Missile", () => { * @returns The effect damage of Gulp Missile */ const getEffectDamage = (pokemon: Pokemon): number => { - return Math.max(1, Math.floor(pokemon.getMaxHp() * 1/4)); + return Math.max(1, Math.floor(pokemon.getMaxHp() * 1 / 4)); }; beforeAll(() => { @@ -58,9 +57,9 @@ describe("Abilities - Gulp Missile", () => { await game.startBattle([Species.CRAMORANT]); const cramorant = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); + game.move.select(Moves.DIVE); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); + game.move.select(Moves.DIVE); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getHpRatio()).toBeGreaterThanOrEqual(.5); @@ -75,7 +74,7 @@ describe("Abilities - Gulp Missile", () => { vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49); expect(cramorant.getHpRatio()).toBe(.49); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined(); @@ -86,7 +85,7 @@ describe("Abilities - Gulp Missile", () => { await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]); const cramorant = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.toNextTurn(); game.doSwitchPokemon(1); @@ -101,7 +100,7 @@ describe("Abilities - Gulp Missile", () => { await game.startBattle([Species.CRAMORANT]); const cramorant = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); + game.move.select(Moves.DIVE); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -115,7 +114,7 @@ describe("Abilities - Gulp Missile", () => { const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "damageAndUpdate"); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy)); @@ -128,7 +127,7 @@ describe("Abilities - Gulp Missile", () => { const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -150,7 +149,7 @@ describe("Abilities - Gulp Missile", () => { vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -174,7 +173,7 @@ describe("Abilities - Gulp Missile", () => { vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeDefined(); @@ -194,7 +193,7 @@ describe("Abilities - Gulp Missile", () => { const cramorant = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); + game.move.select(Moves.DIVE); await game.phaseInterceptor.to(BerryPhase, false); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -210,7 +209,7 @@ describe("Abilities - Gulp Missile", () => { vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); const enemyHpPreEffect = enemy.hp; @@ -232,7 +231,7 @@ describe("Abilities - Gulp Missile", () => { const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -252,7 +251,7 @@ describe("Abilities - Gulp Missile", () => { const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(MoveEndPhase); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); @@ -269,7 +268,7 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyAbility(Abilities.TRACE); await game.startBattle([Species.CRAMORANT]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnStartPhase); expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false); diff --git a/src/test/abilities/heatproof.test.ts b/src/test/abilities/heatproof.test.ts index ee6c0bb6ec9..e2a558e6d99 100644 --- a/src/test/abilities/heatproof.test.ts +++ b/src/test/abilities/heatproof.test.ts @@ -1,14 +1,13 @@ -import { Species } from "#app/enums/species.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Species } from "#app/enums/species"; +import { StatusEffect } from "#app/enums/status-effect"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { toDmgValue } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { StatusEffect } from "#app/enums/status-effect.js"; -import { toDmgValue } from "#app/utils"; describe("Abilities - Heatproof", () => { let phaserGame: Phaser.Game; @@ -46,14 +45,14 @@ describe("Abilities - Heatproof", () => { const initialHP = 1000; enemy.hp = initialHP; - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); + game.move.select(Moves.FLAMETHROWER); await game.phaseInterceptor.to(TurnEndPhase); const heatproofDamage = initialHP - enemy.hp; enemy.hp = initialHP; game.override.enemyAbility(Abilities.BALL_FETCH); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); + game.move.select(Moves.FLAMETHROWER); await game.phaseInterceptor.to(TurnEndPhase); const regularDamage = initialHP - enemy.hp; @@ -69,7 +68,7 @@ describe("Abilities - Heatproof", () => { const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); // Normal burn damage is /16 diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index 8f5547a5518..b7c3b723c4b 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -1,15 +1,14 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { Stat } from "#app/enums/stat.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { Stat } from "#app/enums/stat"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Hustle", () => { let phaserGame: Phaser.Game; @@ -44,7 +43,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getBattleStat"); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -57,7 +56,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getAccuracyMultiplier"); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); expect(pikachu.getAccuracyMultiplier).toHaveReturnedWith(0.8); @@ -71,7 +70,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getBattleStat"); vi.spyOn(pikachu, "getAccuracyMultiplier"); - game.doAttack(getMovePosition(game.scene, 0, Moves.GIGA_DRAIN)); + game.move.select(Moves.GIGA_DRAIN); await game.phaseInterceptor.to(DamagePhase); expect(pikachu.getBattleStat).toHaveReturnedWith(spatk); @@ -89,7 +88,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(allMoves[Moves.FISSURE], "calculateBattleAccuracy"); - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); await game.phaseInterceptor.to(DamagePhase); expect(enemyPokemon.turnData.damageTaken).toBe(enemyPokemon.getMaxHp()); diff --git a/src/test/abilities/hyper_cutter.test.ts b/src/test/abilities/hyper_cutter.test.ts index 9637a80ddb4..28fcc2f6085 100644 --- a/src/test/abilities/hyper_cutter.test.ts +++ b/src/test/abilities/hyper_cutter.test.ts @@ -3,7 +3,6 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -40,16 +39,16 @@ describe("Abilities - Hyper Cutter", () => { const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK)); + game.move.select(Moves.OCTOLOCK); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.DEFOG)); + game.move.select(Moves.DEFOG); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.NOBLE_ROAR)); + game.move.select(Moves.NOBLE_ROAR); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SAND_ATTACK)); + game.move.select(Moves.SAND_ATTACK); await game.toNextTurn(); game.override.moveset([Moves.STRING_SHOT]); - game.doAttack(getMovePosition(game.scene, 0, Moves.STRING_SHOT)); + game.move.select(Moves.STRING_SHOT); await game.toNextTurn(); expect(enemy.summonData.battleStats[BattleStat.ATK]).toEqual(0); diff --git a/src/test/abilities/ice_face.test.ts b/src/test/abilities/ice_face.test.ts index 905e0dfdaf7..fbc660c27c2 100644 --- a/src/test/abilities/ice_face.test.ts +++ b/src/test/abilities/ice_face.test.ts @@ -1,16 +1,15 @@ -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Abilities - Ice Face", () => { let phaserGame: Phaser.Game; @@ -39,7 +38,7 @@ describe("Abilities - Ice Face", () => { it("takes no damage from physical move and transforms to Noice", async () => { await game.startBattle([Species.HITMONLEE]); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEndPhase); @@ -55,7 +54,7 @@ describe("Abilities - Ice Face", () => { game.override.enemyLevel(1); await game.startBattle([Species.HITMONLEE]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES)); + game.move.select(Moves.SURGING_STRIKES); const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); @@ -81,7 +80,7 @@ describe("Abilities - Ice Face", () => { it("takes damage from special moves", async () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); + game.move.select(Moves.ICE_BEAM); await game.phaseInterceptor.to(MoveEndPhase); @@ -95,7 +94,7 @@ describe("Abilities - Ice Face", () => { it("takes effects from status moves", async () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_THREAD)); + game.move.select(Moves.TOXIC_THREAD); await game.phaseInterceptor.to(MoveEndPhase); @@ -111,7 +110,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.phaseInterceptor.to(MoveEndPhase); @@ -133,7 +132,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.EISCUE, Species.NINJASK]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SNOWSCAPE)); + game.move.select(Moves.SNOWSCAPE); await game.phaseInterceptor.to(TurnEndPhase); let eiscue = game.scene.getPlayerPokemon()!; @@ -160,7 +159,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.EISCUE]); - game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL)); + game.move.select(Moves.HAIL); const eiscue = game.scene.getPlayerPokemon()!; await game.phaseInterceptor.to(QuietFormChangePhase); @@ -179,7 +178,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.EISCUE, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); + game.move.select(Moves.ICE_BEAM); await game.phaseInterceptor.to(TurnEndPhase); let eiscue = game.scene.getPlayerPokemon()!; @@ -213,7 +212,7 @@ describe("Abilities - Ice Face", () => { expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); + game.move.select(Moves.ICE_BEAM); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); @@ -228,7 +227,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID)); + game.move.select(Moves.GASTRO_ACID); await game.phaseInterceptor.to(TurnEndPhase); @@ -244,7 +243,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SKILL_SWAP)); + game.move.select(Moves.SKILL_SWAP); await game.phaseInterceptor.to(TurnEndPhase); @@ -260,7 +259,7 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SIMPLE_BEAM)); + game.move.select(Moves.SIMPLE_BEAM); await game.phaseInterceptor.to(TurnInitPhase); diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts index 842b33108a3..93b663d06da 100644 --- a/src/test/abilities/intimidate.test.ts +++ b/src/test/abilities/intimidate.test.ts @@ -1,22 +1,21 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Mode } from "#app/ui/ui"; import { BattleStat } from "#app/data/battle-stat"; -import { generateStarter, getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; import { Status, StatusEffect } from "#app/data/status-effect"; import { GameModes, getGameMode } from "#app/game-mode"; +import { CommandPhase } from "#app/phases/command-phase"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { generateStarter } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Abilities - Intimidate", () => { let phaserGame: Phaser.Game; @@ -217,13 +216,7 @@ describe("Abilities - Intimidate", () => { let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase); await game.killPokemon(game.scene.currentBattle.enemyParty[0]); expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); @@ -243,13 +236,7 @@ describe("Abilities - Intimidate", () => { let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); console.log("===to new turn==="); await game.toNextTurn(); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; @@ -268,13 +255,7 @@ describe("Abilities - Intimidate", () => { let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); console.log("===to new turn==="); await game.toNextTurn(); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; @@ -282,13 +263,7 @@ describe("Abilities - Intimidate", () => { battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); console.log("===to new turn==="); await game.toNextTurn(); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; @@ -307,13 +282,7 @@ describe("Abilities - Intimidate", () => { let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); console.log("===to new turn==="); await game.toNextTurn(); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; @@ -321,13 +290,7 @@ describe("Abilities - Intimidate", () => { battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.AERIAL_ACE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.AERIAL_ACE); console.log("===to new turn==="); await game.toNextTurn(); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; diff --git a/src/test/abilities/intrepid_sword.test.ts b/src/test/abilities/intrepid_sword.test.ts index c1c05b59997..18d6c04adbc 100644 --- a/src/test/abilities/intrepid_sword.test.ts +++ b/src/test/abilities/intrepid_sword.test.ts @@ -1,10 +1,10 @@ import { BattleStat } from "#app/data/battle-stat"; -import GameManager from "#test/utils/gameManager"; +import { CommandPhase } from "#app/phases/command-phase"; import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; describe("Abilities - Intrepid Sword", () => { diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index d35cb8b6e2d..16597e90285 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -1,18 +1,17 @@ -import { allMoves } from "#app/data/move.js"; -import { Type } from "#app/data/type.js"; -import { Weather, WeatherType } from "#app/data/weather.js"; -import { PlayerPokemon } from "#app/field/pokemon.js"; +import { allMoves } from "#app/data/move"; +import { Type } from "#app/data/type"; +import { Weather, WeatherType } from "#app/data/weather"; +import { PlayerPokemon } from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -49,7 +48,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); @@ -67,12 +66,12 @@ describe("Abilities - Libero", () => { let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); - game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY)); + game.move.select(Moves.AGILITY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.LIBERO)).toHaveLength(1); @@ -89,7 +88,7 @@ describe("Abilities - Libero", () => { leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); @@ -108,7 +107,7 @@ describe("Abilities - Libero", () => { expect(leadPokemon).not.toBe(undefined); game.scene.arena.weather = new Weather(WeatherType.SUNNY); - game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL)); + game.move.select(Moves.WEATHER_BALL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); @@ -131,7 +130,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); @@ -154,7 +153,7 @@ describe("Abilities - Libero", () => { expect(leadPokemon).not.toBe(undefined); game.scene.arena.biomeType = Biome.MOUNTAIN; - game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER)); + game.move.select(Moves.NATURE_POWER); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH); @@ -172,7 +171,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.DIG)); + game.move.select(Moves.DIG); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG); @@ -191,7 +190,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); @@ -213,7 +212,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); @@ -232,7 +231,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); @@ -251,7 +250,7 @@ describe("Abilities - Libero", () => { expect(leadPokemon).not.toBe(undefined); leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); @@ -271,7 +270,7 @@ describe("Abilities - Libero", () => { vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); @@ -289,7 +288,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); + game.move.select(Moves.STRUGGLE); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); @@ -307,7 +306,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); + game.move.select(Moves.BURN_UP); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); @@ -326,7 +325,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT)); + game.move.select(Moves.TRICK_OR_TREAT); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT); @@ -344,7 +343,7 @@ describe("Abilities - Libero", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); + game.move.select(Moves.CURSE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE); diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index c7404f83a54..64c1746c7d9 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -1,17 +1,16 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { Moves } from "#enums/moves"; -import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Abilities } from "#enums/abilities"; -import { WeatherType } from "#app/data/weather.js"; import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; +import { WeatherType } from "#app/data/weather"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; const TIMEOUT = 20 * 1000; // 20 sec timeout @@ -58,7 +57,7 @@ describe("Abilities - Magic Guard", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -82,7 +81,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -99,14 +98,14 @@ describe("Abilities - Magic Guard", () => { it( "ability effect should not persist when the ability is replaced", async () => { - game.override.enemyMoveset([Moves.WORRY_SEED,Moves.WORRY_SEED,Moves.WORRY_SEED,Moves.WORRY_SEED]); + game.override.enemyMoveset([Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED]); game.override.statusEffect(StatusEffect.POISON); await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -126,7 +125,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -150,7 +149,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -180,7 +179,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -206,7 +205,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -233,7 +232,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); + game.move.select(Moves.CURSE); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -257,7 +256,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK)); + game.move.select(Moves.HIGH_JUMP_KICK); await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); @@ -276,7 +275,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.TAKE_DOWN)); + game.move.select(Moves.TAKE_DOWN); await game.phaseInterceptor.to(TurnEndPhase); @@ -294,7 +293,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); + game.move.select(Moves.STRUGGLE); await game.phaseInterceptor.to(TurnEndPhase); @@ -313,7 +312,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.STEEL_BEAM)); + game.move.select(Moves.STEEL_BEAM); await game.phaseInterceptor.to(TurnEndPhase); @@ -329,7 +328,7 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard does not prevent self-damage from confusion", async () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + game.move.select(Moves.CHARM); await game.phaseInterceptor.to(TurnEndPhase); }); @@ -341,7 +340,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); + game.move.select(Moves.BELLY_DRUM); await game.phaseInterceptor.to(TurnEndPhase); @@ -353,7 +352,7 @@ describe("Abilities - Magic Guard", () => { }, TIMEOUT ); - it("Magic Guard prevents damage from abilities with PostTurnHurtIfSleepingAbAttr", async() => { + it("Magic Guard prevents damage from abilities with PostTurnHurtIfSleepingAbAttr", async () => { //Tests the ability Bad Dreams game.override.statusEffect(StatusEffect.SLEEP); //enemy pokemon is given Spore just in case player pokemon somehow awakens during test @@ -364,7 +363,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -378,7 +377,7 @@ describe("Abilities - Magic Guard", () => { }, TIMEOUT ); - it("Magic Guard prevents damage from abilities with PostFaintContactDamageAbAttr", async() => { + it("Magic Guard prevents damage from abilities with PostFaintContactDamageAbAttr", async () => { //Tests the abilities Innards Out/Aftermath game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.AFTERMATH); @@ -390,7 +389,7 @@ describe("Abilities - Magic Guard", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; enemyPokemon.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); /** @@ -403,7 +402,7 @@ describe("Abilities - Magic Guard", () => { }, TIMEOUT ); - it("Magic Guard prevents damage from abilities with PostDefendContactDamageAbAttr", async() => { + it("Magic Guard prevents damage from abilities with PostDefendContactDamageAbAttr", async () => { //Tests the abilities Iron Barbs/Rough Skin game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.IRON_BARBS); @@ -414,7 +413,7 @@ describe("Abilities - Magic Guard", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); /** @@ -427,7 +426,7 @@ describe("Abilities - Magic Guard", () => { }, TIMEOUT ); - it("Magic Guard prevents damage from abilities with ReverseDrainAbAttr", async() => { + it("Magic Guard prevents damage from abilities with ReverseDrainAbAttr", async () => { //Tests the ability Liquid Ooze game.override.moveset([Moves.ABSORB]); game.override.enemyAbility(Abilities.LIQUID_OOZE); @@ -438,7 +437,7 @@ describe("Abilities - Magic Guard", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.ABSORB)); + game.move.select(Moves.ABSORB); await game.phaseInterceptor.to(TurnEndPhase); /** @@ -451,14 +450,14 @@ describe("Abilities - Magic Guard", () => { }, TIMEOUT ); - it("Magic Guard prevents HP loss from abilities with PostWeatherLapseDamageAbAttr", async() => { + it("Magic Guard prevents HP loss from abilities with PostWeatherLapseDamageAbAttr", async () => { //Tests the abilities Solar Power/Dry Skin game.override.passiveAbility(Abilities.SOLAR_POWER); game.override.weather(WeatherType.SUNNY); await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); /** diff --git a/src/test/abilities/moxie.test.ts b/src/test/abilities/moxie.test.ts index 6550dcab526..6a1838c9a98 100644 --- a/src/test/abilities/moxie.test.ts +++ b/src/test/abilities/moxie.test.ts @@ -1,17 +1,13 @@ import { BattleStat } from "#app/data/battle-stat"; import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { VictoryPhase } from "#app/phases/victory-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { VictoryPhase } from "#app/phases/victory-phase.js"; describe("Abilities - Moxie", () => { @@ -37,10 +33,10 @@ describe("Abilities - Moxie", () => { game.override.ability(Abilities.MOXIE); game.override.startingLevel(2000); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("MOXIE", async() => { + it("MOXIE", async () => { const moveToUse = Moves.AERIAL_ACE; await game.startBattle([ Species.MIGHTYENA, @@ -50,13 +46,7 @@ describe("Abilities - Moxie", () => { let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[Stat.ATK]).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(VictoryPhase); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(1); diff --git a/src/test/abilities/mycelium_might.test.ts b/src/test/abilities/mycelium_might.test.ts index 2fcdc28b279..83396f7950f 100644 --- a/src/test/abilities/mycelium_might.test.ts +++ b/src/test/abilities/mycelium_might.test.ts @@ -1,11 +1,10 @@ -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Abilities } from "#enums/abilities"; import { BattleStat } from "#app/data/battle-stat"; +import { MovePhase } from "#app/phases/move-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -42,14 +41,14 @@ describe("Abilities - Mycelium Might", () => { * https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24 **/ - it("If a Pokemon with Mycelium Might uses a status move, it will always move last but the status move will ignore protective abilities", async() => { - await game.startBattle([ Species.REGIELEKI ]); + it("will move last in its priority bracket and ignore protective abilities", async () => { + await game.startBattle([Species.REGIELEKI]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyPokemon = game.scene.getEnemyPokemon(); const enemyIndex = enemyPokemon?.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES)); + game.move.select(Moves.BABY_DOLL_EYES); await game.phaseInterceptor.to(MovePhase, false); // The opponent Pokemon (without Mycelium Might) goes first despite having lower speed than the player Pokemon. @@ -64,15 +63,15 @@ describe("Abilities - Mycelium Might", () => { expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); }, 20000); - it("Pokemon with Mycelium Might will go first if a status move that is in a higher priority bracket than the opponent's move is used", async() => { + it("will still go first if a status move that is in a higher priority bracket than the opponent's move is used", async () => { game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - await game.startBattle([ Species.REGIELEKI ]); + await game.startBattle([Species.REGIELEKI]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyPokemon = game.scene.getEnemyPokemon(); const enemyIndex = enemyPokemon?.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES)); + game.move.select(Moves.BABY_DOLL_EYES); await game.phaseInterceptor.to(MovePhase, false); // The player Pokemon (with M.M.) goes first because its move is still within a higher priority bracket than its opponent. @@ -86,13 +85,13 @@ describe("Abilities - Mycelium Might", () => { expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); }, 20000); - it("Order is established normally if the Pokemon uses a non-status move", async() => { - await game.startBattle([ Species.REGIELEKI ]); + it("will not affect non-status moves", async () => { + await game.startBattle([Species.REGIELEKI]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.phaseInterceptor.to(MovePhase, false); // The player Pokemon (with M.M.) goes first because it has a higher speed and did not use a status move. diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index d14d5871ef7..1404f597ccf 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -1,22 +1,21 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { StatusEffect } from "#app/data/status-effect.js"; -import { Type } from "#app/data/type.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { BattleStat } from "#app/data/battle-stat"; +import { StatusEffect } from "#app/data/status-effect"; +import { Type } from "#app/data/type"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { toDmgValue } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { toDmgValue } from "#app/utils"; const TIMEOUT = 20 * 1000; @@ -61,7 +60,7 @@ describe("Abilities - Parental Bond", () => { let enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -92,7 +91,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.POWER_UP_PUNCH)); + game.move.select(Moves.POWER_UP_PUNCH); await game.phaseInterceptor.to(BerryPhase, false); @@ -114,7 +113,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES)); + game.move.select(Moves.BABY_DOLL_EYES); await game.phaseInterceptor.to(BerryPhase, false); expect(enemyPokemon.summonData.battleStats[BattleStat.ATK]).toBe(-1); @@ -134,7 +133,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT)); + game.move.select(Moves.DOUBLE_HIT); await game.move.forceHit(); await game.phaseInterceptor.to(BerryPhase, false); @@ -156,7 +155,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SELF_DESTRUCT)); + game.move.select(Moves.SELF_DESTRUCT); await game.phaseInterceptor.to(DamagePhase, false); @@ -177,7 +176,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT)); + game.move.select(Moves.ROLLOUT); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase, false); @@ -201,7 +200,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(BerryPhase, false); expect(enemyPokemon.hp).toBe(enemyStartingHp - 80); @@ -212,7 +211,7 @@ describe("Abilities - Parental Bond", () => { "ability should not apply multiplier to counter moves", async () => { game.override.moveset([Moves.COUNTER]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle([Species.CHARIZARD]); @@ -225,14 +224,14 @@ describe("Abilities - Parental Bond", () => { const playerStartingHp = leadPokemon.hp; const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.COUNTER)); + game.move.select(Moves.COUNTER); await game.phaseInterceptor.to(DamagePhase); const playerDamage = playerStartingHp - leadPokemon.hp; await game.phaseInterceptor.to(BerryPhase, false); - expect(enemyPokemon.hp).toBe(enemyStartingHp - 4*playerDamage); + expect(enemyPokemon.hp).toBe(enemyStartingHp - 4 * playerDamage); }, TIMEOUT ); @@ -252,10 +251,10 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon.length).toBe(2); enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); - game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE, 1); await game.phaseInterceptor.to(BerryPhase, false); playerPokemon.forEach(p => expect(p.turnData.hitCount).toBe(1)); @@ -275,7 +274,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE); await game.phaseInterceptor.to(DamagePhase, false); expect(leadPokemon.turnData.hitCount).toBe(2); @@ -295,7 +294,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.MIND_BLOWN)); + game.move.select(Moves.MIND_BLOWN); await game.phaseInterceptor.to(DamagePhase, false); @@ -304,7 +303,7 @@ describe("Abilities - Parental Bond", () => { // This test will time out if the user faints await game.phaseInterceptor.to(BerryPhase, false); - expect(leadPokemon.hp).toBe(toDmgValue(leadPokemon.getMaxHp()/2)); + expect(leadPokemon.hp).toBe(toDmgValue(leadPokemon.getMaxHp() / 2)); }, TIMEOUT ); @@ -321,7 +320,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); + game.move.select(Moves.BURN_UP); await game.phaseInterceptor.to(DamagePhase); @@ -339,7 +338,7 @@ describe("Abilities - Parental Bond", () => { "Moves boosted by this ability and Multi-Lens should strike 4 times", async () => { game.override.moveset([Moves.TACKLE]); - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.CHARIZARD]); @@ -349,7 +348,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(DamagePhase); @@ -361,7 +360,7 @@ describe("Abilities - Parental Bond", () => { "Super Fang boosted by this ability and Multi-Lens should strike twice", async () => { game.override.moveset([Moves.SUPER_FANG]); - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.CHARIZARD]); @@ -373,7 +372,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG)); + game.move.select(Moves.SUPER_FANG); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -390,7 +389,7 @@ describe("Abilities - Parental Bond", () => { "Seismic Toss boosted by this ability and Multi-Lens should strike twice", async () => { game.override.moveset([Moves.SEISMIC_TOSS]); - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.CHARIZARD]); @@ -402,7 +401,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS)); + game.move.select(Moves.SEISMIC_TOSS); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -428,7 +427,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); + game.move.select(Moves.HYPER_BEAM); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -456,7 +455,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT)); + game.move.select(Moves.ANCHOR_SHOT); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -486,7 +485,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN)); + game.move.select(Moves.SMACK_DOWN); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -513,7 +512,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.move.select(Moves.U_TURN); await game.move.forceHit(); await game.phaseInterceptor.to(MoveEffectPhase); @@ -537,7 +536,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP)); + game.move.select(Moves.WAKE_UP_SLAP); await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -555,7 +554,7 @@ describe("Abilities - Parental Bond", () => { "ability should not cause user to hit into King's Shield more than once", async () => { game.override.moveset([Moves.TACKLE]); - game.override.enemyMoveset([Moves.KINGS_SHIELD,Moves.KINGS_SHIELD,Moves.KINGS_SHIELD,Moves.KINGS_SHIELD]); + game.override.enemyMoveset([Moves.KINGS_SHIELD, Moves.KINGS_SHIELD, Moves.KINGS_SHIELD, Moves.KINGS_SHIELD]); await game.startBattle([Species.CHARIZARD]); @@ -565,7 +564,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(BerryPhase, false); @@ -587,7 +586,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); + game.move.select(Moves.WATER_GUN); await game.phaseInterceptor.to(BerryPhase, false); @@ -600,7 +599,7 @@ describe("Abilities - Parental Bond", () => { async () => { game.override.battleType("double"); game.override.moveset([Moves.EARTHQUAKE, Moves.SPLASH]); - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.CHARIZARD, Species.PIDGEOT]); @@ -614,10 +613,10 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -626,7 +625,7 @@ describe("Abilities - Parental Bond", () => { await game.phaseInterceptor.to(BerryPhase, false); - enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(2*enemyFirstHitDamage[i])); + enemyPokemon.forEach((p, i) => expect(enemyStartingHp[i] - p.hp).toBe(2 * enemyFirstHitDamage[i])); }, TIMEOUT ); diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts index cb6be666d5f..ba90c7e3b3f 100644 --- a/src/test/abilities/pastel_veil.test.ts +++ b/src/test/abilities/pastel_veil.test.ts @@ -1,15 +1,14 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; +import { BattlerIndex } from "#app/battle"; +import { StatusEffect } from "#app/data/status-effect"; +import { Abilities } from "#app/enums/abilities"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { StatusEffect } from "#app/data/status-effect.js"; -import { allAbilities } from "#app/data/ability.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerIndex } from "#app/battle.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "../utils/testUtils"; describe("Abilities - Pastel Veil", () => { let phaserGame: Phaser.Game; @@ -27,50 +26,49 @@ describe("Abilities - Pastel Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); - game.override.moveset([Moves.SPLASH]); - game.override.enemyAbility(Abilities.BALL_FETCH); - game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyMoveset([Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD]); + game.override + .battleType("double") + .moveset([Moves.TOXIC_THREAD, Moves.SPLASH]) + .enemyAbility(Abilities.BALL_FETCH) + .enemySpecies(Species.SUNKERN) + .enemyMoveset(SPLASH_ONLY); }); it("prevents the user and its allies from being afflicted by poison", async () => { - await game.startBattle([Species.GALAR_PONYTA, Species.MAGIKARP]); - const ponyta = game.scene.getPlayerField()[0]; - - vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]); + await game.startBattle([Species.MAGIKARP, Species.GALAR_PONYTA]); + const ponyta = game.scene.getPlayerField()[1]; + const magikarp = game.scene.getPlayerField()[0]; + ponyta.abilityIndex = 1; expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.TOXIC_THREAD, 1, BattlerIndex.PLAYER); await game.phaseInterceptor.to(TurnEndPhase); - expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false); + expect(magikarp.status?.effect).toBeUndefined(); }); it("it heals the poisoned status condition of allies if user is sent out into battle", async () => { - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.GALAR_PONYTA]); - const ponyta = game.scene.getParty().find(p => p.species.speciesId === Species.GALAR_PONYTA)!; - - vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]); + await game.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.GALAR_PONYTA]); + const ponyta = game.scene.getParty()[2]; + const magikarp = game.scene.getPlayerField()[0]; + ponyta.abilityIndex = 1; expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.TOXIC_THREAD, 1, BattlerIndex.PLAYER); await game.phaseInterceptor.to(TurnEndPhase); - expect(game.scene.getPlayerField().some(p => p.status?.effect === StatusEffect.POISON)).toBe(true); - - const poisonedMon = game.scene.getPlayerField().find(p => p.status?.effect === StatusEffect.POISON); + expect(magikarp.status?.effect).toBe(StatusEffect.POISON); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, (poisonedMon!.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH)); + game.move.select(Moves.SPLASH); game.doSwitchPokemon(2); await game.phaseInterceptor.to(TurnEndPhase); - expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false); + expect(magikarp.status?.effect).toBeUndefined(); }); }); diff --git a/src/test/abilities/power_construct.test.ts b/src/test/abilities/power_construct.test.ts index e6a319d229f..ec37bc96c2f 100644 --- a/src/test/abilities/power_construct.test.ts +++ b/src/test/abilities/power_construct.test.ts @@ -1,11 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; @@ -53,7 +52,7 @@ describe("Abilities - POWER CONSTRUCT", () => { zygarde!.status = new Status(StatusEffect.FAINT); expect(zygarde!.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); diff --git a/src/test/abilities/power_spot.test.ts b/src/test/abilities/power_spot.test.ts index 467fc677ac0..b83284c0bac 100644 --- a/src/test/abilities/power_spot.test.ts +++ b/src/test/abilities/power_spot.test.ts @@ -1,14 +1,13 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Power Spot", () => { let phaserGame: Phaser.Game; @@ -42,8 +41,8 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DAZZLING_GLEAM)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.DAZZLING_GLEAM); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier); @@ -56,8 +55,8 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); - game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.BREAKING_SWIPE); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower * powerSpotMultiplier); @@ -70,8 +69,8 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); await game.startBattle([Species.STONJOURNER, Species.REGIELEKI]); - game.doAttack(getMovePosition(game.scene, 0, Moves.BREAKING_SWIPE)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.BREAKING_SWIPE); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(basePower); diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index ed63613945a..a7c6799132f 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -1,18 +1,17 @@ -import { allMoves } from "#app/data/move.js"; -import { Type } from "#app/data/type.js"; -import { Weather, WeatherType } from "#app/data/weather.js"; -import { PlayerPokemon } from "#app/field/pokemon.js"; +import { allMoves } from "#app/data/move"; +import { Type } from "#app/data/type"; +import { Weather, WeatherType } from "#app/data/weather"; +import { PlayerPokemon } from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -49,7 +48,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); @@ -67,12 +66,12 @@ describe("Abilities - Protean", () => { let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); - game.doAttack(getMovePosition(game.scene, 0, Moves.AGILITY)); + game.move.select(Moves.AGILITY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied.filter((a) => a === Abilities.PROTEAN)).toHaveLength(1); @@ -89,7 +88,7 @@ describe("Abilities - Protean", () => { leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.SPLASH); @@ -108,7 +107,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.scene.arena.weather = new Weather(WeatherType.SUNNY); - game.doAttack(getMovePosition(game.scene, 0, Moves.WEATHER_BALL)); + game.move.select(Moves.WEATHER_BALL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); @@ -131,7 +130,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); @@ -154,7 +153,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.scene.arena.biomeType = Biome.MOUNTAIN; - game.doAttack(getMovePosition(game.scene, 0, Moves.NATURE_POWER)); + game.move.select(Moves.NATURE_POWER); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.AIR_SLASH); @@ -172,7 +171,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.DIG)); + game.move.select(Moves.DIG); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.DIG); @@ -191,7 +190,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); @@ -213,7 +212,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); @@ -232,7 +231,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); @@ -251,7 +250,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); @@ -271,7 +270,7 @@ describe("Abilities - Protean", () => { vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); @@ -289,7 +288,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); + game.move.select(Moves.STRUGGLE); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); @@ -307,7 +306,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); + game.move.select(Moves.BURN_UP); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); @@ -326,7 +325,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT)); + game.move.select(Moves.TRICK_OR_TREAT); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TRICK_OR_TREAT); @@ -344,7 +343,7 @@ describe("Abilities - Protean", () => { const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); + game.move.select(Moves.CURSE); await game.phaseInterceptor.to(TurnEndPhase); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.CURSE); diff --git a/src/test/abilities/quick_draw.test.ts b/src/test/abilities/quick_draw.test.ts index 6e3416b0724..00d344ed333 100644 --- a/src/test/abilities/quick_draw.test.ts +++ b/src/test/abilities/quick_draw.test.ts @@ -1,12 +1,11 @@ import { allAbilities, BypassSpeedChanceAbAttr } from "#app/data/ability"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { FaintPhase } from "#app/phases/faint-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import { FaintPhase } from "#app/phases/faint-phase.js"; describe("Abilities - Quick Draw", () => { let phaserGame: Phaser.Game; @@ -47,7 +46,7 @@ describe("Abilities - Quick Draw", () => { pokemon.hp = 1; enemy.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(FaintPhase, false); expect(pokemon.isFainted()).toBe(false); @@ -67,7 +66,7 @@ describe("Abilities - Quick Draw", () => { pokemon.hp = 1; enemy.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.TAIL_WHIP)); + game.move.select(Moves.TAIL_WHIP); await game.phaseInterceptor.to(FaintPhase, false); expect(pokemon.isFainted()).toBe(true); @@ -87,7 +86,7 @@ describe("Abilities - Quick Draw", () => { pokemon.hp = 1; enemy.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(FaintPhase, false); expect(pokemon.isFainted()).toBe(true); diff --git a/src/test/abilities/sand_spit.test.ts b/src/test/abilities/sand_spit.test.ts index 59d311adb80..041e20faf7f 100644 --- a/src/test/abilities/sand_spit.test.ts +++ b/src/test/abilities/sand_spit.test.ts @@ -1,11 +1,10 @@ -import GameManager from "#test/utils/gameManager"; +import { WeatherType } from "#app/enums/weather-type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { WeatherType } from "#app/enums/weather-type.js"; describe("Abilities - Sand Spit", () => { @@ -35,21 +34,21 @@ describe("Abilities - Sand Spit", () => { game.override.moveset([Moves.SPLASH, Moves.COIL]); }); - it("should trigger when hit with damaging move", async() => { + it("should trigger when hit with damaging move", async () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SANDSTORM); }, 20000); - it("should not trigger when targetted with status moves", async() => { + it("should not trigger when targetted with status moves", async () => { game.override.enemyMoveset(Array(4).fill(Moves.GROWL)); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.COIL)); + game.move.select(Moves.COIL); await game.toNextTurn(); expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.SANDSTORM); diff --git a/src/test/abilities/sand_veil.test.ts b/src/test/abilities/sand_veil.test.ts index 3c5f97bd653..2336e2b50de 100644 --- a/src/test/abilities/sand_veil.test.ts +++ b/src/test/abilities/sand_veil.test.ts @@ -1,16 +1,15 @@ -import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability.js"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { WeatherType } from "#app/data/weather.js"; +import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability"; +import { BattleStat } from "#app/data/battle-stat"; +import { WeatherType } from "#app/data/weather"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -64,11 +63,11 @@ describe("Abilities - Sand Veil", () => { expect(leadPokemon[0].hasAbility(Abilities.SAND_VEIL)).toBe(true); expect(leadPokemon[1].hasAbility(Abilities.SAND_VEIL)).toBe(false); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase, false); diff --git a/src/test/abilities/sap_sipper.test.ts b/src/test/abilities/sap_sipper.test.ts index dfb4ab7e976..f9c20e85eab 100644 --- a/src/test/abilities/sap_sipper.test.ts +++ b/src/test/abilities/sap_sipper.test.ts @@ -1,15 +1,14 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { TerrainType } from "#app/data/terrain.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TerrainType } from "#app/data/terrain"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; // See also: TypeImmunityAbAttr describe("Abilities - Sap Sipper", () => { @@ -32,7 +31,7 @@ describe("Abilities - Sap Sipper", () => { game.override.disableCrits(); }); - it("raise attack 1 level and block effects when activated against a grass attack", async() => { + it("raise attack 1 level and block effects when activated against a grass attack", async () => { const moveToUse = Moves.LEAFAGE; const enemyAbility = Abilities.SAP_SIPPER; @@ -45,7 +44,7 @@ describe("Abilities - Sap Sipper", () => { const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -53,7 +52,7 @@ describe("Abilities - Sap Sipper", () => { expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); }); - it("raise attack 1 level and block effects when activated against a grass status move", async() => { + it("raise attack 1 level and block effects when activated against a grass status move", async () => { const moveToUse = Moves.SPORE; const enemyAbility = Abilities.SAP_SIPPER; @@ -64,7 +63,7 @@ describe("Abilities - Sap Sipper", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -72,7 +71,7 @@ describe("Abilities - Sap Sipper", () => { expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); }); - it("do not activate against status moves that target the field", async() => { + it("do not activate against status moves that target the field", async () => { const moveToUse = Moves.GRASSY_TERRAIN; const enemyAbility = Abilities.SAP_SIPPER; @@ -83,7 +82,7 @@ describe("Abilities - Sap Sipper", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -92,7 +91,7 @@ describe("Abilities - Sap Sipper", () => { expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0); }); - it("activate once against multi-hit grass attacks", async() => { + it("activate once against multi-hit grass attacks", async () => { const moveToUse = Moves.BULLET_SEED; const enemyAbility = Abilities.SAP_SIPPER; @@ -105,7 +104,7 @@ describe("Abilities - Sap Sipper", () => { const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -113,7 +112,7 @@ describe("Abilities - Sap Sipper", () => { expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(1); }); - it("do not activate against status moves that target the user", async() => { + it("do not activate against status moves that target the user", async () => { const moveToUse = Moves.SPIKY_SHIELD; const ability = Abilities.SAP_SIPPER; @@ -125,7 +124,7 @@ describe("Abilities - Sap Sipper", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(MoveEndPhase); @@ -139,7 +138,7 @@ describe("Abilities - Sap Sipper", () => { // TODO Add METRONOME outcome override // To run this testcase, manually modify the METRONOME move to always give SAP_SIPPER, then uncomment - it.todo("activate once against multi-hit grass attacks (metronome)", async() => { + it.todo("activate once against multi-hit grass attacks (metronome)", async () => { const moveToUse = Moves.METRONOME; const enemyAbility = Abilities.SAP_SIPPER; @@ -152,7 +151,7 @@ describe("Abilities - Sap Sipper", () => { const startingOppHp = game.scene.currentBattle.enemyParty[0].hp; - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/schooling.test.ts b/src/test/abilities/schooling.test.ts index 62a7e98bc76..ad9663bf8e5 100644 --- a/src/test/abilities/schooling.test.ts +++ b/src/test/abilities/schooling.test.ts @@ -1,11 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; @@ -53,7 +52,7 @@ describe("Abilities - SCHOOLING", () => { wishiwashi.status = new Status(StatusEffect.FAINT); expect(wishiwashi.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); diff --git a/src/test/abilities/screen_cleaner.test.ts b/src/test/abilities/screen_cleaner.test.ts index 403efcce1c0..3c0d12a06ea 100644 --- a/src/test/abilities/screen_cleaner.test.ts +++ b/src/test/abilities/screen_cleaner.test.ts @@ -1,13 +1,12 @@ -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import { PostSummonPhase } from "#app/phases/post-summon-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Abilities - Screen Cleaner", () => { let phaserGame: Phaser.Game; @@ -36,7 +35,7 @@ describe("Abilities - Screen Cleaner", () => { await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL)); + game.move.select(Moves.HAIL); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.AURORA_VEIL)).toBeDefined(); @@ -53,7 +52,7 @@ describe("Abilities - Screen Cleaner", () => { await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.LIGHT_SCREEN)).toBeDefined(); @@ -70,7 +69,7 @@ describe("Abilities - Screen Cleaner", () => { await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.REFLECT)).toBeDefined(); diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index b126bb5eb7a..7316b2ea920 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -1,18 +1,14 @@ +import { BattlerIndex } from "#app/battle"; import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import * as Utils from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { BattlerIndex } from "#app/battle.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Abilities - Serene Grace", () => { @@ -36,10 +32,10 @@ describe("Abilities - Serene Grace", () => { game.override.enemySpecies(Species.ONIX); game.override.startingLevel(100); game.override.moveset(movesToUse); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("Move chance without Serene Grace", async() => { + it("Move chance without Serene Grace", async () => { const moveToUse = Moves.AIR_SLASH; await game.startBattle([ Species.PIDGEOT @@ -49,13 +45,7 @@ describe("Abilities - Serene Grace", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -72,7 +62,7 @@ describe("Abilities - Serene Grace", () => { }, 20000); - it("Move chance with Serene Grace", async() => { + it("Move chance with Serene Grace", async () => { const moveToUse = Moves.AIR_SLASH; game.override.ability(Abilities.SERENE_GRACE); await game.startBattle([ @@ -82,13 +72,7 @@ describe("Abilities - Serene Grace", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 564e2040af4..f73b749dac2 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -1,18 +1,14 @@ +import { BattlerIndex } from "#app/battle"; import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import * as Utils from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { BattlerIndex } from "#app/battle.js"; describe("Abilities - Sheer Force", () => { @@ -36,10 +32,10 @@ describe("Abilities - Sheer Force", () => { game.override.enemySpecies(Species.ONIX); game.override.startingLevel(100); game.override.moveset(movesToUse); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("Sheer Force", async() => { + it("Sheer Force", async () => { const moveToUse = Moves.AIR_SLASH; game.override.ability(Abilities.SHEER_FORCE); await game.startBattle([ @@ -50,13 +46,7 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -73,12 +63,12 @@ describe("Abilities - Sheer Force", () => { applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, false, power); expect(chance.value).toBe(0); - expect(power.value).toBe(move.power * 5461/4096); + expect(power.value).toBe(move.power * 5461 / 4096); }, 20000); - it("Sheer Force with exceptions including binding moves", async() => { + it("Sheer Force with exceptions including binding moves", async () => { const moveToUse = Moves.BIND; game.override.ability(Abilities.SHEER_FORCE); await game.startBattle([ @@ -89,13 +79,7 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -117,7 +101,7 @@ describe("Abilities - Sheer Force", () => { }, 20000); - it("Sheer Force with moves with no secondary effect", async() => { + it("Sheer Force with moves with no secondary effect", async () => { const moveToUse = Moves.TACKLE; game.override.ability(Abilities.SHEER_FORCE); await game.startBattle([ @@ -128,13 +112,7 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -156,10 +134,10 @@ describe("Abilities - Sheer Force", () => { }, 20000); - it("Sheer Force Disabling Specific Abilities", async() => { + it("Sheer Force Disabling Specific Abilities", async () => { const moveToUse = Moves.CRUSH_CLAW; game.override.enemyAbility(Abilities.COLOR_CHANGE); - game.override.startingHeldItems([{name: "KINGS_ROCK", count: 1}]); + game.override.startingHeldItems([{ name: "KINGS_ROCK", count: 1 }]); game.override.ability(Abilities.SHEER_FORCE); await game.startBattle([ Species.PIDGEOT @@ -169,13 +147,7 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -196,7 +168,7 @@ describe("Abilities - Sheer Force", () => { applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move)); expect(chance.value).toBe(0); - expect(power.value).toBe(move.power * 5461/4096); + expect(power.value).toBe(move.power * 5461 / 4096); expect(target.getTypes().length).toBe(2); expect(target.getTypes()[0]).toBe(opponentType); diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index fe6c941752c..14770c49427 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -1,18 +1,14 @@ +import { BattlerIndex } from "#app/battle"; import { applyAbAttrs, applyPreDefendAbAttrs, IgnoreMoveEffectsAbAttr, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; import { Stat } from "#app/data/pokemon-stat"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import * as Utils from "#app/utils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { BattlerIndex } from "#app/battle.js"; describe("Abilities - Shield Dust", () => { @@ -37,10 +33,10 @@ describe("Abilities - Shield Dust", () => { game.override.enemyAbility(Abilities.SHIELD_DUST); game.override.startingLevel(100); game.override.moveset(movesToUse); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("Shield Dust", async() => { + it("Shield Dust", async () => { const moveToUse = Moves.AIR_SLASH; await game.startBattle([ Species.PIDGEOT @@ -50,13 +46,7 @@ describe("Abilities - Shield Dust", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); diff --git a/src/test/abilities/shields_down.test.ts b/src/test/abilities/shields_down.test.ts index e07c12ebb63..9bfec23ddf1 100644 --- a/src/test/abilities/shields_down.test.ts +++ b/src/test/abilities/shields_down.test.ts @@ -1,11 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; @@ -53,7 +52,7 @@ describe("Abilities - SHIELDS DOWN", () => { minior.status = new Status(StatusEffect.FAINT); expect(minior.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); diff --git a/src/test/abilities/stall.test.ts b/src/test/abilities/stall.test.ts index 5410d2e953e..d8dbe9d0e06 100644 --- a/src/test/abilities/stall.test.ts +++ b/src/test/abilities/stall.test.ts @@ -1,11 +1,10 @@ -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { MovePhase } from "#app/phases/move-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { MovePhase } from "#app/phases/move-phase.js"; describe("Abilities - Stall", () => { @@ -38,13 +37,13 @@ describe("Abilities - Stall", () => { * https://bulbapedia.bulbagarden.net/wiki/Priority **/ - it("Pokemon with Stall should move last in its priority bracket regardless of speed", async() => { - await game.startBattle([ Species.SHUCKLE ]); + it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => { + await game.startBattle([Species.SHUCKLE]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.phaseInterceptor.to(MovePhase, false); // The player Pokemon (without Stall) goes first despite having lower speed than the opponent. @@ -56,13 +55,13 @@ describe("Abilities - Stall", () => { expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); }, 20000); - it("Pokemon with Stall will go first if a move that is in a higher priority bracket than the opponent's move is used", async() => { - await game.startBattle([ Species.SHUCKLE ]); + it("Pokemon with Stall will go first if a move that is in a higher priority bracket than the opponent's move is used", async () => { + await game.startBattle([Species.SHUCKLE]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MovePhase, false); // The opponent Pokemon (with Stall) goes first because its move is still within a higher priority bracket than its opponent. @@ -74,14 +73,14 @@ describe("Abilities - Stall", () => { expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); }, 20000); - it("If both Pokemon have stall and use the same move, speed is used to determine who goes first.", async() => { + it("If both Pokemon have stall and use the same move, speed is used to determine who goes first.", async () => { game.override.ability(Abilities.STALL); - await game.startBattle([ Species.SHUCKLE ]); + await game.startBattle([Species.SHUCKLE]); const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MovePhase, false); // The opponent Pokemon (with Stall) goes first because it has a higher speed. diff --git a/src/test/abilities/steely_spirit.test.ts b/src/test/abilities/steely_spirit.test.ts index 3ca1a55ebee..c632d0be777 100644 --- a/src/test/abilities/steely_spirit.test.ts +++ b/src/test/abilities/steely_spirit.test.ts @@ -1,15 +1,13 @@ -import { allAbilities } from "#app/data/ability.js"; -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allAbilities } from "#app/data/ability"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; describe("Abilities - Steely Spirit", () => { let phaserGame: Phaser.Game; @@ -47,10 +45,8 @@ describe("Abilities - Steely Spirit", () => { expect(boostSource.hasAbility(Abilities.STEELY_SPIRIT)).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, moveToCheck)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(enemyToCheck.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(moveToCheck, 0, enemyToCheck.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(allMoves[moveToCheck].calculateBattlePower).toHaveReturnedWith(ironHeadPower * steelySpiritMultiplier); @@ -66,12 +62,8 @@ describe("Abilities - Steely Spirit", () => { expect(game.scene.getPlayerField().every(p => p.hasAbility(Abilities.STEELY_SPIRIT))).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, moveToCheck)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(enemyToCheck.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, moveToCheck)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(enemyToCheck.getBattlerIndex()); + game.move.select(moveToCheck, 0, enemyToCheck.getBattlerIndex()); + game.move.select(moveToCheck, 1, enemyToCheck.getBattlerIndex()); await game.phaseInterceptor.to(MoveEffectPhase); expect(allMoves[moveToCheck].calculateBattlePower).toHaveReturnedWith(ironHeadPower * Math.pow(steelySpiritMultiplier, 2)); @@ -90,10 +82,8 @@ describe("Abilities - Steely Spirit", () => { expect(boostSource.hasAbility(Abilities.STEELY_SPIRIT)).toBe(false); expect(boostSource.summonData.abilitySuppressed).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, moveToCheck)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(enemyToCheck.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(moveToCheck, 0, enemyToCheck.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); expect(allMoves[moveToCheck].calculateBattlePower).toHaveReturnedWith(ironHeadPower); diff --git a/src/test/abilities/sturdy.test.ts b/src/test/abilities/sturdy.test.ts index 602b2c04eb1..dc9f774cc5b 100644 --- a/src/test/abilities/sturdy.test.ts +++ b/src/test/abilities/sturdy.test.ts @@ -1,13 +1,12 @@ -import { EnemyPokemon } from "#app/field/pokemon.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { EnemyPokemon } from "#app/field/pokemon"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -42,7 +41,7 @@ describe("Abilities - Sturdy", () => { "Sturdy activates when user is at full HP", async () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CLOSE_COMBAT)); + game.move.select(Moves.CLOSE_COMBAT); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.getEnemyParty()[0].hp).toBe(1); }, @@ -57,7 +56,7 @@ describe("Abilities - Sturdy", () => { const enemyPokemon: EnemyPokemon = game.scene.getEnemyParty()[0]; enemyPokemon.hp = enemyPokemon.getMaxHp() - 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.CLOSE_COMBAT)); + game.move.select(Moves.CLOSE_COMBAT); await game.phaseInterceptor.to(DamagePhase); expect(enemyPokemon.hp).toBe(0); @@ -70,7 +69,7 @@ describe("Abilities - Sturdy", () => { "Sturdy pokemon should be immune to OHKO moves", async () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); await game.phaseInterceptor.to(MoveEndPhase); const enemyPokemon: EnemyPokemon = game.scene.getEnemyParty()[0]; @@ -85,7 +84,7 @@ describe("Abilities - Sturdy", () => { game.override.ability(Abilities.MOLD_BREAKER); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CLOSE_COMBAT)); + game.move.select(Moves.CLOSE_COMBAT); await game.phaseInterceptor.to(DamagePhase); const enemyPokemon: EnemyPokemon = game.scene.getEnemyParty()[0]; diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts index 8ab384ae59e..5de3c7285a9 100644 --- a/src/test/abilities/sweet_veil.test.ts +++ b/src/test/abilities/sweet_veil.test.ts @@ -1,16 +1,14 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; +import { BattlerIndex } from "#app/battle"; +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerIndex } from "#app/battle.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Abilities - Sweet Veil", () => { let phaserGame: Phaser.Game; @@ -29,7 +27,7 @@ describe("Abilities - Sweet Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override.battleType("double"); - game.override.moveset([Moves.SPLASH, Moves.REST]); + game.override.moveset([Moves.SPLASH, Moves.REST, Moves.YAWN]); game.override.enemySpecies(Species.MAGIKARP); game.override.enemyAbility(Abilities.BALL_FETCH); game.override.enemyMoveset([Moves.POWDER, Moves.POWDER, Moves.POWDER, Moves.POWDER]); @@ -38,8 +36,8 @@ describe("Abilities - Sweet Veil", () => { it("prevents the user and its allies from falling asleep", async () => { await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -50,8 +48,8 @@ describe("Abilities - Sweet Veil", () => { game.override.enemyMoveset(SPLASH_ONLY); await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.REST)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.REST, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -62,8 +60,8 @@ describe("Abilities - Sweet Veil", () => { game.override.enemyMoveset([Moves.YAWN, Moves.YAWN, Moves.YAWN, Moves.YAWN]); await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -74,28 +72,19 @@ describe("Abilities - Sweet Veil", () => { game.override.enemySpecies(Species.PIKACHU); game.override.enemyLevel(5); game.override.startingLevel(5); - game.override.enemyMoveset([Moves.YAWN, Moves.YAWN, Moves.YAWN, Moves.YAWN]); + game.override.enemyMoveset(SPLASH_ONLY); await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.YAWN, 1, BattlerIndex.PLAYER); - // First pokemon move - await game.move.forceHit(); - - // Second pokemon move - await game.phaseInterceptor.to(MovePhase, false); - await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true); - await game.phaseInterceptor.to(TurnEndPhase); - - const drowsyMon = game.scene.getPlayerField().find(p => !!p.getTag(BattlerTagType.DROWSY))!; - await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, (drowsyMon.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH)); + game.move.select(Moves.SPLASH); game.doSwitchPokemon(2); expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false); diff --git a/src/test/abilities/unseen_fist.test.ts b/src/test/abilities/unseen_fist.test.ts index 7d47d73bb16..ea1996ec66b 100644 --- a/src/test/abilities/unseen_fist.test.ts +++ b/src/test/abilities/unseen_fist.test.ts @@ -1,11 +1,10 @@ +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -80,7 +79,7 @@ async function testUnseenFistHitResult(game: GameManager, attackMove: Moves, pro const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, attackMove)); + game.move.select(attackMove); await game.phaseInterceptor.to(TurnEndPhase, false); if (shouldSucceed) { diff --git a/src/test/abilities/volt_absorb.test.ts b/src/test/abilities/volt_absorb.test.ts index 0e3d5c9792f..d9c3fe34c24 100644 --- a/src/test/abilities/volt_absorb.test.ts +++ b/src/test/abilities/volt_absorb.test.ts @@ -1,11 +1,10 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -42,7 +41,7 @@ describe("Abilities - Volt Absorb", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/wind_power.test.ts b/src/test/abilities/wind_power.test.ts index 24f01cceebc..c944e01b43a 100644 --- a/src/test/abilities/wind_power.test.ts +++ b/src/test/abilities/wind_power.test.ts @@ -1,13 +1,12 @@ -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Wind Power", () => { let phaserGame: Phaser.Game; @@ -38,7 +37,7 @@ describe("Abilities - Wind Power", () => { expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PETAL_BLIZZARD)); + game.move.select(Moves.PETAL_BLIZZARD); await game.phaseInterceptor.to(TurnEndPhase); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeDefined(); @@ -53,7 +52,7 @@ describe("Abilities - Wind Power", () => { expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeDefined(); @@ -70,7 +69,7 @@ describe("Abilities - Wind Power", () => { expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); @@ -86,7 +85,7 @@ describe("Abilities - Wind Power", () => { expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SANDSTORM)); + game.move.select(Moves.SANDSTORM); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/wind_rider.test.ts b/src/test/abilities/wind_rider.test.ts index 92c38507e4f..97e2e6456dc 100644 --- a/src/test/abilities/wind_rider.test.ts +++ b/src/test/abilities/wind_rider.test.ts @@ -1,13 +1,12 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Wind Rider", () => { let phaserGame: Phaser.Game; @@ -38,7 +37,7 @@ describe("Abilities - Wind Rider", () => { expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.PETAL_BLIZZARD)); + game.move.select(Moves.PETAL_BLIZZARD); await game.phaseInterceptor.to(TurnEndPhase); @@ -55,7 +54,7 @@ describe("Abilities - Wind Rider", () => { expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); @@ -73,7 +72,7 @@ describe("Abilities - Wind Rider", () => { expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); @@ -91,7 +90,7 @@ describe("Abilities - Wind Rider", () => { expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); @@ -108,7 +107,7 @@ describe("Abilities - Wind Rider", () => { expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(shiftry.isFullHp()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SANDSTORM)); + game.move.select(Moves.SANDSTORM); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/wonder_skin.test.ts b/src/test/abilities/wonder_skin.test.ts index d6e2b2443c4..0c2aedc8ce8 100644 --- a/src/test/abilities/wonder_skin.test.ts +++ b/src/test/abilities/wonder_skin.test.ts @@ -1,14 +1,13 @@ -import { allAbilities } from "#app/data/ability.js"; -import { allMoves } from "#app/data/move.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allAbilities } from "#app/data/ability"; +import { allMoves } from "#app/data/move"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Wonder Skin", () => { let phaserGame: Phaser.Game; @@ -40,7 +39,7 @@ describe("Abilities - Wonder Skin", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + game.move.select(Moves.CHARM); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(50); @@ -52,7 +51,7 @@ describe("Abilities - Wonder Skin", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(100); @@ -68,7 +67,7 @@ describe("Abilities - Wonder Skin", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + game.move.select(Moves.CHARM); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(100); diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 72fdc5442c5..677d998e876 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -1,26 +1,23 @@ +import { BattlerIndex } from "#app/battle"; import { Stat } from "#app/data/pokemon-stat"; -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { PostSummonPhase } from "#app/phases/post-summon-phase"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { SwitchPhase } from "#app/phases/switch-phase"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { BattlerIndex } from "#app/battle.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { SwitchPhase } from "#app/phases/switch-phase.js"; -import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; const TIMEOUT = 20 * 1000; @@ -59,13 +56,7 @@ describe("Abilities - ZEN MODE", () => { game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); @@ -88,13 +79,7 @@ describe("Abilities - ZEN MODE", () => { game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(QuietFormChangePhase); @@ -114,13 +99,7 @@ describe("Abilities - ZEN MODE", () => { game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); @@ -169,7 +148,7 @@ describe("Abilities - ZEN MODE", () => { darmanitan.status = new Status(StatusEffect.FAINT); expect(darmanitan.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); diff --git a/src/test/abilities/zero_to_hero.test.ts b/src/test/abilities/zero_to_hero.test.ts index ee6c07096a8..1a9697f974e 100644 --- a/src/test/abilities/zero_to_hero.test.ts +++ b/src/test/abilities/zero_to_hero.test.ts @@ -1,11 +1,10 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; @@ -52,7 +51,7 @@ describe("Abilities - ZERO TO HERO", () => { palafin2.status = new Status(StatusEffect.FAINT); expect(palafin2.isFainted()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to(TurnEndPhase); game.doSelectModifier(); @@ -80,7 +79,7 @@ describe("Abilities - ZERO TO HERO", () => { const palafin = game.scene.getPlayerPokemon()!; expect(palafin.formIndex).toBe(baseForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.killPokemon(palafin); game.doSelectPartyPokemon(1); await game.toNextTurn(); @@ -97,7 +96,7 @@ describe("Abilities - ZERO TO HERO", () => { const palafin = game.scene.getPlayerPokemon()!; expect(palafin.formIndex).toBe(heroForm); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.killPokemon(palafin); game.doSelectPartyPokemon(1); await game.toNextTurn(); diff --git a/src/test/account.spec.ts b/src/test/account.spec.ts index d5d0458c7e8..eb6002f3cf2 100644 --- a/src/test/account.spec.ts +++ b/src/test/account.spec.ts @@ -1,4 +1,4 @@ -import * as battleScene from "#app/battle-scene.js"; +import * as battleScene from "#app/battle-scene"; import { describe, expect, it, vi } from "vitest"; import { initLoggedInUser, loggedInUser, updateUserInfo } from "../account"; import * as utils from "../utils"; diff --git a/src/test/achievements/achievement.test.ts b/src/test/achievements/achievement.test.ts index 5cd9c4d4094..36c20ae2248 100644 --- a/src/test/achievements/achievement.test.ts +++ b/src/test/achievements/achievement.test.ts @@ -1,7 +1,7 @@ -import { TurnHeldItemTransferModifier } from "#app/modifier/modifier.js"; +import { TurnHeldItemTransferModifier } from "#app/modifier/modifier"; import { Achv, AchvTier, DamageAchv, HealAchv, LevelAchv, ModifierAchv, MoneyAchv, RibbonAchv, achvs } from "#app/system/achv"; +import { IntegerHolder, NumberHolder } from "#app/utils"; import GameManager from "#test/utils/gameManager"; -import { IntegerHolder, NumberHolder } from "#app/utils.js"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import BattleScene from "../../battle-scene"; diff --git a/src/test/arena/arena_gravity.test.ts b/src/test/arena/arena_gravity.test.ts index 8fad4dde83d..eda8c687ba1 100644 --- a/src/test/arena/arena_gravity.test.ts +++ b/src/test/arena/arena_gravity.test.ts @@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; @@ -45,14 +44,14 @@ describe("Arena - Gravity", () => { // Setup Gravity on first turn await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + game.move.select(Moves.GRAVITY); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); // Use non-OHKO move on second turn await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(100 * 1.67); @@ -69,14 +68,14 @@ describe("Arena - Gravity", () => { // Setup Gravity on first turn await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + game.move.select(Moves.GRAVITY); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); // Use OHKO move on second turn await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(30); @@ -96,21 +95,21 @@ describe("Arena - Gravity", () => { vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); // Try earthquake on 1st turn (fails!); - game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE); await game.phaseInterceptor.to(TurnEndPhase); expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(0); // Setup Gravity on 2nd turn await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + game.move.select(Moves.GRAVITY); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); // Use ground move on 3rd turn await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); + game.move.select(Moves.EARTHQUAKE); await game.phaseInterceptor.to(TurnEndPhase); expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(1); @@ -129,14 +128,14 @@ describe("Arena - Gravity", () => { vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); // Setup Gravity on 1st turn - game.doAttack(getMovePosition(game.scene, 0, Moves.GRAVITY)); + game.move.select(Moves.GRAVITY); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined(); // Use electric move on 2nd turn await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); + game.move.select(Moves.THUNDERBOLT); await game.phaseInterceptor.to(TurnEndPhase); expect(pidgeot.getAttackTypeEffectiveness).toHaveReturnedWith(2); diff --git a/src/test/arena/weather_fog.test.ts b/src/test/arena/weather_fog.test.ts index 350007ae943..b36b0de2e06 100644 --- a/src/test/arena/weather_fog.test.ts +++ b/src/test/arena/weather_fog.test.ts @@ -1,11 +1,10 @@ -import { allMoves } from "#app/data/move.js"; -import { WeatherType } from "#app/data/weather.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { WeatherType } from "#app/data/weather"; +import { Abilities } from "#app/enums/abilities"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -41,7 +40,7 @@ describe("Weather - Fog", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattleAccuracy).toHaveReturnedWith(100 * 0.9); diff --git a/src/test/arena/weather_strong_winds.test.ts b/src/test/arena/weather_strong_winds.test.ts index 79fba30c019..8b2d3e2547e 100644 --- a/src/test/arena/weather_strong_winds.test.ts +++ b/src/test/arena/weather_strong_winds.test.ts @@ -1,12 +1,11 @@ -import { allMoves } from "#app/data/move.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Weather - Strong Winds", () => { let phaserGame: Phaser.Game; @@ -38,7 +37,7 @@ describe("Weather - Strong Winds", () => { const pikachu = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); + game.move.select(Moves.THUNDERBOLT); await game.phaseInterceptor.to(TurnStartPhase); expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(0.5); @@ -49,7 +48,7 @@ describe("Weather - Strong Winds", () => { const pikachu = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); + game.move.select(Moves.THUNDERBOLT); await game.phaseInterceptor.to(TurnStartPhase); expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.THUNDERBOLT].type, pikachu)).toBe(1); @@ -60,7 +59,7 @@ describe("Weather - Strong Winds", () => { const pikachu = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); + game.move.select(Moves.ICE_BEAM); await game.phaseInterceptor.to(TurnStartPhase); expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ICE_BEAM].type, pikachu)).toBe(1); @@ -71,7 +70,7 @@ describe("Weather - Strong Winds", () => { const pikachu = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.ROCK_SLIDE)); + game.move.select(Moves.ROCK_SLIDE); await game.phaseInterceptor.to(TurnStartPhase); expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1); diff --git a/src/test/battle-scene.test.ts b/src/test/battle-scene.test.ts index 21d3f689d1c..9e28ec99791 100644 --- a/src/test/battle-scene.test.ts +++ b/src/test/battle-scene.test.ts @@ -1,4 +1,4 @@ -import { LoadingScene } from "#app/loading-scene.js"; +import { LoadingScene } from "#app/loading-scene"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; diff --git a/src/test/battle-stat.spec.ts b/src/test/battle-stat.spec.ts index 775dd40ff34..16fce962838 100644 --- a/src/test/battle-stat.spec.ts +++ b/src/test/battle-stat.spec.ts @@ -1,4 +1,4 @@ -import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "#app/data/battle-stat.js"; +import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "#app/data/battle-stat"; import { describe, expect, it } from "vitest"; import { arrayOfRange, mockI18next } from "./utils/testUtils"; diff --git a/src/test/battle/battle-order.test.ts b/src/test/battle/battle-order.test.ts index 208b921b843..0129ecad254 100644 --- a/src/test/battle/battle-order.test.ts +++ b/src/test/battle/battle-order.test.ts @@ -1,19 +1,13 @@ import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import TargetSelectUiHandler from "#app/ui/target-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { SelectTargetPhase } from "#app/phases/select-target-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Abilities } from "#enums/abilities"; -import { Button } from "#enums/buttons"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Battle order", () => { @@ -39,20 +33,14 @@ describe("Battle order", () => { game.override.moveset([Moves.TACKLE]); }); - it("opponent faster than player 50 vs 150", async() => { + it("opponent faster than player 50 vs 150", async () => { await game.startBattle([ Species.BULBASAUR, ]); game.scene.getParty()[0].stats[Stat.SPD] = 50; game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 150; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.run(EnemyCommandPhase); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); @@ -60,20 +48,14 @@ describe("Battle order", () => { expect(order[1]).toBe(0); }, 20000); - it("Player faster than opponent 150 vs 50", async() => { + it("Player faster than opponent 150 vs 50", async () => { await game.startBattle([ Species.BULBASAUR, ]); game.scene.getParty()[0].stats[Stat.SPD] = 150; game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 50; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.run(EnemyCommandPhase); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); @@ -81,7 +63,7 @@ describe("Battle order", () => { expect(order[1]).toBe(2); }, 20000); - it("double - both opponents faster than player 50/50 vs 150/150", async() => { + it("double - both opponents faster than player 50/50 vs 150/150", async () => { game.override.battleType("double"); await game.startBattle([ Species.BULBASAUR, @@ -92,28 +74,8 @@ describe("Battle order", () => { game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 150; game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); + game.move.select(Moves.TACKLE); + game.move.select(Moves.TACKLE, 1); await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); @@ -123,7 +85,7 @@ describe("Battle order", () => { expect(order.indexOf(1)).toBeGreaterThan(order.indexOf(3)); }, 20000); - it("double - speed tie except 1 - 100/100 vs 100/150", async() => { + it("double - speed tie except 1 - 100/100 vs 100/150", async () => { game.override.battleType("double"); await game.startBattle([ Species.BULBASAUR, @@ -134,28 +96,8 @@ describe("Battle order", () => { game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 100; game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); + game.move.select(Moves.TACKLE); + game.move.select(Moves.TACKLE, 1); await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); @@ -164,7 +106,7 @@ describe("Battle order", () => { expect(order.indexOf(3)).toBeLessThan(order.indexOf(2)); }, 20000); - it("double - speed tie 100/150 vs 100/150", async() => { + it("double - speed tie 100/150 vs 100/150", async () => { game.override.battleType("double"); await game.startBattle([ Species.BULBASAUR, @@ -175,28 +117,8 @@ describe("Battle order", () => { game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 100; game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - game.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = game.scene.ui.getHandler() as TargetSelectUiHandler; - handler.processInput(Button.ACTION); - }); + game.move.select(Moves.TACKLE); + game.move.select(Moves.TACKLE, 1); await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false); const phase = game.scene.getCurrentPhase() as TurnStartPhase; const order = phase.getOrder(); diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index 43d8ddce4b0..c79eee63a7c 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -1,10 +1,23 @@ import { allSpecies } from "#app/data/pokemon-species"; -import { TempBattleStat } from "#app/data/temp-battle-stat.js"; -import { GameModes } from "#app/game-mode"; -import { getGameMode } from "#app/game-mode.js"; +import { TempBattleStat } from "#app/data/temp-battle-stat"; +import { GameModes, getGameMode } from "#app/game-mode"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { LoginPhase } from "#app/phases/login-phase"; +import { NextEncounterPhase } from "#app/phases/next-encounter-phase"; +import { SelectGenderPhase } from "#app/phases/select-gender-phase"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { SummonPhase } from "#app/phases/summon-phase"; +import { SwitchPhase } from "#app/phases/switch-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { VictoryPhase } from "#app/phases/victory-phase"; import GameManager from "#app/test/utils/gameManager"; -import { generateStarter, getMovePosition, } from "#app/test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; +import { generateStarter } from "#app/test/utils/gameManagerUtils"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -13,21 +26,6 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { LoginPhase } from "#app/phases/login-phase.js"; -import { NextEncounterPhase } from "#app/phases/next-encounter-phase.js"; -import { SelectGenderPhase } from "#app/phases/select-gender-phase.js"; -import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { SummonPhase } from "#app/phases/summon-phase.js"; -import { SwitchPhase } from "#app/phases/switch-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; -import { VictoryPhase } from "#app/phases/victory-phase.js"; describe("Test Battle Phase", () => { let phaserGame: Phaser.Game; @@ -47,7 +45,7 @@ describe("Test Battle Phase", () => { game = new GameManager(phaserGame); }); - it("test phase interceptor with prompt", async() => { + it("test phase interceptor with prompt", async () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { @@ -65,7 +63,7 @@ describe("Test Battle Phase", () => { expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); }, 20000); - it("test phase interceptor with prompt with preparation for a future prompt", async() => { + it("test phase interceptor with prompt with preparation for a future prompt", async () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { @@ -87,13 +85,13 @@ describe("Test Battle Phase", () => { expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); }, 20000); - it("newGame one-liner", async() => { + it("newGame one-liner", async () => { await game.startBattle(); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); - it("do attack wave 3 - single battle - regular - OHKO", async() => { + it("do attack wave 3 - single battle - regular - OHKO", async () => { game.override.starterSpecies(Species.MEWTWO); game.override.enemySpecies(Species.RATTATA); game.override.startingLevel(2000); @@ -104,17 +102,11 @@ describe("Test Battle Phase", () => { game.override.enemyAbility(Abilities.HYDRATION); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle(); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase, false); }, 20000); - it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async() => { + it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async () => { game.override.starterSpecies(Species.MEWTWO); game.override.enemySpecies(Species.RATTATA); game.override.startingLevel(5); @@ -124,17 +116,11 @@ describe("Test Battle Phase", () => { game.override.enemyMoveset([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]); game.override.battleType("single"); await game.startBattle(); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase, false); }, 20000); - it("load 100% data file", async() => { + it("load 100% data file", async () => { await game.importData("src/test/utils/saves/everything.prsv"); const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => { const species = game.scene.gameData.dexData[key]; @@ -143,7 +129,7 @@ describe("Test Battle Phase", () => { expect(caughtCount).toBe(Object.keys(allSpecies).length); }, 20000); - it("start battle with selected team", async() => { + it("start battle with selected team", async () => { await game.startBattle([ Species.CHARIZARD, Species.CHANSEY, @@ -154,26 +140,26 @@ describe("Test Battle Phase", () => { expect(game.scene.getParty()[2].species.speciesId).toBe(Species.MEW); }, 20000); - it("test remove random battle seed int", async() => { - for (let i=0; i<10; i++) { + it("test remove random battle seed int", async () => { + for (let i = 0; i < 10; i++) { const rand = game.scene.randBattleSeedInt(16); expect(rand).toBe(15); } }); - it("wrong phase", async() => { + it("wrong phase", async () => { await game.phaseInterceptor.run(LoginPhase); await game.phaseInterceptor.run(LoginPhase).catch((e) => { expect(e).toBe("Wrong phase: this is SelectGenderPhase and not LoginPhase"); }); }, 20000); - it("wrong phase but skip", async() => { + it("wrong phase but skip", async () => { await game.phaseInterceptor.run(LoginPhase); await game.phaseInterceptor.run(LoginPhase, () => game.isCurrentPhase(SelectGenderPhase)); }, 20000); - it("good run", async() => { + it("good run", async () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; @@ -183,7 +169,7 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.run(TitlePhase); }, 20000); - it("good run from select gender to title", async() => { + it("good run from select gender to title", async () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; @@ -192,7 +178,7 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.runFrom(SelectGenderPhase).to(TitlePhase); }, 20000); - it("good run to SummonPhase phase", async() => { + it("good run to SummonPhase phase", async () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; @@ -208,7 +194,7 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.runFrom(SelectGenderPhase).to(SummonPhase); }, 20000); - it("2vs1", async() => { + it("2vs1", async () => { game.override.battleType("single"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); @@ -221,7 +207,7 @@ describe("Test Battle Phase", () => { expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); - it("1vs1", async() => { + it("1vs1", async () => { game.override.battleType("single"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); @@ -233,7 +219,7 @@ describe("Test Battle Phase", () => { expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); - it("2vs2", async() => { + it("2vs2", async () => { game.override.battleType("double"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); @@ -247,7 +233,7 @@ describe("Test Battle Phase", () => { expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); - it("4vs2", async() => { + it("4vs2", async () => { game.override.battleType("double"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); @@ -263,7 +249,7 @@ describe("Test Battle Phase", () => { expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); - it("kill opponent pokemon", async() => { + it("kill opponent pokemon", async () => { const moveToUse = Moves.SPLASH; game.override.battleType("single"); game.override.starterSpecies(Species.MEWTWO); @@ -273,26 +259,20 @@ describe("Test Battle Phase", () => { game.override.startingLevel(2000); game.override.startingWave(3); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle([ Species.DARMANITAN, Species.CHARIZARD, ]); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.to(DamagePhase, false); await game.killPokemon(game.scene.currentBattle.enemyParty[0]); expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); await game.phaseInterceptor.to(VictoryPhase, false); }, 200000); - it("to next turn", async() => { + it("to next turn", async () => { const moveToUse = Moves.SPLASH; game.override.battleType("single"); game.override.starterSpecies(Species.MEWTWO); @@ -302,15 +282,15 @@ describe("Test Battle Phase", () => { game.override.startingLevel(2000); game.override.startingWave(3); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle(); const turn = game.scene.currentBattle.turn; - game.doAttack(0); + game.move.select(moveToUse); await game.toNextTurn(); expect(game.scene.currentBattle.turn).toBeGreaterThan(turn); }, 20000); - it("to next wave with pokemon killed, single", async() => { + it("to next wave with pokemon killed, single", async () => { const moveToUse = Moves.SPLASH; game.override.battleType("single"); game.override.starterSpecies(Species.MEWTWO); @@ -320,10 +300,10 @@ describe("Test Battle Phase", () => { game.override.startingLevel(2000); game.override.startingWave(3); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle(); const waveIndex = game.scene.currentBattle.waveIndex; - game.doAttack(0); + game.move.select(moveToUse); await game.doKillOpponents(); await game.toNextWave(); expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex); @@ -343,7 +323,7 @@ describe("Test Battle Phase", () => { await game.startBattle(); game.scene.getPlayerPokemon()!.hp = 1; - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(BattleEndPhase); game.doRevivePokemon(0); // pretend max revive was picked diff --git a/src/test/battle/damage_calculation.test.ts b/src/test/battle/damage_calculation.test.ts index 9b13a266d33..665000450be 100644 --- a/src/test/battle/damage_calculation.test.ts +++ b/src/test/battle/damage_calculation.test.ts @@ -1,14 +1,13 @@ import { DamagePhase } from "#app/phases/damage-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { toDmgValue } from "#app/utils"; import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { ArenaTagType } from "#enums/arena-tag-type"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { toDmgValue } from "#app/utils"; describe("Round Down and Minimun 1 test in Damage Calculation", () => { let phaserGame: Phaser.Game; @@ -41,7 +40,7 @@ describe("Round Down and Minimun 1 test in Damage Calculation", () => { const shedinja = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.JUMP_KICK)); + game.move.select(Moves.JUMP_KICK); await game.phaseInterceptor.to(DamagePhase); diff --git a/src/test/battle/double_battle.test.ts b/src/test/battle/double_battle.test.ts index d2ee3812b3e..d264a29ef9b 100644 --- a/src/test/battle/double_battle.test.ts +++ b/src/test/battle/double_battle.test.ts @@ -1,13 +1,12 @@ -import GameManager from "#test/utils/gameManager"; -import { getMovePosition, } from "#test/utils/gameManagerUtils"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Double Battles", () => { let phaserGame: Phaser.Game; @@ -29,7 +28,7 @@ describe("Double Battles", () => { // double-battle player's pokemon both fainted in same round, then revive one, and next double battle summons two player's pokemon successfully. // (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc) - it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async() => { + it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => { game.override.battleType("double").enemyMoveset(SPLASH_ONLY).moveset(SPLASH_ONLY); await game.startBattle([ Species.BULBASAUR, @@ -37,8 +36,8 @@ describe("Double Battles", () => { Species.SQUIRTLE, ]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); for (const pokemon of game.scene.getPlayerField()) { pokemon.hp = 0; diff --git a/src/test/battle/error-handling.test.ts b/src/test/battle/error-handling.test.ts index a88d7cd8c18..da5cc4d1969 100644 --- a/src/test/battle/error-handling.test.ts +++ b/src/test/battle/error-handling.test.ts @@ -1,13 +1,14 @@ -import GameManager from "#test/utils/gameManager"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Error Handling", () => { let phaserGame: Phaser.Game; let game: GameManager; + const moveToUse = Moves.SPLASH; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -21,7 +22,6 @@ describe("Error Handling", () => { beforeEach(() => { game = new GameManager(phaserGame); - const moveToUse = Moves.SPLASH; game.override .battleType("single") .startingWave(3); @@ -31,13 +31,13 @@ describe("Error Handling", () => { game.override.ability(Abilities.ZEN_MODE); game.override.startingLevel(2000); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it.skip("to next turn", async() => { + it.skip("to next turn", async () => { await game.startBattle(); const turn = game.scene.currentBattle.turn; - game.doAttack(0); + game.move.select(moveToUse); await game.toNextTurn(); expect(game.scene.currentBattle.turn).toBeGreaterThan(turn); }, 20000); diff --git a/src/test/battle/special_battle.test.ts b/src/test/battle/special_battle.test.ts index 9b0fd1b3ab1..1d319bea372 100644 --- a/src/test/battle/special_battle.test.ts +++ b/src/test/battle/special_battle.test.ts @@ -1,9 +1,9 @@ -import { CommandPhase } from "#app/phases/command-phase.js"; -import GameManager from "#test/utils/gameManager"; +import { CommandPhase } from "#app/phases/command-phase"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/battlerTags/octolock.test.ts b/src/test/battlerTags/octolock.test.ts index a69b45cdfd2..fa491589f09 100644 --- a/src/test/battlerTags/octolock.test.ts +++ b/src/test/battlerTags/octolock.test.ts @@ -1,10 +1,10 @@ +import BattleScene from "#app/battle-scene"; +import { BattleStat } from "#app/data/battle-stat"; +import { BattlerTag, BattlerTagLapseType, OctolockTag, TrappedTag } from "#app/data/battler-tags"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import Pokemon from "#app/field/pokemon"; +import { StatChangePhase } from "#app/phases/stat-change-phase"; import { describe, expect, it, vi } from "vitest"; -import Pokemon from "#app/field/pokemon.js"; -import BattleScene from "#app/battle-scene.js"; -import { BattlerTag, BattlerTagLapseType, OctolockTag, TrappedTag } from "#app/data/battler-tags.js"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { StatChangePhase } from "#app/phases/stat-change-phase.js"; vi.mock("#app/battle-scene.js"); diff --git a/src/test/battlerTags/stockpiling.test.ts b/src/test/battlerTags/stockpiling.test.ts index 1a39d11e1bd..fef1e938c09 100644 --- a/src/test/battlerTags/stockpiling.test.ts +++ b/src/test/battlerTags/stockpiling.test.ts @@ -1,10 +1,10 @@ +import BattleScene from "#app/battle-scene"; +import { BattleStat } from "#app/data/battle-stat"; +import { StockpilingTag } from "#app/data/battler-tags"; +import Pokemon, { PokemonSummonData } from "#app/field/pokemon"; +import * as messages from "#app/messages"; +import { StatChangePhase } from "#app/phases/stat-change-phase"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import Pokemon, { PokemonSummonData } from "#app/field/pokemon.js"; -import BattleScene from "#app/battle-scene.js"; -import { StockpilingTag } from "#app/data/battler-tags.js"; -import { BattleStat } from "#app/data/battle-stat.js"; -import * as messages from "#app/messages.js"; -import { StatChangePhase } from "#app/phases/stat-change-phase.js"; beforeEach(() => { vi.spyOn(messages, "getPokemonNameWithAffix").mockImplementation(() => ""); diff --git a/src/test/eggs/egg.test.ts b/src/test/eggs/egg.test.ts index 0bc2972e2dc..a01d2257099 100644 --- a/src/test/eggs/egg.test.ts +++ b/src/test/eggs/egg.test.ts @@ -1,14 +1,14 @@ +import { Egg, getLegendaryGachaSpeciesForTimestamp } from "#app/data/egg"; +import { EggSourceType } from "#app/enums/egg-source-types"; +import { EggTier } from "#app/enums/egg-type"; +import { VariantTier } from "#app/enums/variant-tiers"; +import EggData from "#app/system/egg-data"; +import * as Utils from "#app/utils"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import BattleScene from "../../battle-scene"; -import { Egg, getLegendaryGachaSpeciesForTimestamp } from "#app/data/egg.js"; -import { Species } from "#enums/species"; -import Phaser from "phaser"; -import { EggSourceType } from "#app/enums/egg-source-types.js"; -import { EggTier } from "#app/enums/egg-type.js"; -import { VariantTier } from "#app/enums/variant-tiers.js"; -import GameManager from "#test/utils/gameManager"; -import EggData from "#app/system/egg-data.js"; -import * as Utils from "#app/utils.js"; describe("Egg Generation Tests", () => { let phaserGame: Phaser.Game; diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index b54deaa4611..41088c17bcb 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -1,6 +1,6 @@ -import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } from "#app/data/pokemon-evolutions.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { Species } from "#app/enums/species.js"; +import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } from "#app/data/pokemon-evolutions"; +import { Abilities } from "#app/enums/abilities"; +import { Species } from "#app/enums/species"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/evolutions/evolutions.test.ts b/src/test/evolutions/evolutions.test.ts index af43e91b059..2028764115c 100644 --- a/src/test/evolutions/evolutions.test.ts +++ b/src/test/evolutions/evolutions.test.ts @@ -1,8 +1,8 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; import * as Utils from "#app/utils"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Evolution tests", () => { let phaserGame: Phaser.Game; diff --git a/src/test/field/pokemon.test.ts b/src/test/field/pokemon.test.ts index ee8e41e8b42..d597cd5219c 100644 --- a/src/test/field/pokemon.test.ts +++ b/src/test/field/pokemon.test.ts @@ -1,4 +1,4 @@ -import { Species } from "#app/enums/species.js"; +import { Species } from "#app/enums/species"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "../utils/gameManager"; diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index a57d71534a3..0f59572619b 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -1,8 +1,8 @@ -import { Biome } from "#app/enums/biome.js"; -import { Species } from "#app/enums/species.js"; +import { Biome } from "#app/enums/biome"; +import { Species } from "#app/enums/species"; +import { GameModes } from "#app/game-mode"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; -import { GameModes } from "#app/game-mode"; const FinalWave = { Classic: 200, diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index 4a1960a05ff..ccec3a3aa16 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -1,7 +1,7 @@ -import { GameMode, GameModes, getGameMode } from "#app/game-mode.js"; +import { GameMode, GameModes, getGameMode } from "#app/game-mode"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import GameManager from "./utils/gameManager"; import * as Utils from "../utils"; +import GameManager from "./utils/gameManager"; describe("game-mode", () => { let phaserGame: Phaser.Game; let game: GameManager; diff --git a/src/test/imports.test.ts b/src/test/imports.test.ts index 69c145236bc..305eccdc465 100644 --- a/src/test/imports.test.ts +++ b/src/test/imports.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, it } from "vitest"; import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; +import { describe, expect, it } from "vitest"; async function importModule() { try { diff --git a/src/test/inputs/inputs.test.ts b/src/test/inputs/inputs.test.ts index 7182ac2c02c..6306c1b9da6 100644 --- a/src/test/inputs/inputs.test.ts +++ b/src/test/inputs/inputs.test.ts @@ -1,9 +1,9 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import pad_xbox360 from "#app/configs/inputs/pad_xbox360"; import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty"; +import pad_xbox360 from "#app/configs/inputs/pad_xbox360"; +import GameManager from "#test/utils/gameManager"; import InputsHandler from "#test/utils/inputsHandler"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Inputs", () => { diff --git a/src/test/internals.test.ts b/src/test/internals.test.ts index 0ecd156431d..3c76b40e901 100644 --- a/src/test/internals.test.ts +++ b/src/test/internals.test.ts @@ -1,8 +1,8 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; +import { Abilities } from "#app/enums/abilities"; +import { Species } from "#app/enums/species"; import GameManager from "#test/utils/gameManager"; -import { Species } from "#app/enums/species.js"; -import { Abilities } from "#app/enums/abilities.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Internals", () => { let phaserGame: Phaser.Game; diff --git a/src/test/items/eviolite.test.ts b/src/test/items/eviolite.test.ts index 0fe90866de8..e491784acec 100644 --- a/src/test/items/eviolite.test.ts +++ b/src/test/items/eviolite.test.ts @@ -2,9 +2,9 @@ import { Stat } from "#app/data/pokemon-stat"; import { EvolutionStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/items/exp_booster.test.ts b/src/test/items/exp_booster.test.ts index 2b700c92086..9a7464e4866 100644 --- a/src/test/items/exp_booster.test.ts +++ b/src/test/items/exp_booster.test.ts @@ -1,7 +1,7 @@ -import { Abilities } from "#app/enums/abilities.js"; -import { PokemonExpBoosterModifier } from "#app/modifier/modifier.js"; -import GameManager from "#test/utils/gameManager"; +import { Abilities } from "#app/enums/abilities"; +import { PokemonExpBoosterModifier } from "#app/modifier/modifier"; import * as Utils from "#app/utils"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/src/test/items/grip_claw.test.ts b/src/test/items/grip_claw.test.ts index ecf144c96c5..09afa9aea0b 100644 --- a/src/test/items/grip_claw.test.ts +++ b/src/test/items/grip_claw.test.ts @@ -1,16 +1,14 @@ -import { BattlerIndex } from "#app/battle.js"; -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { BerryType } from "#app/enums/berry-type.js"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { BerryType } from "#app/enums/berry-type"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; // 20 seconds @@ -35,12 +33,12 @@ describe("Items - Grip Claw", () => { .battleType("double") .moveset([Moves.POPULATION_BOMB, Moves.SPLASH]) .startingHeldItems([ - { name: "GRIP_CLAW", count: 5 }, + { name: "GRIP_CLAW", count: 5 }, // TODO: Find a way to mock the steal chance of grip claw { name: "MULTI_LENS", count: 3 }, ]) .enemySpecies(Species.SNORLAX) .ability(Abilities.KLUTZ) - .enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]) + .enemyMoveset(SPLASH_ONLY) .enemyHeldItems([ { name: "BERRY", type: BerryType.SITRUS, count: 2 }, { name: "BERRY", type: BerryType.LUM, count: 2 }, @@ -54,19 +52,14 @@ describe("Items - Grip Claw", () => { it( "should only steal items from the attack target", async () => { - await game.startBattle([Species.PANSEAR, Species.ROWLET, Species.PANPOUR, Species.PANSAGE, Species.CHARMANDER, Species.SQUIRTLE]); + await game.startBattle([Species.PANSEAR, Species.ROWLET]); const enemyPokemon = game.scene.getEnemyField(); const enemyHeldItemCt = enemyPokemon.map(p => p.getHeldItems.length); - game.doAttack(getMovePosition(game.scene, 0, Moves.POPULATION_BOMB)); - - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - - await game.phaseInterceptor.to(CommandPhase, false); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.POPULATION_BOMB, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEndPhase, false); diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 1e46bda9f0f..7505b6374a0 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -1,11 +1,11 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import * as Utils from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -27,21 +27,21 @@ describe("Items - Leek", () => { game = new GameManager(phaserGame); game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); game.override.disableCrits(); game.override.battleType("single"); }); - it("LEEK activates in battle correctly", async() => { + it("LEEK activates in battle correctly", async () => { game.override.startingHeldItems([{ name: "LEEK" }]); - game.override.moveset([ Moves.POUND ]); + game.override.moveset([Moves.POUND]); const consoleSpy = vi.spyOn(console, "log"); await game.startBattle([ Species.FARFETCHD ]); - game.doAttack(0); + game.move.select(Moves.POUND); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); @@ -50,7 +50,7 @@ describe("Items - Leek", () => { expect(consoleSpy).toHaveBeenCalledWith("Applied", "Leek", ""); }, 20000); - it("LEEK held by FARFETCHD", async() => { + it("LEEK held by FARFETCHD", async () => { await game.startBattle([ Species.FARFETCHD ]); @@ -70,7 +70,7 @@ describe("Items - Leek", () => { expect(critLevel.value).toBe(2); }, 20000); - it("LEEK held by GALAR_FARFETCHD", async() => { + it("LEEK held by GALAR_FARFETCHD", async () => { await game.startBattle([ Species.GALAR_FARFETCHD ]); @@ -90,7 +90,7 @@ describe("Items - Leek", () => { expect(critLevel.value).toBe(2); }, 20000); - it("LEEK held by SIRFETCHD", async() => { + it("LEEK held by SIRFETCHD", async () => { await game.startBattle([ Species.SIRFETCHD ]); @@ -110,9 +110,9 @@ describe("Items - Leek", () => { expect(critLevel.value).toBe(2); }, 20000); - it("LEEK held by fused FARFETCHD line (base)", async() => { + it("LEEK held by fused FARFETCHD line (base)", async () => { // Randomly choose from the Farfetch'd line - const species = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ]; + const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; await game.startBattle([ species[Utils.randInt(species.length)], @@ -145,9 +145,9 @@ describe("Items - Leek", () => { expect(critLevel.value).toBe(2); }, 20000); - it("LEEK held by fused FARFETCHD line (part)", async() => { + it("LEEK held by fused FARFETCHD line (part)", async () => { // Randomly choose from the Farfetch'd line - const species = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ]; + const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; await game.startBattle([ Species.PIKACHU, @@ -180,7 +180,7 @@ describe("Items - Leek", () => { expect(critLevel.value).toBe(2); }, 20000); - it("LEEK not held by FARFETCHD line", async() => { + it("LEEK not held by FARFETCHD line", async () => { await game.startBattle([ Species.PIKACHU ]); diff --git a/src/test/items/leftovers.test.ts b/src/test/items/leftovers.test.ts index 1a1c95ad9e6..8e548542436 100644 --- a/src/test/items/leftovers.test.ts +++ b/src/test/items/leftovers.test.ts @@ -1,12 +1,11 @@ -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Items - Leftovers", () => { @@ -32,10 +31,10 @@ describe("Items - Leftovers", () => { game.override.enemySpecies(Species.SHUCKLE); game.override.enemyAbility(Abilities.UNNERVE); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - game.override.startingHeldItems([{name: "LEFTOVERS", count: 1}]); + game.override.startingHeldItems([{ name: "LEFTOVERS", count: 1 }]); }); - it("leftovers works", async() => { + it("leftovers works", async () => { await game.startBattle([Species.ARCANINE]); // Make sure leftovers are there @@ -46,7 +45,7 @@ describe("Items - Leftovers", () => { // We should have full hp expect(leadPokemon.isFullHp()).toBe(true); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); // We should have less hp after the attack await game.phaseInterceptor.to(DamagePhase, false); diff --git a/src/test/items/light_ball.test.ts b/src/test/items/light_ball.test.ts index ff7dfa4eba5..cf4f5c9e22f 100644 --- a/src/test/items/light_ball.test.ts +++ b/src/test/items/light_ball.test.ts @@ -2,9 +2,9 @@ import { Stat } from "#app/data/pokemon-stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/items/lock_capsule.test.ts b/src/test/items/lock_capsule.test.ts index 0909e51ea2c..bc4ca1cb014 100644 --- a/src/test/items/lock_capsule.test.ts +++ b/src/test/items/lock_capsule.test.ts @@ -1,11 +1,10 @@ +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { Abilities } from "#app/enums/abilities.js"; -import { Moves } from "#app/enums/moves.js"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; -import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; describe("Items - Lock Capsule", () => { let phaserGame: Phaser.Game; @@ -29,13 +28,13 @@ describe("Items - Lock Capsule", () => { .startingLevel(200) .moveset([Moves.SURF]) .enemyAbility(Abilities.BALL_FETCH) - .startingModifier([{name: "LOCK_CAPSULE"}]); + .startingModifier([{ name: "LOCK_CAPSULE" }]); }); - it("doesn't set the cost of common tier items to 0", async() => { + it("doesn't set the cost of common tier items to 0", async () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); + game.move.select(Moves.SURF); await game.phaseInterceptor.to(SelectModifierPhase, false); const rewards = game.scene.getCurrentPhase() as SelectModifierPhase; diff --git a/src/test/items/metal_powder.test.ts b/src/test/items/metal_powder.test.ts index 966762e4175..a3a4936532f 100644 --- a/src/test/items/metal_powder.test.ts +++ b/src/test/items/metal_powder.test.ts @@ -2,9 +2,9 @@ import { Stat } from "#app/data/pokemon-stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/items/quick_powder.test.ts b/src/test/items/quick_powder.test.ts index d2435dab431..53521ba78f1 100644 --- a/src/test/items/quick_powder.test.ts +++ b/src/test/items/quick_powder.test.ts @@ -2,9 +2,9 @@ import { Stat } from "#app/data/pokemon-stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts index fa605ca7129..85673218762 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -1,11 +1,11 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import * as Utils from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -27,30 +27,30 @@ describe("Items - Scope Lens", () => { game = new GameManager(phaserGame); game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); game.override.disableCrits(); game.override.battleType("single"); }, 20000); - it("SCOPE_LENS activates in battle correctly", async() => { + it("SCOPE_LENS activates in battle correctly", async () => { game.override.startingHeldItems([{ name: "SCOPE_LENS" }]); - game.override.moveset([ Moves.POUND ]); + game.override.moveset([Moves.POUND]); const consoleSpy = vi.spyOn(console, "log"); await game.startBattle([ Species.GASTLY ]); - game.doAttack(0); + game.move.select(Moves.POUND); - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase); expect(consoleSpy).toHaveBeenCalledWith("Applied", "Scope Lens", ""); }, 20000); - it("SCOPE_LENS held by random pokemon", async() => { + it("SCOPE_LENS held by random pokemon", async () => { await game.startBattle([ Species.GASTLY ]); diff --git a/src/test/items/thick_club.test.ts b/src/test/items/thick_club.test.ts index 841cd7c90ac..347921446e6 100644 --- a/src/test/items/thick_club.test.ts +++ b/src/test/items/thick_club.test.ts @@ -2,9 +2,9 @@ import { Stat } from "#app/data/pokemon-stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/src/test/items/toxic_orb.test.ts b/src/test/items/toxic_orb.test.ts index dc54a5a1c36..95336c0793e 100644 --- a/src/test/items/toxic_orb.test.ts +++ b/src/test/items/toxic_orb.test.ts @@ -1,18 +1,14 @@ import { StatusEffect } from "#app/data/status-effect"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import i18next, { initI18n } from "#app/plugins/i18n"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Items - Toxic orb", () => { @@ -45,7 +41,7 @@ describe("Items - Toxic orb", () => { }]); }); - it("TOXIC ORB", async() => { + it("TOXIC ORB", async () => { initI18n(); i18next.changeLanguage("en"); const moveToUse = Moves.GROWTH; @@ -55,15 +51,7 @@ describe("Items - Toxic orb", () => { ]); expect(game.scene.modifiers[0].type.id).toBe("TOXIC_ORB"); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - // Select Attack - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - // Select Move Growth - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); // will run the 13 phase from enemyCommandPhase to TurnEndPhase await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); diff --git a/src/test/localization/battle-stat.test.ts b/src/test/localization/battle-stat.test.ts index b99ed2b7064..e8fc20ab5a4 100644 --- a/src/test/localization/battle-stat.test.ts +++ b/src/test/localization/battle-stat.test.ts @@ -1,26 +1,25 @@ -import { beforeAll, describe, expect, it } from "vitest"; -import { getBattleStatName, getBattleStatLevelChangeDescription } from "#app/data/battle-stat.js"; -import { BattleStat} from "#app/data/battle-stat.js"; -import { pokemonInfo as enPokemonInfo } from "#app/locales/en/pokemon-info.js"; -import { battle as enBattleStat } from "#app/locales/en/battle.js"; -import { pokemonInfo as dePokemonInfo } from "#app/locales/de/pokemon-info.js"; -import { battle as deBattleStat } from "#app/locales/de/battle.js"; -import { pokemonInfo as esPokemonInfo } from "#app/locales/es/pokemon-info.js"; -import { battle as esBattleStat } from "#app/locales/es/battle.js"; -import { pokemonInfo as frPokemonInfo } from "#app/locales/fr/pokemon-info.js"; -import { battle as frBattleStat } from "#app/locales/fr/battle.js"; -import { pokemonInfo as itPokemonInfo } from "#app/locales/it/pokemon-info.js"; -import { battle as itBattleStat } from "#app/locales/it/battle.js"; -import { pokemonInfo as koPokemonInfo } from "#app/locales/ko/pokemon-info.js"; -import { battle as koBattleStat } from "#app/locales/ko/battle.js"; -import { pokemonInfo as ptBrPokemonInfo } from "#app/locales/pt_BR/pokemon-info.js"; -import { battle as ptBrBattleStat } from "#app/locales/pt_BR/battle.js"; -import { pokemonInfo as zhCnPokemonInfo } from "#app/locales/zh_CN/pokemon-info.js"; -import { battle as zhCnBattleStat } from "#app/locales/zh_CN/battle.js"; -import { pokemonInfo as zhTwPokemonInfo } from "#app/locales/zh_TW/pokemon-info.js"; -import { battle as zhTwBattleStat } from "#app/locales/zh_TW/battle.js"; +import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "#app/data/battle-stat"; +import { battle as deBattleStat } from "#app/locales/de/battle"; +import { pokemonInfo as dePokemonInfo } from "#app/locales/de/pokemon-info"; +import { battle as enBattleStat } from "#app/locales/en/battle"; +import { pokemonInfo as enPokemonInfo } from "#app/locales/en/pokemon-info"; +import { battle as esBattleStat } from "#app/locales/es/battle"; +import { pokemonInfo as esPokemonInfo } from "#app/locales/es/pokemon-info"; +import { battle as frBattleStat } from "#app/locales/fr/battle"; +import { pokemonInfo as frPokemonInfo } from "#app/locales/fr/pokemon-info"; +import { battle as itBattleStat } from "#app/locales/it/battle"; +import { pokemonInfo as itPokemonInfo } from "#app/locales/it/pokemon-info"; +import { battle as koBattleStat } from "#app/locales/ko/battle"; +import { pokemonInfo as koPokemonInfo } from "#app/locales/ko/pokemon-info"; +import { battle as ptBrBattleStat } from "#app/locales/pt_BR/battle"; +import { pokemonInfo as ptBrPokemonInfo } from "#app/locales/pt_BR/pokemon-info"; +import { battle as zhCnBattleStat } from "#app/locales/zh_CN/battle"; +import { pokemonInfo as zhCnPokemonInfo } from "#app/locales/zh_CN/pokemon-info"; +import { battle as zhTwBattleStat } from "#app/locales/zh_TW/battle"; +import { pokemonInfo as zhTwPokemonInfo } from "#app/locales/zh_TW/pokemon-info"; import i18next, { initI18n } from "#app/plugins/i18n"; import { KoreanPostpositionProcessor } from "i18next-korean-postposition-processor"; +import { beforeAll, describe, expect, it } from "vitest"; interface BattleStatTestUnit { stat: BattleStat, diff --git a/src/test/localization/french.test.ts b/src/test/localization/french.test.ts index b03a8ee64e8..92b4c82d7cb 100644 --- a/src/test/localization/french.test.ts +++ b/src/test/localization/french.test.ts @@ -1,9 +1,9 @@ -import { afterEach, beforeAll, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; -import i18next from "i18next"; import { initI18n } from "#app/plugins/i18n"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import i18next from "i18next"; +import Phaser from "phaser"; +import { afterEach, beforeAll, describe, expect, it } from "vitest"; describe("Lokalization - french", () => { let phaserGame: Phaser.Game; diff --git a/src/test/localization/status-effect.test.ts b/src/test/localization/status-effect.test.ts index 8a9effe1672..9dcab5aeb5f 100644 --- a/src/test/localization/status-effect.test.ts +++ b/src/test/localization/status-effect.test.ts @@ -1,7 +1,7 @@ -import { beforeAll, describe, afterEach, expect, it, vi } from "vitest"; import { StatusEffect, getStatusEffectActivationText, getStatusEffectDescriptor, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText } from "#app/data/status-effect"; -import i18next from "i18next"; import { mockI18next } from "#test/utils/testUtils"; +import i18next from "i18next"; +import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; const pokemonName = "PKM"; const sourceText = "SOURCE"; diff --git a/src/test/localization/terrain.test.ts b/src/test/localization/terrain.test.ts index c072f9cc9ab..ed280177a06 100644 --- a/src/test/localization/terrain.test.ts +++ b/src/test/localization/terrain.test.ts @@ -1,11 +1,11 @@ import { TerrainType, getTerrainName } from "#app/data/terrain"; import { getTerrainBlockMessage, getTerrainClearMessage, getTerrainStartMessage } from "#app/data/weather"; -import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { mockI18next } from "#test/utils/testUtils"; import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { mockI18next } from "#test/utils/testUtils"; describe("terrain", () => { let phaserGame: Phaser.Game; diff --git a/src/test/moves/astonish.test.ts b/src/test/moves/astonish.test.ts index 21a82f09d33..b21e2a06051 100644 --- a/src/test/moves/astonish.test.ts +++ b/src/test/moves/astonish.test.ts @@ -1,16 +1,15 @@ -import { allMoves } from "#app/data/move.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { allMoves } from "#app/data/move"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -50,7 +49,7 @@ describe("Moves - Astonish", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.ASTONISH)); + game.move.select(Moves.ASTONISH); await game.phaseInterceptor.to(MoveEndPhase, false); @@ -63,7 +62,7 @@ describe("Moves - Astonish", () => { await game.phaseInterceptor.to(CommandPhase, false); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/aurora_veil.test.ts b/src/test/moves/aurora_veil.test.ts index 5429efec2bf..fec280debf4 100644 --- a/src/test/moves/aurora_veil.test.ts +++ b/src/test/moves/aurora_veil.test.ts @@ -1,15 +1,14 @@ -import { ArenaTagSide } from "#app/data/arena-tag.js"; -import Move, { allMoves } from "#app/data/move.js"; -import { WeatherType } from "#app/data/weather.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { NumberHolder } from "#app/utils.js"; +import { ArenaTagSide } from "#app/data/arena-tag"; +import Move, { allMoves } from "#app/data/move"; +import { WeatherType } from "#app/data/weather"; +import { Abilities } from "#app/enums/abilities"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import Pokemon from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { NumberHolder } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -18,7 +17,7 @@ describe("Moves - Aurora Veil", () => { let phaserGame: Phaser.Game; let game: GameManager; const singleBattleMultiplier = 0.5; - const doubleBattleMultiplier = 2732/4096; + const doubleBattleMultiplier = 2732 / 4096; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -42,11 +41,11 @@ describe("Moves - Aurora Veil", () => { game.override.weather(WeatherType.HAIL); }); - it("reduces damage of physical attacks by half in a single battle", async() => { + it("reduces damage of physical attacks by half in a single battle", async () => { const moveToUse = Moves.TACKLE; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); @@ -54,14 +53,14 @@ describe("Moves - Aurora Veil", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); - it("reduces damage of physical attacks by a third in a double battle", async() => { + it("reduces damage of physical attacks by a third in a double battle", async () => { game.override.battleType("double"); const moveToUse = Moves.ROCK_SLIDE; await game.startBattle([Species.SHUCKLE, Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); - game.doAttack(getMovePosition(game.scene, 1, moveToUse)); + game.move.select(moveToUse); + game.move.select(moveToUse, 1); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); @@ -69,11 +68,11 @@ describe("Moves - Aurora Veil", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); - it("reduces damage of special attacks by half in a single battle", async() => { + it("reduces damage of special attacks by half in a single battle", async () => { const moveToUse = Moves.ABSORB; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -82,14 +81,14 @@ describe("Moves - Aurora Veil", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); - it("reduces damage of special attacks by a third in a double battle", async() => { + it("reduces damage of special attacks by a third in a double battle", async () => { game.override.battleType("double"); const moveToUse = Moves.DAZZLING_GLEAM; await game.startBattle([Species.SHUCKLE, Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); - game.doAttack(getMovePosition(game.scene, 1, moveToUse)); + game.move.select(moveToUse); + game.move.select(moveToUse, 1); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); diff --git a/src/test/moves/baton_pass.test.ts b/src/test/moves/baton_pass.test.ts index 790eddbf45c..602da9e37f8 100644 --- a/src/test/moves/baton_pass.test.ts +++ b/src/test/moves/baton_pass.test.ts @@ -1,13 +1,12 @@ -import { BattleStat } from "#app/data/battle-stat.js"; +import { BattleStat } from "#app/data/battle-stat"; +import { PostSummonPhase } from "#app/phases/post-summon-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#app/test/utils/gameManager"; -import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Baton Pass", () => { @@ -36,7 +35,7 @@ describe("Moves - Baton Pass", () => { .disableCrits(); }); - it("passes stat stage buffs when player uses it", async() => { + it("passes stat stage buffs when player uses it", async () => { // arrange await game.startBattle([ Species.RAICHU, @@ -44,12 +43,12 @@ describe("Moves - Baton Pass", () => { ]); // round 1 - buff - game.doAttack(getMovePosition(game.scene, 0, Moves.NASTY_PLOT)); + game.move.select(Moves.NASTY_PLOT); await game.toNextTurn(); expect(game.scene.getPlayerPokemon()!.summonData.battleStats[BattleStat.SPATK]).toEqual(2); // round 2 - baton pass - game.doAttack(getMovePosition(game.scene, 0, Moves.BATON_PASS)); + game.move.select(Moves.BATON_PASS); game.doSelectPartyPokemon(1); await game.phaseInterceptor.to(TurnEndPhase); @@ -59,7 +58,7 @@ describe("Moves - Baton Pass", () => { expect(playerPkm.summonData.battleStats[BattleStat.SPATK]).toEqual(2); }, 20000); - it("passes stat stage buffs when AI uses it", async() => { + it("passes stat stage buffs when AI uses it", async () => { // arrange game.override .startingWave(5) @@ -70,13 +69,13 @@ describe("Moves - Baton Pass", () => { ]); // round 1 - ai buffs - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); // round 2 - baton pass game.scene.getEnemyPokemon()!.hp = 100; game.override.enemyMoveset(new Array(4).fill(Moves.BATON_PASS)); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(PostSummonPhase, false); // assert diff --git a/src/test/moves/beak_blast.test.ts b/src/test/moves/beak_blast.test.ts index 8938b4c7af8..2a93dc00a54 100644 --- a/src/test/moves/beak_blast.test.ts +++ b/src/test/moves/beak_blast.test.ts @@ -1,15 +1,14 @@ -import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { StatusEffect } from "#app/enums/status-effect"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MovePhase } from "#app/phases/move-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { StatusEffect } from "#app/enums/status-effect.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; const TIMEOUT = 20 * 1000; @@ -48,7 +47,7 @@ describe("Moves - Beak Blast", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + game.move.select(Moves.BEAK_BLAST); await game.phaseInterceptor.to(MovePhase, false); expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); @@ -68,7 +67,7 @@ describe("Moves - Beak Blast", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + game.move.select(Moves.BEAK_BLAST); await game.phaseInterceptor.to(MovePhase, false); expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); @@ -88,7 +87,7 @@ describe("Moves - Beak Blast", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + game.move.select(Moves.BEAK_BLAST); await game.phaseInterceptor.to(MovePhase, false); expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); @@ -101,13 +100,13 @@ describe("Moves - Beak Blast", () => { it( "should only hit twice with Multi-Lens", async () => { - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + game.move.select(Moves.BEAK_BLAST); await game.phaseInterceptor.to(BerryPhase, false); expect(leadPokemon.turnData.hitCount).toBe(2); @@ -124,7 +123,7 @@ describe("Moves - Beak Blast", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + game.move.select(Moves.BEAK_BLAST); await game.phaseInterceptor.to(MovePhase, false); expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); diff --git a/src/test/moves/beat_up.test.ts b/src/test/moves/beat_up.test.ts index a0f168ea30f..ce1598a49b4 100644 --- a/src/test/moves/beat_up.test.ts +++ b/src/test/moves/beat_up.test.ts @@ -1,12 +1,11 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { StatusEffect } from "#app/enums/status-effect"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager"; -import { Species } from "#app/enums/species.js"; -import { Moves } from "#app/enums/moves.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { StatusEffect } from "#app/enums/status-effect.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; const TIMEOUT = 20 * 1000; // 20 sec timeout @@ -46,7 +45,7 @@ describe("Moves - Beat Up", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; let enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAT_UP)); + game.move.select(Moves.BEAT_UP); await game.phaseInterceptor.to(MoveEffectPhase); @@ -70,7 +69,7 @@ describe("Moves - Beat Up", () => { game.scene.getParty()[1].trySetStatus(StatusEffect.BURN); - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAT_UP)); + game.move.select(Moves.BEAT_UP); await game.phaseInterceptor.to(MoveEffectPhase); @@ -81,14 +80,14 @@ describe("Moves - Beat Up", () => { it( "should hit twice for each player Pokemon if the user has Multi-Lens", async () => { - game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); await game.startBattle([Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.PIKACHU, Species.EEVEE]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; let enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.BEAT_UP)); + game.move.select(Moves.BEAT_UP); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/moves/belly_drum.test.ts b/src/test/moves/belly_drum.test.ts index 229314c96e6..631de952a58 100644 --- a/src/test/moves/belly_drum.test.ts +++ b/src/test/moves/belly_drum.test.ts @@ -1,12 +1,11 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { toDmgValue } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { BattleStat } from "#app/data/battle-stat"; -import { toDmgValue } from "#app/utils"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; // RATIO : HP Cost of Move @@ -41,13 +40,13 @@ describe("Moves - BELLY DRUM", () => { // Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/Belly_Drum_(move) test("Belly Drum raises the user's Attack to its max, at the cost of 1/2 of its maximum HP", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); - game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); + game.move.select(Moves.BELLY_DRUM); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -56,7 +55,7 @@ describe("Moves - BELLY DRUM", () => { ); test("Belly Drum will still take effect if an uninvolved stat is at max", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -66,7 +65,7 @@ describe("Moves - BELLY DRUM", () => { leadPokemon.summonData.battleStats[BattleStat.ATK] = -3; leadPokemon.summonData.battleStats[BattleStat.SPATK] = 6; - game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); + game.move.select(Moves.BELLY_DRUM); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -76,14 +75,14 @@ describe("Moves - BELLY DRUM", () => { ); test("Belly Drum fails if the pokemon's attack stat is at its maximum", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; - game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); + game.move.select(Moves.BELLY_DRUM); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); @@ -92,14 +91,14 @@ describe("Moves - BELLY DRUM", () => { ); test("Belly Drum fails if the user's health is less than 1/2", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; - game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); + game.move.select(Moves.BELLY_DRUM); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(hpLost - PREDAMAGE); diff --git a/src/test/moves/ceaseless_edge.test.ts b/src/test/moves/ceaseless_edge.test.ts index c8291a99b59..34ecf8f39f6 100644 --- a/src/test/moves/ceaseless_edge.test.ts +++ b/src/test/moves/ceaseless_edge.test.ts @@ -2,14 +2,13 @@ import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; import { allMoves } from "#app/data/move"; import { Abilities } from "#app/enums/abilities"; import { ArenaTagType } from "#app/enums/arena-tag-type"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -35,8 +34,8 @@ describe("Moves - Ceaseless Edge", () => { game.override.enemyPassiveAbility(Abilities.RUN_AWAY); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.CEASELESS_EDGE, Moves.SPLASH, Moves.ROAR ]); - game.override.enemyMoveset([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); + game.override.moveset([Moves.CEASELESS_EDGE, Moves.SPLASH, Moves.ROAR]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); vi.spyOn(allMoves[Moves.CEASELESS_EDGE], "accuracy", "get").mockReturnValue(100); }); @@ -44,13 +43,13 @@ describe("Moves - Ceaseless Edge", () => { test( "move should hit and apply spikes", async () => { - await game.startBattle([ Species.ILLUMISE ]); + await game.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.CEASELESS_EDGE)); + game.move.select(Moves.CEASELESS_EDGE); await game.phaseInterceptor.to(MoveEffectPhase, false); // Spikes should not have any layers before move effect is applied @@ -68,14 +67,14 @@ describe("Moves - Ceaseless Edge", () => { test( "move should hit twice with multi lens and apply two layers of spikes", async () => { - game.override.startingHeldItems([{name: "MULTI_LENS"}]); - await game.startBattle([ Species.ILLUMISE ]); + game.override.startingHeldItems([{ name: "MULTI_LENS" }]); + await game.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.CEASELESS_EDGE)); + game.move.select(Moves.CEASELESS_EDGE); await game.phaseInterceptor.to(MoveEffectPhase, false); // Spikes should not have any layers before move effect is applied @@ -93,12 +92,12 @@ describe("Moves - Ceaseless Edge", () => { test( "trainer - move should hit twice, apply two layers of spikes, force switch opponent - opponent takes damage", async () => { - game.override.startingHeldItems([{name: "MULTI_LENS"}]); + game.override.startingHeldItems([{ name: "MULTI_LENS" }]); game.override.startingWave(5); - await game.startBattle([ Species.ILLUMISE ]); + await game.startBattle([Species.ILLUMISE]); - game.doAttack(getMovePosition(game.scene, 0, Moves.CEASELESS_EDGE)); + game.move.select(Moves.CEASELESS_EDGE); await game.phaseInterceptor.to(MoveEffectPhase, false); // Spikes should not have any layers before move effect is applied const tagBefore = game.scene.arena.getTagOnSide(ArenaTagType.SPIKES, ArenaTagSide.ENEMY) as ArenaTrapTag; @@ -112,7 +111,7 @@ describe("Moves - Ceaseless Edge", () => { const hpBeforeSpikes = game.scene.currentBattle.enemyParty[1].hp; // Check HP of pokemon that WILL BE switched in (index 1) game.forceOpponentToSwitch(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase, false); expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(hpBeforeSpikes); }, TIMEOUT diff --git a/src/test/moves/clangorous_soul.test.ts b/src/test/moves/clangorous_soul.test.ts index afab4c2e9be..9ea6da91595 100644 --- a/src/test/moves/clangorous_soul.test.ts +++ b/src/test/moves/clangorous_soul.test.ts @@ -1,13 +1,12 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { toDmgValue } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { BattleStat } from "#app/data/battle-stat"; +import GameManager from "#test/utils/gameManager"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { toDmgValue } from "#app/utils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; /** HP Cost of Move */ @@ -42,13 +41,13 @@ describe("Moves - CLANGOROUS_SOUL", () => { //Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/Clangorous_Soul_(move) test("Clangorous Soul raises the user's Attack, Defense, Special Attack, Special Defense and Speed by one stage each, at the cost of 1/3 of its maximum HP", - async() => { - await game.startBattle([Species.MAGIKARP]); + async () => { + await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon()!; + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); - game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); + game.move.select(Moves.CLANGOROUS_SOUL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -57,11 +56,11 @@ describe("Moves - CLANGOROUS_SOUL", () => { expect(leadPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(1); expect(leadPokemon.summonData.battleStats[BattleStat.SPDEF]).toBe(1); expect(leadPokemon.summonData.battleStats[BattleStat.SPD]).toBe(1); - }, TIMEOUT + }, TIMEOUT ); test("Clangorous Soul will still take effect if one or more of the involved stats are not at max", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -73,7 +72,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { leadPokemon.summonData.battleStats[BattleStat.SPATK] = 6; leadPokemon.summonData.battleStats[BattleStat.SPDEF] = 4; - game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); + game.move.select(Moves.CLANGOROUS_SOUL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -86,7 +85,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { ); test("Clangorous Soul fails if all stats involved are at max", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -97,7 +96,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { leadPokemon.summonData.battleStats[BattleStat.SPDEF] = 6; leadPokemon.summonData.battleStats[BattleStat.SPD] = 6; - game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); + game.move.select(Moves.CLANGOROUS_SOUL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); @@ -110,14 +109,14 @@ describe("Moves - CLANGOROUS_SOUL", () => { ); test("Clangorous Soul fails if the user's health is less than 1/3", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; - game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); + game.move.select(Moves.CLANGOROUS_SOUL); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(hpLost - PREDAMAGE); diff --git a/src/test/moves/crafty_shield.test.ts b/src/test/moves/crafty_shield.test.ts index c3e50bc52c2..a341a50b0b9 100644 --- a/src/test/moves/crafty_shield.test.ts +++ b/src/test/moves/crafty_shield.test.ts @@ -1,14 +1,13 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "../utils/gameManager"; -import { Species } from "#enums/species"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; @@ -48,11 +47,11 @@ describe("Moves - Crafty Shield", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CRAFTY_SHIELD)); + game.move.select(Moves.CRAFTY_SHIELD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -69,11 +68,11 @@ describe("Moves - Crafty Shield", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CRAFTY_SHIELD)); + game.move.select(Moves.CRAFTY_SHIELD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -91,11 +90,11 @@ describe("Moves - Crafty Shield", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CRAFTY_SHIELD)); + game.move.select(Moves.CRAFTY_SHIELD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -110,11 +109,11 @@ describe("Moves - Crafty Shield", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CRAFTY_SHIELD)); + game.move.select(Moves.CRAFTY_SHIELD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SWORDS_DANCE)); + game.move.select(Moves.SWORDS_DANCE, 1); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/double_team.test.ts b/src/test/moves/double_team.test.ts index 1c89d5b6350..c45c8bd8516 100644 --- a/src/test/moves/double_team.test.ts +++ b/src/test/moves/double_team.test.ts @@ -1,10 +1,9 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { Abilities } from "#app/enums/abilities"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -42,7 +41,7 @@ describe("Moves - Double Team", () => { vi.spyOn(enemy, "getAccuracyMultiplier"); expect(ally.summonData.battleStats[BattleStat.EVA]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_TEAM)); + game.move.select(Moves.DOUBLE_TEAM); await game.phaseInterceptor.to(TurnEndPhase); await game.toNextTurn(); diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index 8a27f4006f4..223635575ab 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -1,17 +1,16 @@ import { BattleStat } from "#app/data/battle-stat"; import { Type } from "#app/data/type"; -import { Species } from "#app/enums/species.js"; +import { Species } from "#app/enums/species"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Dragon Rage", () => { let phaserGame: Phaser.Game; @@ -62,7 +61,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); vi.spyOn(enemyPokemon, "getTypes").mockReturnValue([Type.DRAGON]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -73,7 +72,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); vi.spyOn(enemyPokemon, "getTypes").mockReturnValue([Type.STEEL]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -84,7 +83,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); partyPokemon.summonData.battleStats[BattleStat.SPATK] = 2; - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -95,7 +94,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); vi.spyOn(partyPokemon, "getTypes").mockReturnValue([Type.DRAGON]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -105,7 +104,7 @@ describe("Moves - Dragon Rage", () => { it("ignores criticals", async () => { partyPokemon.addTag(BattlerTagType.ALWAYS_CRIT, 99); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -116,7 +115,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); game.override.enemyAbility(Abilities.ICE_SCALES); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; @@ -127,7 +126,7 @@ describe("Moves - Dragon Rage", () => { game.override.disableCrits(); game.scene.addModifier(modifierTypes.MULTI_LENS().newModifier(partyPokemon), false); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); + game.move.select(Moves.DRAGON_RAGE); await game.phaseInterceptor.to(TurnEndPhase); const damageDealt = enemyPokemon.getMaxHp() - enemyPokemon.hp; diff --git a/src/test/moves/dragon_tail.test.ts b/src/test/moves/dragon_tail.test.ts index 28c47a83454..362383e2fe3 100644 --- a/src/test/moves/dragon_tail.test.ts +++ b/src/test/moves/dragon_tail.test.ts @@ -1,16 +1,15 @@ -import { allMoves } from "#app/data/move.js"; -import { SPLASH_ONLY } from "../utils/testUtils"; +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "../utils/gameManager"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattlerIndex } from "#app/battle.js"; -import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -46,9 +45,8 @@ describe("Moves - Dragon Tail", () => { await game.startBattle([Species.DRATINI]); const enemyPokemon = game.scene.getEnemyPokemon()!; - expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + game.move.select(Moves.DRAGON_TAIL); await game.phaseInterceptor.to(BerryPhase); @@ -68,12 +66,9 @@ describe("Moves - Dragon Tail", () => { await game.startBattle([Species.DRATINI]); const leadPokemon = game.scene.getPlayerPokemon()!; - expect(leadPokemon).toBeDefined(); - const enemyPokemon = game.scene.getEnemyPokemon()!; - expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + game.move.select(Moves.DRAGON_TAIL); await game.phaseInterceptor.to(BerryPhase); @@ -85,7 +80,7 @@ describe("Moves - Dragon Tail", () => { ); test( - "Double battles should proceed without crashing" , + "Double battles should proceed without crashing", async () => { game.override.battleType("double").enemyMoveset(SPLASH_ONLY); game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]) @@ -93,19 +88,12 @@ describe("Moves - Dragon Tail", () => { await game.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]); const leadPokemon = game.scene.getParty()[0]!; - const secPokemon = game.scene.getParty()[1]!; - expect(leadPokemon).toBeDefined(); - expect(secPokemon).toBeDefined(); - const enemyLeadPokemon = game.scene.currentBattle.enemyParty[0]!; - const enemySecPokemon = game.scene.currentBattle.enemyParty[1]!; - expect(enemyLeadPokemon).toBeDefined(); - expect(enemySecPokemon).toBeDefined(); + const enemyLeadPokemon = game.scene.getEnemyParty()[0]!; + const enemySecPokemon = game.scene.getEnemyParty()[1]!; - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.DRAGON_TAIL, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -117,10 +105,8 @@ describe("Moves - Dragon Tail", () => { expect(leadPokemon.hp).toBeLessThan(leadPokemon.getMaxHp()); // second turn - - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); - game.doSelectTarget(BattlerIndex.ENEMY_2); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLAMETHROWER, 0, BattlerIndex.ENEMY_2); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase); expect(enemySecPokemon.hp).toBeLessThan(enemySecPokemon.getMaxHp()); @@ -128,7 +114,7 @@ describe("Moves - Dragon Tail", () => { ); test( - "Flee move redirection works" , + "Flee move redirection works", async () => { game.override.battleType("double").enemyMoveset(SPLASH_ONLY); game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]); @@ -137,20 +123,13 @@ describe("Moves - Dragon Tail", () => { const leadPokemon = game.scene.getParty()[0]!; const secPokemon = game.scene.getParty()[1]!; - expect(leadPokemon).toBeDefined(); - expect(secPokemon).toBeDefined(); - const enemyLeadPokemon = game.scene.currentBattle.enemyParty[0]!; - const enemySecPokemon = game.scene.currentBattle.enemyParty[1]!; - expect(enemyLeadPokemon).toBeDefined(); - expect(enemySecPokemon).toBeDefined(); - - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); - game.doSelectTarget(BattlerIndex.ENEMY); + const enemyLeadPokemon = game.scene.getEnemyParty()[0]!; + const enemySecPokemon = game.scene.getEnemyParty()[1]!; + game.move.select(Moves.DRAGON_TAIL, 0, BattlerIndex.ENEMY); // target the same pokemon, second move should be redirected after first flees - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(Moves.DRAGON_TAIL, 1, BattlerIndex.ENEMY); await game.phaseInterceptor.to(BerryPhase); diff --git a/src/test/moves/dynamax_cannon.test.ts b/src/test/moves/dynamax_cannon.test.ts index 5e81241ef46..6ac0befdb36 100644 --- a/src/test/moves/dynamax_cannon.test.ts +++ b/src/test/moves/dynamax_cannon.test.ts @@ -1,14 +1,12 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; describe("Moves - Dynamax Cannon", () => { let phaserGame: Phaser.Game; @@ -29,7 +27,7 @@ describe("Moves - Dynamax Cannon", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.moveset([ dynamaxCannon.id ]); + game.override.moveset([dynamaxCannon.id]); game.override.startingLevel(200); // Note that, for Waves 1-10, the level cap is 10 @@ -38,18 +36,18 @@ describe("Moves - Dynamax Cannon", () => { game.override.disableCrits(); game.override.enemySpecies(Species.MAGIKARP); - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); vi.spyOn(dynamaxCannon, "calculateBattlePower"); }); - it("should return 100 power against an enemy below level cap", async() => { + it("should return 100 power against an enemy below level cap", async () => { game.override.enemyLevel(1); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); @@ -57,13 +55,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); - it("should return 100 power against an enemy at level cap", async() => { + it("should return 100 power against an enemy at level cap", async () => { game.override.enemyLevel(10); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); @@ -71,13 +69,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); - it("should return 120 power against an enemy 1% above level cap", async() => { + it("should return 120 power against an enemy 1% above level cap", async () => { game.override.enemyLevel(101); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -88,13 +86,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(120); }, 20000); - it("should return 140 power against an enemy 2% above level capp", async() => { + it("should return 140 power against an enemy 2% above level capp", async () => { game.override.enemyLevel(102); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -105,13 +103,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(140); }, 20000); - it("should return 160 power against an enemy 3% above level cap", async() => { + it("should return 160 power against an enemy 3% above level cap", async () => { game.override.enemyLevel(103); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -122,13 +120,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(160); }, 20000); - it("should return 180 power against an enemy 4% above level cap", async() => { + it("should return 180 power against an enemy 4% above level cap", async () => { game.override.enemyLevel(104); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -139,13 +137,13 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(180); }, 20000); - it("should return 200 power against an enemy 5% above level cap", async() => { + it("should return 200 power against an enemy 5% above level cap", async () => { game.override.enemyLevel(105); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); + game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -156,17 +154,14 @@ describe("Moves - Dynamax Cannon", () => { expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("should return 200 power against an enemy way above level cap", async() => { + it("should return 200 power against an enemy way above level cap", async () => { game.override.enemyLevel(999); await game.startBattle([ Species.ETERNATUS, ]); - game.doAttack(getMovePosition(game.scene, 0, dynamaxCannon.id)); - - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force user to act before enemy - vi.spyOn((game.scene.getCurrentPhase() as TurnStartPhase), "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex. ENEMY]); + game.move.select(dynamaxCannon.id); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); diff --git a/src/test/moves/fillet_away.test.ts b/src/test/moves/fillet_away.test.ts index fc87d600eb5..b2ff9e25dba 100644 --- a/src/test/moves/fillet_away.test.ts +++ b/src/test/moves/fillet_away.test.ts @@ -1,13 +1,12 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { toDmgValue } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { BattleStat } from "#app/data/battle-stat"; +import GameManager from "#test/utils/gameManager"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { toDmgValue } from "#app/utils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; const TIMEOUT = 20 * 1000; /** HP Cost of Move */ @@ -42,13 +41,13 @@ describe("Moves - FILLET AWAY", () => { //Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/fillet_away_(move) test("Fillet Away raises the user's Attack, Special Attack, and Speed by two stages each, at the cost of 1/2 of its maximum HP", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); - game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); + game.move.select(Moves.FILLET_AWAY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -59,7 +58,7 @@ describe("Moves - FILLET AWAY", () => { ); test("Fillet Away will still take effect if one or more of the involved stats are not at max", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -69,7 +68,7 @@ describe("Moves - FILLET AWAY", () => { leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; leadPokemon.summonData.battleStats[BattleStat.SPATK] = 3; - game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); + game.move.select(Moves.FILLET_AWAY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp() - hpLost); @@ -80,7 +79,7 @@ describe("Moves - FILLET AWAY", () => { ); test("Fillet Away fails if all stats involved are at max", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -89,7 +88,7 @@ describe("Moves - FILLET AWAY", () => { leadPokemon.summonData.battleStats[BattleStat.SPATK] = 6; leadPokemon.summonData.battleStats[BattleStat.SPD] = 6; - game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); + game.move.select(Moves.FILLET_AWAY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); @@ -100,14 +99,14 @@ describe("Moves - FILLET AWAY", () => { ); test("Fillet Away fails if the user's health is less than 1/2", - async() => { + async () => { await game.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; - game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); + game.move.select(Moves.FILLET_AWAY); await game.phaseInterceptor.to(TurnEndPhase); expect(leadPokemon.hp).toBe(hpLost - PREDAMAGE); diff --git a/src/test/moves/fissure.test.ts b/src/test/moves/fissure.test.ts index 65d692a5cc1..51122b269b8 100644 --- a/src/test/moves/fissure.test.ts +++ b/src/test/moves/fissure.test.ts @@ -1,15 +1,14 @@ import { BattleStat } from "#app/data/battle-stat"; -import { Species } from "#app/enums/species.js"; +import { Species } from "#app/enums/species"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Fissure", () => { let phaserGame: Phaser.Game; @@ -57,7 +56,7 @@ describe("Moves - Fissure", () => { game.override.ability(Abilities.NO_GUARD); game.override.enemyAbility(Abilities.FUR_COAT); - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); await game.phaseInterceptor.to(DamagePhase, true); expect(enemyPokemon.isFainted()).toBe(true); @@ -68,7 +67,7 @@ describe("Moves - Fissure", () => { enemyPokemon.summonData.battleStats[BattleStat.ACC] = -6; - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); // wait for TurnEndPhase instead of DamagePhase as fissure might not actually inflict damage await game.phaseInterceptor.to(TurnEndPhase); @@ -81,7 +80,7 @@ describe("Moves - Fissure", () => { enemyPokemon.summonData.battleStats[BattleStat.EVA] = 6; - game.doAttack(getMovePosition(game.scene, 0, Moves.FISSURE)); + game.move.select(Moves.FISSURE); // wait for TurnEndPhase instead of DamagePhase as fissure might not actually inflict damage await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/moves/flame_burst.test.ts b/src/test/moves/flame_burst.test.ts index d6679f921df..2777b8178b8 100644 --- a/src/test/moves/flame_burst.test.ts +++ b/src/test/moves/flame_burst.test.ts @@ -1,14 +1,12 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; +import { allAbilities } from "#app/data/ability"; +import { Abilities } from "#app/enums/abilities"; +import Pokemon from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Abilities } from "#app/enums/abilities.js"; -import { allAbilities } from "#app/data/ability.js"; -import Pokemon from "#app/field/pokemon.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Moves - Flame Burst", () => { let phaserGame: Phaser.Game; @@ -22,7 +20,7 @@ describe("Moves - Flame Burst", () => { * @returns Effect damage of Flame Burst */ const getEffectDamage = (pokemon: Pokemon): number => { - return Math.max(1, Math.floor(pokemon.getMaxHp() * 1/16)); + return Math.max(1, Math.floor(pokemon.getMaxHp() * 1 / 16)); }; beforeAll(() => { @@ -49,12 +47,10 @@ describe("Moves - Flame Burst", () => { it("inflicts damage to the target's ally equal to 1/16 of its max HP", async () => { await game.startBattle([Species.PIKACHU, Species.PIKACHU]); - const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField(); + const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAME_BURST)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(leftEnemy.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp()); @@ -65,12 +61,10 @@ describe("Moves - Flame Burst", () => { game.override.enemyAbility(Abilities.FLASH_FIRE); await game.startBattle([Species.PIKACHU, Species.PIKACHU]); - const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField(); + const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAME_BURST)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(leftEnemy.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(leftEnemy.hp).toBe(leftEnemy.getMaxHp()); @@ -79,14 +73,12 @@ describe("Moves - Flame Burst", () => { it("does not interact with the target ally's abilities", async () => { await game.startBattle([Species.PIKACHU, Species.PIKACHU]); - const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField(); + const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.FLASH_FIRE]); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAME_BURST)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(leftEnemy.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp()); @@ -95,14 +87,12 @@ describe("Moves - Flame Burst", () => { it("effect damage is prevented by Magic Guard", async () => { await game.startBattle([Species.PIKACHU, Species.PIKACHU]); - const [ leftEnemy, rightEnemy ] = game.scene.getEnemyField(); + const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.MAGIC_GUARD]); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLAME_BURST)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(leftEnemy.getBattlerIndex()); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); expect(leftEnemy.hp).toBeLessThan(leftEnemy.getMaxHp()); diff --git a/src/test/moves/flower_shield.test.ts b/src/test/moves/flower_shield.test.ts index 9001e8ceacb..b3e50219aec 100644 --- a/src/test/moves/flower_shield.test.ts +++ b/src/test/moves/flower_shield.test.ts @@ -1,16 +1,15 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { SemiInvulnerableTag } from "#app/data/battler-tags.js"; -import { Type } from "#app/data/type.js"; -import { Biome } from "#app/enums/biome.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { SemiInvulnerableTag } from "#app/data/battler-tags"; +import { Type } from "#app/data/type"; +import { Biome } from "#app/enums/biome"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Flower Shield", () => { let phaserGame: Phaser.Game; @@ -45,7 +44,7 @@ describe("Moves - Flower Shield", () => { expect(magikarp.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(cherrim.summonData.battleStats[BattleStat.DEF]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLOWER_SHIELD)); + game.move.select(Moves.FLOWER_SHIELD); await game.phaseInterceptor.to(TurnEndPhase); expect(magikarp.summonData.battleStats[BattleStat.DEF]).toBe(0); @@ -64,8 +63,8 @@ describe("Moves - Flower Shield", () => { grassPokemons.forEach(p => expect(p.summonData.battleStats[BattleStat.DEF]).toBe(0)); nonGrassPokemons.forEach(p => expect(p.summonData.battleStats[BattleStat.DEF]).toBe(0)); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLOWER_SHIELD)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FLOWER_SHIELD); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); grassPokemons.forEach(p => expect(p.summonData.battleStats[BattleStat.DEF]).toBe(1)); @@ -88,7 +87,7 @@ describe("Moves - Flower Shield", () => { expect(cherrim.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(paras.getTag(SemiInvulnerableTag)).toBeUndefined; - game.doAttack(getMovePosition(game.scene, 0, Moves.FLOWER_SHIELD)); + game.move.select(Moves.FLOWER_SHIELD); await game.phaseInterceptor.to(TurnEndPhase); expect(paras.getTag(SemiInvulnerableTag)).toBeDefined(); @@ -106,7 +105,7 @@ describe("Moves - Flower Shield", () => { expect(enemy.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(ally.summonData.battleStats[BattleStat.DEF]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.FLOWER_SHIELD)); + game.move.select(Moves.FLOWER_SHIELD); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.summonData.battleStats[BattleStat.DEF]).toBe(0); diff --git a/src/test/moves/focus_punch.test.ts b/src/test/moves/focus_punch.test.ts index 385234f0b71..99399623a1c 100644 --- a/src/test/moves/focus_punch.test.ts +++ b/src/test/moves/focus_punch.test.ts @@ -1,16 +1,15 @@ -import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { Species } from "#enums/species"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { MoveHeaderPhase } from "#app/phases/move-header-phase"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { MoveHeaderPhase } from "#app/phases/move-header-phase.js"; -import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; const TIMEOUT = 20 * 1000; @@ -51,7 +50,7 @@ describe("Moves - Focus Punch", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + game.move.select(Moves.FOCUS_PUNCH); await game.phaseInterceptor.to(MessagePhase); @@ -78,7 +77,7 @@ describe("Moves - Focus Punch", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + game.move.select(Moves.FOCUS_PUNCH); await game.phaseInterceptor.to(MessagePhase); @@ -103,7 +102,7 @@ describe("Moves - Focus Punch", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + game.move.select(Moves.FOCUS_PUNCH); await game.phaseInterceptor.to(MessagePhase); // Header message @@ -125,7 +124,7 @@ describe("Moves - Focus Punch", () => { await game.startBattle([Species.CHARIZARD]); game.forceOpponentToSwitch(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + game.move.select(Moves.FOCUS_PUNCH); await game.phaseInterceptor.to(TurnStartPhase); diff --git a/src/test/moves/follow_me.test.ts b/src/test/moves/follow_me.test.ts index a0fff9afbf8..d7ef199df3e 100644 --- a/src/test/moves/follow_me.test.ts +++ b/src/test/moves/follow_me.test.ts @@ -1,15 +1,12 @@ -import { BattlerIndex } from "#app/battle.js"; +import { BattlerIndex } from "#app/battle"; import { Stat } from "#app/data/pokemon-stat"; -import { Abilities } from "#app/enums/abilities.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Abilities } from "#app/enums/abilities"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -34,32 +31,21 @@ describe("Moves - Follow Me", () => { game.override.enemySpecies(Species.SNORLAX); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.moveset([Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); test( "move should redirect enemy attacks to the user", async () => { - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); - - const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const playerStartingHp = playerPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(Moves.FOLLOW_ME); + game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY); await game.phaseInterceptor.to(TurnEndPhase, false); expect(playerPokemon[0].hp).toBeLessThan(playerStartingHp[0]); @@ -70,22 +56,14 @@ describe("Moves - Follow Me", () => { test( "move should redirect enemy attacks to the first ally that uses it", async () => { - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); - - const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const playerStartingHp = playerPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.FOLLOW_ME)); + game.move.select(Moves.FOLLOW_ME); + game.move.select(Moves.FOLLOW_ME, 1); await game.phaseInterceptor.to(TurnEndPhase, false); playerPokemon.sort((a, b) => a.getBattleStat(Stat.SPD) - b.getBattleStat(Stat.SPD)); @@ -99,29 +77,17 @@ describe("Moves - Follow Me", () => { "move effect should be bypassed by Stalwart", async () => { game.override.ability(Abilities.STALWART); - game.override.moveset([ Moves.QUICK_ATTACK ]); - game.override.enemyMoveset([ Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME ]); + game.override.moveset([Moves.QUICK_ATTACK]); + game.override.enemyMoveset([Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME]); - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.QUICK_ATTACK, 0, BattlerIndex.ENEMY); + game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to(TurnEndPhase, false); // If redirection was bypassed, both enemies should be damaged @@ -133,29 +99,17 @@ describe("Moves - Follow Me", () => { test( "move effect should be bypassed by Snipe Shot", async () => { - game.override.moveset([ Moves.SNIPE_SHOT ]); - game.override.enemyMoveset([ Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME ]); + game.override.moveset([Moves.SNIPE_SHOT]); + game.override.enemyMoveset([Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME]); - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.SNIPE_SHOT)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.SNIPE_SHOT)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.SNIPE_SHOT, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SNIPE_SHOT, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to(TurnEndPhase, false); // If redirection was bypassed, both enemies should be damaged diff --git a/src/test/moves/foresight.test.ts b/src/test/moves/foresight.test.ts index 91d3e3c37e0..b856ec0f852 100644 --- a/src/test/moves/foresight.test.ts +++ b/src/test/moves/foresight.test.ts @@ -1,11 +1,10 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager"; -import { Species } from "#app/enums/species.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { Moves } from "#app/enums/moves.js"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Moves - Foresight", () => { let phaserGame: Phaser.Game; @@ -37,19 +36,19 @@ describe("Moves - Foresight", () => { const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.toNextTurn(); expect(enemy.hp).toBe(enemy.getMaxHp()); - game.doAttack(getMovePosition(game.scene, 0, Moves.FORESIGHT)); + game.move.select(Moves.FORESIGHT); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.toNextTurn(); expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); enemy.hp = enemy.getMaxHp(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MACH_PUNCH)); + game.move.select(Moves.MACH_PUNCH); await game.phaseInterceptor.to(MoveEffectPhase); expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); @@ -62,9 +61,9 @@ describe("Moves - Foresight", () => { const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getAccuracyMultiplier"); - game.doAttack(getMovePosition(game.scene, 0, Moves.FORESIGHT)); + game.move.select(Moves.FORESIGHT); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + game.move.select(Moves.QUICK_ATTACK); await game.phaseInterceptor.to(MoveEffectPhase); expect(pokemon.getAccuracyMultiplier).toHaveReturnedWith(1); diff --git a/src/test/moves/freezy_frost.test.ts b/src/test/moves/freezy_frost.test.ts index b4c30279c21..00d7104d373 100644 --- a/src/test/moves/freezy_frost.test.ts +++ b/src/test/moves/freezy_frost.test.ts @@ -1,15 +1,14 @@ import { BattleStat } from "#app/data/battle-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { allMoves } from "#app/data/move.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Freezy Frost", () => { describe("integration tests", () => { @@ -47,17 +46,17 @@ describe("Moves - Freezy Frost", () => { expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + game.move.select(Moves.SWORDS_DANCE); await game.phaseInterceptor.to(TurnInitPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + game.move.select(Moves.CHARM); await game.phaseInterceptor.to(TurnInitPhase); const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK]; expect(userAtkBefore).toBe(2); expect(enemyAtkBefore).toBe(-2); - game.doAttack(getMovePosition(game.scene, 0, Moves.FREEZY_FROST)); + game.move.select(Moves.FREEZY_FROST); await game.phaseInterceptor.to(TurnInitPhase); expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -69,13 +68,13 @@ describe("Moves - Freezy Frost", () => { const user = game.scene.getPlayerPokemon()!; expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + game.move.select(Moves.SWORDS_DANCE); await game.phaseInterceptor.to(TurnInitPhase); const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; expect(userAtkBefore).toBe(2); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(MoveEndPhase); expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); }); diff --git a/src/test/moves/fusion_bolt.test.ts b/src/test/moves/fusion_bolt.test.ts index c7a21e2c736..db31863ad03 100644 --- a/src/test/moves/fusion_bolt.test.ts +++ b/src/test/moves/fusion_bolt.test.ts @@ -1,10 +1,9 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Species } from "#enums/species"; -import { Moves } from "#enums/moves"; import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Moves - Fusion Bolt", () => { let phaserGame: Phaser.Game; @@ -24,19 +23,19 @@ describe("Moves - Fusion Bolt", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.moveset([ fusionBolt ]); + game.override.moveset([fusionBolt]); game.override.startingLevel(1); game.override.enemySpecies(Species.RESHIRAM); game.override.enemyAbility(Abilities.ROUGH_SKIN); - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); game.override.battleType("single"); game.override.startingWave(97); game.override.disableCrits(); }); - it("should not make contact", async() => { + it("should not make contact", async () => { await game.startBattle([ Species.ZEKROM, ]); @@ -44,7 +43,7 @@ describe("Moves - Fusion Bolt", () => { const partyMember = game.scene.getPlayerPokemon()!; const initialHp = partyMember.hp; - game.doAttack(getMovePosition(game.scene, 0, fusionBolt)); + game.move.select(fusionBolt); await game.toNextTurn(); diff --git a/src/test/moves/fusion_flare.test.ts b/src/test/moves/fusion_flare.test.ts index aa38357ddd3..471f6a2ac7b 100644 --- a/src/test/moves/fusion_flare.test.ts +++ b/src/test/moves/fusion_flare.test.ts @@ -1,11 +1,10 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { StatusEffect } from "#app/data/status-effect"; -import { Species } from "#enums/species"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Moves } from "#enums/moves"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Moves - Fusion Flare", () => { let phaserGame: Phaser.Game; @@ -25,25 +24,25 @@ describe("Moves - Fusion Flare", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.moveset([ fusionFlare ]); + game.override.moveset([fusionFlare]); game.override.startingLevel(1); game.override.enemySpecies(Species.RESHIRAM); - game.override.enemyMoveset([ Moves.REST, Moves.REST, Moves.REST, Moves.REST ]); + game.override.enemyMoveset([Moves.REST, Moves.REST, Moves.REST, Moves.REST]); game.override.battleType("single"); game.override.startingWave(97); game.override.disableCrits(); }); - it("should thaw freeze status condition", async() => { + it("should thaw freeze status condition", async () => { await game.startBattle([ Species.RESHIRAM, ]); const partyMember = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, fusionFlare)); + game.move.select(fusionFlare); await game.phaseInterceptor.to(TurnStartPhase, false); diff --git a/src/test/moves/fusion_flare_bolt.test.ts b/src/test/moves/fusion_flare_bolt.test.ts index 1b95062ee81..ebef5148778 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -1,16 +1,15 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Stat } from "#app/data/pokemon-stat"; -import { allMoves } from "#app/data/move"; import { BattlerIndex } from "#app/battle"; -import { Species } from "#enums/species"; +import { allMoves } from "#app/data/move"; +import { Stat } from "#app/data/pokemon-stat"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { MovePhase } from "#app/phases/move-phase"; import { Moves } from "#enums/moves"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Moves - Fusion Flare and Fusion Bolt", () => { let phaserGame: Phaser.Game; @@ -31,11 +30,11 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.moveset([ fusionFlare.id, fusionBolt.id ]); + game.override.moveset([fusionFlare.id, fusionBolt.id]); game.override.startingLevel(1); game.override.enemySpecies(Species.RESHIRAM); - game.override.enemyMoveset([ Moves.REST, Moves.REST, Moves.REST, Moves.REST ]); + game.override.enemyMoveset([Moves.REST, Moves.REST, Moves.REST, Moves.REST]); game.override.battleType("double"); game.override.startingWave(97); @@ -45,20 +44,17 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { vi.spyOn(fusionBolt, "calculateBattlePower"); }); - it("FUSION_FLARE should double power of subsequent FUSION_BOLT", async() => { + it("FUSION_FLARE should double power of subsequent FUSION_BOLT", async () => { await game.startBattle([ Species.ZEKROM, Species.ZEKROM ]); - game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(fusionFlare.id, 0, BattlerIndex.ENEMY); + game.move.select(fusionBolt.id, 1, BattlerIndex.ENEMY); // Force user party to act before enemy party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -71,20 +67,17 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("FUSION_BOLT should double power of subsequent FUSION_FLARE", async() => { + it("FUSION_BOLT should double power of subsequent FUSION_FLARE", async () => { await game.startBattle([ Species.ZEKROM, Species.ZEKROM ]); - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(fusionBolt.id, 0, BattlerIndex.ENEMY); + game.move.select(fusionFlare.id, 1, BattlerIndex.ENEMY); // Force user party to act before enemy party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -97,20 +90,17 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("FUSION_FLARE should double power of subsequent FUSION_BOLT if a move failed in between", async() => { + it("FUSION_FLARE should double power of subsequent FUSION_BOLT if a move failed in between", async () => { await game.startBattle([ Species.ZEKROM, Species.ZEKROM ]); - game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); - game.doSelectTarget(0); - - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(0); + game.move.select(fusionFlare.id, 0, BattlerIndex.PLAYER); + game.move.select(fusionBolt.id, 1, BattlerIndex.PLAYER); // Force first enemy to act (and fail) in between party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -128,21 +118,18 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("FUSION_FLARE should not double power of subsequent FUSION_BOLT if a move succeeded in between", async() => { - game.override.enemyMoveset([ Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH ]); + it("FUSION_FLARE should not double power of subsequent FUSION_BOLT if a move succeeded in between", async () => { + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); await game.startBattle([ Species.ZEKROM, Species.ZEKROM ]); - game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(fusionFlare.id, 0, BattlerIndex.ENEMY); + game.move.select(fusionBolt.id, 1, BattlerIndex.ENEMY); // Force first enemy to act in between party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -159,20 +146,17 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); - it("FUSION_FLARE should double power of subsequent FUSION_BOLT if moves are aimed at allies", async() => { + it("FUSION_FLARE should double power of subsequent FUSION_BOLT if moves are aimed at allies", async () => { await game.startBattle([ Species.ZEKROM, Species.RESHIRAM ]); - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.PLAYER_2); - - game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); - game.doSelectTarget(BattlerIndex.PLAYER); + game.move.select(fusionBolt.id, 0, BattlerIndex.PLAYER_2); + game.move.select(fusionFlare.id, 1, BattlerIndex.PLAYER); // Force user party to act before enemy party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -185,8 +169,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("FUSION_FLARE and FUSION_BOLT alternating throughout turn should double power of subsequent moves", async() => { - game.override.enemyMoveset([ fusionFlare.id, fusionFlare.id, fusionFlare.id, fusionFlare.id ]); + it("FUSION_FLARE and FUSION_BOLT alternating throughout turn should double power of subsequent moves", async () => { + game.override.enemyMoveset([fusionFlare.id, fusionFlare.id, fusionFlare.id, fusionFlare.id]); await game.startBattle([ Species.ZEKROM, Species.ZEKROM @@ -217,14 +201,11 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { vi.spyOn(party[1], "stats", "get").mockReturnValue(stats.player[0].map((val, i) => (i === Stat.SPDEF ? 250 : val))); vi.spyOn(party[1], "stats", "get").mockReturnValue(stats.player[1].map((val, i) => (i === Stat.SPDEF ? 250 : val))); - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.ENEMY); + game.move.select(fusionBolt.id, 0, BattlerIndex.ENEMY); + game.move.select(fusionBolt.id, 1, BattlerIndex.ENEMY); // Force first enemy to act in between party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -247,8 +228,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); - it("FUSION_FLARE and FUSION_BOLT alternating throughout turn should double power of subsequent moves if moves are aimed at allies", async() => { - game.override.enemyMoveset([ fusionFlare.id, fusionFlare.id, fusionFlare.id, fusionFlare.id ]); + it("FUSION_FLARE and FUSION_BOLT alternating throughout turn should double power of subsequent moves if moves are aimed at allies", async () => { + game.override.enemyMoveset([fusionFlare.id, fusionFlare.id, fusionFlare.id, fusionFlare.id]); await game.startBattle([ Species.ZEKROM, Species.ZEKROM @@ -279,14 +260,11 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { vi.spyOn(party[1], "stats", "get").mockReturnValue(stats.player[0].map((val, i) => (i === Stat.SPDEF ? 250 : val))); vi.spyOn(party[1], "stats", "get").mockReturnValue(stats.player[1].map((val, i) => (i === Stat.SPDEF ? 250 : val))); - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.PLAYER_2); - - game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); - game.doSelectTarget(BattlerIndex.PLAYER); + game.move.select(fusionBolt.id, 0, BattlerIndex.PLAYER_2); + game.move.select(fusionBolt.id, 1, BattlerIndex.PLAYER); // Force first enemy to act in between party - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts index cc247890754..67fd3464cf9 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -1,12 +1,11 @@ -import { BattlerIndex } from "#app/battle.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; -import { MoveResult } from "#app/field/pokemon.js"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { BattlerIndex } from "#app/battle"; +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveResult } from "#app/field/pokemon"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; const TIMEOUT = 20 * 1000; @@ -46,10 +45,8 @@ describe("Moves - Gastro Acid", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID)); - game.doSelectTarget(BattlerIndex.ENEMY); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doSelectTarget(BattlerIndex.PLAYER_2); + game.move.select(Moves.GASTRO_ACID, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to("TurnInitPhase"); @@ -57,10 +54,8 @@ describe("Moves - Gastro Acid", () => { expect(enemyField[0].summonData.abilitySuppressed).toBe(true); expect(enemyField[1].summonData.abilitySuppressed).toBe(false); - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); - game.doSelectTarget(BattlerIndex.ENEMY); - game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.WATER_GUN, 0, BattlerIndex.ENEMY); + game.move.select(Moves.WATER_GUN, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to("TurnEndPhase"); @@ -73,13 +68,13 @@ describe("Moves - Gastro Acid", () => { await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER)); + game.move.select(Moves.CORE_ENFORCER); // Force player to be slower to enable Core Enforcer to proc its suppression effect await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnInitPhase"); - game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID)); + game.move.select(Moves.GASTRO_ACID); await game.phaseInterceptor.to("TurnInitPhase"); diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts index f97ba1f0367..1eac3c32bb4 100644 --- a/src/test/moves/glaive_rush.test.ts +++ b/src/test/moves/glaive_rush.test.ts @@ -1,13 +1,12 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Glaive Rush", () => { @@ -37,36 +36,36 @@ describe("Moves - Glaive Rush", () => { game.override.moveset([Moves.SHADOW_SNEAK, Moves.AVALANCHE, Moves.SPLASH, Moves.GLAIVE_RUSH]); }); - it("takes double damage from attacks", async() => { + it("takes double damage from attacks", async () => { await game.startBattle(); const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; vi.spyOn(game.scene, "randBattleSeedInt").mockReturnValue(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK)); + game.move.select(Moves.SHADOW_SNEAK); await game.phaseInterceptor.to(DamagePhase); const damageDealt = 1000 - enemy.hp; await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK)); + game.move.select(Moves.SHADOW_SNEAK); await game.phaseInterceptor.to(DamagePhase); expect(enemy.hp).toBeLessThanOrEqual(1001 - (damageDealt * 3)); }, 5000); // TODO: revert back to 20s - it("always gets hit by attacks", async() => { + it("always gets hit by attacks", async () => { await game.startBattle(); const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; allMoves[Moves.AVALANCHE].accuracy = 0; - game.doAttack(getMovePosition(game.scene, 0, Moves.AVALANCHE)); + game.move.select(Moves.AVALANCHE); await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.hp).toBeLessThan(1000); }, 20000); - it("interacts properly with multi-lens", async() => { - game.override.startingHeldItems([{name: "MULTI_LENS", count: 2}]); + it("interacts properly with multi-lens", async () => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 2 }]); game.override.enemyMoveset(Array(4).fill(Moves.AVALANCHE)); await game.startBattle(); const player = game.scene.getPlayerPokemon()!; @@ -75,17 +74,17 @@ describe("Moves - Glaive Rush", () => { player.hp = 1000; allMoves[Moves.AVALANCHE].accuracy = 0; - game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH)); + game.move.select(Moves.GLAIVE_RUSH); await game.phaseInterceptor.to(TurnEndPhase); expect(player.hp).toBeLessThan(1000); player.hp = 1000; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(player.hp).toBe(1000); }, 20000); - it("secondary effects only last until next move", async() => { + it("secondary effects only last until next move", async () => { game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK)); await game.startBattle(); const player = game.scene.getPlayerPokemon()!; @@ -94,22 +93,22 @@ describe("Moves - Glaive Rush", () => { player.hp = 1000; allMoves[Moves.SHADOW_SNEAK].accuracy = 0; - game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH)); + game.move.select(Moves.GLAIVE_RUSH); await game.phaseInterceptor.to(TurnEndPhase); expect(player.hp).toBe(1000); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); const damagedHp = player.hp; expect(player.hp).toBeLessThan(1000); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(player.hp).toBe(damagedHp); }, 20000); - it("secondary effects are removed upon switching", async() => { + it("secondary effects are removed upon switching", async () => { game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK)); game.override.starterSpecies(0); await game.startBattle([Species.KLINK, Species.FEEBAS]); @@ -118,7 +117,7 @@ describe("Moves - Glaive Rush", () => { enemy.hp = 1000; allMoves[Moves.SHADOW_SNEAK].accuracy = 0; - game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH)); + game.move.select(Moves.GLAIVE_RUSH); await game.phaseInterceptor.to(TurnEndPhase); expect(player.hp).toBe(player.getMaxHp()); @@ -130,7 +129,7 @@ describe("Moves - Glaive Rush", () => { }, 20000); - it("secondary effects don't activate if move fails", async() => { + it("secondary effects don't activate if move fails", async () => { game.override.moveset([Moves.SHADOW_SNEAK, Moves.PROTECT, Moves.SPLASH, Moves.GLAIVE_RUSH]); await game.startBattle(); const player = game.scene.getPlayerPokemon()!; @@ -138,16 +137,16 @@ describe("Moves - Glaive Rush", () => { enemy.hp = 1000; player.hp = 1000; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK)); + game.move.select(Moves.SHADOW_SNEAK); await game.phaseInterceptor.to(TurnEndPhase); game.override.enemyMoveset(Array(4).fill(Moves.SPLASH)); const damagedHP1 = 1000 - enemy.hp; enemy.hp = 1000; - game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK)); + game.move.select(Moves.SHADOW_SNEAK); await game.phaseInterceptor.to(TurnEndPhase); const damagedHP2 = 1000 - enemy.hp; diff --git a/src/test/moves/growth.test.ts b/src/test/moves/growth.test.ts index 0c60bb723f4..dfbf5406351 100644 --- a/src/test/moves/growth.test.ts +++ b/src/test/moves/growth.test.ts @@ -1,17 +1,13 @@ import { BattleStat } from "#app/data/battle-stat"; import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Growth", () => { @@ -37,10 +33,10 @@ describe("Moves - Growth", () => { game.override.ability(Abilities.INSOMNIA); game.override.startingLevel(2000); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("GROWTH", async() => { + it("GROWTH", async () => { const moveToUse = Moves.GROWTH; await game.startBattle([ Species.MIGHTYENA, @@ -52,13 +48,7 @@ describe("Moves - Growth", () => { const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.SPATK]).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.SPATK]).toBe(1); diff --git a/src/test/moves/hard_press.test.ts b/src/test/moves/hard_press.test.ts index 255b9f1f4b1..70c78490269 100644 --- a/src/test/moves/hard_press.test.ts +++ b/src/test/moves/hard_press.test.ts @@ -1,13 +1,12 @@ -import { allMoves } from "#app/data/move.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { allMoves } from "#app/data/move"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Hard Press", () => { let phaserGame: Phaser.Game; @@ -39,7 +38,7 @@ describe("Moves - Hard Press", () => { it("should return 100 power if target HP ratio is at 100%", async () => { await game.startBattle([Species.PIKACHU]); - game.doAttack(getMovePosition(game.scene, 0, Moves.HARD_PRESS)); + game.move.select(Moves.HARD_PRESS); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(100); @@ -52,7 +51,7 @@ describe("Moves - Hard Press", () => { vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); - game.doAttack(getMovePosition(game.scene, 0, Moves.HARD_PRESS)); + game.move.select(Moves.HARD_PRESS); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(50); @@ -65,7 +64,7 @@ describe("Moves - Hard Press", () => { vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); - game.doAttack(getMovePosition(game.scene, 0, Moves.HARD_PRESS)); + game.move.select(Moves.HARD_PRESS); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(1); @@ -78,7 +77,7 @@ describe("Moves - Hard Press", () => { vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); - game.doAttack(getMovePosition(game.scene, 0, Moves.HARD_PRESS)); + game.move.select(Moves.HARD_PRESS); await game.phaseInterceptor.to(MoveEffectPhase); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(1); diff --git a/src/test/moves/haze.test.ts b/src/test/moves/haze.test.ts index d5e3efcbd9d..8a32a40cb32 100644 --- a/src/test/moves/haze.test.ts +++ b/src/test/moves/haze.test.ts @@ -1,14 +1,13 @@ import { BattleStat } from "#app/data/battle-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Haze", () => { describe("integration tests", () => { @@ -45,17 +44,17 @@ describe("Moves - Haze", () => { expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + game.move.select(Moves.SWORDS_DANCE); await game.phaseInterceptor.to(TurnInitPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + game.move.select(Moves.CHARM); await game.phaseInterceptor.to(TurnInitPhase); const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK]; expect(userAtkBefore).toBe(2); expect(enemyAtkBefore).toBe(-2); - game.doAttack(getMovePosition(game.scene, 0, Moves.HAZE)); + game.move.select(Moves.HAZE); await game.phaseInterceptor.to(TurnInitPhase); expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -67,13 +66,13 @@ describe("Moves - Haze", () => { const user = game.scene.getPlayerPokemon()!; expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + game.move.select(Moves.SWORDS_DANCE); await game.phaseInterceptor.to(TurnInitPhase); const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; expect(userAtkBefore).toBe(2); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(MoveEndPhase); expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); }); diff --git a/src/test/moves/hyper_beam.test.ts b/src/test/moves/hyper_beam.test.ts index ac8075081fb..1280d8b429a 100644 --- a/src/test/moves/hyper_beam.test.ts +++ b/src/test/moves/hyper_beam.test.ts @@ -1,14 +1,13 @@ -import { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; // 20 sec timeout for all tests @@ -48,7 +47,7 @@ describe("Moves - Hyper Beam", () => { const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); + game.move.select(Moves.HYPER_BEAM); await game.phaseInterceptor.to(TurnEndPhase); @@ -63,7 +62,7 @@ describe("Moves - Hyper Beam", () => { expect(enemyPokemon.hp).toBe(enemyPostAttackHp); expect(leadPokemon.getTag(BattlerTagType.RECHARGING)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); + game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/jaw_lock.test.ts b/src/test/moves/jaw_lock.test.ts index 4fe996588e4..42f7a244977 100644 --- a/src/test/moves/jaw_lock.test.ts +++ b/src/test/moves/jaw_lock.test.ts @@ -1,17 +1,16 @@ +import { BattlerIndex } from "#app/battle"; import { Abilities } from "#app/enums/abilities"; import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { FaintPhase } from "#app/phases/faint-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#app/test/utils/gameManager"; -import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +import { SPLASH_ONLY } from "#app/test/utils/testUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#app/test/utils/testUtils"; -import { BattlerIndex } from "#app/battle"; -import { FaintPhase } from "#app/phases/faint-phase"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase"; -import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { BerryPhase } from "#app/phases/berry-phase"; const TIMEOUT = 20 * 1000; @@ -46,12 +45,13 @@ describe("Moves - Jaw Lock", () => { it( "should trap the move's user and target", async () => { - await game.startBattle([ Species.BULBASAUR ]); + await game.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.move.select(Moves.JAW_LOCK); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -69,12 +69,13 @@ describe("Moves - Jaw Lock", () => { "should not trap either pokemon if the target faints", async () => { game.override.enemyLevel(1); - await game.startBattle([ Species.BULBASAUR ]); + await game.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.move.select(Moves.JAW_LOCK); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -96,12 +97,13 @@ describe("Moves - Jaw Lock", () => { it( "should only trap the user until the target faints", async () => { - await game.startBattle([ Species.BULBASAUR ]); + await game.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.move.select(Moves.JAW_LOCK); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase); @@ -121,15 +123,14 @@ describe("Moves - Jaw Lock", () => { async () => { game.override.battleType("double"); - await game.startBattle([ Species.CHARMANDER, Species.BULBASAUR ]); + await game.startBattle([Species.CHARMANDER, Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); - game.doSelectTarget(BattlerIndex.ENEMY); - - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.JAW_LOCK, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase); @@ -138,10 +139,8 @@ describe("Moves - Jaw Lock", () => { await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); - game.doSelectTarget(BattlerIndex.ENEMY_2); - - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.JAW_LOCK, 0, BattlerIndex.ENEMY_2); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); @@ -156,12 +155,12 @@ describe("Moves - Jaw Lock", () => { async () => { game.override.enemyMoveset(Array(4).fill(Moves.PROTECT)); - await game.startBattle([ Species.BULBASAUR ]); + await game.startBattle([Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.JAW_LOCK)); + game.move.select(Moves.JAW_LOCK); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/light_screen.test.ts b/src/test/moves/light_screen.test.ts index 4577ffc574a..e94dc4a299e 100644 --- a/src/test/moves/light_screen.test.ts +++ b/src/test/moves/light_screen.test.ts @@ -1,14 +1,13 @@ -import { ArenaTagSide } from "#app/data/arena-tag.js"; -import Move, { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { NumberHolder } from "#app/utils.js"; +import { ArenaTagSide } from "#app/data/arena-tag"; +import Move, { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import Pokemon from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { NumberHolder } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -17,7 +16,7 @@ describe("Moves - Light Screen", () => { let phaserGame: Phaser.Game; let game: GameManager; const singleBattleMultiplier = 0.5; - const doubleBattleMultiplier = 2732/4096; + const doubleBattleMultiplier = 2732 / 4096; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -40,11 +39,11 @@ describe("Moves - Light Screen", () => { game.override.disableCrits(); }); - it("reduces damage of special attacks by half in a single battle", async() => { + it("reduces damage of special attacks by half in a single battle", async () => { const moveToUse = Moves.ABSORB; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); @@ -53,14 +52,14 @@ describe("Moves - Light Screen", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); - it("reduces damage of special attacks by a third in a double battle", async() => { + it("reduces damage of special attacks by a third in a double battle", async () => { game.override.battleType("double"); const moveToUse = Moves.DAZZLING_GLEAM; await game.startBattle([Species.SHUCKLE, Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); - game.doAttack(getMovePosition(game.scene, 1, moveToUse)); + game.move.select(moveToUse); + game.move.select(moveToUse, 1); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); @@ -68,11 +67,11 @@ describe("Moves - Light Screen", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); - it("does not affect physical attacks", async() => { + it("does not affect physical attacks", async () => { const moveToUse = Moves.TACKLE; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); diff --git a/src/test/moves/lucky_chant.test.ts b/src/test/moves/lucky_chant.test.ts index 643a5eddb00..7d5bfe02476 100644 --- a/src/test/moves/lucky_chant.test.ts +++ b/src/test/moves/lucky_chant.test.ts @@ -1,12 +1,11 @@ +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "../utils/gameManager"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -44,13 +43,13 @@ describe("Moves - Lucky Chant", () => { const playerPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); const firstTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.LUCKY_CHANT)); + game.move.select(Moves.LUCKY_CHANT); await game.phaseInterceptor.to(BerryPhase, false); @@ -68,15 +67,15 @@ describe("Moves - Lucky Chant", () => { const playerPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.FOLLOW_ME); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); const firstTurnDamage = playerPokemon[0].getMaxHp() - playerPokemon[0].hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); - game.doAttack(getMovePosition(game.scene, 1, Moves.LUCKY_CHANT)); + game.move.select(Moves.FOLLOW_ME); + game.move.select(Moves.LUCKY_CHANT, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -97,13 +96,13 @@ describe("Moves - Lucky Chant", () => { enemyPokemon.addTag(BattlerTagType.ALWAYS_CRIT, 2, Moves.NONE, 0); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); const firstTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.LUCKY_CHANT)); + game.move.select(Moves.LUCKY_CHANT); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/magnet_rise.test.ts b/src/test/moves/magnet_rise.test.ts index 4ab32b5d048..9037e377090 100644 --- a/src/test/moves/magnet_rise.test.ts +++ b/src/test/moves/magnet_rise.test.ts @@ -1,14 +1,15 @@ -import GameManager from "#test/utils/gameManager"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Magnet Rise", () => { let phaserGame: Phaser.Game; let game: GameManager; + const moveToUse = Moves.MAGNET_RISE; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -22,7 +23,6 @@ describe("Moves - Magnet Rise", () => { beforeEach(() => { game = new GameManager(phaserGame); - const moveToUse = Moves.MAGNET_RISE; game.override.battleType("single"); game.override.starterSpecies(Species.MAGNEZONE); game.override.enemySpecies(Species.RATTATA); @@ -36,7 +36,7 @@ describe("Moves - Magnet Rise", () => { await game.startBattle(); const startingHp = game.scene.getParty()[0].hp; - game.doAttack(0); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); const finalHp = game.scene.getParty()[0].hp; const hpLost = finalHp - startingHp; @@ -47,12 +47,12 @@ describe("Moves - Magnet Rise", () => { await game.startBattle(); const startingHp = game.scene.getParty()[0].hp; - game.doAttack(0); + game.move.select(moveToUse); await game.phaseInterceptor.to(CommandPhase); let finalHp = game.scene.getParty()[0].hp; let hpLost = finalHp - startingHp; expect(hpLost).toBe(0); - game.doAttack(2); + game.move.select(Moves.GRAVITY); await game.phaseInterceptor.to(TurnEndPhase); finalHp = game.scene.getParty()[0].hp; hpLost = finalHp - startingHp; diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts index 5b0a8c6d62a..0af7763f175 100644 --- a/src/test/moves/make_it_rain.test.ts +++ b/src/test/moves/make_it_rain.test.ts @@ -1,14 +1,13 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { StatChangePhase } from "#app/phases/stat-change-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { StatChangePhase } from "#app/phases/stat-change-phase.js"; const TIMEOUT = 20 * 1000; @@ -42,8 +41,8 @@ describe("Moves - Make It Rain", () => { const playerPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.MAKE_IT_RAIN); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEndPhase); @@ -59,7 +58,7 @@ describe("Moves - Make It Rain", () => { const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); + game.move.select(Moves.MAKE_IT_RAIN); await game.phaseInterceptor.to(StatChangePhase); @@ -75,8 +74,8 @@ describe("Moves - Make It Rain", () => { const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.MAKE_IT_RAIN); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(StatChangePhase); @@ -89,8 +88,8 @@ describe("Moves - Make It Rain", () => { const playerPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.MAKE_IT_RAIN); + game.move.select(Moves.SPLASH, 1); // Make Make It Rain miss the first target await game.move.forceMiss(true); diff --git a/src/test/moves/mat_block.test.ts b/src/test/moves/mat_block.test.ts index 27a55cab289..29a97806242 100644 --- a/src/test/moves/mat_block.test.ts +++ b/src/test/moves/mat_block.test.ts @@ -1,14 +1,13 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "../utils/gameManager"; -import { Species } from "#enums/species"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -48,11 +47,11 @@ describe("Moves - Mat Block", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAT_BLOCK)); + game.move.select(Moves.MAT_BLOCK); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -69,11 +68,11 @@ describe("Moves - Mat Block", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAT_BLOCK)); + game.move.select(Moves.MAT_BLOCK); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -88,18 +87,18 @@ describe("Moves - Mat Block", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); const leadStartingHp = leadPokemon.map(p => p.hp); await game.phaseInterceptor.to(CommandPhase, false); - game.doAttack(getMovePosition(game.scene, 0, Moves.MAT_BLOCK)); + game.move.select(Moves.MAT_BLOCK); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.MAT_BLOCK)); + game.move.select(Moves.MAT_BLOCK, 1); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts index 3e1e151e7d4..f47e4ce0c16 100644 --- a/src/test/moves/miracle_eye.test.ts +++ b/src/test/moves/miracle_eye.test.ts @@ -1,12 +1,11 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; +import { BattlerIndex } from "#app/battle"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import GameManager from "#test/utils/gameManager"; -import { Species } from "#app/enums/species.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { Moves } from "#app/enums/moves.js"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattlerIndex } from "#app/battle.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; describe("Moves - Miracle Eye", () => { let phaserGame: Phaser.Game; @@ -38,14 +37,14 @@ describe("Moves - Miracle Eye", () => { const enemy = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); + game.move.select(Moves.CONFUSION); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); expect(enemy.hp).toBe(enemy.getMaxHp()); - game.doAttack(getMovePosition(game.scene, 0, Moves.MIRACLE_EYE)); + game.move.select(Moves.MIRACLE_EYE); await game.toNextTurn(); - game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); + game.move.select(Moves.CONFUSION); await game.phaseInterceptor.to(MoveEffectPhase); expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); diff --git a/src/test/moves/multi_target.test.ts b/src/test/moves/multi_target.test.ts index 6e8a7c99e9b..b8c1f67b3df 100644 --- a/src/test/moves/multi_target.test.ts +++ b/src/test/moves/multi_target.test.ts @@ -1,13 +1,12 @@ -import { getMoveTargets } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { Species } from "#app/enums/species.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; +import { getMoveTargets } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { Species } from "#app/enums/species"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -95,8 +94,8 @@ async function checkDamageDecrease(game: GameManager, attackMove: Moves, killAll game.scene.getEnemyField()[1].abilityIndex = ability; } - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -105,9 +104,9 @@ async function checkDamageDecrease(game: GameManager, attackMove: Moves, killAll await game.toNextTurn(); const initialHp = game.scene.getEnemyField()[0].hp; - game.doAttack(getMovePosition(game.scene, 0, attackMove)); + game.move.select(attackMove); if (!killAlly) { - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); } await game.phaseInterceptor.to(TurnEndPhase); @@ -119,7 +118,7 @@ async function checkDamageDecrease(game: GameManager, attackMove: Moves, killAll game.scene.getEnemyField()[0].hp = initialHp; const initialHp1v1 = game.scene.getEnemyField()[0].hp; - game.doAttack(getMovePosition(game.scene, 0, attackMove)); + game.move.select(attackMove); await game.phaseInterceptor.to(TurnEndPhase); const afterHp1v1 = game.scene.getEnemyField()[0].hp; diff --git a/src/test/moves/octolock.test.ts b/src/test/moves/octolock.test.ts index fcd68446eff..389e4a4c4cf 100644 --- a/src/test/moves/octolock.test.ts +++ b/src/test/moves/octolock.test.ts @@ -1,16 +1,15 @@ import { BattleStat } from "#app/data/battle-stat"; -import { TrappedTag } from "#app/data/battler-tags.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { TrappedTag } from "#app/data/battler-tags"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Octolock", () => { describe("integration tests", () => { @@ -47,7 +46,7 @@ describe("Moves - Octolock", () => { const enemyPokemon = game.scene.getEnemyField(); // use Octolock and advance to init phase of next turn to check for stat changes - game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK)); + game.move.select(Moves.OCTOLOCK); await game.phaseInterceptor.to(TurnInitPhase); expect(enemyPokemon[0].summonData.battleStats[BattleStat.DEF]).toBe(-1); @@ -55,7 +54,7 @@ describe("Moves - Octolock", () => { // take a second turn to make sure stat changes occur again await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnInitPhase); expect(enemyPokemon[0].summonData.battleStats[BattleStat.DEF]).toBe(-2); @@ -70,7 +69,7 @@ describe("Moves - Octolock", () => { // before Octolock - enemy should not be trapped expect(enemyPokemon[0].findTag(t => t instanceof TrappedTag)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.OCTOLOCK)); + game.move.select(Moves.OCTOLOCK); // after Octolock - enemy should be trapped await game.phaseInterceptor.to(MoveEndPhase); diff --git a/src/test/moves/parting_shot.test.ts b/src/test/moves/parting_shot.test.ts index 32995d2d563..7c2ca3f334c 100644 --- a/src/test/moves/parting_shot.test.ts +++ b/src/test/moves/parting_shot.test.ts @@ -1,16 +1,15 @@ -import { SPLASH_ONLY } from "../utils/testUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { FaintPhase } from "#app/phases/faint-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, test, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, test } from "vitest"; import GameManager from "../utils/gameManager"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { FaintPhase } from "#app/phases/faint-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -49,7 +48,7 @@ describe("Moves - Parting Shot", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = enemyPokemon.summonData.battleStats; @@ -70,7 +69,7 @@ describe("Moves - Parting Shot", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = enemyPokemon.summonData.battleStats; @@ -87,19 +86,19 @@ describe("Moves - Parting Shot", () => { await game.startBattle([Species.MEOWTH, Species.MEOWTH, Species.MEOWTH, Species.MURKROW, Species.ABRA]); // use Memento 3 times to debuff enemy - game.doAttack(getMovePosition(game.scene, 0, Moves.MEMENTO)); + game.move.select(Moves.MEMENTO); await game.phaseInterceptor.to(FaintPhase); expect(game.scene.getParty()[0].isFainted()).toBe(true); game.doSelectPartyPokemon(1); await game.phaseInterceptor.to(TurnInitPhase, false); - game.doAttack(getMovePosition(game.scene, 0, Moves.MEMENTO)); + game.move.select(Moves.MEMENTO); await game.phaseInterceptor.to(FaintPhase); expect(game.scene.getParty()[0].isFainted()).toBe(true); game.doSelectPartyPokemon(2); await game.phaseInterceptor.to(TurnInitPhase, false); - game.doAttack(getMovePosition(game.scene, 0, Moves.MEMENTO)); + game.move.select(Moves.MEMENTO); await game.phaseInterceptor.to(FaintPhase); expect(game.scene.getParty()[0].isFainted()).toBe(true); game.doSelectPartyPokemon(3); @@ -114,7 +113,7 @@ describe("Moves - Parting Shot", () => { expect(battleStatsOpponent[BattleStat.SPATK]).toBe(-6); // now parting shot should fail - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); expect(battleStatsOpponent[BattleStat.ATK]).toBe(-6); @@ -135,7 +134,7 @@ describe("Moves - Parting Shot", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = enemyPokemon.summonData.battleStats; @@ -156,7 +155,7 @@ describe("Moves - Parting Shot", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = enemyPokemon.summonData.battleStats; @@ -174,7 +173,7 @@ describe("Moves - Parting Shot", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = enemyPokemon.summonData.battleStats; @@ -188,7 +187,7 @@ describe("Moves - Parting Shot", () => { "Parting shot regularly not fail if no party available to switch - party fainted", async () => { await game.startBattle([Species.MURKROW, Species.MEOWTH]); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); // intentionally kill party pokemon, switch to second slot (now 1 party mon is fainted) await game.killPokemon(game.scene.getParty()[0]); @@ -197,7 +196,7 @@ describe("Moves - Parting Shot", () => { game.doSelectPartyPokemon(1); await game.phaseInterceptor.to(TurnInitPhase, false); - game.doAttack(getMovePosition(game.scene, 0, Moves.PARTING_SHOT)); + game.move.select(Moves.PARTING_SHOT); await game.phaseInterceptor.to(BerryPhase, false); const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; diff --git a/src/test/moves/protect.test.ts b/src/test/moves/protect.test.ts index 4d97ef5ce82..3fd51f4bc93 100644 --- a/src/test/moves/protect.test.ts +++ b/src/test/moves/protect.test.ts @@ -1,14 +1,13 @@ +import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; +import { BattleStat } from "#app/data/battle-stat"; +import { allMoves } from "#app/data/move"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "../utils/gameManager"; -import { Species } from "#enums/species"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { allMoves } from "#app/data/move.js"; -import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; const TIMEOUT = 20 * 1000; @@ -48,7 +47,7 @@ describe("Moves - Protect", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(BerryPhase, false); @@ -66,7 +65,7 @@ describe("Moves - Protect", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(BerryPhase, false); @@ -84,7 +83,7 @@ describe("Moves - Protect", () => { const leadPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(BerryPhase, false); @@ -103,7 +102,7 @@ describe("Moves - Protect", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.PROTECT)); + game.move.select(Moves.PROTECT); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 3020e4b47ac..15d684b2d60 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -1,13 +1,12 @@ -import { Status, StatusEffect } from "#app/data/status-effect.js"; -import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattlerIndex } from "#app/battle"; +import { Status, StatusEffect } from "#app/data/status-effect"; +import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { BattlerIndex } from "#app/battle.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -49,7 +48,7 @@ describe("Moves - Purify", () => { playerPokemon.hp = playerPokemon.getMaxHp() - 1; enemyPokemon.status = new Status(StatusEffect.BURN); - game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); + game.move.select(Moves.PURIFY); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); @@ -69,7 +68,7 @@ describe("Moves - Purify", () => { playerPokemon.hp = playerPokemon.getMaxHp() - 1; const playerInitialHp = playerPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); + game.move.select(Moves.PURIFY); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); diff --git a/src/test/moves/quick_guard.test.ts b/src/test/moves/quick_guard.test.ts index 8bf647f2027..26d9a74e9fd 100644 --- a/src/test/moves/quick_guard.test.ts +++ b/src/test/moves/quick_guard.test.ts @@ -1,13 +1,12 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "../utils/gameManager"; -import { Species } from "#enums/species"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; @@ -47,11 +46,11 @@ describe("Moves - Quick Guard", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_GUARD)); + game.move.select(Moves.QUICK_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -69,11 +68,11 @@ describe("Moves - Quick Guard", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_GUARD)); + game.move.select(Moves.QUICK_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -91,11 +90,11 @@ describe("Moves - Quick Guard", () => { const leadPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_GUARD)); + game.move.select(Moves.QUICK_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.FOLLOW_ME)); + game.move.select(Moves.FOLLOW_ME, 1); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/rage_powder.test.ts b/src/test/moves/rage_powder.test.ts index 17b687feead..3e78c6fe0c9 100644 --- a/src/test/moves/rage_powder.test.ts +++ b/src/test/moves/rage_powder.test.ts @@ -1,14 +1,11 @@ -import { BattlerIndex } from "#app/battle.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattlerIndex } from "#app/battle"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -33,35 +30,23 @@ describe("Moves - Rage Powder", () => { game.override.enemySpecies(Species.SNORLAX); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.moveset([Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); test( "move effect should be bypassed by Grass type", async () => { - game.override.enemyMoveset([ Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER ]); + game.override.enemyMoveset([Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER]); - await game.startBattle([ Species.AMOONGUSS, Species.VENUSAUR ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.AMOONGUSS, Species.VENUSAUR]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.QUICK_ATTACK, 0, BattlerIndex.ENEMY); + game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to(TurnEndPhase, false); // If redirection was bypassed, both enemies should be damaged @@ -74,29 +59,17 @@ describe("Moves - Rage Powder", () => { "move effect should be bypassed by Overcoat", async () => { game.override.ability(Abilities.OVERCOAT); - game.override.enemyMoveset([ Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER ]); + game.override.enemyMoveset([Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER, Moves.RAGE_POWDER]); // Test with two non-Grass type player Pokemon - await game.startBattle([ Species.BLASTOISE, Species.CHARIZARD ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.QUICK_ATTACK, 0, BattlerIndex.ENEMY); + game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to(TurnEndPhase, false); // If redirection was bypassed, both enemies should be damaged diff --git a/src/test/moves/reflect.test.ts b/src/test/moves/reflect.test.ts index 79dd4f8202b..9780ede3c55 100644 --- a/src/test/moves/reflect.test.ts +++ b/src/test/moves/reflect.test.ts @@ -1,14 +1,13 @@ -import { ArenaTagSide } from "#app/data/arena-tag.js"; -import Move, { allMoves } from "#app/data/move.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import Pokemon from "#app/field/pokemon.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { NumberHolder } from "#app/utils.js"; +import { ArenaTagSide } from "#app/data/arena-tag"; +import Move, { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import Pokemon from "#app/field/pokemon"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { NumberHolder } from "#app/utils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -17,7 +16,7 @@ describe("Moves - Reflect", () => { let phaserGame: Phaser.Game; let game: GameManager; const singleBattleMultiplier = 0.5; - const doubleBattleMultiplier = 2732/4096; + const doubleBattleMultiplier = 2732 / 4096; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -40,11 +39,11 @@ describe("Moves - Reflect", () => { game.override.disableCrits(); }); - it("reduces damage of physical attacks by half in a single battle", async() => { + it("reduces damage of physical attacks by half in a single battle", async () => { const moveToUse = Moves.TACKLE; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); @@ -52,14 +51,14 @@ describe("Moves - Reflect", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); - it("reduces damage of physical attacks by a third in a double battle", async() => { + it("reduces damage of physical attacks by a third in a double battle", async () => { game.override.battleType("double"); const moveToUse = Moves.ROCK_SLIDE; await game.startBattle([Species.SHUCKLE, Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); - game.doAttack(getMovePosition(game.scene, 1, moveToUse)); + game.move.select(moveToUse); + game.move.select(moveToUse, 1); await game.phaseInterceptor.to(TurnEndPhase); const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); @@ -67,11 +66,11 @@ describe("Moves - Reflect", () => { expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); - it("does not affect special attacks", async() => { + it("does not affect special attacks", async () => { const moveToUse = Moves.ABSORB; await game.startBattle([Species.SHUCKLE]); - game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + game.move.select(moveToUse); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts index cad65768a1c..ddb0b22e642 100644 --- a/src/test/moves/rollout.test.ts +++ b/src/test/moves/rollout.test.ts @@ -1,10 +1,9 @@ -import { allMoves } from "#app/data/move.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; +import { allMoves } from "#app/data/move"; +import { CommandPhase } from "#app/phases/command-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -12,7 +11,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite describe("Moves - Rollout", () => { let phaserGame: Phaser.Game; let game: GameManager; - const TIMEOUT = 20 * 1000; beforeAll(() => { phaserGame = new Phaser.Game({ @@ -58,7 +56,7 @@ describe("Moves - Rollout", () => { let previousHp = enemyPkm.hp; for (let i = 0; i < turns; i++) { - game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT)); + game.move.select(Moves.ROLLOUT); await game.phaseInterceptor.to(CommandPhase); dmgHistory.push(previousHp - enemyPkm.hp); @@ -78,5 +76,5 @@ describe("Moves - Rollout", () => { // reset expect(turn6Dmg).toBeGreaterThanOrEqual(turn1Dmg - variance); expect(turn6Dmg).toBeLessThanOrEqual(turn1Dmg + variance); - }, TIMEOUT); + }); }); diff --git a/src/test/moves/roost.test.ts b/src/test/moves/roost.test.ts index c40bb18cdb1..cf07a3485e7 100644 --- a/src/test/moves/roost.test.ts +++ b/src/test/moves/roost.test.ts @@ -1,13 +1,12 @@ -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -32,8 +31,8 @@ describe("Moves - Roost", () => { game.override.enemyAbility(Abilities.INSOMNIA); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.STOMPING_TANTRUM ]); - game.override.enemyMoveset([Moves.ROOST,Moves.ROOST,Moves.ROOST,Moves.ROOST]); + game.override.moveset([Moves.STOMPING_TANTRUM]); + game.override.enemyMoveset([Moves.ROOST, Moves.ROOST, Moves.ROOST, Moves.ROOST]); }); test( @@ -45,7 +44,7 @@ describe("Moves - Roost", () => { const enemyStartingHp = enemyPokemon.hp; - game.doAttack(getMovePosition(game.scene, 0, Moves.STOMPING_TANTRUM)); + game.move.select(Moves.STOMPING_TANTRUM); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/moves/shell_trap.test.ts b/src/test/moves/shell_trap.test.ts index c600b1ee1cc..4549a8b2b73 100644 --- a/src/test/moves/shell_trap.test.ts +++ b/src/test/moves/shell_trap.test.ts @@ -1,16 +1,15 @@ +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { MoveResult } from "#app/field/pokemon"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { MovePhase } from "#app/phases/move-phase"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import GameManager from "#test/utils/gameManager"; -import { Moves } from "#app/enums/moves.js"; -import { Species } from "#app/enums/species.js"; -import { allMoves } from "#app/data/move.js"; -import { BattlerIndex } from "#app/battle.js"; -import { getMovePosition } from "../utils/gameManagerUtils"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { MoveResult } from "#app/field/pokemon.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; const TIMEOUT = 20 * 1000; @@ -49,8 +48,8 @@ describe("Moves - Shell Trap", () => { const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SHELL_TRAP)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SHELL_TRAP, 1); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2]); @@ -75,8 +74,8 @@ describe("Moves - Shell Trap", () => { const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SHELL_TRAP)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SHELL_TRAP, 1); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2]); @@ -101,8 +100,8 @@ describe("Moves - Shell Trap", () => { const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SHELL_TRAP)); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SHELL_TRAP, 1); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2]); @@ -127,8 +126,8 @@ describe("Moves - Shell Trap", () => { const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SHELL_TRAP)); - game.doAttack(getMovePosition(game.scene, 1, Moves.BULLDOZE)); + game.move.select(Moves.SHELL_TRAP); + game.move.select(Moves.BULLDOZE, 1); await game.phaseInterceptor.to(MoveEndPhase); @@ -154,7 +153,7 @@ describe("Moves - Shell Trap", () => { const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.SHELL_TRAP)); + game.move.select(Moves.SHELL_TRAP); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts index ae3c676b893..c4096111c6f 100644 --- a/src/test/moves/spikes.test.ts +++ b/src/test/moves/spikes.test.ts @@ -1,8 +1,8 @@ -import { CommandPhase } from "#app/phases/command-phase.js"; -import GameManager from "#test/utils/gameManager"; +import { CommandPhase } from "#app/phases/command-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -31,14 +31,11 @@ describe("Moves - Spikes", () => { game.override.ability(Abilities.HYDRATION); game.override.passiveAbility(Abilities.HYDRATION); game.override.startingWave(3); - game.override.enemyMoveset([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); - game.override.moveset([Moves.SPIKES,Moves.SPLASH, Moves.ROAR]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); + game.override.moveset([Moves.SPIKES, Moves.SPLASH, Moves.ROAR]); }); - it("single - wild - stay on field - no damage", async() => { - // player set spikes on the field and do splash for 3 turns - // opponent do splash for 4 turns - // nobody should take damage + it("single - wild - stay on field - no damage", async () => { await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA, @@ -46,21 +43,14 @@ describe("Moves - Spikes", () => { await game.phaseInterceptor.to(CommandPhase, true); const initialHp = game.scene.getParty()[0].hp; expect(game.scene.getParty()[0].hp).toBe(initialHp); - game.doAttack(0); + game.move.select(Moves.SPIKES); await game.toNextTurn(); - game.doAttack(1); - await game.toNextTurn(); - game.doAttack(1); - await game.toNextTurn(); - game.doAttack(1); - await game.toNextTurn(); - game.doAttack(1); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.getParty()[0].hp).toBe(initialHp); - console.log(game.textInterceptor.logs); }, 20000); - it("single - wild - take some damage", async() => { + it("single - wild - take some damage", async () => { // player set spikes on the field and switch back to back // opponent do splash for 2 turns // nobody should take damage @@ -82,7 +72,7 @@ describe("Moves - Spikes", () => { expect(game.scene.getParty()[0].hp).toBe(initialHp); }, 20000); - it("trainer - wild - force switch opponent - should take damage", async() => { + it("trainer - wild - force switch opponent - should take damage", async () => { game.override.startingWave(5); // player set spikes on the field and do splash for 3 turns // opponent do splash for 4 turns @@ -93,14 +83,14 @@ describe("Moves - Spikes", () => { ]); await game.phaseInterceptor.to(CommandPhase, true); const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; - game.doAttack(0); + game.move.select(Moves.SPIKES); await game.toNextTurn(); - game.doAttack(2); + game.move.select(Moves.ROAR); await game.toNextTurn(); expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); }, 20000); - it("trainer - wild - force switch by himself opponent - should take damage", async() => { + it("trainer - wild - force switch by himself opponent - should take damage", async () => { game.override.startingWave(5); game.override.startingLevel(5000); game.override.enemySpecies(0); @@ -113,11 +103,11 @@ describe("Moves - Spikes", () => { ]); await game.phaseInterceptor.to(CommandPhase, true); const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; - game.doAttack(0); + game.move.select(Moves.SPIKES); await game.toNextTurn(); game.forceOpponentToSwitch(); - game.doAttack(1); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); }, 20000); diff --git a/src/test/moves/spit_up.test.ts b/src/test/moves/spit_up.test.ts index 51d84a5e151..ab47e65d653 100644 --- a/src/test/moves/spit_up.test.ts +++ b/src/test/moves/spit_up.test.ts @@ -1,17 +1,17 @@ import { BattleStat } from "#app/data/battle-stat"; -import { StockpilingTag } from "#app/data/battler-tags.js"; -import { allMoves } from "#app/data/move.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import GameManager from "#test/utils/gameManager"; +import { StockpilingTag } from "#app/data/battler-tags"; +import { allMoves } from "#app/data/move"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { MoveResult, TurnMove } from "#app/field/pokemon"; +import { MovePhase } from "#app/phases/move-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Spit Up", () => { let phaserGame: Phaser.Game; @@ -55,7 +55,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(TurnInitPhase); expect(allMoves[Moves.SPIT_UP].calculateBattlePower).toHaveBeenCalledOnce(); @@ -80,7 +80,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(TurnInitPhase); expect(allMoves[Moves.SPIT_UP].calculateBattlePower).toHaveBeenCalledOnce(); @@ -106,7 +106,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(TurnInitPhase); expect(allMoves[Moves.SPIT_UP].calculateBattlePower).toHaveBeenCalledOnce(); @@ -126,7 +126,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.getMoveHistory().at(-1)).toMatchObject({ move: Moves.SPIT_UP, result: MoveResult.FAIL }); @@ -146,7 +146,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(MovePhase); expect(pokemon.summonData.battleStats[BattleStat.DEF]).toBe(1); @@ -186,7 +186,7 @@ describe("Moves - Spit Up", () => { vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); - game.doAttack(0); + game.move.select(Moves.SPIT_UP); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.getMoveHistory().at(-1)).toMatchObject({ move: Moves.SPIT_UP, result: MoveResult.SUCCESS }); diff --git a/src/test/moves/spotlight.test.ts b/src/test/moves/spotlight.test.ts index 40ab78471ae..e5f4719d1d3 100644 --- a/src/test/moves/spotlight.test.ts +++ b/src/test/moves/spotlight.test.ts @@ -1,14 +1,11 @@ -import { BattlerIndex } from "#app/battle.js"; +import { BattlerIndex } from "#app/battle"; import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; const TIMEOUT = 20 * 1000; @@ -33,33 +30,21 @@ describe("Moves - Spotlight", () => { game.override.enemySpecies(Species.SNORLAX); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK ]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.moveset([Moves.FOLLOW_ME, Moves.RAGE_POWDER, Moves.SPOTLIGHT, Moves.QUICK_ATTACK]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); test( "move should redirect attacks to the target", async () => { - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPOTLIGHT)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(BattlerIndex.ENEMY_2); + game.move.select(Moves.SPOTLIGHT, 0, BattlerIndex.ENEMY); + game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); await game.phaseInterceptor.to(TurnEndPhase, false); expect(enemyPokemon[0].hp).toBeLessThan(enemyStartingHp[0]); @@ -70,17 +55,11 @@ describe("Moves - Spotlight", () => { test( "move should cause other redirection moves to fail", async () => { - game.override.enemyMoveset([ Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME ]); + game.override.enemyMoveset([Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME, Moves.FOLLOW_ME]); - await game.startBattle([ Species.AMOONGUSS, Species.CHARIZARD ]); - - const playerPokemon = game.scene.getPlayerField(); - expect(playerPokemon.length).toBe(2); - playerPokemon.forEach(p => expect(p).not.toBe(undefined)); + await game.startBattle([Species.AMOONGUSS, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyField(); - expect(enemyPokemon.length).toBe(2); - enemyPokemon.forEach(p => expect(p).not.toBe(undefined)); /** * Spotlight will target the slower enemy. In this situation without Spotlight being used, @@ -92,14 +71,8 @@ describe("Moves - Spotlight", () => { const enemyStartingHp = enemyPokemon.map(p => p.hp); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPOTLIGHT)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(spotTarget); - await game.phaseInterceptor.to(CommandPhase); - - game.doAttack(getMovePosition(game.scene, 1, Moves.QUICK_ATTACK)); - await game.phaseInterceptor.to(SelectTargetPhase, false); - game.doSelectTarget(attackTarget); + game.move.select(Moves.SPOTLIGHT, 0, spotTarget); + game.move.select(Moves.QUICK_ATTACK, 1, attackTarget); await game.phaseInterceptor.to(TurnEndPhase, false); expect(enemyPokemon[1].hp).toBeLessThan(enemyStartingHp[1]); diff --git a/src/test/moves/stockpile.test.ts b/src/test/moves/stockpile.test.ts index 0b208e20f81..b1941b9f9b3 100644 --- a/src/test/moves/stockpile.test.ts +++ b/src/test/moves/stockpile.test.ts @@ -1,16 +1,15 @@ import { BattleStat } from "#app/data/battle-stat"; -import { StockpilingTag } from "#app/data/battler-tags.js"; -import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { StockpilingTag } from "#app/data/battler-tags"; +import { MoveResult, TurnMove } from "#app/field/pokemon"; +import { CommandPhase } from "#app/phases/command-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Stockpile", () => { describe("integration tests", () => { @@ -57,7 +56,7 @@ describe("Moves - Stockpile", () => { await game.phaseInterceptor.to(CommandPhase); } - game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); + game.move.select(Moves.STOCKPILE); await game.phaseInterceptor.to(TurnInitPhase); const stockpilingTag = user.getTag(StockpilingTag)!; @@ -92,7 +91,7 @@ describe("Moves - Stockpile", () => { expect(user.summonData.battleStats[BattleStat.DEF]).toBe(6); expect(user.summonData.battleStats[BattleStat.SPDEF]).toBe(6); - game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); + game.move.select(Moves.STOCKPILE); await game.phaseInterceptor.to(TurnInitPhase); const stockpilingTag = user.getTag(StockpilingTag)!; @@ -104,7 +103,7 @@ describe("Moves - Stockpile", () => { // do it again, just for good measure await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); + game.move.select(Moves.STOCKPILE); await game.phaseInterceptor.to(TurnInitPhase); const stockpilingTagAgain = user.getTag(StockpilingTag)!; diff --git a/src/test/moves/swallow.test.ts b/src/test/moves/swallow.test.ts index 6a054393acc..202f25fee74 100644 --- a/src/test/moves/swallow.test.ts +++ b/src/test/moves/swallow.test.ts @@ -1,16 +1,16 @@ import { BattleStat } from "#app/data/battle-stat"; -import { StockpilingTag } from "#app/data/battler-tags.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import { MoveResult, TurnMove } from "#app/field/pokemon.js"; -import GameManager from "#test/utils/gameManager"; +import { StockpilingTag } from "#app/data/battler-tags"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { MoveResult, TurnMove } from "#app/field/pokemon"; +import { MovePhase } from "#app/phases/move-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Swallow", () => { let phaserGame: Phaser.Game; @@ -57,7 +57,7 @@ describe("Moves - Swallow", () => { vi.spyOn(pokemon, "heal"); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.heal).toHaveBeenCalledOnce(); @@ -85,7 +85,7 @@ describe("Moves - Swallow", () => { vi.spyOn(pokemon, "heal"); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.heal).toHaveBeenCalledOnce(); @@ -114,7 +114,7 @@ describe("Moves - Swallow", () => { vi.spyOn(pokemon, "heal"); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.heal).toHaveBeenCalledOnce(); @@ -132,7 +132,7 @@ describe("Moves - Swallow", () => { const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeUndefined(); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.getMoveHistory().at(-1)).toMatchObject({ move: Moves.SWALLOW, result: MoveResult.FAIL }); @@ -148,7 +148,7 @@ describe("Moves - Swallow", () => { const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(MovePhase); expect(pokemon.summonData.battleStats[BattleStat.DEF]).toBe(1); @@ -184,7 +184,7 @@ describe("Moves - Swallow", () => { [BattleStat.SPDEF]: 2, }); - game.doAttack(0); + game.move.select(Moves.SWALLOW); await game.phaseInterceptor.to(TurnInitPhase); expect(pokemon.getMoveHistory().at(-1)).toMatchObject({ move: Moves.SWALLOW, result: MoveResult.SUCCESS }); diff --git a/src/test/moves/tackle.test.ts b/src/test/moves/tackle.test.ts index 3da8bc6f978..5eca9e344c8 100644 --- a/src/test/moves/tackle.test.ts +++ b/src/test/moves/tackle.test.ts @@ -1,15 +1,11 @@ import { Stat } from "#app/data/pokemon-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Tackle", () => { @@ -34,30 +30,24 @@ describe("Moves - Tackle", () => { game.override.startingLevel(1); game.override.startingWave(97); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.GROWTH,Moves.GROWTH,Moves.GROWTH,Moves.GROWTH]); + game.override.enemyMoveset([Moves.GROWTH, Moves.GROWTH, Moves.GROWTH, Moves.GROWTH]); game.override.disableCrits(); }); - it("TACKLE against ghost", async() => { + it("TACKLE against ghost", async () => { const moveToUse = Moves.TACKLE; game.override.enemySpecies(Species.GENGAR); await game.startBattle([ Species.MIGHTYENA, ]); const hpOpponent = game.scene.currentBattle.enemyParty[0].hp; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); const hpLost = hpOpponent - game.scene.currentBattle.enemyParty[0].hp; expect(hpLost).toBe(0); }, 20000); - it("TACKLE against not resistant", async() => { + it("TACKLE against not resistant", async () => { const moveToUse = Moves.TACKLE; await game.startBattle([ Species.MIGHTYENA, @@ -68,13 +58,7 @@ describe("Moves - Tackle", () => { const hpOpponent = game.scene.currentBattle.enemyParty[0].hp; - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); const hpLost = hpOpponent - game.scene.currentBattle.enemyParty[0].hp; expect(hpLost).toBeGreaterThan(0); diff --git a/src/test/moves/tail_whip.test.ts b/src/test/moves/tail_whip.test.ts index ba4a7459094..0a999fe1920 100644 --- a/src/test/moves/tail_whip.test.ts +++ b/src/test/moves/tail_whip.test.ts @@ -1,16 +1,12 @@ import { BattleStat } from "#app/data/battle-stat"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; describe("Moves - Tail whip", () => { @@ -36,10 +32,10 @@ describe("Moves - Tail whip", () => { game.override.ability(Abilities.INSOMNIA); game.override.startingLevel(2000); game.override.moveset([moveToUse]); - game.override.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]); + game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); }); - it("TAIL_WHIP", async() => { + it("TAIL_WHIP", async () => { const moveToUse = Moves.TAIL_WHIP; await game.startBattle([ Species.MIGHTYENA, @@ -49,13 +45,7 @@ describe("Moves - Tail whip", () => { let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.DEF]).toBe(0); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - const movePosition = getMovePosition(game.scene, 0, moveToUse); - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); + game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase); battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.DEF]).toBe(-1); diff --git a/src/test/moves/tailwind.test.ts b/src/test/moves/tailwind.test.ts index 115a97f3be4..6b70122d08d 100644 --- a/src/test/moves/tailwind.test.ts +++ b/src/test/moves/tailwind.test.ts @@ -1,14 +1,13 @@ -import { ArenaTagSide } from "#app/data/arena-tag.js"; -import { Stat } from "#app/data/pokemon-stat.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { ArenaTagSide } from "#app/data/arena-tag"; +import { Stat } from "#app/data/pokemon-stat"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Moves - Tailwind", () => { let phaserGame: Phaser.Game; @@ -42,8 +41,8 @@ describe("Moves - Tailwind", () => { expect(magikarp.getBattleStat(Stat.SPD)).equal(magikarpSpd); expect(meowth.getBattleStat(Stat.SPD)).equal(meowthSpd); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.TAILWIND); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); @@ -57,19 +56,19 @@ describe("Moves - Tailwind", () => { await game.startBattle([Species.MAGIKARP]); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.toNextTurn(); expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeDefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + game.move.select(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeUndefined(); @@ -92,7 +91,7 @@ describe("Moves - Tailwind", () => { expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)).toBeUndefined(); expect(game.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.ENEMY)).toBeUndefined(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TAILWIND)); + game.move.select(Moves.TAILWIND); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/moves/tera_blast.test.ts b/src/test/moves/tera_blast.test.ts index 0bd2ad24e23..d261d4b856b 100644 --- a/src/test/moves/tera_blast.test.ts +++ b/src/test/moves/tera_blast.test.ts @@ -1,17 +1,16 @@ +import { BattlerIndex } from "#app/battle"; +import { BattleStat } from "#app/data/battle-stat"; import { allMoves } from "#app/data/move"; -import GameManager from "#test/utils/gameManager"; +import { Type } from "#app/data/type"; +import { Abilities } from "#app/enums/abilities"; +import { Stat } from "#app/enums/stat"; +import { HitResult } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { Abilities } from "#app/enums/abilities"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { Type } from "#app/data/type"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat"; -import { Stat } from "#app/enums/stat"; -import { BattlerIndex } from "#app/battle"; -import { HitResult } from "#app/field/pokemon"; describe("Moves - Tera Blast", () => { let phaserGame: Phaser.Game; @@ -37,7 +36,7 @@ describe("Moves - Tera Blast", () => { .starterSpecies(Species.FEEBAS) .moveset([Moves.TERA_BLAST]) .ability(Abilities.BALL_FETCH) - .startingHeldItems([{name: "TERA_SHARD", type: Type.FIRE}]) + .startingHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }]) .enemySpecies(Species.MAGIKARP) .enemyMoveset(SPLASH_ONLY) .enemyAbility(Abilities.BALL_FETCH) @@ -46,30 +45,30 @@ describe("Moves - Tera Blast", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); }); - it("changes type to match user's tera type", async() => { + it("changes type to match user's tera type", async () => { game.override .enemySpecies(Species.FURRET) - .startingHeldItems([{name: "TERA_SHARD", type: Type.FIGHTING}]); + .startingHeldItems([{ name: "TERA_SHARD", type: Type.FIGHTING }]); await game.startBattle(); const enemyPokemon = game.scene.getEnemyPokemon()!; vi.spyOn(enemyPokemon, "apply"); - game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEffectPhase"); expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); }, 20000); - it("increases power if user is Stellar tera type", async() => { - game.override.startingHeldItems([{name: "TERA_SHARD", type: Type.STELLAR}]); + it("increases power if user is Stellar tera type", async () => { + game.override.startingHeldItems([{ name: "TERA_SHARD", type: Type.STELLAR }]); const stellarTypeMultiplier = 2; const stellarTypeDmgBonus = 20; const basePower = moveToCheck.power; await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEffectPhase"); @@ -77,7 +76,7 @@ describe("Moves - Tera Blast", () => { }, 20000); // Currently abilities are bugged and can't see when a move's category is changed - it.skip("uses the higher stat of the user's Atk and SpAtk for damage calculation", async() => { + it.skip("uses the higher stat of the user's Atk and SpAtk for damage calculation", async () => { game.override.enemyAbility(Abilities.TOXIC_DEBRIS); await game.startBattle(); @@ -85,18 +84,18 @@ describe("Moves - Tera Blast", () => { playerPokemon.stats[Stat.ATK] = 100; playerPokemon.stats[Stat.SPATK] = 1; - game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + game.move.select(Moves.TERA_BLAST); await game.phaseInterceptor.to("TurnEndPhase"); expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); }, 20000); - it("causes stat drops if user is Stellar tera type", async() => { - game.override.startingHeldItems([{name: "TERA_SHARD", type: Type.STELLAR}]); + it("causes stat drops if user is Stellar tera type", async () => { + game.override.startingHeldItems([{ name: "TERA_SHARD", type: Type.STELLAR }]); await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.TERA_BLAST)); + game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEndPhase"); diff --git a/src/test/moves/thousand_arrows.test.ts b/src/test/moves/thousand_arrows.test.ts index d72f3ed3fac..8d1d6ee5f4a 100644 --- a/src/test/moves/thousand_arrows.test.ts +++ b/src/test/moves/thousand_arrows.test.ts @@ -1,13 +1,12 @@ -import { Abilities } from "#app/enums/abilities.js"; -import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; const TIMEOUT = 20 * 1000; @@ -31,18 +30,18 @@ describe("Moves - Thousand Arrows", () => { game.override.enemySpecies(Species.TOGETIC); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.moveset([ Moves.THOUSAND_ARROWS ]); - game.override.enemyMoveset([Moves.SPLASH,Moves.SPLASH,Moves.SPLASH,Moves.SPLASH]); + game.override.moveset([Moves.THOUSAND_ARROWS]); + game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); }); it( "move should hit and ground Flying-type targets", async () => { - await game.startBattle([ Species.ILLUMISE ]); + await game.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); + game.move.select(Moves.THOUSAND_ARROWS); await game.phaseInterceptor.to(MoveEffectPhase, false); // Enemy should not be grounded before move effect is applied @@ -61,11 +60,11 @@ describe("Moves - Thousand Arrows", () => { game.override.enemySpecies(Species.SNORLAX); game.override.enemyAbility(Abilities.LEVITATE); - await game.startBattle([ Species.ILLUMISE ]); + await game.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; - game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); + game.move.select(Moves.THOUSAND_ARROWS); await game.phaseInterceptor.to(MoveEffectPhase, false); // Enemy should not be grounded before move effect is applied @@ -83,13 +82,13 @@ describe("Moves - Thousand Arrows", () => { async () => { game.override.enemySpecies(Species.SNORLAX); - await game.startBattle([ Species.ILLUMISE ]); + await game.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; enemyPokemon.addTag(BattlerTagType.MAGNET_RISEN, undefined, Moves.MAGNET_RISE); - game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); + game.move.select(Moves.THOUSAND_ARROWS); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/moves/tidy_up.test.ts b/src/test/moves/tidy_up.test.ts index 64a63df08df..1ef7933c114 100644 --- a/src/test/moves/tidy_up.test.ts +++ b/src/test/moves/tidy_up.test.ts @@ -1,15 +1,14 @@ -import { BattleStat } from "#app/data/battle-stat.js"; -import { ArenaTagType } from "#app/enums/arena-tag-type.js"; -import GameManager from "#test/utils/gameManager"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BattleStat } from "#app/data/battle-stat"; +import { ArenaTagType } from "#app/enums/arena-tag-type"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - Tidy Up", () => { @@ -38,81 +37,81 @@ describe("Moves - Tidy Up", () => { game.override.startingLevel(50); }); - it("spikes are cleared", async() => { + it("spikes are cleared", async () => { game.override.moveset([Moves.SPIKES, Moves.TIDY_UP]); game.override.enemyMoveset([Moves.SPIKES, Moves.SPIKES, Moves.SPIKES, Moves.SPIKES]); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SPIKES)); + game.move.select(Moves.SPIKES); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.arena.getTag(ArenaTagType.SPIKES)).toBeUndefined(); }, 20000); - it("stealth rocks are cleared", async() => { + it("stealth rocks are cleared", async () => { game.override.moveset([Moves.STEALTH_ROCK, Moves.TIDY_UP]); game.override.enemyMoveset([Moves.STEALTH_ROCK, Moves.STEALTH_ROCK, Moves.STEALTH_ROCK, Moves.STEALTH_ROCK]); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.STEALTH_ROCK)); + game.move.select(Moves.STEALTH_ROCK); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.arena.getTag(ArenaTagType.STEALTH_ROCK)).toBeUndefined(); }, 20000); - it("toxic spikes are cleared", async() => { + it("toxic spikes are cleared", async () => { game.override.moveset([Moves.TOXIC_SPIKES, Moves.TIDY_UP]); game.override.enemyMoveset([Moves.TOXIC_SPIKES, Moves.TOXIC_SPIKES, Moves.TOXIC_SPIKES, Moves.TOXIC_SPIKES]); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_SPIKES)); + game.move.select(Moves.TOXIC_SPIKES); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.arena.getTag(ArenaTagType.TOXIC_SPIKES)).toBeUndefined(); }, 20000); - it("sticky webs are cleared", async() => { + it("sticky webs are cleared", async () => { game.override.moveset([Moves.STICKY_WEB, Moves.TIDY_UP]); game.override.enemyMoveset([Moves.STICKY_WEB, Moves.STICKY_WEB, Moves.STICKY_WEB, Moves.STICKY_WEB]); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.STICKY_WEB)); + game.move.select(Moves.STICKY_WEB); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.arena.getTag(ArenaTagType.STICKY_WEB)).toBeUndefined(); }, 20000); - it.skip("substitutes are cleared", async() => { + it.skip("substitutes are cleared", async () => { game.override.moveset([Moves.SUBSTITUTE, Moves.TIDY_UP]); game.override.enemyMoveset([Moves.SUBSTITUTE, Moves.SUBSTITUTE, Moves.SUBSTITUTE, Moves.SUBSTITUTE]); await game.startBattle(); - game.doAttack(getMovePosition(game.scene, 0, Moves.SUBSTITUTE)); + game.move.select(Moves.SUBSTITUTE); await game.phaseInterceptor.to(TurnEndPhase); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(MoveEndPhase); // TODO: check for subs here once the move is implemented }, 20000); - it("user's stats are raised with no traps set", async() => { + it("user's stats are raised with no traps set", async () => { await game.startBattle(); const player = game.scene.getPlayerPokemon()!.summonData.battleStats; expect(player[BattleStat.ATK]).toBe(0); expect(player[BattleStat.SPD]).toBe(0); - game.doAttack(getMovePosition(game.scene, 0, Moves.TIDY_UP)); + game.move.select(Moves.TIDY_UP); await game.phaseInterceptor.to(TurnEndPhase); expect(player[BattleStat.ATK]).toBe(+1); diff --git a/src/test/moves/u_turn.test.ts b/src/test/moves/u_turn.test.ts index b93f997c487..ae55302bb42 100644 --- a/src/test/moves/u_turn.test.ts +++ b/src/test/moves/u_turn.test.ts @@ -1,14 +1,13 @@ -import { Abilities } from "#app/enums/abilities.js"; +import { Abilities } from "#app/enums/abilities"; +import { StatusEffect } from "#app/enums/status-effect"; +import { SwitchPhase } from "#app/phases/switch-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#app/test/utils/gameManager"; -import { getMovePosition } from "#app/test/utils/gameManagerUtils"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { StatusEffect } from "#app/enums/status-effect.js"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { SwitchPhase } from "#app/phases/switch-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; describe("Moves - U-turn", () => { let phaserGame: Phaser.Game; @@ -36,7 +35,7 @@ describe("Moves - U-turn", () => { .disableCrits(); }); - it("triggers regenerator a single time when a regenerator user switches out with u-turn", async() => { + it("triggers regenerator a single time when a regenerator user switches out with u-turn", async () => { // arrange const playerHp = 1; game.override.ability(Abilities.REGENERATOR); @@ -47,7 +46,7 @@ describe("Moves - U-turn", () => { game.scene.getPlayerPokemon()!.hp = playerHp; // act - game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.move.select(Moves.U_TURN); game.doSelectPartyPokemon(1); await game.phaseInterceptor.to(TurnEndPhase); @@ -57,7 +56,7 @@ describe("Moves - U-turn", () => { expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.SHUCKLE); }, 20000); - it("triggers rough skin on the u-turn user before a new pokemon is switched in", async() => { + it("triggers rough skin on the u-turn user before a new pokemon is switched in", async () => { // arrange game.override.enemyAbility(Abilities.ROUGH_SKIN); await game.startBattle([ @@ -66,7 +65,7 @@ describe("Moves - U-turn", () => { ]); // act - game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.move.select(Moves.U_TURN); game.doSelectPartyPokemon(1); await game.phaseInterceptor.to(SwitchPhase, false); @@ -78,7 +77,7 @@ describe("Moves - U-turn", () => { expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); }, 20000); - it("triggers contact abilities on the u-turn user (eg poison point) before a new pokemon is switched in", async() => { + it("triggers contact abilities on the u-turn user (eg poison point) before a new pokemon is switched in", async () => { // arrange game.override.enemyAbility(Abilities.POISON_POINT); await game.startBattle([ @@ -88,7 +87,7 @@ describe("Moves - U-turn", () => { vi.spyOn(game.scene.getEnemyPokemon()!, "randSeedInt").mockReturnValue(0); // act - game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.move.select(Moves.U_TURN); await game.phaseInterceptor.to(SwitchPhase, false); // assert diff --git a/src/test/moves/wide_guard.test.ts b/src/test/moves/wide_guard.test.ts index 1f22428de4b..616972de01b 100644 --- a/src/test/moves/wide_guard.test.ts +++ b/src/test/moves/wide_guard.test.ts @@ -1,13 +1,12 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "../utils/gameManager"; -import { Species } from "#enums/species"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { getMovePosition } from "../utils/gameManagerUtils"; -import { BattleStat } from "#app/data/battle-stat.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; const TIMEOUT = 20 * 1000; @@ -47,11 +46,11 @@ describe("Moves - Wide Guard", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.WIDE_GUARD)); + game.move.select(Moves.WIDE_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -68,11 +67,11 @@ describe("Moves - Wide Guard", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.WIDE_GUARD)); + game.move.select(Moves.WIDE_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -89,11 +88,11 @@ describe("Moves - Wide Guard", () => { const leadPokemon = game.scene.getPlayerField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.WIDE_GUARD)); + game.move.select(Moves.WIDE_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(BerryPhase, false); @@ -111,11 +110,11 @@ describe("Moves - Wide Guard", () => { const leadPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); - game.doAttack(getMovePosition(game.scene, 0, Moves.WIDE_GUARD)); + game.move.select(Moves.WIDE_GUARD); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, 1, Moves.SURF)); + game.move.select(Moves.SURF, 1); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/src/test/phases/phases.test.ts b/src/test/phases/phases.test.ts index 2ed1e48c706..5ef25361a3f 100644 --- a/src/test/phases/phases.test.ts +++ b/src/test/phases/phases.test.ts @@ -1,11 +1,11 @@ -import BattleScene from "#app/battle-scene.js"; -import { Mode } from "#app/ui/ui.js"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; +import BattleScene from "#app/battle-scene"; +import { LoginPhase } from "#app/phases/login-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import { UnavailablePhase } from "#app/phases/unavailable-phase"; +import { Mode } from "#app/ui/ui"; import GameManager from "#test/utils/gameManager"; -import { LoginPhase } from "#app/phases/login-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; -import { UnavailablePhase } from "#app/phases/unavailable-phase.js"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Phases", () => { let phaserGame: Phaser.Game; diff --git a/src/test/settingMenu/helpers/inGameManip.ts b/src/test/settingMenu/helpers/inGameManip.ts index e18a82ca571..b81e577f5b9 100644 --- a/src/test/settingMenu/helpers/inGameManip.ts +++ b/src/test/settingMenu/helpers/inGameManip.ts @@ -1,6 +1,6 @@ import { getIconForLatestInput, getSettingNameWithKeycode } from "#app/configs/inputs/configHandler"; -import { expect } from "vitest"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; +import { expect } from "vitest"; export class InGameManip { private config; diff --git a/src/test/settingMenu/helpers/menuManip.ts b/src/test/settingMenu/helpers/menuManip.ts index 4fd5f526897..90b3f1e96e6 100644 --- a/src/test/settingMenu/helpers/menuManip.ts +++ b/src/test/settingMenu/helpers/menuManip.ts @@ -1,6 +1,6 @@ -import { expect } from "vitest"; -import { deleteBind, getIconWithKeycode, getIconWithSettingName, getKeyWithKeycode, getKeyWithSettingName, assign, getSettingNameWithKeycode, canIAssignThisKey, canIDeleteThisKey, canIOverrideThisSetting } from "#app/configs/inputs/configHandler"; +import { assign, canIAssignThisKey, canIDeleteThisKey, canIOverrideThisSetting, deleteBind, getIconWithKeycode, getIconWithSettingName, getKeyWithKeycode, getKeyWithSettingName, getSettingNameWithKeycode } from "#app/configs/inputs/configHandler"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; +import { expect } from "vitest"; export class MenuManip { private config; diff --git a/src/test/settingMenu/rebinding_setting.test.ts b/src/test/settingMenu/rebinding_setting.test.ts index eead23972c2..ec2343cfb41 100644 --- a/src/test/settingMenu/rebinding_setting.test.ts +++ b/src/test/settingMenu/rebinding_setting.test.ts @@ -1,13 +1,13 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { deepCopy } from "#app/utils"; -import { getKeyWithKeycode, getKeyWithSettingName } from "#app/configs/inputs/configHandler"; -import { MenuManip } from "#test/settingMenu/helpers/menuManip"; -import { InGameManip } from "#test/settingMenu/helpers/inGameManip"; -import { InterfaceConfig } from "#app/inputs-controller"; import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty"; +import { getKeyWithKeycode, getKeyWithSettingName } from "#app/configs/inputs/configHandler"; +import { InterfaceConfig } from "#app/inputs-controller"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; -import { Device } from "#enums/devices"; +import { deepCopy } from "#app/utils"; import { Button } from "#enums/buttons"; +import { Device } from "#enums/devices"; +import { InGameManip } from "#test/settingMenu/helpers/inGameManip"; +import { MenuManip } from "#test/settingMenu/helpers/menuManip"; +import { beforeEach, describe, expect, it } from "vitest"; describe("Test Rebinding", () => { diff --git a/src/test/sprites/pokemonSprite.test.ts b/src/test/sprites/pokemonSprite.test.ts index deb5844d677..faf0626b365 100644 --- a/src/test/sprites/pokemonSprite.test.ts +++ b/src/test/sprites/pokemonSprite.test.ts @@ -1,8 +1,8 @@ -import { beforeAll, describe, expect, it } from "vitest"; -import _masterlist from "../../../public/images/pokemon/variant/_masterlist.json"; +import { getAppRootDir } from "#test/sprites/spritesUtils"; import fs from "fs"; import path from "path"; -import { getAppRootDir } from "#test/sprites/spritesUtils"; +import { beforeAll, describe, expect, it } from "vitest"; +import _masterlist from "../../../public/images/pokemon/variant/_masterlist.json"; type PokemonVariantMasterlist = typeof _masterlist; diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index dbbdb1999b9..8ef1ea16b4a 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -1,21 +1,21 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; -import { Mode } from "#app/ui/ui"; -import { GameModes } from "#app/game-mode"; -import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; -import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; -import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; -import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { Gender } from "#app/data/gender"; +import { Nature } from "#app/data/nature"; import { allSpecies } from "#app/data/pokemon-species"; -import { Nature} from "#app/data/nature"; -import { Button } from "#enums/buttons"; +import { GameModes } from "#app/game-mode"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; +import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; +import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; +import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; +import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; +import { Button } from "#enums/buttons"; import { Species } from "#enums/species"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("UI - Starter select", () => { diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index 21aed9b5b87..f7dea463574 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -2,16 +2,15 @@ import { BerryType } from "#app/enums/berry-type"; import { Button } from "#app/enums/buttons"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import GameManager from "#test/utils/gameManager"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; import { Mode } from "#app/ui/ui"; +import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; -import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; describe("UI - Transfer Items", () => { @@ -44,7 +43,7 @@ describe("UI - Transfer Items", () => { await game.startBattle([Species.RAYQUAZA, Species.RAYQUAZA, Species.RAYQUAZA]); - game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_CLAW)); + game.move.select(Moves.DRAGON_CLAW); game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); @@ -88,6 +87,7 @@ describe("UI - Transfer Items", () => { handler.processInput(Button.ACTION); // select Pokemon expect(handler.optionsContainer.list.some((option) => (option as BBCodeText).text?.includes("Transfer"))).toBe(true); + game.phaseInterceptor.unlock(); }); diff --git a/src/test/ui/type-hints.test.ts b/src/test/ui/type-hints.test.ts index f93260f15b7..ccab02b82bf 100644 --- a/src/test/ui/type-hints.test.ts +++ b/src/test/ui/type-hints.test.ts @@ -1,14 +1,14 @@ -import { Button } from "#app/enums/buttons.js"; +import { Button } from "#app/enums/buttons"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import FightUiHandler from "#app/ui/fight-ui-handler.js"; -import { Mode } from "#app/ui/ui.js"; +import { CommandPhase } from "#app/phases/command-phase"; +import FightUiHandler from "#app/ui/fight-ui-handler"; +import { Mode } from "#app/ui/ui"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import MockText from "../utils/mocks/mocksContainer/mockText"; import { SPLASH_ONLY } from "../utils/testUtils"; -import { CommandPhase } from "#app/phases/command-phase.js"; describe("UI - Type Hints", () => { let phaserGame: Phaser.Game; diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index d60cbd62836..cb3c547744b 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -1,47 +1,47 @@ -import GameWrapper from "#test/utils/gameWrapper"; -import { Mode } from "#app/ui/ui"; -import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils"; -import BattleScene from "#app/battle-scene.js"; -import PhaseInterceptor from "#test/utils/phaseInterceptor"; -import TextInterceptor from "#test/utils/TextInterceptor"; -import { GameModes, getGameMode } from "#app/game-mode"; -import fs from "fs"; -import { AES, enc } from "crypto-js"; import { updateUserInfo } from "#app/account"; -import InputsHandler from "#app/test/utils/inputsHandler"; -import ErrorInterceptor from "#app/test/utils/errorInterceptor"; +import { BattlerIndex } from "#app/battle"; +import BattleScene from "#app/battle-scene"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { MockClock } from "#app/test/utils/mocks/mockClock"; -import PartyUiHandler from "#app/ui/party-ui-handler"; -import CommandUiHandler, { Command } from "#app/ui/command-ui-handler"; import Trainer from "#app/field/trainer"; +import { GameModes, getGameMode } from "#app/game-mode"; +import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; +import { CommandPhase } from "#app/phases/command-phase"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { FaintPhase } from "#app/phases/faint-phase"; +import { LoginPhase } from "#app/phases/login-phase"; +import { MovePhase } from "#app/phases/move-phase"; +import { NewBattlePhase } from "#app/phases/new-battle-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { SelectTargetPhase } from "#app/phases/select-target-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; +import ErrorInterceptor from "#app/test/utils/errorInterceptor"; +import InputsHandler from "#app/test/utils/inputsHandler"; +import { MockClock } from "#app/test/utils/mocks/mockClock"; +import CommandUiHandler from "#app/ui/command-ui-handler"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; +import PartyUiHandler from "#app/ui/party-ui-handler"; +import TargetSelectUiHandler from "#app/ui/target-select-ui-handler"; +import { Mode } from "#app/ui/ui"; +import { Button } from "#enums/buttons"; import { ExpNotification } from "#enums/exp-notification"; import { GameDataType } from "#enums/game-data-type"; import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; -import { Button } from "#enums/buttons"; -import { BattlerIndex } from "#app/battle.js"; -import TargetSelectUiHandler from "#app/ui/target-select-ui-handler.js"; -import { OverridesHelper } from "./helpers/overridesHelper"; -import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; -import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js"; -import { MoveHelper } from "./helpers/moveHelper"; +import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils"; +import GameWrapper from "#test/utils/gameWrapper"; +import PhaseInterceptor from "#test/utils/phaseInterceptor"; +import TextInterceptor from "#test/utils/TextInterceptor"; +import { AES, enc } from "crypto-js"; +import fs from "fs"; import { vi } from "vitest"; import { ClassicModeHelper } from "./helpers/classicModeHelper"; import { DailyModeHelper } from "./helpers/dailyModeHelper"; +import { MoveHelper } from "./helpers/moveHelper"; +import { OverridesHelper } from "./helpers/overridesHelper"; import { SettingsHelper } from "./helpers/settingsHelper"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { FaintPhase } from "#app/phases/faint-phase.js"; -import { LoginPhase } from "#app/phases/login-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { NewBattlePhase } from "#app/phases/new-battle-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; /** * Class to manage the game state and transitions between phases. @@ -192,38 +192,23 @@ export default class GameManager { } /** - * Emulate a player attack - * @param movePosition the index of the move in the pokemon's moveset array + * Emulate a player's target selection after a move is chosen, usually called automatically by {@linkcode MoveHelper.select}. + * Will trigger during the next {@linkcode SelectTargetPhase} + * @param {BattlerIndex} targetIndex The index of the attack target, or `undefined` for multi-target attacks + * @param movePosition The index of the move in the pokemon's moveset array */ - doAttack(movePosition: integer) { - this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - this.scene.ui.setMode(Mode.FIGHT, (this.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); - }); - this.onNextPrompt("CommandPhase", Mode.FIGHT, () => { - (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); - }); - - // Confirm target selection if move is multi-target + selectTarget(movePosition: integer, targetIndex?: BattlerIndex) { this.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { const handler = this.scene.ui.getHandler() as TargetSelectUiHandler; const move = (this.scene.getCurrentPhase() as SelectTargetPhase).getPokemon().getMoveset()[movePosition]!.getMove(); // TODO: is the bang correct? - if (move.isMultiTarget()) { - handler.processInput(Button.ACTION); + if (!move.isMultiTarget()) { + handler.setCursor(targetIndex !== undefined ? targetIndex : BattlerIndex.ENEMY); + } + if (move.isMultiTarget() && targetIndex !== undefined) { + throw new Error(`targetIndex was passed to selectMove() but move ("${move.name}") is not targetted`); } - }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(MovePhase) || this.isCurrentPhase(TurnEndPhase)); - } - - /** - * Emulate a player's target selection after an attack is chosen, - * usually called after {@linkcode doAttack} in a double battle. - * @param {BattlerIndex} targetIndex the index of the attack target - */ - doSelectTarget(targetIndex: BattlerIndex) { - this.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { - const handler = this.scene.ui.getHandler() as TargetSelectUiHandler; - handler.setCursor(targetIndex); handler.processInput(Button.ACTION); - }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnStartPhase)); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(MovePhase) || this.isCurrentPhase(TurnStartPhase) || this.isCurrentPhase(TurnEndPhase)); } /** Faint all opponents currently on the field */ @@ -321,7 +306,7 @@ export default class GameManager { */ async importData(path): Promise<[boolean, integer]> { const saveKey = "x0i2O7WRiANTqPmZ"; - const dataRaw = fs.readFileSync(path, {encoding: "utf8", flag: "r"}); + const dataRaw = fs.readFileSync(path, { encoding: "utf8", flag: "r" }); let dataStr = AES.decrypt(dataRaw, saveKey).toString(enc.Utf8); dataStr = this.scene.gameData.convertSystemDataStr(dataStr); const systemData = this.scene.gameData.parseSystemData(dataStr); @@ -335,7 +320,7 @@ export default class GameManager { async killPokemon(pokemon: PlayerPokemon | EnemyPokemon) { (this.scene.time as MockClock).overrideDelay = 0.01; - return new Promise(async(resolve, reject) => { + return new Promise(async (resolve, reject) => { pokemon.hp = 0; this.scene.pushPhase(new FaintPhase(this.scene, pokemon.getBattlerIndex(), true)); await this.phaseInterceptor.to(FaintPhase).catch((e) => reject(e)); diff --git a/src/test/utils/gameManagerUtils.ts b/src/test/utils/gameManagerUtils.ts index dfba55fc75c..20a3fd179fd 100644 --- a/src/test/utils/gameManagerUtils.ts +++ b/src/test/utils/gameManagerUtils.ts @@ -1,12 +1,12 @@ +import BattleScene from "#app/battle-scene"; import { getDailyRunStarters } from "#app/data/daily-run"; import { Gender } from "#app/data/gender"; -import { Species } from "#enums/species"; -import { Starter } from "#app/ui/starter-select-ui-handler"; -import { GameModes, getGameMode } from "#app/game-mode"; import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; -import { PlayerPokemon } from "#app/field/pokemon"; import { Moves } from "#app/enums/moves"; -import BattleScene from "#app/battle-scene"; +import { PlayerPokemon } from "#app/field/pokemon"; +import { GameModes, getGameMode } from "#app/game-mode"; +import { Starter } from "#app/ui/starter-select-ui-handler"; +import { Species } from "#enums/species"; /** Function to convert Blob to string */ export function blobToString(blob) { diff --git a/src/test/utils/gameWrapper.ts b/src/test/utils/gameWrapper.ts index 49044c260fa..f3098fa9b71 100644 --- a/src/test/utils/gameWrapper.ts +++ b/src/test/utils/gameWrapper.ts @@ -1,31 +1,28 @@ /* eslint-disable */ // @ts-nocheck -import * as main from "#app/main"; +import BattleScene, * as battleScene from "#app/battle-scene"; +import { MoveAnim } from "#app/data/battle-anims"; +import Pokemon from "#app/field/pokemon"; +import * as Utils from "#app/utils"; +import { blobToString } from "#test/utils/gameManagerUtils"; +import { MockClock } from "#test/utils/mocks/mockClock"; +import mockConsoleLog from "#test/utils/mocks/mockConsoleLog"; +import { MockFetch } from "#test/utils/mocks/mockFetch"; +import MockLoader from "#test/utils/mocks/mockLoader"; +import mockLocalStorage from "#test/utils/mocks/mockLocalStorage"; +import MockImage from "#test/utils/mocks/mocksContainer/mockImage"; +import MockTextureManager from "#test/utils/mocks/mockTextureManager"; import fs from "fs"; +import Phaser from "phaser"; +import InputText from "phaser3-rex-plugins/plugins/inputtext"; +import { vi } from "vitest"; +import { MockGameObjectCreator } from "./mocks/mockGameObjectCreator"; import InputManager = Phaser.Input.InputManager; import KeyboardManager = Phaser.Input.Keyboard.KeyboardManager; import KeyboardPlugin = Phaser.Input.Keyboard.KeyboardPlugin; import GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin; import EventEmitter = Phaser.Events.EventEmitter; import UpdateList = Phaser.GameObjects.UpdateList; -import MockGraphics from "#test/utils/mocks/mocksContainer/mockGraphics"; -import MockTextureManager from "#test/utils/mocks/mockTextureManager"; -import Phaser from "phaser"; -import { blobToString } from "#test/utils/gameManagerUtils"; -import { vi } from "vitest"; -import mockLocalStorage from "#test/utils/mocks/mockLocalStorage"; -import mockConsoleLog from "#test/utils/mocks/mockConsoleLog"; -import MockLoader from "#test/utils/mocks/mockLoader"; -import { MockFetch } from "#test/utils/mocks/mockFetch"; -import * as Utils from "#app/utils"; -import InputText from "phaser3-rex-plugins/plugins/inputtext"; -import { MockClock } from "#test/utils/mocks/mockClock"; -import BattleScene from "#app/battle-scene.js"; -import { MoveAnim } from "#app/data/battle-anims"; -import Pokemon from "#app/field/pokemon"; -import * as battleScene from "#app/battle-scene"; -import MockImage from "#test/utils/mocks/mocksContainer/mockImage.js"; -import { MockGameObjectCreator } from "./mocks/mockGameObjectCreator"; Object.defineProperty(window, "localStorage", { value: mockLocalStorage(), diff --git a/src/test/utils/helpers/classicModeHelper.ts b/src/test/utils/helpers/classicModeHelper.ts index cf59dd81183..f41472303b4 100644 --- a/src/test/utils/helpers/classicModeHelper.ts +++ b/src/test/utils/helpers/classicModeHelper.ts @@ -1,9 +1,9 @@ -import { Species } from "#app/enums/species.js"; -import { GameModes, getGameMode } from "#app/game-mode.js"; -import overrides from "#app/overrides.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { Mode } from "#app/ui/ui.js"; +import { Species } from "#app/enums/species"; +import { GameModes, getGameMode } from "#app/game-mode"; +import overrides from "#app/overrides"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { Mode } from "#app/ui/ui"; import { generateStarter } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; diff --git a/src/test/utils/helpers/dailyModeHelper.ts b/src/test/utils/helpers/dailyModeHelper.ts index a143e212fcb..8f60981f4d8 100644 --- a/src/test/utils/helpers/dailyModeHelper.ts +++ b/src/test/utils/helpers/dailyModeHelper.ts @@ -1,9 +1,9 @@ -import { Button } from "#app/enums/buttons.js"; -import overrides from "#app/overrides.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; -import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler.js"; -import { Mode } from "#app/ui/ui.js"; +import { Button } from "#app/enums/buttons"; +import overrides from "#app/overrides"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; +import { Mode } from "#app/ui/ui"; import { GameManagerHelper } from "./gameManagerHelper"; /** diff --git a/src/test/utils/helpers/moveHelper.ts b/src/test/utils/helpers/moveHelper.ts index 3179e63a6d0..a53fa521785 100644 --- a/src/test/utils/helpers/moveHelper.ts +++ b/src/test/utils/helpers/moveHelper.ts @@ -1,6 +1,12 @@ +import { BattlerIndex } from "#app/battle"; +import { Moves } from "#app/enums/moves"; +import { CommandPhase } from "#app/phases/command-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { Command } from "#app/ui/command-ui-handler"; +import { Mode } from "#app/ui/ui"; import { vi } from "vitest"; +import { getMovePosition } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; /** * Helper to handle a Pokemon's move @@ -32,4 +38,25 @@ export class MoveHelper extends GameManagerHelper { hitCheck.mockReturnValue(false); } } + + /** + * Select the move to be used by the given Pokemon(-index). Triggers during the next {@linkcode CommandPhase} + * @param move the move to use + * @param pkmIndex the pokemon index. Relevant for double-battles only (defaults to 0) + * @param targetIndex The {@linkcode BattlerIndex} of the Pokemon to target for single-target moves, or `null` if a manual call to `selectTarget()` is required + */ + select(move: Moves, pkmIndex: 0 | 1 = 0, targetIndex?: BattlerIndex | null) { + const movePosition = getMovePosition(this.game.scene, pkmIndex, move); + + this.game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + this.game.scene.ui.setMode(Mode.FIGHT, (this.game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + }); + this.game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); + }); + + if (targetIndex !== null) { + this.game.selectTarget(movePosition, targetIndex); + } + } } diff --git a/src/test/utils/inputsHandler.ts b/src/test/utils/inputsHandler.ts index 148329ada32..30dd101f43d 100644 --- a/src/test/utils/inputsHandler.ts +++ b/src/test/utils/inputsHandler.ts @@ -1,11 +1,11 @@ import BattleScene from "#app/battle-scene"; -import Phaser from "phaser"; -import { InputsController } from "#app/inputs-controller"; import pad_xbox360 from "#app/configs/inputs/pad_xbox360"; -import { holdOn } from "#test/utils/gameManagerUtils"; +import { InputsController } from "#app/inputs-controller"; import TouchControl from "#app/touch-controls"; -import { JSDOM } from "jsdom"; +import { holdOn } from "#test/utils/gameManagerUtils"; import fs from "fs"; +import { JSDOM } from "jsdom"; +import Phaser from "phaser"; interface LogEntry { type: string; diff --git a/src/test/utils/misc.test.ts b/src/test/utils/misc.test.ts index c1947dbe8a2..a49b2894ca2 100644 --- a/src/test/utils/misc.test.ts +++ b/src/test/utils/misc.test.ts @@ -1,8 +1,8 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/utils/gameManager"; import { apiFetch } from "#app/utils"; +import GameManager from "#test/utils/gameManager"; import { waitUntil } from "#test/utils/gameManagerUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Test misc", () => { let phaserGame: Phaser.Game; diff --git a/src/test/utils/mocks/mockTextureManager.ts b/src/test/utils/mocks/mockTextureManager.ts index 330409e9776..16d94da28ad 100644 --- a/src/test/utils/mocks/mockTextureManager.ts +++ b/src/test/utils/mocks/mockTextureManager.ts @@ -1,12 +1,12 @@ import MockContainer from "#test/utils/mocks/mocksContainer/mockContainer"; -import MockSprite from "#test/utils/mocks/mocksContainer/mockSprite"; -import MockRectangle from "#test/utils/mocks/mocksContainer/mockRectangle"; -import MockNineslice from "#test/utils/mocks/mocksContainer/mockNineslice"; import MockImage from "#test/utils/mocks/mocksContainer/mockImage"; -import MockText from "#test/utils/mocks/mocksContainer/mockText"; +import MockNineslice from "#test/utils/mocks/mocksContainer/mockNineslice"; import MockPolygon from "#test/utils/mocks/mocksContainer/mockPolygon"; -import { MockGameObject } from "./mockGameObject"; +import MockRectangle from "#test/utils/mocks/mocksContainer/mockRectangle"; +import MockSprite from "#test/utils/mocks/mocksContainer/mockSprite"; +import MockText from "#test/utils/mocks/mocksContainer/mockText"; import MockTexture from "#test/utils/mocks/mocksContainer/mockTexture"; +import { MockGameObject } from "./mockGameObject"; /** * Stub class for Phaser.Textures.TextureManager diff --git a/src/test/utils/mocks/mocksContainer/mockSprite.ts b/src/test/utils/mocks/mocksContainer/mockSprite.ts index 9c566fc4bcb..35cd2d5faab 100644 --- a/src/test/utils/mocks/mocksContainer/mockSprite.ts +++ b/src/test/utils/mocks/mocksContainer/mockSprite.ts @@ -1,7 +1,7 @@ +import Phaser from "phaser"; import { MockGameObject } from "../mockGameObject"; import Sprite = Phaser.GameObjects.Sprite; import Frame = Phaser.Textures.Frame; -import Phaser from "phaser"; export default class MockSprite implements MockGameObject { diff --git a/src/test/utils/mocks/mocksContainer/mockTexture.ts b/src/test/utils/mocks/mocksContainer/mockTexture.ts index 03bedb4751b..cb31480cc60 100644 --- a/src/test/utils/mocks/mocksContainer/mockTexture.ts +++ b/src/test/utils/mocks/mocksContainer/mockTexture.ts @@ -1,5 +1,5 @@ -import { MockGameObject } from "../mockGameObject"; import MockTextureManager from "#test/utils/mocks/mockTextureManager"; +import { MockGameObject } from "../mockGameObject"; /** diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 2304d726757..ca3d55137fa 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -1,42 +1,42 @@ -import UI, { Mode } from "#app/ui/ui"; import { Phase } from "#app/phase"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; +import { CommandPhase } from "#app/phases/command-phase"; +import { DamagePhase } from "#app/phases/damage-phase"; +import { EggLapsePhase } from "#app/phases/egg-lapse-phase"; +import { EncounterPhase } from "#app/phases/encounter-phase"; +import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { FaintPhase } from "#app/phases/faint-phase"; +import { LoginPhase } from "#app/phases/login-phase"; +import { MessagePhase } from "#app/phases/message-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { MovePhase } from "#app/phases/move-phase"; +import { NewBattlePhase } from "#app/phases/new-battle-phase"; +import { NextEncounterPhase } from "#app/phases/next-encounter-phase"; +import { PartyHealPhase } from "#app/phases/party-heal-phase"; +import { PostSummonPhase } from "#app/phases/post-summon-phase"; +import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; +import { SelectGenderPhase } from "#app/phases/select-gender-phase"; +import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { SelectTargetPhase } from "#app/phases/select-target-phase"; +import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase"; +import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; +import { StatChangePhase } from "#app/phases/stat-change-phase"; +import { SummonPhase } from "#app/phases/summon-phase"; +import { SwitchPhase } from "#app/phases/switch-phase"; +import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; +import { TitlePhase } from "#app/phases/title-phase"; +import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; +import { UnavailablePhase } from "#app/phases/unavailable-phase"; +import { VictoryPhase } from "#app/phases/victory-phase"; import ErrorInterceptor from "#app/test/utils/errorInterceptor"; -import { BattleEndPhase } from "#app/phases/battle-end-phase.js"; -import { BerryPhase } from "#app/phases/berry-phase.js"; -import { CheckSwitchPhase } from "#app/phases/check-switch-phase.js"; -import { CommandPhase } from "#app/phases/command-phase.js"; -import { DamagePhase } from "#app/phases/damage-phase.js"; -import { EggLapsePhase } from "#app/phases/egg-lapse-phase.js"; -import { EncounterPhase } from "#app/phases/encounter-phase.js"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase.js"; -import { FaintPhase } from "#app/phases/faint-phase.js"; -import { LoginPhase } from "#app/phases/login-phase.js"; -import { MessagePhase } from "#app/phases/message-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MoveEndPhase } from "#app/phases/move-end-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { NewBattlePhase } from "#app/phases/new-battle-phase.js"; -import { NextEncounterPhase } from "#app/phases/next-encounter-phase.js"; -import { PostSummonPhase } from "#app/phases/post-summon-phase.js"; -import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase.js"; -import { SelectGenderPhase } from "#app/phases/select-gender-phase.js"; -import { SelectModifierPhase } from "#app/phases/select-modifier-phase.js"; -import { SelectStarterPhase } from "#app/phases/select-starter-phase.js"; -import { SelectTargetPhase } from "#app/phases/select-target-phase.js"; -import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase.js"; -import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; -import { StatChangePhase } from "#app/phases/stat-change-phase.js"; -import { SummonPhase } from "#app/phases/summon-phase.js"; -import { SwitchPhase } from "#app/phases/switch-phase.js"; -import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; -import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase.js"; -import { TurnEndPhase } from "#app/phases/turn-end-phase.js"; -import { TurnInitPhase } from "#app/phases/turn-init-phase.js"; -import { TurnStartPhase } from "#app/phases/turn-start-phase.js"; -import { UnavailablePhase } from "#app/phases/unavailable-phase.js"; -import { VictoryPhase } from "#app/phases/victory-phase.js"; -import { PartyHealPhase } from "#app/phases/party-heal-phase.js"; +import UI, { Mode } from "#app/ui/ui"; export default class PhaseInterceptor { public scene; diff --git a/src/test/vitest.setup.ts b/src/test/vitest.setup.ts index b2861b7071c..eaa987c1a66 100644 --- a/src/test/vitest.setup.ts +++ b/src/test/vitest.setup.ts @@ -9,8 +9,8 @@ import { initMoves } from "#app/data/move"; import { initPokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { initPokemonForms } from "#app/data/pokemon-forms"; import { initSpecies } from "#app/data/pokemon-species"; -import { initAchievements } from "#app/system/achv.js"; -import { initVouchers } from "#app/system/voucher.js"; +import { initAchievements } from "#app/system/achv"; +import { initVouchers } from "#app/system/voucher"; import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; import { beforeAll, vi } from "vitest"; From 0cd52b86d27d8eca77bf1a710b9a88a793f5f115 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:20:14 -0700 Subject: [PATCH 58/63] [Refactor] Move Daily Pokerus Start Generation to its own function in data/pokemon-species (#3501) * Moving daily Pokerus generation to game-data * Moved pokerus starter generation to pokemon-species * Added JsDocs * Update src/data/pokemon-species.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * boo typedocs boo --------- Co-authored-by: Frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/pokemon-species.ts | 22 ++++++++++++++++++ src/ui/starter-select-ui-handler.ts | 36 +++-------------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index aa2c29a9725..da2892f8128 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3317,6 +3317,28 @@ export function getStarterValueFriendshipCap(value: integer): integer { } } +/** +* Method to get the daily list of starters with Pokerus. +* @param scene {@linkcode BattleScene} used as part of RNG +* @returns A list of starters with Pokerus +*/ +export function getPokerusStarters(scene: BattleScene): PokemonSpecies[] { + const pokerusStarters: PokemonSpecies[] = []; + const date = new Date(); + const starterCount = 3; //for easy future adjustment! + date.setUTCHours(0, 0, 0, 0); + scene.executeWithSeedOffset(() => { + while (pokerusStarters.length < starterCount) { + const randomSpeciesId = parseInt(Utils.randSeedItem(Object.keys(speciesStarters)), 10); + const species = getPokemonSpecies(randomSpeciesId); + if (!pokerusStarters.includes(species)) { + pokerusStarters.push(species); + } + } + }, 0, date.getTime().toString()); + return pokerusStarters; +} + export const starterPassiveAbilities = { [Species.BULBASAUR]: Abilities.GRASSY_SURGE, [Species.CHARMANDER]: Abilities.BEAST_BOOST, diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 67e870838a2..bc809d8c686 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -13,7 +13,7 @@ import { allMoves } from "../data/move"; import { Nature, getNatureName } from "../data/nature"; import { pokemonFormChanges } from "../data/pokemon-forms"; import { LevelMoves, pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "../data/pokemon-level-moves"; -import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; +import PokemonSpecies, { allSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities, getPokerusStarters } from "../data/pokemon-species"; import { Type } from "../data/type"; import { GameModes } from "../game-mode"; import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterMoveset, StarterAttributes, StarterPreferences, StarterPrefs } from "../system/game-data"; @@ -872,38 +872,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.message.setOrigin(0, 0); this.starterSelectMessageBoxContainer.add(this.message); - const date = new Date(); - date.setUTCHours(0, 0, 0, 0); - - this.scene.executeWithSeedOffset(() => { - for (let c = 0; c < 3; c++) { - let randomSpeciesId: Species; - let species: PokemonSpecies | undefined; - - const generateSpecies = () => { - randomSpeciesId = Utils.randSeedItem(starterSpecies); - species = getPokemonSpecies(randomSpeciesId); - }; - - let dupe = false; - - do { - dupe = false; - - generateSpecies(); - - for (let ps = 0; ps < c; ps++) { - if (this.pokerusSpecies[ps] === species) { - dupe = true; - break; - } - } - } while (dupe); - - this.pokerusSpecies.push(species!); // TODO: is the bang correct? - } - }, 0, date.getTime().toString()); - this.statsContainer = new StatsContainer(this.scene, 6, 16); this.scene.add.existing(this.statsContainer); @@ -934,6 +902,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterPreferences = StarterPrefs.load(); } this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers + this.pokerusSpecies = getPokerusStarters(this.scene); + if (args.length >= 1 && args[0] instanceof Function) { super.show(args); this.starterSelectCallback = args[0] as StarterSelectCallback; From a7acf752db6ca3c95226fa7caeefa736e513ccde Mon Sep 17 00:00:00 2001 From: Enoch Date: Fri, 23 Aug 2024 01:23:47 +0900 Subject: [PATCH 59/63] [Localization] Add localization hard-coded message in ability (AIR_LOCK, CLOUD_NINE) (#3641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * localize ability message "The effects of the weather disappeared." * Update src/locales/de/ability-trigger.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/it/ability-trigger.ts Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> * Update src/locales/fr/ability-trigger.ts Co-authored-by: Lugiad' * Apply suggestions from code review Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/es/ability-trigger.ts Co-authored-by: Asdar --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Asdar --- src/data/ability.ts | 4 ++-- src/locales/ca_ES/ability-trigger.ts | 1 + src/locales/de/ability-trigger.ts | 1 + src/locales/en/ability-trigger.ts | 1 + src/locales/es/ability-trigger.ts | 1 + src/locales/fr/ability-trigger.ts | 1 + src/locales/it/ability-trigger.ts | 1 + src/locales/ja/ability-trigger.ts | 1 + src/locales/ko/ability-trigger.ts | 1 + src/locales/pt_BR/ability-trigger.ts | 1 + src/locales/zh_CN/ability-trigger.ts | 1 + src/locales/zh_TW/ability-trigger.ts | 1 + 12 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 284a9cb4e91..8b220b14cf1 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4591,7 +4591,7 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.CLOUD_NINE, 3) .attr(SuppressWeatherEffectAbAttr, true) - .attr(PostSummonUnnamedMessageAbAttr, "The effects of the weather disappeared."), + .attr(PostSummonUnnamedMessageAbAttr, i18next.t("abilityTriggers:weatherEffectDisappeared")), new Ability(Abilities.COMPOUND_EYES, 3) .attr(BattleStatMultiplierAbAttr, BattleStat.ACC, 1.3), new Ability(Abilities.INSOMNIA, 3) @@ -4786,7 +4786,7 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.AIR_LOCK, 3) .attr(SuppressWeatherEffectAbAttr, true) - .attr(PostSummonUnnamedMessageAbAttr, "The effects of the weather disappeared."), + .attr(PostSummonUnnamedMessageAbAttr, i18next.t("abilityTriggers:weatherEffectDisappeared")), new Ability(Abilities.TANGLED_FEET, 4) .conditionalAttr(pokemon => !!pokemon.getTag(BattlerTagType.CONFUSED), BattleStatMultiplierAbAttr, BattleStat.EVA, 2) .ignorable(), diff --git a/src/locales/ca_ES/ability-trigger.ts b/src/locales/ca_ES/ability-trigger.ts index 2bdd17baa56..0b7fe8bd0bc 100644 --- a/src/locales/ca_ES/ability-trigger.ts +++ b/src/locales/ca_ES/ability-trigger.ts @@ -47,6 +47,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", + "weatherEffectDisappeared": "The effects of the weather disappeared.", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts index 72023a842b3..9e4ef9df6ed 100644 --- a/src/locales/de/ability-trigger.ts +++ b/src/locales/de/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{abilityName}} von {{pokemonNameWithAffix}} schadet seinem Angreifer!", "postFaintHpDamage": "{{abilityName}} von {{pokemonNameWithAffix}} schadet seinem Angreifer!", "postSummonPressure": "{{pokemonNameWithAffix}} setzt Gegner mit Erzwinger unter Druck!", + "weatherEffectDisappeared": "Jegliche wetterbedingten Effekte wurden aufgehoben!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} gelingt es, gegnerische Fähigkeiten zu überbrücken!", "postSummonAnticipation": "{{pokemonNameWithAffix}} erschaudert!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} strahlt eine lodernde Aura aus!", diff --git a/src/locales/en/ability-trigger.ts b/src/locales/en/ability-trigger.ts index 035fe8371be..2a0e0df255a 100644 --- a/src/locales/en/ability-trigger.ts +++ b/src/locales/en/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", + "weatherEffectDisappeared": "The effects of the weather disappeared.", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", diff --git a/src/locales/es/ability-trigger.ts b/src/locales/es/ability-trigger.ts index 60bc186e99d..99ebfe3bd4c 100644 --- a/src/locales/es/ability-trigger.ts +++ b/src/locales/es/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", + "weatherEffectDisappeared": "El tiempo atmosférico ya no ejerce ninguna influencia.", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", diff --git a/src/locales/fr/ability-trigger.ts b/src/locales/fr/ability-trigger.ts index cd077993b4e..92e02b82414 100644 --- a/src/locales/fr/ability-trigger.ts +++ b/src/locales/fr/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}} est blessé\npar son talent {{abilityName}} !", "postFaintHpDamage": "{{pokemonNameWithAffix}} est blessé\npar son talent {{abilityName}} !", "postSummonPressure": "{{pokemonNameWithAffix}}\naugmente la pression !", + "weatherEffectDisappeared": "Les effets de la météo se dissipent !", "postSummonMoldBreaker": "{{pokemonNameWithAffix}}\nbrise le moule !", "postSummonAnticipation": "{{pokemonNameWithAffix}}\nest tout tremblant !", "postSummonTurboblaze": "{{pokemonNameWithAffix}} dégage\nune aura de flammes incandescentes !", diff --git a/src/locales/it/ability-trigger.ts b/src/locales/it/ability-trigger.ts index c834fa28fbe..6ac5e76ee3e 100644 --- a/src/locales/it/ability-trigger.ts +++ b/src/locales/it/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", "postFaintHpDamage": "{{abilityName}} di {{pokemonNameWithAffix}}\nferisce il Pokémon che lo ha attaccato!", "postSummonPressure": "{{pokemonNameWithAffix}} fa pressione!", + "weatherEffectDisappeared": "Le condizioni atmosferiche non hanno alcun effetto.", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} ha l’abilità Rompiforma!", "postSummonAnticipation": "{{pokemonNameWithAffix}} rabbrividisce!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} emana un’aura infuocata!", diff --git a/src/locales/ja/ability-trigger.ts b/src/locales/ja/ability-trigger.ts index 7c7d081f645..cf4c89ff5a4 100644 --- a/src/locales/ja/ability-trigger.ts +++ b/src/locales/ja/ability-trigger.ts @@ -47,6 +47,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}は {{abilityName}}で\n相手に ダメージを 与えた!", "postFaintHpDamage": "{{pokemonNameWithAffix}}は {{abilityName}}で\n相手に ダメージを 与えた!", "postSummonPressure": "{{pokemonNameWithAffix}}は\nプレッシャーを 放っている!", + "weatherEffectDisappeared": "天候の影響が なくなった!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}}は\nかたやぶりだ!", "postSummonAnticipation": "{{pokemonNameWithAffix}}は\nみぶるいした!", "postSummonTurboblaze": "{{pokemonNameWithAffix}}は\n燃え盛(もえさか)る オーラを 放っている!", diff --git a/src/locales/ko/ability-trigger.ts b/src/locales/ko/ability-trigger.ts index 974e6970569..9e330c176e7 100644 --- a/src/locales/ko/ability-trigger.ts +++ b/src/locales/ko/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}[[는]] {{abilityName}}[[로]]\n상대에게 데미지를 입혔다!", "postFaintHpDamage": "{{pokemonNameWithAffix}}[[는]] {{abilityName}}[[로]]\n상대에게 데미지를 입혔다!", "postSummonPressure": "{{pokemonNameWithAffix}}[[는]]\n프레셔를 발산하고 있다!", + "weatherEffectDisappeared": "날씨의 영향이 없어졌다!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}}의\n틀깨기!", "postSummonAnticipation": "{{pokemonNameWithAffix}}[[는]]\n몸을 떨었다!", "postSummonTurboblaze": "{{pokemonNameWithAffix}}[[는]]\n활활 타오르는 오라를 발산하고 있다!", diff --git a/src/locales/pt_BR/ability-trigger.ts b/src/locales/pt_BR/ability-trigger.ts index da91fa3213f..9cfa42edce3 100644 --- a/src/locales/pt_BR/ability-trigger.ts +++ b/src/locales/pt_BR/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{abilityName}} de {{pokemonNameWithAffix}}\nferiu seu adversário!", "postFaintHpDamage": "{{abilityName}} de {{pokemonNameWithAffix}}\nferiu seu adversário!", "postSummonPressure": "{{pokemonNameWithAffix}} está exercendo sua pressão!", + "weatherEffectDisappeared": "Os efeitos do clima desapareceram.", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} quebra o molde!", "postSummonAnticipation": "{{pokemonNameWithAffix}} se arrepiou!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} está irradiando uma aura ardente!", diff --git a/src/locales/zh_CN/ability-trigger.ts b/src/locales/zh_CN/ability-trigger.ts index 0d69a78f0f7..337c0655c87 100644 --- a/src/locales/zh_CN/ability-trigger.ts +++ b/src/locales/zh_CN/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}的{{abilityName}}\n使对方受到了伤害!", "postFaintHpDamage": "{{pokemonNameWithAffix}}的{{abilityName}}\n使对方受到了伤害!", "postSummonPressure": "从{{pokemonNameWithAffix}}的身上\n感到了一种压迫感!", + "weatherEffectDisappeared": "天气的影响消失了!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}}\n打破了常规!", "postSummonAnticipation": "{{pokemonNameWithAffix}}\n发抖了!", "postSummonTurboblaze": "{{pokemonNameWithAffix}}\n正在释放炽焰气场!", diff --git a/src/locales/zh_TW/ability-trigger.ts b/src/locales/zh_TW/ability-trigger.ts index c0d348633bc..14aa6de1af7 100644 --- a/src/locales/zh_TW/ability-trigger.ts +++ b/src/locales/zh_TW/ability-trigger.ts @@ -46,6 +46,7 @@ export const abilityTriggers: SimpleTranslationEntries = { "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", + "weatherEffectDisappeared": "天氣的影響消失了!", "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", From 03ee764e230626b1a175795c938b8e38a2d1ddc8 Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:26:10 +0800 Subject: [PATCH 60/63] [QoL] Settings Option: Shop Cursor Target (#3666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [QoL] Post Reroll UI Targeting * removed hasRolled from battlescene and handled in UI * Added getter for reroll count and ternary * Explicit catch instead of falsy * Fixed Settings errors with proper labeling * changed setting label to translate as well * translations and fixes * move option further down * change integer to number * change integer to number * update implementation * remove unused method * change name set to update * Update src/ui/modifier-select-ui-handler.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * Update src/system/settings/settings.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> * Update src/locales/fr/settings.ts Co-authored-by: Lugiad' * Update src/locales/pt_BR/settings.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/ko/settings.ts Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> * Update src/locales/zh_CN/settings.ts Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> * Update src/locales/it/settings.ts Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> * Revert "Update src/locales/ko/settings.ts" This reverts commit 08c0b89f4caf7c33f49722200d7aeb20b79b0ba5. * Update src/locales/ko/settings.ts Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> * Revert "Revert "Update src/locales/ko/settings.ts"" This reverts commit a57d8777f2e0538ee34764c91d6841bd3ef0dc60. --------- Co-authored-by: Matthew Kroeger Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> --- src/battle-scene.ts | 2 ++ src/enums/shop-cursor-target.ts | 13 +++++++++++++ src/locales/ca_ES/settings.ts | 7 ++++++- src/locales/de/settings.ts | 5 +++++ src/locales/en/settings.ts | 7 ++++++- src/locales/es/settings.ts | 7 ++++++- src/locales/fr/settings.ts | 7 ++++++- src/locales/it/settings.ts | 7 ++++++- src/locales/ja/settings.ts | 5 +++++ src/locales/ko/settings.ts | 7 ++++++- src/locales/pt_BR/settings.ts | 7 ++++++- src/locales/zh_CN/settings.ts | 7 ++++++- src/locales/zh_TW/settings.ts | 7 ++++++- src/phases/select-modifier-phase.ts | 2 +- src/system/settings/settings.ts | 28 ++++++++++++++++++++++++++++ src/ui/modifier-select-ui-handler.ts | 20 ++++++++++++++++---- 16 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 src/enums/shop-cursor-target.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index af63f0b0a39..eaf550e7d10 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -83,6 +83,7 @@ import { SwitchPhase } from "./phases/switch-phase"; import { TitlePhase } from "./phases/title-phase"; import { ToggleDoublePositionPhase } from "./phases/toggle-double-position-phase"; import { TurnInitPhase } from "./phases/turn-init-phase"; +import { ShopCursorTarget } from "./enums/shop-cursor-target"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -127,6 +128,7 @@ export default class BattleScene extends SceneBase { public gameSpeed: integer = 1; public damageNumbersMode: integer = 0; public reroll: boolean = false; + public shopCursorTarget: number = ShopCursorTarget.CHECK_TEAM; public showMovesetFlyout: boolean = true; public showArenaFlyout: boolean = true; public showTimeOfDayWidget: boolean = true; diff --git a/src/enums/shop-cursor-target.ts b/src/enums/shop-cursor-target.ts new file mode 100644 index 00000000000..d2f72fed0d6 --- /dev/null +++ b/src/enums/shop-cursor-target.ts @@ -0,0 +1,13 @@ +/** + * Determines the cursor target when entering the shop phase. + */ +export enum ShopCursorTarget { + /** Cursor points to Reroll */ + REROLL, + /** Cursor points to Items */ + ITEMS, + /** Cursor points to Shop */ + SHOP, + /** Cursor points to Check Team */ + CHECK_TEAM +} diff --git a/src/locales/ca_ES/settings.ts b/src/locales/ca_ES/settings.ts index 491bfa4a481..9c0b3f36365 100644 --- a/src/locales/ca_ES/settings.ts +++ b/src/locales/ca_ES/settings.ts @@ -96,5 +96,10 @@ export const settings: SimpleTranslationEntries = { "controller": "Controller", "gamepadSupport": "Gamepad Support", "showBgmBar": "Show Music Names", - "shopOverlayOpacity": "Shop Overlay Opacity" + "shopOverlayOpacity": "Shop Overlay Opacity", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts index 7d4523c8cbd..3942e470e3f 100644 --- a/src/locales/de/settings.ts +++ b/src/locales/de/settings.ts @@ -99,4 +99,9 @@ export const settings: SimpleTranslationEntries = { "showBgmBar": "Musiknamen anzeigen", "moveTouchControls": "Bewegung Touch Steuerung", "shopOverlayOpacity": "Shop Overlay Deckkraft", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts index c63f9de6049..ad2ea914dc9 100644 --- a/src/locales/en/settings.ts +++ b/src/locales/en/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "Gamepad Support", "showBgmBar": "Show Music Names", "moveTouchControls": "Move Touch Controls", - "shopOverlayOpacity": "Shop Overlay Opacity" + "shopOverlayOpacity": "Shop Overlay Opacity", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts index c7f723fe80c..fbc56d92fe5 100644 --- a/src/locales/es/settings.ts +++ b/src/locales/es/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "Gamepad Support", "showBgmBar": "Show Music Names", "moveTouchControls": "Move Touch Controls", - "shopOverlayOpacity": "Opacidad de la fase de compra" + "shopOverlayOpacity": "Opacidad de la fase de compra", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts index 95246ccb7d0..d5e4047bb12 100644 --- a/src/locales/fr/settings.ts +++ b/src/locales/fr/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "Gamepad Support", "showBgmBar": "Titre de la musique", "moveTouchControls": "Déplacer les contrôles tactiles", - "shopOverlayOpacity": "Opacité boutique" + "shopOverlayOpacity": "Opacité boutique", + "shopCursorTarget": "Choix après relance", + "items": "Obj. gratuits", + "reroll": "Relance", + "shop": "Boutique", + "checkTeam": "Équipe" } as const; diff --git a/src/locales/it/settings.ts b/src/locales/it/settings.ts index 0d05d01ba1c..278a02bef52 100644 --- a/src/locales/it/settings.ts +++ b/src/locales/it/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "Supporto Gamepad", "showBgmBar": "Mostra Nomi Musica", "moveTouchControls": "Move Touch Controls", - "shopOverlayOpacity": "Opacità Finestra Negozio" + "shopOverlayOpacity": "Opacità Finestra Negozio", + "shopCursorTarget": "Target Cursore Negozio", + "items": "Oggetti", + "reroll": "Rerolla", + "shop": "Negozio", + "checkTeam": "Squadra" } as const; diff --git a/src/locales/ja/settings.ts b/src/locales/ja/settings.ts index ef20d071d2d..3be237e26ae 100644 --- a/src/locales/ja/settings.ts +++ b/src/locales/ja/settings.ts @@ -98,4 +98,9 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "コントローラーサポート", "showBgmBar": "Show Music Names", "shopOverlayOpacity": "Shop Overlay Opacity", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/locales/ko/settings.ts b/src/locales/ko/settings.ts index aa4adfc4e41..38b0679d911 100644 --- a/src/locales/ko/settings.ts +++ b/src/locales/ko/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "게임패드 지원", "showBgmBar": "BGM 제목 보여주기", "moveTouchControls": "터치 컨트롤 이동", - "shopOverlayOpacity": "상점 오버레이 투명도" + "shopOverlayOpacity": "상점 오버레이 투명도", + "shopCursorTarget": "상점 커서 위치", + "items": "아이템", + "reroll": "갱신", + "shop": "상점", + "checkTeam": "파티 확인" } as const; diff --git a/src/locales/pt_BR/settings.ts b/src/locales/pt_BR/settings.ts index 14646b59742..e34fdfa0e5d 100644 --- a/src/locales/pt_BR/settings.ts +++ b/src/locales/pt_BR/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "Suporte para Controle", "showBgmBar": "Exibir Nomes das Músicas", "moveTouchControls": "Move Touch Controls", - "shopOverlayOpacity": "Opacidade da Loja" + "shopOverlayOpacity": "Opacidade da Loja", + "shopCursorTarget": "Alvo do Cursor da Loja", + "items": "Itens", + "reroll": "Atualizar", + "shop": "Loja", + "checkTeam": "Checar Time" } as const; diff --git a/src/locales/zh_CN/settings.ts b/src/locales/zh_CN/settings.ts index 422b1bd591d..d727ac2bef5 100644 --- a/src/locales/zh_CN/settings.ts +++ b/src/locales/zh_CN/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "手柄支持", "showBgmBar": "显示音乐名称", "moveTouchControls": "移动触摸控制", - "shopOverlayOpacity": "商店显示不透明度" + "shopOverlayOpacity": "商店显示不透明度", + "shopCursorTarget": "商店指针位置", + "items": "道具", + "reroll": "刷新", + "shop": "购买", + "checkTeam": "检查队伍" } as const; diff --git a/src/locales/zh_TW/settings.ts b/src/locales/zh_TW/settings.ts index 35499f45d15..7e6bf25bd7a 100644 --- a/src/locales/zh_TW/settings.ts +++ b/src/locales/zh_TW/settings.ts @@ -98,5 +98,10 @@ export const settings: SimpleTranslationEntries = { "gamepadSupport": "手柄支持", "showBgmBar": "Show Music Names", "moveTouchControls": "移動觸控控制", - "shopOverlayOpacity": "Shop Overlay Opacity" + "shopOverlayOpacity": "Shop Overlay Opacity", + "shopCursorTarget": "Shop Cursor Target", + "items": "Items", + "reroll": "Reroll", + "shop": "Shop", + "checkTeam": "Check Team" } as const; diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 67ae904fb58..57b842e7b38 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -205,7 +205,7 @@ export class SelectModifierPhase extends BattlePhase { return true; } - getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): integer { + getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): number { let baseValue = 0; if (Overrides.WAIVE_ROLL_FEE_OVERRIDE) { return baseValue; diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 7263ae3a3de..4bd69788f04 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -9,6 +9,7 @@ import { EaseType } from "#enums/ease-type"; import { MoneyFormat } from "#enums/money-format"; import { PlayerGender } from "#enums/player-gender"; import { getIsInitialized, initI18n } from "#app/plugins/i18n.js"; +import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; function getTranslation(key: string): string { if (!getIsInitialized()) { @@ -102,6 +103,7 @@ export const SettingKeys = { Damage_Numbers: "DAMAGE_NUMBERS", Move_Animations: "MOVE_ANIMATIONS", Show_Stats_on_Level_Up: "SHOW_LEVEL_UP_STATS", + Reroll_Target: "REROLL_TARGET", Candy_Upgrade_Notification: "CANDY_UPGRADE_NOTIFICATION", Candy_Upgrade_Display: "CANDY_UPGRADE_DISPLAY", Move_Info: "MOVE_INFO", @@ -577,6 +579,30 @@ export const Setting: Array = [ activatable: true, isHidden: () => !hasTouchscreen() }, + { + key: SettingKeys.Reroll_Target, + label: i18next.t("settings:shopCursorTarget"), + options: [ + { + value:"Reroll", + label: i18next.t("settings:reroll") + }, + { + value:"Items", + label: i18next.t("settings:items") + }, + { + value:"Shop", + label: i18next.t("settings:shop") + }, + { + value:"Check Team", + label: i18next.t("settings:checkTeam") + } + ], + default: ShopCursorTarget.CHECK_TEAM, + type: SettingType.DISPLAY + }, { key: SettingKeys.Shop_Overlay_Opacity, label: i18next.t("settings:shopOverlayOpacity"), @@ -709,6 +735,8 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): case SettingKeys.Show_Stats_on_Level_Up: scene.showLevelUpStats = Setting[index].options[value].value === "On"; break; + case SettingKeys.Reroll_Target: + scene.shopCursorTarget = value; case SettingKeys.EXP_Gains_Speed: scene.expGainsSpeed = value; break; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 016708027ca..bb1f970fe1c 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -12,6 +12,7 @@ import { allMoves } from "../data/move"; import * as Utils from "./../utils"; import Overrides from "#app/overrides"; import i18next from "i18next"; +import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; export const SHOP_OPTIONS_ROW_LIMIT = 6; @@ -249,11 +250,22 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { duration: 250 }); - this.setCursor(0); - this.setRowCursor(1); + const updateCursorTarget = () => { + if (this.scene.shopCursorTarget === ShopCursorTarget.CHECK_TEAM) { + this.setRowCursor(0); + this.setCursor(2); + } else { + this.setRowCursor(this.scene.shopCursorTarget); + this.setCursor(0); + } + }; - handleTutorial(this.scene, Tutorial.Select_Item).then(() => { - this.setCursor(0); + updateCursorTarget(); + + handleTutorial(this.scene, Tutorial.Select_Item).then((res) => { + if (res) { + updateCursorTarget(); + } this.awaitingActionInput = true; this.onActionInput = args[2]; }); From 3baa1400cc4161b815ebebeaa1740778a070c8cc Mon Sep 17 00:00:00 2001 From: schmidtc1 <62030095+schmidtc1@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:57:38 -0400 Subject: [PATCH 61/63] [Bug] Fixes Moody increasing and decreasing the same stat (#3694) * Replaces selectableStats array with the proper decreaseStatArray * Adds docs to MoodyAbAttr * Updates docs, creates unit tests for moody --- src/data/ability.ts | 18 ++++++- src/test/abilities/moody.test.ts | 93 ++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/test/abilities/moody.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 8b220b14cf1..35ab55c0159 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3299,11 +3299,25 @@ export class PostTurnLootAbAttr extends PostTurnAbAttr { } } +/** + * Attribute used for {@linkcode Abilities.MOODY} + */ export class MoodyAbAttr extends PostTurnAbAttr { constructor() { super(true); } - + /** + * Randomly increases one BattleStat by 2 stages and decreases a different BattleStat by 1 stage + * @param {Pokemon} pokemon Pokemon that has this ability + * @param passive N/A + * @param simulated true if applying in a simulated call. + * @param args N/A + * @returns true + * + * Any BattleStats at +6 or -6 are excluded from being increased or decreased, respectively + * If the pokemon already has all BattleStats raised to stage 6, it will only decrease one BattleStat by 1 stage + * If the pokemon already has all BattleStats lowered to stage -6, it will only increase one BattleStat by 2 stages + */ applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const selectableStats = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD]; const increaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] < 6); @@ -3315,7 +3329,7 @@ export class MoodyAbAttr extends PostTurnAbAttr { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2)); } if (!simulated && decreaseStatArray.length > 0) { - const decreaseStat = selectableStats[Utils.randInt(selectableStats.length)]; + const decreaseStat = decreaseStatArray[Utils.randInt(decreaseStatArray.length)]; pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1)); } return true; diff --git a/src/test/abilities/moody.test.ts b/src/test/abilities/moody.test.ts new file mode 100644 index 00000000000..9e936e8100a --- /dev/null +++ b/src/test/abilities/moody.test.ts @@ -0,0 +1,93 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Moody", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + const battleStatsArray = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD]; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .enemySpecies(Species.RATTATA) + .enemyAbility(Abilities.BALL_FETCH) + .enemyPassiveAbility(Abilities.HYDRATION) + .ability(Abilities.MOODY) + .enemyMoveset(SPLASH_ONLY) + .moveset(SPLASH_ONLY); + }); + + it( + "should increase one BattleStat by 2 stages and decrease a different BattleStat by 1 stage", + async () => { + await game.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // Find the increased and decreased stats, make sure they are different. + const statChanges = playerPokemon.summonData.battleStats; + const changedStats = battleStatsArray.filter(bs => statChanges[bs] === 2 || statChanges[bs] === -1); + + expect(changedStats).toBeTruthy(); + expect(changedStats.length).toBe(2); + expect(changedStats[0] !== changedStats[1]).toBeTruthy(); + }); + + it( + "should only increase one BattleStat by 2 stages if all BattleStats are at -6", + async () => { + await game.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + // Set all BattleStats to -6 + battleStatsArray.forEach(bs => playerPokemon.summonData.battleStats[bs] = -6); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // Should increase one BattleStat by 2 (from -6, meaning it will be -4) + const increasedStat = battleStatsArray.filter(bs => playerPokemon.summonData.battleStats[bs] === -4); + + expect(increasedStat).toBeTruthy(); + expect(increasedStat.length).toBe(1); + }); + + it( + "should only decrease one BattleStat by 1 stage if all BattleStats are at 6", + async () => { + await game.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + // Set all BattleStats to 6 + battleStatsArray.forEach(bs => playerPokemon.summonData.battleStats[bs] = 6); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // Should decrease one BattleStat by 1 (from 6, meaning it will be 5) + const decreasedStat = battleStatsArray.filter(bs => playerPokemon.summonData.battleStats[bs] === 5); + expect(decreasedStat).toBeTruthy(); + expect(decreasedStat.length).toBe(1); + }); +}); From de5d6458470eeffe508208ef0b1116afc3087cdd Mon Sep 17 00:00:00 2001 From: Enoch Date: Fri, 23 Aug 2024 09:59:35 +0900 Subject: [PATCH 62/63] [Localization] Add localization hard-coded message in move, pokemon. (#3639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add localization missing messages. * Apply suggestions from code review Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> * Update src/locales/fr/move-trigger.ts Co-authored-by: Lugiad' * Update src/locales/fr/battle.ts Co-authored-by: Lugiad' * Apply suggestions from code review Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira * Apply suggestions from code review - ES Co-authored-by: Asdar --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Asdar --- src/data/move.ts | 4 ++-- src/field/pokemon.ts | 4 ++-- src/locales/ca_ES/battle.ts | 1 + src/locales/ca_ES/move-trigger.ts | 1 + src/locales/de/battle.ts | 1 + src/locales/de/move-trigger.ts | 1 + src/locales/en/battle.ts | 1 + src/locales/en/move-trigger.ts | 1 + src/locales/es/battle.ts | 1 + src/locales/es/move-trigger.ts | 1 + src/locales/fr/battle.ts | 1 + src/locales/fr/move-trigger.ts | 1 + src/locales/it/battle.ts | 1 + src/locales/it/move-trigger.ts | 1 + src/locales/ja/battle.ts | 1 + src/locales/ja/move-trigger.ts | 1 + src/locales/ko/battle.ts | 1 + src/locales/ko/move-trigger.ts | 1 + src/locales/pt_BR/battle.ts | 1 + src/locales/pt_BR/move-trigger.ts | 1 + src/locales/zh_CN/battle.ts | 1 + src/locales/zh_CN/move-trigger.ts | 1 + src/locales/zh_TW/battle.ts | 1 + src/locales/zh_TW/move-trigger.ts | 1 + src/phases/move-phase.ts | 2 +- 25 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index b1b82009f3e..b47a9ea2a0b 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4905,7 +4905,7 @@ export class SwapArenaTagsAttr extends MoveEffectAttr { } - user.scene.queueMessage( i18next.t("moveTriggers:swapArenaTags", {pokemonName: getPokemonNameWithAffix(user)})); + user.scene.queueMessage(i18next.t("moveTriggers:swapArenaTags", {pokemonName: getPokemonNameWithAffix(user)})); return true; } } @@ -4946,7 +4946,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr { const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id); pokemon.resetStatus(); pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); - user.scene.queueMessage(`${getPokemonNameWithAffix(pokemon)} was revived!`,0,true); + user.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", {pokemonName: getPokemonNameWithAffix(pokemon)}),0,true); if (user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) { const allyPokemon = user.getAlly(); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 030297a2126..97ecb65cc02 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2228,7 +2228,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.queueMessage(i18next.t("battle:hitResultNoEffect", { pokemonName: getPokemonNameWithAffix(this) })); break; case HitResult.IMMUNE: - this.scene.queueMessage(`${this.name} is unaffected!`); + this.scene.queueMessage(i18next.t("battle:hitResultImmune", { pokemonName: this.name })); break; case HitResult.ONE_HIT_KO: this.scene.queueMessage(i18next.t("battle:hitResultOneHitKO")); @@ -3456,7 +3456,7 @@ export class PlayerPokemon extends Pokemon { pokemon.resetTurnData(); pokemon.resetStatus(); pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); - this.scene.queueMessage(`${pokemon.name} was revived!`,0,true); + this.scene.queueMessage(i18next.t("moveTriggers:revivalBlessing", {pokemonName: pokemon.name}),0,true); if (this.scene.currentBattle.double && this.scene.getParty().length > 1) { const allyPokemon = this.getAlly(); diff --git a/src/locales/ca_ES/battle.ts b/src/locales/ca_ES/battle.ts index 522fbb3261b..f86b597874f 100644 --- a/src/locales/ca_ES/battle.ts +++ b/src/locales/ca_ES/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "It's super effective!", "hitResultNotVeryEffective": "It's not very effective…", "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultImmune": "{{pokemonName}} is unaffected!", "hitResultOneHitKO": "It's a one-hit KO!", "attackFailed": "But it failed!", "attackMissed": "{{pokemonNameWithAffix}} avoided the attack!", diff --git a/src/locales/ca_ES/move-trigger.ts b/src/locales/ca_ES/move-trigger.ts index 5f9c6c0cdc2..96a9874a4fa 100644 --- a/src/locales/ca_ES/move-trigger.ts +++ b/src/locales/ca_ES/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", + "revivalBlessing": "{{pokemonName}} was revived!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts index b082a6932e9..bb8af9e0bda 100644 --- a/src/locales/de/battle.ts +++ b/src/locales/de/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "Das ist sehr effektiv!", "hitResultNotVeryEffective": "Das ist nicht sehr effektiv…", "hitResultNoEffect": "Es hat keine Wirkung auf {{pokemonName}}…", + "hitResultImmune": "{{pokemonName}} ist unversehrt!", "hitResultOneHitKO": "Ein K.O.-Treffer!", "attackFailed": "Es ist fehlgeschlagen!", "attackMissed": "Die Attacke hat {{pokemonNameWithAffix}} verfehlt!", diff --git a/src/locales/de/move-trigger.ts b/src/locales/de/move-trigger.ts index c3d063c4b3f..7f942fd6554 100644 --- a/src/locales/de/move-trigger.ts +++ b/src/locales/de/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}} geht nach {{turnCount}} Runden K.O.!", "copyType": "{{pokemonName}} hat den Typ von {{targetPokemonName}} angenommen!", "suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!", + "revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!", "swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!", "exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!", } as const; diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts index 522fbb3261b..f86b597874f 100644 --- a/src/locales/en/battle.ts +++ b/src/locales/en/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "It's super effective!", "hitResultNotVeryEffective": "It's not very effective…", "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultImmune": "{{pokemonName}} is unaffected!", "hitResultOneHitKO": "It's a one-hit KO!", "attackFailed": "But it failed!", "attackMissed": "{{pokemonNameWithAffix}} avoided the attack!", diff --git a/src/locales/en/move-trigger.ts b/src/locales/en/move-trigger.ts index 5f9c6c0cdc2..96a9874a4fa 100644 --- a/src/locales/en/move-trigger.ts +++ b/src/locales/en/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", + "revivalBlessing": "{{pokemonName}} was revived!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts index eb37699d911..83ecbc93503 100644 --- a/src/locales/es/battle.ts +++ b/src/locales/es/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "¡Es supereficaz!", "hitResultNotVeryEffective": "No es muy eficaz…", "hitResultNoEffect": "No afecta a {{pokemonName}}!", + "hitResultImmune": "¡No afecta a {{pokemonName}}!", "hitResultOneHitKO": "¡KO en 1 golpe!", "attackFailed": "¡Pero ha fallado!", "attackMissed": "¡{{pokemonNameWithAffix}}\nha evitado el ataque!", diff --git a/src/locales/es/move-trigger.ts b/src/locales/es/move-trigger.ts index cee5b58508f..140d7d8a4bd 100644 --- a/src/locales/es/move-trigger.ts +++ b/src/locales/es/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type\nchanged to match {{targetPokemonName}}'s!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", + "revivalBlessing": "¡{{pokemonName}} ha revivido!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts index 12ee9e0d696..fcb78e02f84 100644 --- a/src/locales/fr/battle.ts +++ b/src/locales/fr/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "C’est super efficace !", "hitResultNotVeryEffective": "Ce n’est pas très efficace…", "hitResultNoEffect": "Ça n’affecte pas {{pokemonName}}…", + "hitResultImmune": "{{pokemonName}} n’est pas affecté !", "hitResultOneHitKO": "K.O. en un coup !", "attackFailed": "Mais cela échoue !", "attackMissed": "{{pokemonNameWithAffix}}\névite l’attaque !", diff --git a/src/locales/fr/move-trigger.ts b/src/locales/fr/move-trigger.ts index 988db2e1959..e30bf2c313e 100644 --- a/src/locales/fr/move-trigger.ts +++ b/src/locales/fr/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nsera K.O. dans {{turnCount}} tours !", "copyType": "{{pokemonName}} prend le type\nde {{targetPokemonName}} !", "suppressAbilities": "Le talent de {{pokemonName}}\na été rendu inactif !", + "revivalBlessing": "{{pokemonName}} a repris connaissance\net est prêt à se battre de nouveau !", "swapArenaTags": "Les effets affectant chaque côté du terrain\nont été échangés par {{pokemonName}} !", "exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !", } as const; diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts index 347a9968e96..5d024547aa8 100644 --- a/src/locales/it/battle.ts +++ b/src/locales/it/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "È superefficace!", "hitResultNotVeryEffective": "Non è molto efficace…", "hitResultNoEffect": "Non ha effetto su {{pokemonName}}!", + "hitResultImmune": "{{pokemonName}} è incolume!", "hitResultOneHitKO": "KO con un colpo!", "attackFailed": "Ma ha fallito!", "attackMissed": "{{pokemonNameWithAffix}}\nevita l’attacco!", diff --git a/src/locales/it/move-trigger.ts b/src/locales/it/move-trigger.ts index 92ce6a76a74..b3dee3d8f8c 100644 --- a/src/locales/it/move-trigger.ts +++ b/src/locales/it/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.", "copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!", "suppressAbilities": "L’abilità di {{pokemonName}}\nperde ogni efficacia!", + "revivalBlessing": "{{pokemonName}} torna in forze!", "swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!", "exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/ja/battle.ts b/src/locales/ja/battle.ts index 926e2d9b0e4..061614202a0 100644 --- a/src/locales/ja/battle.ts +++ b/src/locales/ja/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "効果は バツグンだ!", "hitResultNotVeryEffective": "効果は 今ひとつの ようだ……", "hitResultNoEffect": "{{pokemonName}}には 効果が ないようだ…", + "hitResultImmune": "{{pokemonName}}には\n全然 効いてない!", "hitResultOneHitKO": "一撃必殺!", "attackFailed": "しかし うまく 決まらなかった!!", "attackMissed": "{{pokemonNameWithAffix}}には 当たらなかった!", diff --git a/src/locales/ja/move-trigger.ts b/src/locales/ja/move-trigger.ts index e3a089db53b..231af3596df 100644 --- a/src/locales/ja/move-trigger.ts +++ b/src/locales/ja/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}は\n{{turnCount}}ターンごに ほろびてしまう!", "copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった!", "suppressAbilities": "{{pokemonName}}の とくせいが きかなくなった!", + "revivalBlessing": "{{pokemonName}}は\n復活して 戦えるようになった!", "swapArenaTags": "{{pokemonName}}は\nおたがいの ばのこうかを いれかえた!", "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts index bdbcbcdf8d2..e4f67c32c74 100644 --- a/src/locales/ko/battle.ts +++ b/src/locales/ko/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "효과가 굉장했다!", "hitResultNotVeryEffective": "효과가 별로인 듯하다…", "hitResultNoEffect": "{{pokemonName}}에게는\n효과가 없는 것 같다…", + "hitResultImmune": "{{pokemonName}}에게는\n전혀 효과가 없다!", "hitResultOneHitKO": "일격필살!", "attackFailed": "그러나 실패하고 말았다!!", "attackMissed": "{{pokemonNameWithAffix}}에게는\n맞지 않았다!", diff --git a/src/locales/ko/move-trigger.ts b/src/locales/ko/move-trigger.ts index e93639689d8..f4c981a2c78 100644 --- a/src/locales/ko/move-trigger.ts +++ b/src/locales/ko/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}[[는]]\n{{turnCount}}턴 후에 쓰러져 버린다!", "copyType": "{{pokemonName}}[[는]]\n{{targetPokemonName}}[[와]] 같은 타입이 되었다!", "suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!", + "revivalBlessing": "{{pokemonName}}[[는]]\n정신을 차려 싸울 수 있게 되었다!", "swapArenaTags": "{{pokemonName}}[[는]]\n서로의 필드 효과를 교체했다!", "exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!", } as const; diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts index 24d4e8c928f..fd2695ed3c3 100644 --- a/src/locales/pt_BR/battle.ts +++ b/src/locales/pt_BR/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "É supereficaz!", "hitResultNotVeryEffective": "É pouco eficaz...", "hitResultNoEffect": "Isso não afeta {{pokemonName}}!", + "hitResultImmune": "{{pokemonName}} não é afetado!", "hitResultOneHitKO": "Foi um nocaute de um golpe!", "attackFailed": "Mas falhou!", "attackMissed": "{{pokemonNameWithAffix}} desviou do ataque!", diff --git a/src/locales/pt_BR/move-trigger.ts b/src/locales/pt_BR/move-trigger.ts index 620f867ae9a..33d05867a6a 100644 --- a/src/locales/pt_BR/move-trigger.ts +++ b/src/locales/pt_BR/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\nirá desmaiar em {{turnCount}} turnos.", "copyType": "O tipo de {{pokemonName}}\nmudou para combinar com {{targetPokemonName}}!", "suppressAbilities": "A habilidade de {{pokemonName}}\nfoi suprimida!", + "revivalBlessing": "{{pokemonName}} foi reanimado!", "swapArenaTags": "{{pokemonName}} trocou os efeitos de batalha que afetam cada lado do campo!", "exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/zh_CN/battle.ts b/src/locales/zh_CN/battle.ts index 5a73fbba09f..7b757941983 100644 --- a/src/locales/zh_CN/battle.ts +++ b/src/locales/zh_CN/battle.ts @@ -24,6 +24,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "效果拔群!", "hitResultNotVeryEffective": "收效甚微…", "hitResultNoEffect": "对{{pokemonName}}没有效果!!", + "hitResultImmune": "对于{{pokemonName}},\n完全没有效果!", "hitResultOneHitKO": "一击必杀!", "attackFailed": "但是失败了!", "attackMissed": "没有命中{{pokemonNameWithAffix}}!", diff --git a/src/locales/zh_CN/move-trigger.ts b/src/locales/zh_CN/move-trigger.ts index 3bbab276a87..cc39220d7f5 100644 --- a/src/locales/zh_CN/move-trigger.ts +++ b/src/locales/zh_CN/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\n将在{{turnCount}}回合后灭亡!", "copyType": "{{pokemonName}}\n变成了{{targetPokemonName}}的属性!", "suppressAbilities": "{{pokemonName}}的特性\n变得无效了!", + "revivalBlessing": "{{pokemonName}}复活了!", "swapArenaTags": "{{pokemonName}}\n交换了双方的场地效果!", "exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!", } as const; diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts index 357ad4ffbc3..116c891d74c 100644 --- a/src/locales/zh_TW/battle.ts +++ b/src/locales/zh_TW/battle.ts @@ -21,6 +21,7 @@ export const battle: SimpleTranslationEntries = { "hitResultSuperEffective": "效果拔群!", "hitResultNotVeryEffective": "收效甚微…", "hitResultNoEffect": "對 {{pokemonName}} 沒有效果!", + "hitResultImmune": "對于{{pokemonName}},\n完全沒有效果!", "hitResultOneHitKO": "一擊切殺!", "attackFailed": "但是失敗了!", "attackMissed": "沒有命中{{pokemonNameWithAffix}}!", diff --git a/src/locales/zh_TW/move-trigger.ts b/src/locales/zh_TW/move-trigger.ts index 9eb7a38dfb3..39b8cebaa78 100644 --- a/src/locales/zh_TW/move-trigger.ts +++ b/src/locales/zh_TW/move-trigger.ts @@ -61,6 +61,7 @@ export const moveTriggers: SimpleTranslationEntries = { "faintCountdown": "{{pokemonName}}\n將在{{turnCount}}回合後滅亡!", "copyType": "{{pokemonName}}變成了{{targetPokemonName}}的屬性!", "suppressAbilities": "{{pokemonName}}的特性\n變得無效了!", + "revivalBlessing": "{{pokemonName}}復活了!", "swapArenaTags": "{{pokemonName}}\n交換了雙方的場地效果!", "exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!", } as const; diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 2aed0bb9495..c446660b16f 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -65,7 +65,7 @@ export class MovePhase extends BattlePhase { if (!this.canMove()) { if (this.move.moveId && this.pokemon.summonData?.disabledMove === this.move.moveId) { - this.scene.queueMessage(`${this.move.getName()} is disabled!`); + this.scene.queueMessage(i18next.t("battle:moveDisabled", { moveName: this.move.getName() })); } if (this.pokemon.isActive(true) && this.move.ppUsed >= this.move.getMovePp()) { // if the move PP was reduced from Spite or otherwise, the move fails this.fail(); From 3cd1a60df838eb2013b769a40c21c598c709223c Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Thu, 22 Aug 2024 21:32:38 -0700 Subject: [PATCH 63/63] [Bug] Giving gender to Dipplin (#3702) Co-authored-by: frutescens --- 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 da2892f8128..6eca5d08811 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -2581,7 +2581,7 @@ export function initSpecies() { ), new PokemonSpecies(Species.WALKING_WAKE, 9, false, false, false, "Paradox Pokémon", Type.WATER, Type.DRAGON, 3.5, 280, Abilities.PROTOSYNTHESIS, Abilities.NONE, Abilities.NONE, 590, 99, 83, 91, 125, 83, 109, 5, 0, 295, GrowthRate.SLOW, null, false), new PokemonSpecies(Species.IRON_LEAVES, 9, false, false, false, "Paradox Pokémon", Type.GRASS, Type.PSYCHIC, 1.5, 125, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 90, 130, 88, 70, 108, 104, 5, 0, 295, GrowthRate.SLOW, null, false), - new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", Type.GRASS, Type.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, null, false), + new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", Type.GRASS, Type.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.POLTCHAGEIST, 9, false, false, false, "Matcha Pokémon", Type.GRASS, Type.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", Type.GRASS, Type.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", Type.GRASS, Type.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, true),