From 1be95e8a1a36ec8ac9ac8b112d45b0abc61af496 Mon Sep 17 00:00:00 2001 From: Lugiad <2070109+Adri1@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:43:40 +0100 Subject: [PATCH 1/7] [Localization] [UI/UX] Updates for pokemon-emerald-pro & pkmnems (#4968) * Add files via upload * Add files via upload --- public/fonts/pkmnems.ttf | Bin 26132 -> 26504 bytes public/fonts/pokemon-emerald-pro.ttf | Bin 93528 -> 93816 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/fonts/pkmnems.ttf b/public/fonts/pkmnems.ttf index b0b50d0f10ff8a64753acb663781be30d9b0213d..2cc7bfeee62569b1190a20ad91dcfada349b0d32 100644 GIT binary patch delta 1094 zcmY*YZ){Ul6hG(ny|!)*ZIL33+P?R0``SlzZflDKQBjwM5dH`(laRskwv`pLjfRzF z`hgN-3?a)TmJlOu*@p$^mkBgXd>_!@6ojc{A7-+U*p!42N%&?&*6}>|ZA5*^x#!>g zoqK-woqJ{mPyUJpKmhQ-32?xcbh>3nf93rgKz9#CgS+;=)Z~4X8V10vm z2g(3W4}fr`+vv|(79pX#i}LR7p7#!ojNX_8sHp<9B(oW#>#vU%3Y426*^s3`?E!Zq z)f35&WP9_4!3U9=7bq|WAimpkq|<15aJWLXrs;rQu zy#c`SPVPv5Ucde^ZSgp409kF716XOX&Gm#_ zHweWQsJrSo4%d}l!w($AG09V$7FQJ~Bv0v%_!br>i6FnEAc*jZt$h^nz;Uq9fnjXK zz1S(D=oWX2`{cFSn{*}AD~zFlA#A`scu)k#lXp`p!CUowWu4s=rik zR==-)TjnT!&cC0Jo55wDJ2&B$?ajc?xR!R;mCifAK<^FsX?YVVTvKdwzmC^SpS#at z;m7Bzp^c$jXejhq=xXR*SPkzC_k>S}uY}9thjNX)UfwSE$)Cy-@{D{>2`c-PL1jXj zQy!{LRaVpLesxeCSEtl@=445>on_exHp;HDN<@exBZnfxkxP*~Q6aiA+7NAx4n?m; zE1FN+thH!IwIS_NlQykYVk=^DtT~p8jmD;8v#~$o?zk4;7SF~{#m#tGU#U0i`}G0+ zj6R{yudgeWYhHXMBM}o*xKF>y0WPQoFRUYKsYF0wsf0hJ1SEybgkSL|{ESv6)SHX5 zriu9{LtMCJnxtLLrmgK2^9$ob{o*VQFt1-cm1ae0ldtJNU^1WXH%;mGQ>S`xsp8@+ z$D3xUHvOegu+l=kblYyx3!ns8>gB|949TFT81LX4q$cc|REgJH7#G`Ubomqt_odZj zJp+Ly?6ZUmFb8oA5FtMi|2=hpZTSJ5nr@Cg2f$M73m zfQzsI)#6;o=_KyJowy6%hOcoq?s3s0&1D;t&Nn)aW(G1&!&a_ieTN$wH#9BlL@D3d XE-<=rnq`3x6$$)4cZ;6x|6kKTDlJBg delta 714 zcmXX^Ur19?82`?8S!**j(V1@Cf4hICq~@}enFUe{1kEx`25MKG4sp5K9@dK!>A^sv zxY9#OL=1!wS>7l}DY3E;so{%06j(|4;DZlprWe*X>A>Nf-}n2@kMsS$Z}=-2T_iCe z0B{5b!3d3B@74Nn%*_J$cQNX?c>aPH)`=bQ3S#yhjO#QYlmde-e3fPv7nC_YKx+0Lv=Cm9>Ch>H6c;%8>hp`*a}Sk15txa|sIO zVn7H4Bhl~8mg9&M0F$(|Qajiw^0UVTBI*Wc;WtNX|i^@l0{Fol;q+&1lvX`E!u!zZNvFOsW< z%;(5QEn$94VoS7zmgow)g&w45=yfKWsbaiL2Q$RPnR#ZD1y*3svJp1HCOP0rIWO17 zMY$*36qn?5K9hIzZTtuy=V$p9e#dEZdYnGzi1V%Uw_p(}1fS3=3=5OOnph}$#DF*| zPKXQQnq-k2l1J*6qQ%mf^jX@GGv#8rR=zF|$j{_i`KK$#Rpsh+jk%^=UtAkSP~0k#{ZAuYYF|%*F~`334+*=!J^%m! diff --git a/public/fonts/pokemon-emerald-pro.ttf b/public/fonts/pokemon-emerald-pro.ttf index 84e49ebbc40def70813370e460324d84e021cc69..e4ee49dbff37948936b7770f697ab143b9f434d5 100644 GIT binary patch delta 4252 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 delta 3617 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 Ku>OPyfd2zVR<#!Z From 197b264fb0bf07ece381bd7e9488f3e8048b058b Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:24:08 -0800 Subject: [PATCH 2/7] [Bug] Gimmighoul & Eevee eggs will now properly randomize their forms (#5080) --- src/battle-scene.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 327ab1cc926..ae992f5c00f 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1424,6 +1424,8 @@ export default class BattleScene extends SceneBase { return 0; } + const isEggPhase: boolean = [ "EggLapsePhase", "EggHatchPhase" ].includes(this.getCurrentPhase()?.constructor.name ?? ""); + switch (species.speciesId) { case Species.UNOWN: case Species.SHELLOS: @@ -1455,7 +1457,7 @@ export default class BattleScene extends SceneBase { } return Utils.randSeedInt(8); case Species.EEVEE: - if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { + if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30 && !isEggPhase) { return 0; // No Partner Eevee for Wave 12 Preschoolers } return Utils.randSeedInt(2); @@ -1483,7 +1485,7 @@ export default class BattleScene extends SceneBase { return 0; case Species.GIMMIGHOUL: // Chest form can only be found in Mysterious Chest Encounter, if this is a game mode with MEs - if (this.gameMode.hasMysteryEncounters) { + if (this.gameMode.hasMysteryEncounters && !isEggPhase) { return 1; // Wandering form } else { return Utils.randSeedInt(species.forms.length); From 07b69c9485841063a4fc0353c48460eaf1e8083e Mon Sep 17 00:00:00 2001 From: Unicornpowerstar Date: Tue, 7 Jan 2025 01:26:00 +0100 Subject: [PATCH 3/7] [Sprite] Fix Issues with the 658-ash.json to display sprite correctly (#5055) * [Sprite][Color] Fixing Issues with the 658-ash.json to display sprite correctly - Fix colors not being shown correctly in the json. - Said fix are adding a new entry to separate the whites that are F8f8f8 by adding f4f4f4 - Changed the wrong color into the correct one on the rare. --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- public/images/pokemon/658-ash.png | Bin 1244 -> 1246 bytes public/images/pokemon/exp/658-ash.png | Bin 2468 -> 2472 bytes public/images/pokemon/shiny/658-ash.png | Bin 1247 -> 1247 bytes public/images/pokemon/variant/658-ash.json | 4 +++- .../images/pokemon/variant/exp/658-ash.json | 2 ++ 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/images/pokemon/658-ash.png b/public/images/pokemon/658-ash.png index a122df859bd0ed45c2bd78ee2d024b343a4cdc88..fa6ce5cb16521b9b690cd05cd6192b31b198b3fc 100644 GIT binary patch delta 1121 zcmV-n1fKic3El~iHUro1^pQC^3iR~!@E90I;80ePd?kMxg= zqE&PDC5!j0yfh(@tdofeQWtq2cpTUkiyW*k;eI6e27)r4V>}!?5R{uNuK)~OKMX0`&&PegUj-qJy~lr`defxu3tnwI`RBUVp5 z8J@GFpQ^jM!12+uH9T;f6xg_2o=*l*cU6%l>AK(%Cy@ot5J(yi%-7jzw&XcKea>m7 z@3((OXV7ak)s1F`Js~AL$8Tp+&?;B1i6|Z)R*r)Eb^d)kgICMFBp}+t(?r^@3!3+; zIrb)<^x;>+gXY;p?pX)Y{2BFdUglu{*=$YIh$n&8fu?z~C&$lXjAvE7WKXE2(vmw-@0P^2%HQMvWJXNFX%{*h`{E-iFdhbXnf7Tiu z$gA3e(23^{{RCc;zL@eZZ9$~uwNzMA6S8dN=%r=};Dh80mpT;k)+~ZO#wO;Szxu;GBGmn#AwK0;k zF4xSHlDcW#_%5n$t8^bJ#8`{N*37t%R(vh@T)cYUkyzLl4Hj3Oku0q&+mG}k?D-B1 zW#(-tkRxu28YO+&mTS7)FF7jwv7LV-OyZ(m(Q?Dchw~=sOAtnC=ZG79=ZZc}_GCrU z4|j5jY;OV#aV-l--46367K$dLw3z!2hd8TUTnuoGvp`&2pk*S6W&MBhUM0r}Za!h$ ziu`oD9^uaLn)|L^3}RvCEbDe1re*suBn(3XGsN7v$=SPyY<_FePu98voQcK1kWmZ-b^{S?i00000NkvXXu0mjf#V0qZ delta 1119 zcmV-l1fcug3ET;gHUj_v0FgO43i$Z=@E91BQ=k8ld?kM-Nklmj;EW9>DCmq`hD~ z^EeLrN$-EM?~^xx*MxiBb4V0g;?iXGqloGagJ|;rIrrTYjf0!`<{028B8um^VaSsG z$|Vgk+lmB|2<%0Uz#TUny_hNDx-R+KXK*0T?zrf|ScZo@CLOG;3l=Y!!4Z^u^M57} zwv7AGn7)n!2+GZtR{#cX+_seM=i|0*QxMWPdJKQ6H_!UM;3WqXJ!ebY=A0AHW=A3L zTxC-TK%jbW1?7B#ZJ#aui$M;j+WL@A zb9VAmbypWSK62ab~h8<)%T$sp>ks?sD~7d+x5vcMSvN#lX#Iy=plJm;s+InDI_ z*64o>dab3p(af+Xq=e`A?aT^VqaH5nvTY!nt?N4RB+xd{bWir=_*soHT}LE)hTp3s-UOQN zhdc}zOY*1DRniQSXXb=ap2}HYD1mIN_&V+5Yg?bb~{=Zv|_PjAq)#!S&ESNZd zs`elZ;`u{AftRE&ro2mg5Gi>*6_!**_TcGMhT6=Vz8?i-FB~iVAUS)m5HC312|a(^ z%HR^`@4+3|n7}f`GfwwaKQb7z4d;}K0VMIK^NXwWxD-pR*ZX+xsguFNDL zRsI6HM#uhxQWWPcE`R}tZ*C)4p!&NUDrz6h5MD>eYbP*Kq&uN7a5$O!@fyaGSoIE?>uK7VIr+_%5aO+t!mO l{Wr`HY^hu|qw1yBj6c9cS26bNh?M{U002ovPDHLkV1k{3Ky?5B diff --git a/public/images/pokemon/exp/658-ash.png b/public/images/pokemon/exp/658-ash.png index 6bb84f3e4fd622689fb60ec1c06599aad87670a7..ced4cbcec716965af329c30e41f496414ccc6716 100644 GIT binary patch delta 2351 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 delta 2347 zcmYk2c{~&TAIHBMGNP87qnUL;K=4{rcng`Q!6^zh0lu`}O#|KNa$&@=sj=>+9?3u1CbPE*Ea6 zM`>eu_UBH!VhY%vPwI=I3dbw-bf(YrZEw%d790r#KFyVk_(=>Xo1Yqb%lzRhGhR+t z7!vlK+|xR9MJoMcPLW^aF_PlUl3i#dmw%&;VvC^n9<(A$5V&R|+@j9Rru>N3rF=c! zH0$D|`9;$#0gmx7!Q$!Iaay^Gor6+1pO3v!wK3_@2s59Eh<+R@NV)$oW6LINouBM+ zNbPp>+OK_UmV~T~Eem`@$s<^H+r;x)1cQ5>Svg!?I^0ZL3!ek-H@rOIirK2j3KtkKs>~uuDP3`aZ7_Y|Sz&sIOlo5D8*S;Ch28)X0DIS> zuv(~68rAN7?L9h~|IG%+ooe(jGn!~sT+@GkWLR=`bu**W*U|>Va^Z+i;f#exIBixg zDdW~^Vf(I=PRfM@yWYRx+iRZa?*(mGdp*yvE^K~%^g3)Mw`DU3(>69xfy(+AM9-xm ztk%zYWV*F6UI%%g-`Ly&4w>MeVZGy#$%d(kgKzXxCd%um-xk!&iA_in-4= zJCoEEr||SCe4llSSEK;GI&*}?o*Of)#O_CMEA~Z?xQBgH?D2#dRl?mS2-RM&Z5{Hu z3#hcSLLRJb=t@xkr;zh(=m6mwd28q35OK71WYO2RKd|UWK#e#j2)lT18NC)L2G z*lbR2HglwvgJ5nz2O$#kgrk^a+Wl3Y8t$TylVt7~EK_`KCd-9! zg8Y6Zk?Qu-9{DVOX&d(hJi_C#UNT04lgbFMBa-2M$}QrXXB2=aAr8sOSg#)Ie@#ah z&GvTZ840fc;HkfGQ>KL5$oMyT!~U89yXjmItp& z_`b4HvTVE%;O~-RIHJ|L0Cs-h$8OcEk}i55!y7hOX-+dP)P)$55zP2hnBx;{fAto1 zoZrD`GZc~9|E?+=)<`K-Mw~);Vtl3CWkcM+M0E`y3pe>_mbutdB|RF7@+-1e){l-@ zV&UfIY2Qm20g(i!#7ce~NA-pKkl!{dD$n!a_F{m?kJn#a_%4s>4|lvzCNe*Ls-EY*W21#K6iyFE=r?C!ZVc@p%nDPh0xOiRL z<&UPugUV-bt%bMnUB|gOEc=Y_!KO}AL!cqRfxE%%s~!(9_x#&s(%9Xslwfa7ybDYd z)OmC6aA#6!C(btQRB!u$l?lc9%>aH&D%zgaZ3n%I5pcfX+Wm){z$XE4dl(Zfa*zQ74XI(?zw^ zRD!7z;J^OmUzww@@Y!!;t|>~t8{6dBwO2z-$Wg>$zSBZ5yrkAyAheBhC0dhJM2YV! zX4-eX@;1nk2p}xb42k$a1q~yzRL9`$XHo53VmFrS@D$a}ve)*PgKPL!S`p2b9z@Fc zJ|Fs!pvyk00lvU6t5ym7_A)d(P01)0r9%#ca(tXkzoNe|sb$y)22go~Idg7*v0Ood zq;bwt9Vd5j75&BXv6cs=j^ik2R9`|jURM=YU<`7UBsaZFh1X(FCCvi59NqhmK!#|<-sxVwI5J|90X zK>Cmz2TrXaV@Qs*)Dy_^oxD7-owmKSq~!q(D)S`U01coz%S zJWVeWgJ{MM6~#g{PygBf_;vOhSgB;WJ*W+-Y&n_04XONKKuzs3=(xt`%Ckjl-EnDj*v=M$&bm>on?41p%Tshg_%{w)bD*k^U|4)gKBHLpdgSr{$ZJpuv zNldaON?bIeBr!_dVYg%pc1P_@3h??Q_ECwg)diJ1X0ERpJGk@e(_?pi#CWtA5$aBF zNHwPdWJKRgP6Z@+QElJ8`bya~StwQ`g12>C=|g~rbzIrmuj5`iS7WHQ(_T9J4v?tg z$q#eVV(zXigN!iu-rWMwgJMfWhS*dv+A2VYr3jfWe3^GieA@Ug(Xv19bguf0Puzb2 D;d-~P diff --git a/public/images/pokemon/shiny/658-ash.png b/public/images/pokemon/shiny/658-ash.png index f5de608708eb8b505f1e837a4a697ad7e2c3f4cd..b25693fd24e91b07e97e897fe743ab36853a84b1 100644 GIT binary patch delta 690 zcmV;j0!{tj3Ev5jbqe(K^zaxM=HIC{k$*S^0;V8X=aIZ3f4JYPJe*EE*6O%3Pqb>z z9NeH6~U5K+Cp7j5n#<=%Uuac~pgdy{xt3nWPi~&s8#o00gS{ zP*Ca^+_~hk1p1l|yiYM89JQx684AzCGGh(#j$#9&R+>`GC zFkA6((Y3O8jj1`^XlB?GQo^(RbY=z9`cW#1$HmH0aKF|)4@wrk;_ea%<@$q%q zH_PW3?(U1aR6JV?vXNaOVy_^=Q%|PjshqX4Crdy)zKUjz@>LJ=s`y2Kd?-9cd#P6f zo?pZLzm-p0W#A`IN%#H7e$~GLP5GC9bS-`o3j*AF>muT@S>bWJw641YHMs=!16s*9 zkm&X~;LbxoT=6K{?>mvn-##sF)0^t@b{uBG-m?1dQfj|#J$R=-!`#4{ldEJDJ=Bu% Y4eqk$*S^f~Fu?=8?Q2e|S8qJRDCv*6O%3Pqb>z z9NeH6~U5K+Cp7j5bx<=%Uuad0Ewd8D0VCx#50~*}h(OT~`Gmj=jgAdefxO3m#IS=zZ>yTdlR?nWPi~&s8#o00gS{ zR8Z;@+_%{R#YP~9lkdK))N&*s@yW}3JbN)Z6i>4IcrXC04AzCGGh(#j$#9$*-IMPD zFkAU_(Y3O8jj1`^XlB?GQo^(RbS4GU`cW#1$HmH0aKF|)4@wrk;vNzZZQ*Gm?bmwE zdDR?ylTP}&D%Z80=di5v*op^}sR)I~|vM1$dX_I;a905g>mjXxv z^Nf?>0zv|u!;>WgNdcvkZvzz!l756e*Ma#g-2pjblaK=(EsWI85jVQd6(M@EBI(7Q zTqJKF0`ze$3+2cywD;IT(PWgCQrF=SXS9n80gjW|0~`VvYm@f_E`Pqhpa`Va`1m^Q zo8@y1clSkIDxR$c*~qRCu~!h`sVCF%QqEf0lO-S?Uq!P<`KkwbRs14AJ``S}t?HG4 z=htxmZ{^cg8TiRl(tZE2U-fT5Q~u>2U5lT@f&jPPGK+X@R(RYlEz9meO)f$GfL8Ji zB)WYLxbx5tS3HXLdpl(Ew@-`P_@=tN9fw)4H!uFXl-h4w58mm|FgLK~<{9 diff --git a/public/images/pokemon/variant/658-ash.json b/public/images/pokemon/variant/658-ash.json index 29b5bd2560b..1845b2b1bea 100644 --- a/public/images/pokemon/variant/658-ash.json +++ b/public/images/pokemon/variant/658-ash.json @@ -4,6 +4,7 @@ "3f4447": "466698", "de3431": "3fca9f", "f8f8f8": "a1e9f0", + "f4f4f4": "d7eff4", "7b282e": "0e3e81", "6b1d1d": "206d74", "4ebdd9": "41a7b0", @@ -11,7 +12,7 @@ "bfbfbf": "8cc7d4", "ffb2bf": "b7e9ff", "bf4c60": "4386df", - "fff0a6": "271f4c", + "fff0a6": "208698", "3e7acc": "6b4592", "18335c": "170738", "f2798d": "8dcfff", @@ -25,6 +26,7 @@ "3f4447": "466698", "de3431": "9ceec6", "f8f8f8": "89d2b8", + "f4f4f4": "d7eff4", "7b282e": "152a5c", "6b1d1d": "356e8d", "4ebdd9": "2f6e74", diff --git a/public/images/pokemon/variant/exp/658-ash.json b/public/images/pokemon/variant/exp/658-ash.json index 96b60b02adf..79cad7ea42d 100644 --- a/public/images/pokemon/variant/exp/658-ash.json +++ b/public/images/pokemon/variant/exp/658-ash.json @@ -4,6 +4,7 @@ "3f4447": "466698", "de3431": "3fca9f", "f8f8f8": "a1e9f0", + "f4f4f4": "d7effa", "7b282e": "0e3e81", "6b1d1d": "206d74", "4ebdd9": "41a7b0", @@ -25,6 +26,7 @@ "3f4447": "466698", "de3431": "9ceec6", "f8f8f8": "89d2b8", + "f4f4f4": "d7effa", "7b282e": "152a5c", "6b1d1d": "356e8d", "4ebdd9": "2f6e74", From d0db6a35d2afd6318e6bb9a8e9d2be7e0254b35f Mon Sep 17 00:00:00 2001 From: Jimmybald1 <122436263+Jimmybald1@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:27:23 +0100 Subject: [PATCH 4/7] [Bug] fix #5102 Catching Charm now always max weight in Daily Mode (#5103) Co-authored-by: Jimmybald1 <147992650+IBBCalc@users.noreply.github.com> --- src/modifier/modifier-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 540af8a0b41..e1c8cb04405 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1843,7 +1843,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.BATON, 2), new WeightedModifierType(modifierTypes.SOUL_DEW, 7), //new WeightedModifierType(modifierTypes.OVAL_CHARM, 6), - new WeightedModifierType(modifierTypes.CATCHING_CHARM, (party: Pokemon[]) => !party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.getSpeciesCount(d => !!d.caughtAttr) > 100 ? 4 : 0, 4), + new WeightedModifierType(modifierTypes.CATCHING_CHARM, (party: Pokemon[]) => party[0].scene.gameMode.isDaily || (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.getSpeciesCount(d => !!d.caughtAttr) > 100) ? 4 : 0, 4), new WeightedModifierType(modifierTypes.ABILITY_CHARM, skipInClassicAfterWave(189, 6)), new WeightedModifierType(modifierTypes.FOCUS_BAND, 5), new WeightedModifierType(modifierTypes.KINGS_ROCK, 3), From b0c347e20d8843885e9b3c8a9f569072ce2bdca8 Mon Sep 17 00:00:00 2001 From: Zain <34523777+Zain-A-Abbas@users.noreply.github.com> Date: Fri, 10 Jan 2025 19:29:25 -0500 Subject: [PATCH 5/7] [Bug] Fixed defog not removing the target's Safeguard and Mist (#5107) * Fixed defog not removing the target's Safeguard and Mist * Made requested changes and added unit test * Remove stray newline --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/move.ts | 3 +- src/test/moves/defog.test.ts | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/test/moves/defog.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 7a6f08a5372..c86b168fb57 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -9220,7 +9220,8 @@ export function initMoves() { .attr(ClearWeatherAttr, WeatherType.FOG) .attr(ClearTerrainAttr) .attr(RemoveScreensAttr, false) - .attr(RemoveArenaTrapAttr, true), + .attr(RemoveArenaTrapAttr, true) + .attr(RemoveArenaTagsAttr, [ ArenaTagType.MIST, ArenaTagType.SAFEGUARD ], false), new StatusMove(Moves.TRICK_ROOM, Type.PSYCHIC, -1, 5, -1, -7, 4) .attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5) .ignoresProtect() diff --git a/src/test/moves/defog.test.ts b/src/test/moves/defog.test.ts new file mode 100644 index 00000000000..c83cdc192bf --- /dev/null +++ b/src/test/moves/defog.test.ts @@ -0,0 +1,71 @@ +import { Stat } from "#enums/stat"; +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 - Defog", () => { + 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 + .moveset([ Moves.MIST, Moves.SAFEGUARD, Moves.SPLASH ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.SHUCKLE) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset([ Moves.DEFOG, Moves.GROWL ]); + }); + + it("should not allow Safeguard to be active", async () => { + await game.classicMode.startBattle([ Species.REGIELEKI ]); + + const playerPokemon = game.scene.getPlayerField(); + const enemyPokemon = game.scene.getEnemyField(); + + game.move.select(Moves.SAFEGUARD); + await game.forceEnemyMove(Moves.DEFOG); + await game.phaseInterceptor.to("BerryPhase"); + + expect(playerPokemon[0].isSafeguarded(enemyPokemon[0])).toBe(false); + + + expect(true).toBe(true); + }); + + + it("should not allow Mist to be active", async () => { + await game.classicMode.startBattle([ Species.REGIELEKI ]); + + const playerPokemon = game.scene.getPlayerField(); + + game.move.select(Moves.MIST); + await game.forceEnemyMove(Moves.DEFOG); + + await game.toNextTurn(); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.GROWL); + + await game.phaseInterceptor.to("BerryPhase"); + + expect(playerPokemon[0].getStatStage(Stat.ATK)).toBe(-1); + + expect(true).toBe(true); + }); +}); From 29087710b7e180efe31594c5d178ec9770a3c2ad Mon Sep 17 00:00:00 2001 From: "Amani H." <109637146+xsn34kzx@users.noreply.github.com> Date: Fri, 10 Jan 2025 19:34:16 -0500 Subject: [PATCH 6/7] [Balance] Adjust Orb & Light Ball Weight Functions (#5070) * [Balance] Adjust Orb & Light Ball Weight Functions * Apply Kev's Suggestions Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: damocleas --- src/modifier/modifier-type.ts | 74 +++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index e1c8cb04405..b6cf78fb414 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1040,7 +1040,8 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { for (const p of party) { const speciesId = p.getSpeciesForm(true).speciesId; const fusionSpeciesId = p.isFusion() ? p.getFusionSpeciesForm(true).speciesId : null; - const hasFling = p.getMoveset(true).some(m => m?.moveId === Moves.FLING); + // TODO: Use commented boolean when Fling is implemented + const hasFling = false; /* p.getMoveset(true).some(m => m?.moveId === Moves.FLING) */ for (const i in values) { const checkedSpecies = values[i].species; @@ -1755,56 +1756,69 @@ const modifierPool: ModifierPool = { }, 12), new WeightedModifierType(modifierTypes.TOXIC_ORB, (party: Pokemon[]) => { return party.some(p => { - const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId); - - const canSetStatus = p.canSetStatus(StatusEffect.TOXIC, true, true, null, true); const isHoldingOrb = p.getHeldItems().some(i => i.type.id === "FLAME_ORB" || i.type.id === "TOXIC_ORB"); - // Moves that take advantage of obtaining the actual status effect - const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ] - .some(m => moveset.includes(m)); - // Moves that take advantage of being able to give the target a status orb - // TODO: Take moves from comment they are implemented - const hasItemMoves = [ /* Moves.TRICK, Moves.FLING, Moves.SWITCHEROO */ ] - .some(m => moveset.includes(m)); - // Abilities that take advantage of obtaining the actual status effect - const hasRelevantAbilities = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD ] - .some(a => p.hasAbility(a, false, true)); - if (!isHoldingOrb) { + const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId); + const canSetStatus = p.canSetStatus(StatusEffect.TOXIC, true, true, null, true); + + // Moves that take advantage of obtaining the actual status effect + const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ] + .some(m => moveset.includes(m)); + // Moves that take advantage of being able to give the target a status orb + // TODO: Take moves (Trick, Fling, Switcheroo) from comment when they are implemented + const hasItemMoves = [ /* Moves.TRICK, Moves.FLING, Moves.SWITCHEROO */ ] + .some(m => moveset.includes(m)); + if (canSetStatus) { - return hasRelevantAbilities || hasStatusMoves; + // Abilities that take advantage of obtaining the actual status effect, separated based on specificity to the orb + const hasGeneralAbility = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.MAGIC_GUARD ] + .some(a => p.hasAbility(a, false, true)); + const hasSpecificAbility = [ Abilities.TOXIC_BOOST, Abilities.POISON_HEAL ] + .some(a => p.hasAbility(a, false, true)); + const hasOppositeAbility = [ Abilities.FLARE_BOOST ] + .some(a => p.hasAbility(a, false, true)); + + return hasSpecificAbility || (hasGeneralAbility && !hasOppositeAbility) || hasStatusMoves; } else { return hasItemMoves; } } + return false; }) ? 10 : 0; }, 10), new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => { return party.some(p => { - const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId); - const canSetStatus = p.canSetStatus(StatusEffect.BURN, true, true, null, true); const isHoldingOrb = p.getHeldItems().some(i => i.type.id === "FLAME_ORB" || i.type.id === "TOXIC_ORB"); - // Moves that take advantage of obtaining the actual status effect - const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ] - .some(m => moveset.includes(m)); - // Moves that take advantage of being able to give the target a status orb - // TODO: Take moves from comment they are implemented - const hasItemMoves = [ /* Moves.TRICK, Moves.FLING, Moves.SWITCHEROO */ ] - .some(m => moveset.includes(m)); - // Abilities that take advantage of obtaining the actual status effect - const hasRelevantAbilities = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD ] - .some(a => p.hasAbility(a, false, true)); - if (!isHoldingOrb) { + const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId); + const canSetStatus = p.canSetStatus(StatusEffect.TOXIC, true, true, null, true); + + // Moves that take advantage of obtaining the actual status effect + const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ] + .some(m => moveset.includes(m)); + // Moves that take advantage of being able to give the target a status orb + // TODO: Take moves (Trick, Fling, Switcheroo) from comment when they are implemented + const hasItemMoves = [ /* Moves.TRICK, Moves.FLING, Moves.SWITCHEROO */ ] + .some(m => moveset.includes(m)); + if (canSetStatus) { - return hasRelevantAbilities || hasStatusMoves; + // Abilities that take advantage of obtaining the actual status effect, separated based on specificity to the orb + const hasGeneralAbility = [ Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.MAGIC_GUARD ] + .some(a => p.hasAbility(a, false, true)); + const hasSpecificAbility = [ Abilities.FLARE_BOOST ] + .some(a => p.hasAbility(a, false, true)); + const hasOppositeAbility = [ Abilities.TOXIC_BOOST, Abilities.POISON_HEAL ] + .some(a => p.hasAbility(a, false, true)); + + return hasSpecificAbility || (hasGeneralAbility && !hasOppositeAbility) || hasStatusMoves; } else { return hasItemMoves; } } + return false; }) ? 10 : 0; }, 10), From d3fafa27702f2121e89852cc45481dd935a6a7fd Mon Sep 17 00:00:00 2001 From: Ori shalhon Date: Sat, 11 Jan 2025 03:10:52 +0100 Subject: [PATCH 7/7] [UI/UX] Add random selection option during starter select (#5075) * Update submodule public/locales to the latest upstream commit * feat: add random selection option during starter select * move random selection behavior to seperate label * Update public/locales submodule reference * Remove debug console.log statement * Update locales * Update src/ui/starter-select-ui-handler.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/ui/starter-select-ui-handler.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/ui/starter-select-ui-handler.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update locales submodule --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- public/locales | 2 +- src/ui/starter-select-ui-handler.ts | 166 +++++++++++++++++++++++----- 2 files changed, 140 insertions(+), 28 deletions(-) diff --git a/public/locales b/public/locales index 2e03bc8f273..4928231e22a 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 2e03bc8f2736269bfa365faad587c3ec54a37621 +Subproject commit 4928231e22a06dce2b55d9b04cd2b283c2ee4afb diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 691e339eafc..38a2bb85de6 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -130,9 +130,10 @@ const valueReductionMax = 2; const filterBarHeight = 17; const speciesContainerX = 109; // if team on the RIGHT: 109 / if on the LEFT: 143 const teamWindowX = 285; // if team on the RIGHT: 285 / if on the LEFT: 109 -const teamWindowY = 18; +const teamWindowY = 38; const teamWindowWidth = 34; -const teamWindowHeight = 132; +const teamWindowHeight = 107; +const randomSelectionWindowHeight = 20; /** * Calculates the starter position for a Pokemon of a given UI index @@ -318,6 +319,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private starterIconsCursorObj: Phaser.GameObjects.Image; private valueLimitLabel: Phaser.GameObjects.Text; private startCursorObj: Phaser.GameObjects.NineSlice; + private randomCursorObj: Phaser.GameObjects.NineSlice; private iconAnimHandler: PokemonIconAnimHandler; @@ -366,8 +368,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { starterContainerBg.setOrigin(0, 0); this.starterSelectContainer.add(starterContainerBg); - this.starterSelectContainer.add(addWindow(this.scene, teamWindowX, teamWindowY, teamWindowWidth, teamWindowHeight)); - this.starterSelectContainer.add(addWindow(this.scene, teamWindowX, teamWindowY + teamWindowHeight - 5, teamWindowWidth, teamWindowWidth, true)); + this.starterSelectContainer.add(addWindow(this.scene, teamWindowX, teamWindowY - randomSelectionWindowHeight, teamWindowWidth, randomSelectionWindowHeight, true)); + this.starterSelectContainer.add(addWindow(this.scene, teamWindowX, teamWindowY, teamWindowWidth, teamWindowHeight )); + this.starterSelectContainer.add(addWindow(this.scene, teamWindowX, teamWindowY + teamWindowHeight, teamWindowWidth, teamWindowWidth, true)); this.starterSelectContainer.add(starterContainerWindow); // Create and initialise filter bar @@ -605,6 +608,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.startCursorObj.setOrigin(0, 0); this.starterSelectContainer.add(this.startCursorObj); + const randomSelectLabel = addTextObject(this.scene, teamWindowX + 17, 23, i18next.t("starterSelectUiHandler:randomize"), TextStyle.TOOLTIP_CONTENT); + randomSelectLabel.setOrigin(0.5, 0); + this.starterSelectContainer.add(randomSelectLabel); + + this.randomCursorObj = this.scene.add.nineslice(teamWindowX + 4, 21, "select_cursor", undefined, 26, 15, 6, 6, 6, 6); + this.randomCursorObj.setVisible(false); + this.randomCursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(this.randomCursorObj); + const starterSpecies: Species[] = []; const starterBoxContainer = this.scene.add.container(speciesContainerX + 6, 9); //115 @@ -1337,9 +1349,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterIconsCursorIndex = this.starterSpecies.length - 1; this.moveStarterIconsCursor(this.starterIconsCursorIndex); } else { + // TODO: how can we get here if start button can't be selected? this appears to be redundant this.startCursorObj.setVisible(false); - this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1); - this.setFilterMode(true); + this.randomCursorObj.setVisible(true); } success = true; break; @@ -1386,14 +1398,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case Button.UP: if (this.filterBar.openDropDown) { success = this.filterBar.decDropDownCursor(); - } else if (this.filterBarCursor === this.filterBar.numFilters - 1 && this.starterSpecies.length > 0) { + } else if (this.filterBarCursor === this.filterBar.numFilters - 1 ) { // UP from the last filter, move to start button this.setFilterMode(false); this.cursorObj.setVisible(false); - this.startCursorObj.setVisible(true); + if (this.starterSpecies.length > 0) { + this.startCursorObj.setVisible(true); + } else { + this.randomCursorObj.setVisible(true); + } success = true; } else if (numberOfStarters > 0) { - // UP from filter bar to bottom of Pokemon list + // UP from filter bar to bottom of Pokemon list this.setFilterMode(false); this.scrollCursor = Math.max(0, numOfRows - 9); this.updateScroll(); @@ -1410,12 +1426,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case Button.DOWN: if (this.filterBar.openDropDown) { success = this.filterBar.incDropDownCursor(); - } else if (this.filterBarCursor === this.filterBar.numFilters - 1 && this.starterSpecies.length > 0) { - // DOWN from the last filter, move to Pokemon in party if any + } else if (this.filterBarCursor === this.filterBar.numFilters - 1) { + // DOWN from the last filter, move to random selection label this.setFilterMode(false); this.cursorObj.setVisible(false); - this.starterIconsCursorIndex = 0; - this.moveStarterIconsCursor(this.starterIconsCursorIndex); + this.randomCursorObj.setVisible(true); success = true; } else if (numberOfStarters > 0) { // DOWN from filter bar to top of Pokemon list @@ -1437,8 +1452,100 @@ export default class StarterSelectUiHandler extends MessageUiHandler { success = true; break; } + } else if (this.randomCursorObj.visible) { + switch (button) { + case Button.ACTION: + if (this.starterSpecies.length >= 6) { + error = true; + break; + } + const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, _gen: number, i: number ) => total + this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); + // Filter valid starters + const validStarters = this.filteredStarterContainers.filter(starter => { + const species = starter.species; + const [ isDupe ] = this.isInParty(species); + const starterCost = this.scene.gameData.getSpeciesStarterValue(species.speciesId); + const isValidForChallenge = new BooleanHolder(true); + Challenge.applyChallenges( + this.scene.gameMode, + Challenge.ChallengeType.STARTER_CHOICE, + species, + isValidForChallenge, + this.scene.gameData.getSpeciesDexAttrProps( + species, + this.getCurrentDexProps(species.speciesId) + ), + this.isPartyValid() + ); + const isCaught = this.scene.gameData.dexData[species.speciesId].caughtAttr; + return ( + !isDupe && + isValidForChallenge.value && + currentPartyValue + starterCost <= this.getValueLimit() && + isCaught + ); + }); + if (validStarters.length === 0) { + error = true; // No valid starters available + break; + } + // Select random starter + const randomStarter = validStarters[Math.floor(Math.random() * validStarters.length)]; + const randomSpecies = randomStarter.species; + // Set species and prepare attributes + this.setSpecies(randomSpecies); + const dexAttr = this.getCurrentDexProps(randomSpecies.speciesId); + const props = this.scene.gameData.getSpeciesDexAttrProps(randomSpecies, dexAttr); + const abilityIndex = this.abilityCursor; + const nature = this.natureCursor as unknown as Nature; + const moveset = this.starterMoveset?.slice(0) as StarterMoveset; + const starterCost = this.scene.gameData.getSpeciesStarterValue(randomSpecies.speciesId); + const speciesForm = getPokemonSpeciesForm(randomSpecies.speciesId, props.formIndex); + // Load assets and add to party + speciesForm + .loadAssets(this.scene, props.female, props.formIndex, props.shiny, props.variant, true) + .then(() => { + if (this.tryUpdateValue(starterCost, true)) { + this.addToParty(randomSpecies, dexAttr, abilityIndex, nature, moveset, true); + ui.playSelect(); + } + }); + break; + case Button.UP: + this.randomCursorObj.setVisible(false); + this.filterBarCursor = this.filterBar.numFilters - 1; + this.setFilterMode(true); + success = true; + break; + case Button.DOWN: + this.randomCursorObj.setVisible(false); + if (this.starterSpecies.length > 0) { + this.starterIconsCursorIndex = 0; + this.moveStarterIconsCursor(this.starterIconsCursorIndex); + } else { + this.filterBarCursor = this.filterBar.numFilters - 1; + this.setFilterMode(true); + } + success = true; + break; + case Button.LEFT: + if (numberOfStarters > 0) { + this.randomCursorObj.setVisible(false); + this.cursorObj.setVisible(true); + this.setCursor(onScreenFirstIndex + 8); // set last column + success = true; + } + break; + case Button.RIGHT: + if (numberOfStarters > 0) { + this.randomCursorObj.setVisible(false); + this.cursorObj.setVisible(true); + this.setCursor(onScreenFirstIndex); // set first column + success = true; + } + break; + } } else { - let starterContainer; const starterData = this.scene.gameData.starterData[this.lastSpecies.speciesId]; // prepare persistent starter data to store changes @@ -1466,7 +1573,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.lastSpecies, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)), isPartyValid); - const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, gen: number, i: number) => total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); + const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, _gen: number, i: number) => total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); const newCost = this.scene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId); if (!isDupe && isValidForChallenge.value && currentPartyValue + newCost <= this.getValueLimit() && this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE) { // this checks to make sure the pokemon doesn't exist in your party, it's valid for the challenge and that it won't go over the cost limit; if it meets all these criteria it will add it to your party options = [ @@ -1605,7 +1712,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ui.showText(i18next.t("starterSelectUiHandler:selectNature"), null, () => { const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr); ui.setModeWithoutClear(Mode.OPTION_SELECT, { - options: natures.map((n: Nature, i: number) => { + options: natures.map((n: Nature, _i: number) => { const option: OptionSelectItem = { label: getNatureName(n, true, true, true, this.scene.uiTheme), handler: () => { @@ -2016,11 +2123,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } else { if (this.starterIconsCursorIndex === 0) { - // Up from first Pokemon in the team > go to filter + // Up from first Pokemon in the team > go to Random selection this.starterIconsCursorObj.setVisible(false); this.setSpecies(null); - this.filterBarCursor = Math.max(1, this.filterBar.numFilters - 1); - this.setFilterMode(true); + this.randomCursorObj.setVisible(true); } else { this.starterIconsCursorIndex--; this.moveStarterIconsCursor(this.starterIconsCursorIndex); @@ -2065,9 +2171,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { success = this.setCursor(this.cursor - 1); } else { // LEFT from filtered Pokemon, on the left edge - - if (this.starterSpecies.length === 0) { - // no starter in team > wrap around to the last column + if ( onScreenCurrentRow === 0 ) { + // from the first row of starters we go to the random selection + this.cursorObj.setVisible(false); + this.randomCursorObj.setVisible(true); + } else if (this.starterSpecies.length === 0) { + // no starter in team and not on first row > wrap around to the last column success = this.setCursor(this.cursor + Math.min(8, numberOfStarters - this.cursor)); } else if (onScreenCurrentRow < 7) { @@ -2103,7 +2212,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { success = this.setCursor(this.cursor + 1); } else { // RIGHT from filtered Pokemon, on the right edge - if (this.starterSpecies.length === 0) { + if ( onScreenCurrentRow === 0 ) { + // from the first row of starters we go to the random selection + this.cursorObj.setVisible(false); + this.randomCursorObj.setVisible(true); + } else if (this.starterSpecies.length === 0) { // no selected starter in team > wrap around to the first column success = this.setCursor(this.cursor - Math.min(8, this.cursor % 9)); @@ -2159,7 +2272,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return [ isDupe, removeIndex ]; } - addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: integer, nature: Nature, moveset: StarterMoveset) { + addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: integer, nature: Nature, moveset: StarterMoveset, randomSelection: boolean = false) { const props = this.scene.gameData.getSpeciesDexAttrProps(species, dexAttr); this.starterIcons[this.starterSpecies.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant)); this.starterIcons[this.starterSpecies.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant)); @@ -2170,7 +2283,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterAbilityIndexes.push(abilityIndex); this.starterNatures.push(nature); this.starterMovesets.push(moveset); - if (this.speciesLoaded.get(species.speciesId)) { + if (this.speciesLoaded.get(species.speciesId) || randomSelection ) { getPokemonSpeciesForm(species.speciesId, props.formIndex).cry(this.scene); } this.updateInstructions(); @@ -3001,7 +3114,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.dexAttrCursor = 0n; this.abilityCursor = -1; this.natureCursor = -1; - // We will only update the sprite if there is a change to form, shiny/variant // or gender for species with gender sprite differences const shouldUpdateSprite = (species?.genderDiffs && !isNullOrUndefined(female)) @@ -3431,7 +3543,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } tryUpdateValue(add?: integer, addingToParty?: boolean): boolean { - const value = this.starterSpecies.map(s => s.generation).reduce((total: integer, gen: integer, i: integer) => total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); + const value = this.starterSpecies.map(s => s.generation).reduce((total: integer, _gen: integer, i: integer) => total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); const newValue = value + (add || 0); const valueLimit = this.getValueLimit(); const overLimit = newValue > valueLimit;