From 762aa9e49b8df80d7ab2bea1a7074f5b6da53be3 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 25 Aug 2024 09:28:29 -0700 Subject: [PATCH 01/40] Update the GitHub pull request template (#3755) --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3e6b8bf6d0d..a30cb642a46 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -30,7 +30,7 @@ - [ ] The PR is self-contained and cannot be split into smaller PRs? - [ ] Have I provided a clear explanation of the changes? - [ ] Have I considered writing automated tests for the issue? -- [ ] If I have text, did I add make it translatable and added a key in the English language? +- [ ] If I have text, did I make it translatable and add a key in the English locale file(s)? - [ ] Have I tested the changes (manually)? - [ ] Are all unit tests still passing? (`npm run test`) - [ ] Are the changes visual? From 15fea2e171511e8d917f9ce2da8e6ffb86568b30 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sat, 31 Aug 2024 11:50:09 -0700 Subject: [PATCH 02/40] Gamepad for Run Info (#3940) Co-authored-by: frutescens --- index.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.css b/index.css index 8034c1a4b38..abf4f9f708c 100644 --- a/index.css +++ b/index.css @@ -148,10 +148,10 @@ input:-internal-autofill-selected { /* Show cycle buttons only on STARTER_SELECT and on touch configuration panel */ #touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadOpenFilters, -#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleForm, -#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleShiny, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleForm, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleShiny, #touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleNature, -#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleAbility, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleAbility, #touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleGender, #touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleVariant { display: none; From 85a8abc0e8bedaebd4b087a0136fbeda4e329135 Mon Sep 17 00:00:00 2001 From: damocleas Date: Sat, 31 Aug 2024 19:39:21 -0400 Subject: [PATCH 03/40] [Balance] Final Adjustments to biomes + Gmax Snorlax Ability + Passive changed (#3950) * Biome Adjustments 1 * MOUNTAIN OUT FROM ANCIENT RUINS * snorlax gmax adjustment * Localizers please calm down - Snorlax Ability + Passive change * One more time let's give it a go biomes.ts * fixed ] * Update biomes.ts * fixed spelling mistake --- src/data/biomes.ts | 18 +++++++++--------- src/data/pokemon-species.ts | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 3879053b066..d9ea22f50f2 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -35,18 +35,18 @@ interface BiomeDepths { export const biomeLinks: BiomeLinks = { [Biome.TOWN]: Biome.PLAINS, [Biome.PLAINS]: [ Biome.GRASS, Biome.METROPOLIS, Biome.LAKE ], - [Biome.GRASS]: [ Biome.TALL_GRASS, [ Biome.CONSTRUCTION_SITE, 2 ] ], + [Biome.GRASS]: Biome.TALL_GRASS, [Biome.TALL_GRASS]: [ Biome.FOREST, Biome.CAVE ], - [Biome.SLUM]: Biome.CONSTRUCTION_SITE, + [Biome.SLUM]: [ Biome.CONSTRUCTION_SITE, [ Biome.SWAMP, 2 ] ], [Biome.FOREST]: [ Biome.JUNGLE, Biome.MEADOW ], [Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ], [Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ], - [Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 3 ] ], + [Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 2 ] ], [Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP, Biome.CONSTRUCTION_SITE ], [Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ], - [Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.DOJO, 2] [ Biome.WASTELAND, 2 ] ], + [Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 2 ], [ Biome.SPACE, 3 ] ], [Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ], - [Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE ], + [Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE [ Biome.LABORATORY, 2 ] ], [Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ], [Biome.ICE_CAVE]: Biome.SNOWY_FOREST, [Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ], @@ -54,17 +54,17 @@ export const biomeLinks: BiomeLinks = { [Biome.VOLCANO]: [ Biome.BEACH, [ Biome.ICE_CAVE, 3 ] ], [Biome.GRAVEYARD]: Biome.ABYSS, [Biome.DOJO]: [ Biome.PLAINS, [ Biome.JUNGLE, 2], [ Biome.TEMPLE, 2 ] ], - [Biome.FACTORY]: [ Biome.TALL_GRASS, [ Biome.LABORATORY, 3 ] ], - [Biome.RUINS]: [ Biome.FOREST ], + [Biome.FACTORY]: [ Biome.PLAINS, [ Biome.LABORATORY, 2 ] ], + [Biome.RUINS]: [ Biome.MOUNTAIN, [ Biome.FOREST, 2 ] ], [Biome.WASTELAND]: Biome.BADLANDS, - [Biome.ABYSS]: [ Biome.CAVE, [ Biome.SPACE, 3 ], [ Biome.WASTELAND, 3 ] ], + [Biome.ABYSS]: [ Biome.CAVE, [ Biome.SPACE, 2 ], [ Biome.WASTELAND, 2 ] ], [Biome.SPACE]: Biome.RUINS, [Biome.CONSTRUCTION_SITE]: [ Biome.POWER_PLANT, [ Biome.DOJO, 2 ] ], [Biome.JUNGLE]: [ Biome.TEMPLE ], [Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 2 ] ], [Biome.TEMPLE]: [ Biome.DESERT, [ Biome.SWAMP, 2 ], [ Biome.RUINS, 2 ] ], [Biome.METROPOLIS]: Biome.SLUM, - [Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.MOUNTAIN, [ Biome.LAKE, 2 ] ], + [Biome.SNOWY_FOREST]: [ Biome.FOREST, [ Biome.MOUNTAIN, 2 ], [ Biome.LAKE, 2 ] ], [Biome.ISLAND]: Biome.SEA, [Biome.LABORATORY]: Biome.CONSTRUCTION_SITE }; diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index db601935bfc..17f2de794ae 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1132,7 +1132,7 @@ export function initSpecies() { ), new PokemonSpecies(Species.SNORLAX, 1, false, false, false, "Sleeping Pokémon", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, GrowthRate.SLOW, 87.5, false, true, new PokemonForm("Normal", "", Type.NORMAL, null, 2.1, 460, Abilities.IMMUNITY, Abilities.THICK_FAT, Abilities.GLUTTONY, 540, 160, 110, 65, 65, 110, 30, 25, 50, 189, false, null, true), - new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, null, 35, 460, Abilities.THICK_FAT, Abilities.THICK_FAT, Abilities.THICK_FAT, 640, 200, 135, 85, 80, 125, 15, 25, 50, 189), + new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.NORMAL, null, 35, 460, Abilities.HARVEST, Abilities.HARVEST, Abilities.HARVEST, 640, 200, 135, 80, 80, 125, 20, 25, 50, 189), ), new PokemonSpecies(Species.ARTICUNO, 1, true, false, false, "Freeze Pokémon", Type.ICE, Type.FLYING, 1.7, 55.4, Abilities.PRESSURE, Abilities.NONE, Abilities.SNOW_CLOAK, 580, 90, 85, 100, 95, 125, 85, 3, 35, 290, GrowthRate.SLOW, null, false), new PokemonSpecies(Species.ZAPDOS, 1, true, false, false, "Electric Pokémon", Type.ELECTRIC, Type.FLYING, 1.6, 52.6, Abilities.PRESSURE, Abilities.NONE, Abilities.STATIC, 580, 90, 90, 85, 125, 90, 100, 3, 35, 290, GrowthRate.SLOW, null, false), @@ -3573,7 +3573,7 @@ export const starterPassiveAbilities = { [Species.CHATOT]: Abilities.PUNK_ROCK, [Species.SPIRITOMB]: Abilities.VESSEL_OF_RUIN, [Species.GIBLE]: Abilities.SAND_STREAM, - [Species.MUNCHLAX]: Abilities.HARVEST, + [Species.MUNCHLAX]: Abilities.RIPEN, [Species.RIOLU]: Abilities.MINDS_EYE, [Species.HIPPOPOTAS]: Abilities.UNAWARE, [Species.SKORUPI]: Abilities.SUPER_LUCK, From de66b450a540554f48e8891834d2ded7b7e3f558 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:18:40 -0700 Subject: [PATCH 04/40] [Beta][Misc] Banner (#3926) * Initial work - does not work. * Revert * image replacement * better scaling * Removing most of the bangs * no more bangs * Update src/timed-event-manager.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Implemented Torranx's suggestion * Ready for Translations * Delete Picture * Localized banners * Biomes fix * Corrections * Update src/timed-event-manager.ts Co-authored-by: Frederico Santos --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Frederico Santos --- public/images/events/september-update-de.png | Bin 0 -> 33189 bytes public/images/events/september-update-en.png | Bin 0 -> 35659 bytes public/images/events/september-update-es.png | Bin 0 -> 33188 bytes public/images/events/september-update-fr.png | Bin 0 -> 33232 bytes public/images/events/september-update-it.png | Bin 0 -> 36302 bytes public/images/events/september-update-ja.png | Bin 0 -> 41143 bytes public/images/events/september-update-ko.png | Bin 0 -> 37600 bytes .../images/events/september-update-pt_BR.png | Bin 0 -> 34325 bytes .../images/events/september-update-zh_CN.png | Bin 0 -> 38689 bytes src/data/biomes.ts | 2 +- src/loading-scene.ts | 9 +- src/timed-event-manager.ts | 118 +++++++++--------- 12 files changed, 68 insertions(+), 61 deletions(-) create mode 100644 public/images/events/september-update-de.png create mode 100644 public/images/events/september-update-en.png create mode 100644 public/images/events/september-update-es.png create mode 100644 public/images/events/september-update-fr.png create mode 100644 public/images/events/september-update-it.png create mode 100644 public/images/events/september-update-ja.png create mode 100644 public/images/events/september-update-ko.png create mode 100644 public/images/events/september-update-pt_BR.png create mode 100644 public/images/events/september-update-zh_CN.png diff --git a/public/images/events/september-update-de.png b/public/images/events/september-update-de.png new file mode 100644 index 0000000000000000000000000000000000000000..1ecb46e408caa9cde921b970d712e48116af7cac GIT binary patch literal 33189 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

J3<(K=;c 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 literal 0 HcmV?d00001 diff --git a/public/images/events/september-update-fr.png b/public/images/events/september-update-fr.png new file mode 100644 index 0000000000000000000000000000000000000000..4be33c85e9acc06813d46af37aa8e37cd684627d GIT binary patch literal 33232 zcmce7g;$e**#3f&7~P|!yJ3jH2q}?HX+%^Krgph#{0059^sH^A$0HAT~c`yM8d&KNJ zF=Ib~p89G^!1+OeAncb12z4`00Dy?{zc&!@DT@vOK$&Z(C>r`??RPvt*!TP9nb}FV zen!w7b_Y@)f^>IO*S{Sx;!0HGF{nxZb!UF|?(4k$lwneVcC^??BG1IfXJ!$+^QqGm zPdlffwYTJtAyu7=-K_2N^!z z_>q<&{59d;B*@{;`KwtMq4Aes>Pj12e$)S(Qy3tB*gxyXrdlq3;=?K*{^e+egcAu! z`vuGW{KpP1#)IsN>yLjs%eYYr+1lJXnCWhXe_bGgr6=XS4RN9O4|uPu77f{J})m9>@ zJ1tBTt@sM4s2T3e!QS6GTzh2Sd3#ibu65oLDUH4Vdt?BY!h_PX_>NLM6=-3x?~F;m zEPYkrJ>Fh>7)c68=0@VenjU5dMRIVYV}d59V_IXtY!1ql{5Mbk%-%zgpgi=?j2;3Q z>zT$dNCL>i*@UOI*%k7xxbWT|JLeAypj)I+Jl3PAB9nJbDMep`>{Qfq6MA|Me`a z7cB?%`(EKz-Vj~Le^9s_#~+hB*UBisuu+7TPcBUEEqvTtnE9cDN_Lv%AtUu3v-&4V zrm6Af&(M@(jlAGP@Cm2ibu!+WF9Y+c49>bJi?PH&#*d~ki$)Y)JE|jN`aHVM*GT7yKz|cH@?V#V+0-e9a~Mk2=M+#ScBYcnaHsO`jqTzqZq(ty?;IYiLG0@U_RJ{taei(G|M`ac z-dnxoy3z!u`QL@h(oozIQN)*j+D$^&dZ+PLE>&~0;P;n6LMUSai3$!oJHB->3auDa z5l+@kg_B(6)hfhKhG<{-RKxFMLJJ#rQEIc5o~oz|4%!)&vFu}s^11B`P&GK-ca*#P z7;Zhsvefcs%);02V)EdlOD9NM^Qm`l?{^tW#^*OC5=gj;y4Ew#-d>K9B1vxuZJPhV zgec@A9h-A?R(%XqeXF`swM%W%VxBc!wawhfP!IRIsKgPao?#=OB1!TbVwA2d5@Z6| zOvuU3Oh_gsJ-t=T8sx3cdh8SM{$e6}&rhAzi25w*8KT6&KJ2GKZ%#+E^dK=m)ApHdE4?%GgftPc7i=pyP#R9x&cZSRAIqeb9{CI|gLb^8uS zWC&Io30c_qA!*L(?rO?+=KjO{ z2Zi2$o%^3%$1GY&I={?F0vW41^;*`_{$6t*&-&`Sw8n-}j>wVm8otr|B)AVCZ2rD{C-8U}neoxpCw5`mUMG%as0+DL6n^gs)FWJI6)m8GHP!lPZ~x z<%`SKYXiX6oL`XHN$bh<069yWpx(<%|A;oJepaS@B}KbP*Nz$0h%f0=cqwg1NcOB{ zJ!i1G67^uCV(@1P^_V}6tcXgv>yc;Pt;gVD zo#7noi*2ZJ<0?(ywR0Z!C;v7_t1O;Aqm8~*Q}{bE`|Xcp^MD{v*uZ>oM85pz&!5Q@ zU@(Fc;g0jkc;fCV^CnisgDA*VsOxU^_(?haU^%^2%`6W-flwOJ#|H<8Z#0_n7zWF$ zLEd3{lB^W&)HMFA^gqp{F+>iVR9)Qd$zHS-X`ga%J>*2b5zv~F47W5d$#z`XxCI{L zvWZ$KhpWC+l(fk3U7YhyO)#ymP2<$>2w6gVCzpBhw4!T;JYPKlA4tyQxUnj$J98AF zXBbrl?6jF(wix%k;)rY~@j&=;>a=7necu|ZEdOD`H}+E;M+pZ2tYitbZ%)cLiFAar zgFpkA^M#SVukpe;9jj>#{cPBDL74#fsJJF>w{}0vihp+7Fzg|m+liYoTw{?b^H2Ba zIN(k6(|=Kww*61kJ#rkcf}iyK7Rc%lZ4!viv1*Qf`K!(Q$Wh^j-a@6n7xgCl(OdfJ zqoo$`NuF$?`XPO&@cWYwhK|jthm%#KquPZ~){X7$7h=r`?uwE;l)qe9f7+lQ{l*JW zBtF)kv@By@*8JIw|9KU^q<%Om<80p7-A_@An4Tde?Co-O+}F_Fg4hm$!~>=}w_Af9 zUiVf?9u>x3Xe*`AC8L{`7)C^q#L^tMA7VLxac;zgaVbz*43o>dA-3T2k6fqbBls2{f-2c~BQ5zUx+|opy`^Mjx0e8_!c9l^5_V}br)dX)zEkt6ZsT|)G+KfW zl?nj_M&MOEyG)}Ne$e37+wcC=aGt%Rr_?0I39J$9^rC``B=k#&Qg5agHl(J){XW!y z`y}ZpOc7h-k{*~ls)5+aSLCoS{fSbOH%9^9#iq2vtjvd+4-&*1YYV9{<3Fu-h!G3Z zQF$b_^j#l5&;baJo8B8Ml9xf*JGw)@XbflZ8~wD>Z862kBi^t!HI|VIe22J|kSEGI zDfN(#@2&-BfM-3^rxmh%?6R?8!nG~DnU=gsoo2^dw97P6OEo6hAuifX5W-0_Kut;O zK@`FUVUpKM%+zidQf?MICP>dcWr#_6KmLkOajtHZ$3WcZ7+1OgIqBh4Ht4ie;ZD(Lme>F&{LXtIDd$Us8h5 zK#|u+CijH7t!PE>Vw}arSusSUB)uPaX>YUC1mR!QNDtI4#HKX_#|w*=IO$ZqC4B~A0{P#%Cz{r4fyj| z7xxy?{}6`Qz*}o6@i@A8xv}*lib)i_Ug{YgUEF(YrTpz>-I5I;?3cL2q8yB!6ECMn z-JAzuzeTH*FZBX5AjC5yL^cJ@Vw)8A6h9-3n>)~7TV9ose64CMPZc$k`Qx``(=kssx)rl1#wzgJxP z_P58mmHy)t`L}yRbAyt3(OKPgDQs^(Xc~s^>|_Q@=~0r#371DjaHU3Yo3M3QzKH9I zD70H!Ly`Vf)xLm?>;n3c%!m!@`nNij_|PX(eckz_P-V~7sJ6eQ@qAH6806y-RFAZO zZP^mo&3ymzJKH;vuzBJCfGzX1V`{?w=CYo2|MPlVp^8Dp(|?>9kDTnDJnujy+Am^| zbqB*J^vSQ3H52o*`vY1zE(1P3&9F;ZKM&4ezHLL9ebV*p_u#lz97 zT@#NGR$C-Su$7B2F+Jo@gMQ0#kBPyx5n3YeNcN^AQflB!7b;{?25Dm~B;W96xA77D zcV`-f4q8+u$k~367zw)D+5WVA7@1GeQgXDfkda}{16K1Q{u1T_S?xNE#B<9wu}J+b z#6+j?OQDsO6A!W@_61S@F1`i~4Xc{~(LLnv)O{JrEJuXT5q_z^s{(}htGdgNvQ)_y zQ{<*^42?daG)ezw*O%FQ^fJ(4@Z0a~w;AiK!2ZT_2tMSk9WD|qv+k{M3L_N5*DgV9 zVeme>;Xv|8EC-N27*fltJWD}YQmCEx=gKdN(pmD}XVV$|(R?`g0Jl7bug>)+J&UfF zcUuvxOO2>9Hp|aHA)ic7(ilzAY=nGOfWVbyaTM>heRORiyXqp9=hKV({2MEm$G`}W z!?l48K10^0Hxu!n?zR=~eI1?Po6(=X`6I%)ORi}L)Q&THP&axtmTg=wgNGBX^&!JR zuV7bWB~%Y~WT2(-1xW`yXqY=SOswt{s4{IvAzECZ#*Gdz$ARny{umlk8I@^Sz5GD! zLDhM5J|D<=Q}69Wg1=2{F>E^#&OzZ;_N|jZQoc@XI3r|H%5V!Vy}d{P&6435h5v}q zWR&fKHl{pn8hLrWW>7k|@*L*>;@x%P;PsE5q|e6&SEkC`K>P=_VL0?u8Yk0Jg;S1c zl9@RCzoQHst95eUJH7gAv9hCNKBn?2Ybr~oIT4&=Y3d(vvh-}gaksk)TToALdwiz2 zwX-|qzn&lWF7>gkXdVqbzWv7i%!5jI%Jqk^gAs;Ku0=}hZAn=@g9p9ahmoPTq*?-s zXOQbu&hQ=jPrsQzdN#`1<+*RsKnU}H!-?`LqBP105yO{G#p>vZ3F(Zyst8FS#L-Uk z={CGECEcn8{G>dEh+saG|bQ$*1QgHF(LUx z13n8{wqs)L%xt=qoKt+ttQOD(BDBg6JqQE#ft~TQg z4ed#Cg!d`MjBU3ShPuvHI}hvO42B1M#tz@xl}OeQ}qbB;Keor_Cnkv!!3bBXhApfm1Z?{HXt)Mi%qn!ro5@L$YJfMH3wal8=;y|tYk z(*ez^Gcs|mVh!ir<|nE6ngK9A7oRt8O@VP)N=?yXu;R(da)siDxTmRlX1~T|0|@uZ zwaek;Wnr^ycN3ah`S%09}RxEzlrO*vo?6`X${Bht|m3&sE5 zT^rl+!fqKIR=m{Rl>x@dP`0dB+(x_6BDC;mV#9@17?BJ-<4171``e_WUpF(I!Fe|m z&qN}Kp-*XZaBS;WSBmyBJ7YfZV5=6~RX=xCNe==&j>01)vmwWJbWNUc-VfV3rjNb9 zN;Dt*4Eb;C&d*8Fz1<)v;h1J+!<1$3;nnWq+I&hZ|B4Moef-0O%a^XO?~bFSAVg^O zDnU9;fuilU(<|~iCoh{v<{l*Y_F<4-ijN=TA3^in*%otFufHW4w4y~f%=M6kb50~` zp4(+Yh`g|nN--ZIzH#Z+adC-KB53x%DRmP9=+U9)fZuqoAIGQqVx4xIp z{9YPVd#_>UuBV}PWN)x2!m4d(_(k_rI(itGRr_Z~7^&{vqC7c$E?@(>_#!=c+J$=I zWY=etrYSKVKH509%sT^pSYlW*27b)Rf%_}CPnNO`-w|7n-y(ZTv1PMQl_qWr5{Q8d zG}G>-O7x}7%LY`q!Uf!oyvyPLUYpnK*;;zP9Z*HR2-pg46T^gpGnAc!3g6fM2eN42 z9Q#F#RqT6j&HY(syJY;2V?fQa+8-lv_8O@;VyXc6WPm(?7_c8=ANRIad5xHTVNMDI z3%vWe*22xPz{B$yN~aJQEQ9Gr8t@T7;fza-w!P2_-yUYBq-~*WGe7&k=RKb;^>u8` zUcPts#n!Tec1glWDkOu`qAqRHn|;6*CP!f>uw|2-0Q!{{ezM*A6r26q*zpM9xN((P zO5<(K`5|DnH_`lTGPojP+J3Sw-moNn#qkqb{J8vB0Ddy{kyf0Jx)=yD{#QOXKF;*R z6r8&$Z{H~|=kaSLyJ&WeF(Rw2q4^Ka1l}#j3>1+v({!E$7BaV~;vo=RhhxSY5J^%`6~8oJZb!hcB;%vh`yhy;okOE2pQ=AfN9t%Gv0~FecNe!Y zmM{L4tVqkGB67SPUJ`l9p0q^cwlvCkX{W8UJw&plcC-w#voh)2?*HC!7k4 zhEuYi)^{;^ka=QS^&%q_c7-BHaUe!J{@9|9y5TAU#J`@HF%M)y!Il_I?oV3Aey^nPs=P-X$ zJ|1Xro#mMy3%c`E4`)_6T<-X79X#}A3z($Hg#%TXBs#Y7dQ~~6(YvrxW?gv&t{m&8 z?IkLT&VA3uL*ctG?+M*sp2+_HGnF8zgbVRN$`rLwtB`07b_EZ-_>E?x=fLPJ;s4M8 z*#T&q=|)Nsm;~ne-dS|xmv>1&%D={sRmn?zJs;TUo~hkE15^I63=z+g;%LL|)%A}4 zS9^JQ5=CtTDI&vxG#l&nl+d3U#a!(nq#uXm`Y6t-FgHIj?j~|x5m-^LB5T zWVdSf*Y?;_x~1>=#+vfC>!*cN+u>X$`MCC&$T+6cD&iR7`R+O9U=-A5PU|0n_}VyM zmyCD2D{AwuwlBPq?G;bq`mT`&{YZ9UqVX)qcSS}AIsIZ zxLcccZ`%C+DiY=tQizup_S{4zef|9olXK9%JSZ;vkjV}bC8f*yWz^D`0j z_NOWejMJ2a%wtk|o|Rvqnm&i(ime(C-+^33X}sARUO)RR?T{Asy-y}AC;$2diKPnT zWXyw75)dRm(~RNjjM3v;)Rd6Zy)G&Q6cLpxB#}fGfCR{)OUV&s+(VP0L@8ntwS*o+ z){o~vpQX2qnKR}84Q!NuUKgiT)5&4Xc$}FIeFJAo=o*-2K%=TPzH=BFO4I$))PDVJ z*lKd)VKPzBWK|JW8jrhOanQck(Q&Z2sF5^&q%gwdG`)92!tKcbpT(=P94txb<9OOS zm=(pVEvFxvfYJK?uYQZo2%Y<0%~VNgg!;tncp%zkPB(0W^zC`-O^Np;3O7hTT))>5@*r@mj3B-Yxrt2YeriwUEN7bD24(dAp{5BdLCfF#Nd zAZ+<=`k4)+7xMl?S+KC|CjOMi0%`x53GHBGE!%(7-8gw6h8Px7c&EQ87#z{?k(Myi z0nJ)k;IxdU%aX3eHca!u!l!xm^&i0$!WQ@4(#rvqIP@T&wGrtc9u%%!gv&M@1K)xV zpmoHYb@P`@=%n9VUH1QkW}0^Z^($VhI@@??YfuCFmGf>s@O_rp8ZWBT6yVD4d@Slc zPZE^sA3enPI)y*MY-Pai=vc}9wR28_7%Mn3q74grBT9b~)+YmSa9?hIioBXg+U7NH zDpeJjxR}<;X(iO(FBkf07yY@t57AWT@@lI)asWS?lG8F&c@>@u zMKbCnXwZxNc?h=r}Jg_Fo9fzY*owyfD)Sh0E+CJcv$OBHg6LtGnP zF~n^kf1lqEFY_|=DVA&ye;Pk3U`grDCZV_hkW_fPr?|32UHeR$Rmq?L7qr%Qm+ev? zM8IV6Tom?A4AvMkBx{X)f~y43?cSM|QRF5jfPdG{Vafcq^T$vz=Y8Y23ZVaX#;yvY zcrqO`X2p;xPkJ4>HpKTpfR(~jr7)Eb&6@mhmG^>zpg=#LMYcBtKodgAj|)(KPd*Jg zVNY_^op~r2%XLLa9YSfRkLQdR&3+q0IdR@(bZF+$SKe!`wSeh6%B3! zFyuBVB=#>2y|9)ZT^rUH*>Sx(9eVE3BqWJfLm3d$*6x z$o21DF~MLi>cgnHE`#84K~JH1gO0Dx7&J~M7$W=vvh)fxr}#r%+HGUbFa8G_Sa?6Z zrfk28<)f6g3HjcMd^81n0f6C1R}KmbI(3WSxJL=%PF!K?pmgLgBZ6&Q@v9@5X+pL# z2y$Ql;X93!aqTLvE5mt0*ZM)}XwIisei!p<-0te7v8G zcdx1v^)D4a700omH*!i`{Q7B9P(I-$6-9WV}oC@;S`*Q>1PG1 zf>?vS*1C4-0Fl@p14V&5lsDt(_4hGAMWlG8_u*s+&M7IV%d|Ps%Oz7l_v9oA_ z$Xd!N=suSrEZJ#8G?umC#dR~JfNvj6(^;xIJU}@4{cYw`iU;x>3khFd_<#0V`4d+k z^WwvBmvhe`2%l)<0dpY;i{AXJyt{#M&yF-iY3(5r9%VUgQuZ52t;W7QPB1?4xd9QW zvn%ZJHRns2CwfYNXBtvRPY0*K0GU@Ooy;l)W>`>RrM{BQJO6@N)_@A zm-ZOs6LL1b61e$?Megmp=__Vo1%0_Ocs z;Lp9uh7+2_)U^*D#O=(*>?`q_y$YT(Sgd%=nEfdu1xrJ{tt63T9o^M+N3XVS#~euBGVm94P7O_VLgRo&_rvbaa??!`(4XynC1n8!qN6uFY#Z& zKvf(W(%syog9EiBTO0$1U%zESO~mmQQPKXDBm*6e*_cd71Y*C zwQyzl6^zl+Hljs^v*=r9ta5}b__>%5Q&JiE7=HOeKWn`S{-tX+CD3xwK*i@k!k(Bh0RicG%7 zAYIAibAz`?4&NmIkOD=_$WGqPJ!6zfkQ&b2+)$j=2Nk5sEy^OPa-Y+~F}fKq_!q5v zsFv#OKv1sZ+U(ELBEtd-LofYy6U+M|0!ypoMl3?Dn*s|zF#Vf)mR;DN>G$DBeAkhW z20xi9#^M18zjXU5%mPLB3HjBTgnUmc@LG0QFSEV)+1to+ z#ZLVvYOZk;Exa&-?C}ieRvWF!Z6gUTJTC{BV!92mmjsbZDp#_}6Ig#y%rztFcNBhP zw^rs`_+qWs@ac~9AJ)NTs3<#+L~d|`V!?A5M_OT~r$TgpSdF;d@@2}zzM6QYQ9Z+zol7k8_GcO zuF@Pz{8uOF@->!bNS%@87{3cJ4&yRz>|m|SBXcA3+^<4WvrRFhL5CZ*?FfkxT(qJRIm}UlzNes%YDbI1Vho%e0nU^TVQBSZTH$H4A|9 z+!T8w`L0^^c8#yHYin%*i|0 zPW4+Et|~Qz5eykG*{g~V+<%c5=<%!dB@Q%V-T)CB@oSL@;5lWDs5?!&nt=&Gt=e02vdlBM7={)}jU~J*9XAZCD&Zt^e{~>0`I_ z%AI^Z=>CEx4#zS2lP#8)xx}=KQ^BI^vxULy{HzEzVE;yW1ctw&aDbL&zVl?dy{7Ze z-+#P&wme+#h_Dii^WEP~r_&DGhv|4eeMJle&;clw^F>@WT=+POx=s~-b#}jb!?SX` z*IDRFHC|)8Cs)i`8f(16QSW&dtkLn2m&C4#xBEJ7_HUq^aZ0d41w-T zyg-JmJjB4dk?ZOJ*m0sx`!R2T2o6kh=n?+bejHt7L~;VAWjp64R;P2V%43hke3#Ku zNZ@lavPb%U96PN>Pnd6)51Xz6MePpD%3jqT3OpbVXx622>ft!4F=b_p@_jilz!sZM z?olkqW4|rZjpgjS?IFYXjxI&lRG*CI)jE{XimGuWa@u99#O&%DFMc)KK{83z1&*Q?`@r!2I^Wqj7>7q*4#YYavk#JdT!1P>kzE>l|S2AODEJ$I18hm60os!3x7Tm!&6GR;I4 z$>4r+JSbTd>E3gg7qYM+8wrm7t{=&VWmrClCbP|uJ!C@(A-vAVuu=MP$|7MfeeAM4 z&FXIaZ0tpT7O9AO04oqb;97*fowc2-eP0#DUejDz81(Zn(im0f@v6n!OM?`~e4g#6 zZnSah-xj}i`6IH$^WiGU&7M;f2q_}Taun@`NZuo2paf9kqx28<8wmqgpG-3#EZx;& zXrtk?r79X&C+&|v%k(tS{J$$yB1B}vlKPF2$_23`K>Sh?`NKgh0+wMJ9~=M{D%{dt zv~7wwKyV=6egQ@(kOWXkrw-gE-|=OWnTE8Ht1r}J zw(!CZ4>^o(i6I&6qyAJK(Ng31lR{mIpQ}Hs%mE}^Xhk>m&stt6uty&!M>$tg``YB6 zZ_bW(E(6KYTXZDfJV3CamzebQHp1b2zBjx6ZNh7pTahi9-OfmY5IT@(aC!(M9|rVY zz6k$Yg<%+JLnH$E;_vzk^m!9Gg4u zmV0SldH9~vBF;u+ag7cN<&cL7fYl63>zpJWNyQ<1Hs4G*pJH{}H9_}ZO0KA9vLUf6 zdpnsUZ`0ffV7(^!l`+ef-f7WZ9~=izU?IQ+rkpeY1D0xZN(M&^@)>5DT2X?abh}vg zVULbBu5XR9-AY*KU6d!6_OR9FicaCt!E$`*Z2T1&y&@X}ri?B7E;^Msj=?8Z6=IIEdB z^Jd84{!Ah8o;K)Y>qQ5*nfVq%aQM|x!_{Pn(ar4!3Jflp8>)NJVdY>>y{6+fro4=$jZ62+G|La1}~Ql2Hp zXXMHrG|S^C)A=By&MjhH7zctL+7hzPYE+wb*uNr@KDm3f9@puU7ue`Ra`WA!nFXTe z1r1;u>8$m){&N@EB8$cBtPkql=qB())vnN8_Y%Ok-T3(OVcQExnxpWA`ss!XKf!;_ zEmSbM+wrrnkqoRGaxn?G4?-Mq<1yjMfhvqO;uzK~q>eLvznXEl(bgP~8yyy|^g@@y z$_AD63JdMnSOogY;qOC*eW}^?J6dJ$U~f>;0egru&PUpkv|tRsZ|-prG~pzf&G} z>nuV4j@}=qoPPVhar@YX$-`{IfR@%RpG{J(pGH+(T|3IQdZZ=uEVPKKt;hDx2kR!J zO3F5=pdqDSa`mKlD?pauyS^ZaV+JM};_2P@zwgp!zj zF}5G1e_3~tke+<_$FM)FRf;9Ej!g$UDdR#4NFKnjj_{8N_I?`Dl5Jn5Jie2Arn3`WJc#XNddEWr06L#uMxqJI zJnkkF)<@rR?VK?$bA3m--7*mz18qcW;a@I=B?(*+G`S!akdA|4X@bczua@T1-lc8B z&F!6ccY^Lt4enQhZtsNePDk!<#ybD4+|7F2F0+?zS>N^cYm-d-hOS4ir*N+LZYl?z zefLnf!DxDFBq%*^U5%QBI9$MORB@qL(>%uk)Te zq`uq8ytim78I8(GEbe|oO2eI<1qyQ5qORyKhZE}%zf=s&yDJ#S;cmxmPlG*etS_kc zW$ntKIJHqs6qo7CNGCi1U&Ld1-cqcy$0)eVNZ{P@xvJHh)~8`21J+fxc5nQiUUIbN zeDMBD>cL-KL7&-DdG=4@@A6@-k6&9PX{0Q70K&qXM+E|R2UJ|m)VzNZ+Ep`?&2^bP zwKp>Mk#is3MlgX#P<@6RGVLfNqTzW=AyJG2wHQW)a2NJ-_TWw6rD0pTNUD!$lMet; zr!xUmosq&5?x)Q-E{g+Y>?88r@@bG{v8Sx>!j_4<-<>+Ze7e2txBbfWFjYsPkTTLM zl=9+3B0j0oGP?J7T*bvx$wSlAUnKODD4|l{X(k)&7qRV~&v3^G02Ue|?7)=obC?9~ zHuyB=K{!+B_96G*g{z#w{W*8%ebC*`<=shq=N)O#ZNn_fr+Z-q;^(38OK(Wd9>e2J zg`N%p#9Dyw%gb@Qv18{)RXIi8UgaLI=xhFQFStS~0aS3p6Nzh#?IrU7{<>Z?Xi}~o z&`r5Man@02m&ud!k_FbXOf)IoNZ7QrAbQ@FwDyB9|1KMR=5s)MaOG2>qdq}x1Q&cR z|1ju4@b+S3*Q~1SZlBK2mWtQoceeXMMmP~$@q1n#{-d4TgPq($@Nc4_;0vmQ${AoL zm9-nXNovQuaBA;g#57}&!sYv0D`rt|gNSmp;tpV)RuRwg^XQL3o^I!!4FR)Z)O()w zuK^mncYiP1T|2;riXY@w|K3>p(cn&RaOe6{*MwByLmc#XsLU+S@bEBr->BenRU00wXX3F*KrVCkSy#EuS_rB3?U%Fd zGFk)4X9u7t{I&=kZ&zfn43){>*ZGcKEsiQ+T(0B1k}F(OswAgSpbc#z}^Ttz*1YNzERi!me;NXU$B^c_xUaaVqLg# zR3sC~8tk46DPhe^I$XuIVsXjMArA_yzpUUbKTS3C#}C}b;~pb-Ay^nk_UzoW^sirD zMYc>m(qf{#|1;L9ZNLYG#n7NC+8ihBP!EcFeiwhWe|^DI5YC5X8yY`*!{JP8N+i8R z(Hp--y0MT}&)D0S_mYl__ebCaHudGnfoY?cp{`2!g+3%obHLn>f;i6D9!s^N;|0h4 zYP=O#Z=G`s9-fc`(o52_!=Wu8!GUNquEs=&A&7I^aSG%`B;MMhz2iy@vGNtY%-w^? ztp!OC78+IH-wk59A_2^Jt(#L4yE@~}L*k5{l93d|B3>#e3l$v1T)T*+53sK|XhUXF zf4p^@ucu9FKdhi|Rr02P^gK2f_|F77eIi+Q<=;O_@bakKcCV$xq&KNsRg+A2QoNmb z?N2|>X?gcKfASntLe2y=SsWGc>38~61&4yZ`077#c#8e8m8`cVmFITyti3b|_XC6k zuPIiEwyf9674xGn;wq6;Kk^D2dUh&OAF#&dG9zUc@V8|DhP}jf3VEEV_<5@hWohhF zn1AlV8dg)7AHGr~3iExBI0dPZoE>dj#jVh?JHS2(K$*Clh5zD~#3A_*=~^F-8*=Sa zSuqK5Ni%X!Q^EKLwlX61wFe!_uTWU`VJsmp^gmM05(A$`4i`V#FI)x+pyg)N83B~N z^d|l;SGi~?9k#U_2Fm1VfUBL2`?5qh>@ZmNuC*R(s;~#G)&n0-sKVCs38A!#UdR`x zw@42X37p&15q_a5n%FH0L}kad$)y(9cO5>h``;q`Vy(gYd3vEZ(DRB44R#?mUUq5W zS~BXx5TCbHyfrqX(oM7F7)FcgzsE(r*F}AjvyMDk zLMBK?hR*imQlfEw^_1o_O^Tm6KX|HS=Mwl^B;b@-R6jaGAG7^UT!u-$%~al*-nVf) zA<@#*YNkj~O%Q9m9pOJkfAxKmqR(qewnWIrt@cXwo!;d!MS|MVoXgmbrgYx$vA*(R znYdn2s7|7%v7*{N)R5i!hebf$FeSy*p1B&l=&y8ryfS;Tkz`99(T~R@OyE)xpoF~T z#zxu%I~ppK#xFWQBP?>5RZaYN@%Axcz-ISfheNk~n#e2PluRN{Z-3}ei5mWdwW$1{_9^^aiAMVKcFx}ZX12{ z(m-7B%z8cfNy%~on*Uga>aAwj;^T2}dNjkHRm$6PkiS}VXsSe$Ibs1mjs7Bp&^>zP zqh7?etc8@~`U&@VOClIdQ{%yi+d%Rc??Vy0?FkjNd6~7|x1t`JbgkO3(Tb~BdQ=p} zH?I)!2nE%z2*f2LS^I@tRfqWTVyh>{a2unPW;)qSK$}OzMu90TzOgqbt;rAESNW}O z`9rt3Nm5F_c|{D{VYyJh-wg5lnaZEj)AZBc&BpH8`1c*Y0z7*nnd1&dx=FE9H%+8{ zfZAuOH$?n~qvIsDTuDl*#^g#AhHb8hT5&j@{-`cVArz~(>{$*JO;5ptXwq1kc-iC? zmvw$?X&%v=G4yV2W_599d92Hm`<+CR1}_#5A2*%0{?L4g2uVbJU{}Wf4j0pyO(k!bygqk`XW%5rq`qllSq;~80%JlDS&CCr5 ztfIplAn$&iXwi?)A9Q@Jk4=J_uWI5Bj?jA74bGw$K%-sz6BDo|?{_JyLh1BzbA??8 zE*_nnZ^ksodMn!%4R=r2V-NHstFv_ZU@OLFAFz*S*{YxM+7gcW<}U1cw_<%BWcWLG z?p#gulTwr#F%Cvf{Lw;){mbR9umbGEq};}a*cAce%myQVgn9u4-VqMA*1tZC$)p2a zewz$yg@LPif$uek$%|s2#U_a%Fh|-Kz^mQ(Ha@uRdX6asI?}Ld;vtMlCVZffPBNJw zE;I^F(CUUfZ$&9Rm5!7ul7!|7c>e0kGk85{o7*^-lnP4zJ4@)(rk2`v+a|6g8C7vOBd?2u= z{yHUBif}0O2U(^N0#-097nAdFkdfCYB-iRGI{$_WKxPeeISpK#JvskL&Vu9pEW<5Q ziUWhzGn&;^3}s_Vse6FQ(|q1h=vtrWOEL;dku8NqUUugABPc zZz(zLA@qboEnb2AxNPHsTssZ}EsC98T0v5r$cvgL9*v?v#-Fa1yOUY0qUvo8VxY}e z%9CmJx*@XLm@N{`@(EQ9G>k10=v3%&`|8UU@N|cX`Zpcu15XH}9JY3`GUv{?;VU#a zF_#hkkb7pCL~?NVHCqb_X0p-HuWL7OgS0W75BKN*$^KFQDc$>Kptaa$5+c7W>3KVdidZtmEQb(fzwQLyV?d1{Qgyjy? ze=w^(+(#o zArDE}yX=wVJ3q2uA=NSn#KQRI$2_aKZWu3EZRLs~@-KXB$7Oq*!n-^1Q{t0)pp7jK zme=pbK+K6xZ?l)gijNJY@m-2Ad=eSlLN8)%Zf zF(oIlo^`B0$jTk=CS9*H-4LUWR^%R~WI6WSYvDvfV}E}V)zWU7#g7XO{SIM?OlRh! zt`^>(5G~rx*4W)yRK8*ptO6_~XeW~Z`fYih;>H!#dyND+QGg-%a&JR{YF@9%U{-#+ z#aOTSYpq(@VPsEP=O5?Cf#U4)Y3+TIz}wQV6I&Y5q%4wNt6(Qg_w5t*@I1=x;(=p5 zuroONi(fwuEK>X`io2dMb((o3N1agzy8}zLr`xh*di6gxS%YQhI>3T>bc(~MIBAa0 zSP^*j{wvu#GS5(UMi4}jgloONHs!TG9^{#5ZVF48%ul)YNzrB=Bs(UQT~sm_2_^u~ zE78K55eE1co*1M;=gC$kh37bw(3)IH*jlUJ*6JRBz_cN(_2mj3Z%^9Dx zFJeO|5OY*S5#$KuQ0ZVI_L;hZOu}YHJj9%D_K~=EImqH3Jz3mPg=& zA?Nr+BcaauqQBO8&L}N#q_GnP&>^#O6vgO26LWV)RZwuA;Zk|n$H3n(I9%nD1?HbN zy645+2Pm1o7I%UC%@}rMB4l{vNtGFv7e^o^h@sJlsEkwmZL>TyA2t3YCVVDsG7|FK z`I3+>_|{uq$TtlEtzw-9F1ZZv>P`)uK}C!HVN;pc6^URLf6)}sdoqv8UCB>kxrBUnGC|--M3or9Q zX6M^-0LyQzsxkj0Rn`D!ctJX3YPw`8VRd|?Mfs1!XbIMU}&7)4oq~DRZ-~# z;WwhX7<7M9?XOZJX|C!V>-0;!$LaZbCQ}QR?R0RQPn^v*KzFxX|Cm!*-&OpA21m`(wlLj4Vl$W`p? zWFT6-dsAj_Uqdx#yNs$mB6X8j!Z-Z1^S9^dH{%W1iEH#_M;Ma>&VyZMDid}xt(6T< zRW%LyO?m6ckPxKjrrB0x@IDI`45{)0|KkZh6Lhvd8WAt(0yCZDrL_^!&P{cJz036N zPeiu)KUY%Ou)V$i4#T&YkN9qV4#?nGD%Z}@U1`fq_p^1BZ%T^q^07el#jNmo74CLq z+%J1!!Q=`jJS7!v1LMOzT24(kTrYhIyiluPI;dp76+1T?jx<`+zpLz*k1H$AvR>Ra zQE7zjJa%-bNJ*dF`&_X(Wy(%1l1~~YMdVipS_w)1{fZ3q=nBGjNkKrUi(dckKH z36$UwG3KjF3XFq>}zd4aidv>l*48g4r0p# z>r49?5ph5O{l|(mRUD4S62|*eYh~RX(~o^7dstE~!NwJjyp(h&Yj0E`}U`x%2)RLp4|4NJdE89i3<`-99hxdU!pB z9Tll6Lgc;U&GPMCNYbiM76{H7*&k)y^xT5KU$X6Sx zPqvG&z?m|mG;Gkff5+w<|6PWw)MAED*SbVm(SzY#a#TcjnjEHxXoAj)nD2hQkZcd* z0u%@NvM;m2;P6bbs^RCQQ4@|U6iBbz+Lwir5DMf#1 z1-da}83d~OMlA>TlhQLP+7vVR#A+o4UG$P3jVC#>%#9|+$9HIGM6|z+&juGwQJz*B zMHD56HyJE9JGrdUstYF?e#XI2z8e}^usBB{I|PTHV&bYXfFU?o_IB;=7QVL)9lCr5 z!EBU-xZmnv0E~t}ir4!`8*upGceXP>`_$>8J?Jq0>$qfHlQwX|-YK2%dmq{KyAid> zY+k4<78h)&OLN!$Sop(&FjGd_AJW3lyPtyJjZyrr?oIC+6&B*8(D?@-C6lLsT6la%$J_PY7d4DJ z3N)g-eq3P)7p)L|(QB$PPA(K-SdkeKQ<%zs?hqtNdRyDo7fO=e8sLejw_*wX=F!Xf z+D6Ti6w4(SS>=d=Vs1OdNFyU|$xIAIv8`{4Mccle?{t?PLK7D1zClN%n9a$S`rSCE zz569=5fbMc?=eT%HYsVDco=^heW3jFPShqwX>^FYqI9Xj@4J;~yIUV=<;gx~6LdiN zx(`cKirIL&>3dHUxTUj~0Y1ryMGRrl%2coRvRvDkl$ZCoG8snxDocgOqD9Kj01rTO z&vTF5(>*O)$DrnCnE2FkB=FVh5ep3xRAGOdA-v9O(*bnQv9W-zUAoz(q#hVptV@;A z`|eQ{wQ8d0X#8>j39;Ttl~vr^3 z!t3CGE`kmzz>g0IgvwHKF~*0~k?Vv@^=Qn{K=s=Rqa9u;WCJM(%3AjLM<_k2*$5!` z*})1jecR|veH$G_u5|`kTC&@#tET9h5{HsAyv{!`m?XO~^B;-5N5m0N1@!wFLi@9V ztAy;J(8C)QFv?)Gwo_l9Gd%W)I?@FBq7$ER@|(TytDm{+T_duObm;X6R6|>6(WhjB zEY9lng`-c1lBhlA8sv|dO_-T}s59=FLDzDAHW#)|O~sCARRKPw;ULObs=8OE9}Xa7 z@YkHxOgHu&Ap+TkGk>4y-omX;(?F~^vwRvF#As>oR9-}@LfPhJ{!U^=YGkG)s_wED z^lo%enJ+J2<19Yqb{PJTgf!jq%)EtZk&R_{We3YMCo2p8&LHKgr{A5~tyJnJn)K|p zkNwG-bPiD)T!a@PA!=)yKeo}Sx$bMUnOE*cqQGp%pAg+5FpHwX8h6AGGo#q}TmU#( zWI+T#44_{9hm4zkufzwu(Q$fA`29H z3Gad_=C*PsRUr||F#g^^EJmCT=&?N!o1?Sn_=#qLQy@gMoPD*WTdBxIfHq^EwzOBV zR9KN(SaDFO)`g-}80^Y}v1&7^4=T_cA{q!Yg#Ie=jD3h!BDyI0M9K*pvJ9!2zQkYx z0w5baR{{^@@Eo)f@oDW7si~|?%(!t4Yg{F2ALJ{nwr@jZrwyuER_O@CW31KIuXKjb zKIj^I#^=;6?VT=>Jbg7rS5&NR3}M2vYEt7qYYO5sL$vwm`G;B(UF4S1KZQD=gBX6E zE{Ry&z2JYISmaLuK<{)|Msz~wb=58ai_QK-m5WU@n^qdPt!!N}C$jl>JQ_FmS59Qq z&!3JRC6*0R>FOmFXY6Ix>}+M)FdzobR_8Ir87G?_Uv$%pRPLHW6dpe2RFguSg#P|U z@r8d^aAr}}0?JD>gU5P`sEz;^!OJ35fbPeOevTp=K_ry1 zGqg3K+UlJbIQ@>_HIwMu`@>1hlN3y%KZMh#B2v?Po#;uy{lR8vbMr5X=`T_jVJz;v zci-}!p|*JyZpR*@DeSGU#XMs>E4#b9A(r9AHVX-zaV43pmX9Z^qXm}H%c7H{bW|Oo z2HffH*W=1}^h|KMGt!NnMHndsWgAuN1;>a(bjlG<=3B2zkn5Vs7oh92&`0LVAc#rL zc+Ve))>)YHFG%1kknms6d}wrUy371Cs`LDT>8hCQqD~m&y_(P8 za~JP+KDt-e?N2k!+ZFBr%-oN#kM0=i2n#JSRu|m~q4{|~W}Kt>V*n=~A;dVRaiEUP z!J^{}GzlRB;@<}WvRUS#Zj3|YKFfS9rB**OHEl2K!ZIZ-D>*4~dp^mQ=)LYmO))u; zo*7!!29wZYv_?Cir*#X81|`<358 zCW}cK8-Pz;kDo@C0pTbgdXaR1jEj`!%G+b1^~_Yg*reUR4#PM(+zXlN-AHOYubaX3 zztDiXfX6gNwsCIXk2CI)=g%<4>?k9?oGu;LF1(_BbFHY;5jKt9y7a)cALfxY%F4f| zRZFxpYMz3moo&84Xx2{|p-*y8s+NA;(13FX|EVp138PPQTwQZjR959KEk^9hOYw1! zNoeMXfFDmW^5S$oqU&6jV9dV^yVyIHc6-lEH=mEx+XQ#_ejwpmEy%* zb7FooPIW+u5V1(XM}4=fT`Ku_YChPppGiq6;n{`-{w;O|#6%txp=>d~aKUf0ooA`y zvp&e4^{VS^hL$4NU{}%-MsCO;1QRvaPmdc7RHg?~HZpoqNQ-o-f&;gD7IM=n|J+ZQh+on~=cKW3^ks9<{^Z#+pBEo*k7p4fI z0zd>0IR^d5mod=7hep^ZILn2>#Bz>5m!%8lsJ<#-o%rWcR=FlUwRhgrVw#~b0Y+Jh zBAihH`5nH8vgwPN-8U@8N5U94daS}NRpnamy-Oz?50VNv-ZO6{_^lZhrwA3k7DK7) z7IPqLrYg!gA|<{LSj{NI?&nK*BiD$%;MS+6-rX21VkWrNyqDE%goINHO{s$wcYihv zFt6kpBpK9j6Xk!fx8#}?!FLQ2V@K<7hnq~J^ER0x#a|@g_eF~VYOkk2drG*~VHOew zO0+?vf<6QRQUg3)tZo8FzY|R-;j2|V%d<_Z} z6Rya)_E45DOwdXT%WeHRXWyTwT5-GzNItaghrn#mNo@^549M(5@;o{zxto3bATrdW z21#5{irsQ&S0vsDurEsTZd0W{9|7E8P=4|PMm9U&`o!c*Bp(XMD~sj12S zZ{az7lEj+Lr_*rKeT~0ez=upX~uP4huLR^42$Wtv?(1%YLpYj8< z9tA$c&h?v>O-=Eg-aWz;Eng-0Ay88m3<*p5O9WYqnv1TUUE)lN1cl1O-b5J)is zTAMWnIvS3pv%H@Y86q`Ep?=MBtlH#k0Lu^@A! z%|+Nwby14Bptq&Mpn9)UeYNepEV;1dp@`ai{ew-qeCgrCNa+gZsM-#ZE+F`{L|05T z)S>63X?pfa8 zR8VM&myl6ZLE6-vx+CoU%(gF(J%MI$(*Acn@W?XT_cWN)q~hFTrZ(K>koH3IUHPI- za5SU%<7SK>Ko(Wh=c7SEI!ya|VLqoa6P=goCV(O{z(7hD?`o^k|6y0%|9Ov4-RwPx zl;$#@`enyb{BQs6+|^Vy#;~;zpu!;#mX*Ws-?npRh(3Zeej7g6~sgmG5&T3Ns`3p@H(|DG(VbmKzIZen2!WfXyZ%djZ{&r z4yN)}QP-sCNxzNCs1Y&SoN(XpB^A$pIae^g|IPjLGs$wDHBFf3X8%S&N*S(kAh(j4 zbKxHk+)#n0kjG6``!p1k7KE0uy4FV3ZySrdXSoO8_GIDeVF`VGZMm2Tp=n5Ys6yB> zn_aMUUAVUISCdy!MTcEB3~laobOHE9W;hoT-mPg;0h|REHapKho~A`IXvgFP8D-_$ zO5B^>znT)wQ5%>d3&uxVPtFe-GE2UH1uwQn`!Kup<%#= zc+G>NWBf0#59iRRAhJGPPp+FlX9okaB^^MY>R?JCT@O^-|DZr6w`Ix(`WP!R+V22S z{JlA~KfZ(Mhe=lgD1s>i!%xdyJ%lZby##6Z1@{!!zqet+W&|$#)2Lz1o&dLi5D70+ z^;GV|S*G(o4=~TKA+_4}&tRbe3fvJ9n34<)G?<$gU~QZN*#h?-K}Uej=Lhdt@@=U$ zrnlG5$P_Q_15w+dh^3?lmV?fPK-4#0!q7%*iudo5oF)xn^RA!&T&^XuLC>#=2fdub z!+HD-9%(^ne2xs1j_EoRd$EV=mhJNmk>2U@b>?G_q1pTb0$Z*KfM7t_%#7Lt4%=VU zU*3laynL$(AA6L}01Mf;2RzrZM#!H`O=Y!+$6Dyg+xbX4r?FQy&5{V?6B3eU8|jQO zn}K;S8e&sf-Awm&&@#mNn#G$fNdm=xn$wEiFG4pp=v@g>vNZi9D#;E;v7wZ8u(rrs9P!)+ z1Oxd9`FO3`Cxu=e&-!LQ9$#HtJhF%XU^oY^td6K@Q*31Lp%Ny=�(91b4=4Fuuex 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 xHofMh_GhMYBT(zoKrsLY; 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 literal 0 HcmV?d00001 diff --git a/public/images/events/september-update-ko.png b/public/images/events/september-update-ko.png new file mode 100644 index 0000000000000000000000000000000000000000..13585327fced331ecd36eface22bab0e6512cff1 GIT binary patch literal 37600 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

($RZZr7#cKVWb%mki7Xg#7L%F# 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

<kQYozxTH{9 zY2{EMIGKo;6%!;VlvUlIHn#XRRSG?qMG1)quVPvX7aSY@e%fA65f zKp2IU;e9{jqb{4-o7xIlbp4IZ*dcpMt@T!yk#EoSEWhFvIx~ZcoylxBXhl~vsGh!Q zYP~eif3ZogYZV^du_QAw9T|In+p(^Ohi}dWx#bAib#B^-pr!Ry)B@x_?seUOK#WKMY#)tJu;h_p0N=@gQ%ZI;F*vzxl*w{t^H7_9Xa!XmR zlnPeI1L3=Mmll&RxxpT}OH~t;rQKM-x7+pgtiUKOCR-sV*Ii<709++L0o7RECsHB& zzXVInnzCCgeaQ*?N*humq^)N~jutkxx;@(zBb#eRLOOHF2XVcy7oRoE{V*-lo|Cp^ zAX;hx+l2FXiXpz#hX0Ko?{573(z>6|(8FD>(6@*8kExmE=k$H45N6wR?4gh4-1k2I z2L^i+=X~2Ta521$w&a6*ehe42!0-4Czp{RT=l*InAqU=#R92b>+^8xA&VNoZ*VSid zoZV8?PGmG>qA3cwjG{u5(ZfHsERODFecdsvFEV1_HgJ%jF;aNUPenxqx%&!r|7LnK zP}&-c;jl+p@G}wXYf@G&kDazB7d93(I3RM^q$m4C9g~fiPf9k2kou*=Tl;?DbYFPp zqxJ^L!Q`*_z&#ojn@-)3swvsU!U;+xG&8I~-mwiV;K%uCMSH*;prJuvo4#$~O* z1r2w^)QMgTEXptkz zTp;kdLhjkCb;N3ZrOe)Te_imkZA<`7Ozdiyqla#0$W<&?=T%g!F3nkth8P|w8oVex zEsh8?*2Ohmq(#4Se7ayvzJF|al;~oIeTWnM;D;>eb}aQVL^ADyAVgT?-JMp?jWQ)$ zv*M{ifK)ek`je}7NRuTj=rABDv$!(N_zO{7-4$SBW}|dF6a3q(8CucP+uLNfXo2dv zE207fqmLJ!JLQ_SlfAoX zrVyLAzeS zQxiJ}|FUfrVrgZ(e1d)b-rbgE@w9ed$99K44QOOESvcvz@SBcB_oG`sefbg@iG55) ziz`>_brCa>-(BFg^6|`&<$DkI7!UV9)fAjLBNvxyH;0PaM8{Fe9x|gUWqYc`!x#cp z^Dyodo6o}~5zgf`uU}epLM|R99;|^aPg%bO^D8r5$$V0=_%z6sKRmU8BiSX7I!UxYIYU z&%o?F4Tzj(nnmkbJ^@(`%pZzh#qd-$xq&6UTq8p<`+DSZr3K;dFKOMR_~VWDoroo}p2QU;!E; z_RaM}81SsrEvI=;7fZLJgVAs*XkgX^Cz~RJh=J z8_oqItiZr^4wwJ1uVKydyD%S%hX|Nu+NM-G#|~Yj(!~b+_{tV7EGlJ*36MUSt6a@b zdNSP?%+H0i_7IwyT7-r}!Us)r>ia**P_g2os}%XHC<%K(whObx4bdZ8T`c0aT@v6q zp_pFc=I~v5mpl~bUqmbqr=e3~ODIM|(Pg+8fHbk$4?4JjY^x!eU&DgpjZ&a4s-^V) zEHDcBk!T5NpphBQB5$aw#={r7vdsfgREjw&cru14Sh8BW{npwkKu+x!ie>$`P2X>b zoH}5B!FTLko#2puI-^Q{+^DA0fX>7>qam%E_*Mh?G4XBsnF)vARIgnXx@;`L0jc^l zYdPx_U;Keoz?+zb!=3Wk3KRkg2WmjgJ`$25}c*@xOUrwjjklnxKLnPvj9_*V<=?2KRmQ<+%~0k+f}`nl4=v zS?_V>xHWn6De&dCeJAtkvpx|cLEhu zC`D*Bey)f+bUUIA-D)J_ArqD3&)dEwjqo*GL5#GlY?2U^nG#U{Z88^922C3~octs8 z&%Tf*xpbm90mCCC5oD~_v17`b8Ve=6AYCf{5rok9$XDamqNWG74d%$YxlS0)LG_%FAR_30?7&Q>>4E$$Pa`2 zHRyv4YUum_@~w*c98-v*<8oYtaj3ef~U(B5ht5V5Hu<61dkXDcL2yr# z!fKOJBe(aISz7*6)@$Z3@1Bcta>o#dYy==6;osB2{yc!Sxc+~pMZ}aKfaBVmb8e0* zAO>ix(QqYYYu@wdc6Xkk15ex*9XRz>!*6KMqi{hvV^s=7B04ksfo}>b$_0LVOyU-W z5|7{+RZG9bL_XtA{zL|S?kUtlzCoUG3WHV0YI-fVAcH8e}ng^FG3?39` zrQsU9I*FTHXUL+$)C^|Tu*7VnW!v7Ro~iwU=$RGn77Xe<42=WZ{Y2w|exL)zW zQT{xPbyZ_9FC0)wq~lgNayyhRH}=je4+H2VY`aBTJdhs;{kOR$JotLJ6FnIvaFV+T zcz*`~4|J&iD;1_G;Ab_(qtuL_Ab%#T7$YFzq2Y49AH`;s8Y5^)*Q7orMdB&M5hP57 zr3x$3F>?3xj={Q7bPCGrBb2pO(6lito-N>AVIJMCN#P^TO?9rzt$njG?|Jwjl5)Dj zEplk*wkcmw8hktWFcK+oQ0U(E^G|2r=FdM&rE)}a|EZ75e1=PBs^JkIX%8*|YySOI zAd#gh2cN0I1H>3Qy4z96A*P$RKEargSjQjLI$UsxP_w^Z&`G)^q^$PKptU~b?QchQ zWX_`GKlg9(ASdR^$GIf!t^6ixS^SHRU=wrJ9 zseosp2uE+d|uIZD2bi(y|$MY$N8VcWAJ zqOYm>BjARvYfpB6Wyqy=8)APkcXcjJ#G0*+(`om}i4h&+y&?xeXg=?Tk-DAn5Dx(Tay2(XLT>`(+S_#i<&7$<~HK47A>|XJvw@DNhsmW@##Pi?pWr zqw_Xsv-i?D2b#n7H)QCW%q&bHQ^c5Yp9Bq5lBA%WPSK8NszTI%Vd<_YX<`v^(HAwV zPwKaedsiXhH_b#SRb(b=xYX0w8JWS643<1_u>Mm^i}^Ci-a8VXs({#>YNOv8>0r!| z{THoSq`}|O)wiXpwh*JLdWj@*JoT)j`>rEA=8kY*axZMhTQ2Tvis87bu)4B+T znIQ@&Zsh;=j@dA}=TrposP@!&LFliF8l=_fI5*G%X?#sC z|6X5hpV4T%9qBBLD~Ie7bC&Gy;5taj^2NP8N|-o`p0p20 zb#K4`mNjAn)+80oOKk~(W)YoD5uyF>h=AYvHKfAfSn*$JW#k?F8zqypg*7U)R}&1G(pLzSvltbO`4{qUb_lyR%N zAC*k+WCI1?o;9}xfa#PBm!M#cbXz2e{d?nF{r8BjJe@B-vXqj)$QMGcKU=?mW#8ZA z2T)2QdN#fTHJ|OG5m;7Rctt_B`c(s?aGuY+rqk4eVb&D?#6dMF9}GYr^)k*a%7gCB zixSL>Xu)_AoxbsauYN_u>d{W&uyAvZ^haG>0H;~>P0wuHT}mujkDiG!EH7Ih!!2=_ z2{JXGM;dUZNo zkame~sufT286=(sJ~pZ-fngI5f)W4P=YCvh)V zHki{;8w%uICggOMr7>~saQDJLRP}5KqHy=3*ftW6i(`r9Q)a&%pSO`-zuh>d{Zgp! z*h}t_m)u?cT%DOS^G<=u@3%)y1Yg_jcbSr$bxY$S7x9TJXRkH5$HBltOdq#B=#-G& zaxlnZ7Ya2jf_zof+k?I%;rF#9chLv5^NR7Y8Z6IB^0XwTAGII#GsmPS7h$S6S0PG= z;21C(rb*knt4HbAHx(^MNsX*8MOlB|kVmW2k-FzD z-YJlS3LvM;XhWN;=aIo^Dn^#9?XF-akxM0Q+_FWpYf-EXrFwR#|EEg2&O?+*Evw(| zsM;o51cfIFe~cDZn^?-#AbdZGSU(@*?6bHB>8K%>qW zrM@Z3PQvqcE7w2lj^;}-RQ8%p6L5gA_Pj!Da*%5=OF0G{5rCucnGXt;D&{6a;x%ND zL;Z`!W&RE`=N)whtzj!#N+{greg~Bli60YX5P76y0RNpn6+VE|TK%FYRZ}X(H4m{Y zQ?uGJana#-_0i-|R5MPu@s=FGiWh!Ga{j`6NC{4l0TQW)E&)GLjaJ=A#@1lkGA$MC z)J0H#ry>G&N}~du-TehnmzadPNEUe5`UVBJ-o-v8XKuZuFi{{jUy81j$+2jsw#0H< zX_NMI@qd4}wCKFhV`08$60GsEbg1LQG@1Lx#U}AmsQ;|naGHX?q_4p%!zEXZB>WmNB1Ya*wDG}o0jG3 zG@m=z7QVYPd10OW&M$P#dgeu_uFrb40UDj(#R3k~oZf4hf3EJCW`k=RB7f7j!8*yJ zB|B=yKR)|Hn|FGYUs!Bi?Cz#5nx1R!f3ENK$^7%{S&@LofpdQX9JU!c8Xp($_!xTX zL@y%~eW?b2jWV2Lc$VqZXaXBdHbRW>Q;Xmmk}fML41aK z|5dh(YUH`%A*80?K+)~*eE#DPYnTA^?1S}5kBvJ<88{~Hm@`!>O$@cc8TT259KC`d zs&0J7Jw|gVifS`v<2KSggydDI`E^99(?!s37h&MGOu#x6ITwCoEM=}U=C0CZuY?sv zrbjLT#C(LIQ|GSlVq!SFto3}<;X|~V=Zf)F5ucvV%YGF1QLv9sOlX2uEPM1c`+mBN ztF`Fp!l9taSyYr}Zl$4F59L4>`+-Wr>;7q3@8`Ngjx~PZ>BNj(?)qM8p&C*c2Nslf zrJ)9ECAp^|Jo9eIxX?xIS9MR)DNk|cb5JrmlP|nwXE&q%nbE0NZC_84L1+&HYGkDn zMat5VIiRL#4+HPNn-_UZ%S^2cc`K)DTB z910Ub`v8CWKffAApy&Tz*v(z0v65L6y%!!+lAUHz+598@S2~rx(uQC9FHq z)Es5?Th*J+P3TX>;&>dPamNGA4F;cg~*Xa(sonT!ma}M#h0+aB=GK z^iJ>pLH#-MxZ8LSBu>gK7EQ*=ESBC7Ut^38bnP@O!oWdqjTSo;B z<^bF8X5KbKTV|q()2IqBMX?2rv)(#1QItng)PWU~Hca4v&|DDJGNBy+OO3)3l{W6& zs$qtpwXb|(PR_tJ2cW+ib8zb%uAkI_V_ba4-!UJcFMDVgC~R62s{%()TixS#H)%+P zMLn1eVR$nxl{pZMB4O;{sT(9bb%SX`o5KP9T2@mFs_;u<01zOn0l8V3kmfeOkk;Yp zouR3lbUL{_HB<<$2PZa%r*8TqX~VG|0336-0A74HJwS(#r!Ok4$uBM;pnWF)+Rk1cdIFKB;s(JwOVN6jxMhNyDY4Wu|+x%KbqnZH-90Ik_fF zK`|E;m!im&mNzTEyf%oMC!~`Hu?o;>?HJJ>#7}qz8aoNa@UytG8Wn|Nrpv8JkrSuP zpvZZJ#p2wxx`v$mf}FgfOGzoH9OR#3FbhZy5hgjrnVgzhUfq~mPhv}V-z z|3LnnP~1Dg6H{gfq74l=s8_W$R4`#^N2MGBI5?Au*0D8O@VJJ`0W?=s)oR)Xw6Q#W|Vs1tCgsA0<-5C8-TwTsh83jR_sVh92V+D`QS z$6LIws7f2;Pr+0!VY3If&Y}BB9XPJf??cQ7MrZeir?#QV2sjGMD)Neop%E#00uB-j zKI*2Hh9NY=gJ{EJ7&&P2ho%pBqK3LThicvkYcfF_e#Wx)K5Gos}%mom{qO@MMOOCheQ;r zE(9n&LrX{(SrUJd0h#)>u{D4c7n4QS^Lj)*ivwUAP$*F@c^IrJJ;O^#B2@oY5s-h- zCm1x)9BaGB?tj*MOih_ZomzNM)Zi|XxPgAQ)&{j95*05r;2?lF5O5&=vpY-l1X_oI zgRz6I;jig4ZFf-V|IyjoqqAiBXcOTrLAgd} zZfRO4N<0W}DOx6&!HJuY(C2<5D@Z6{D1Jq8N^K1p7~h0&FiW6NH{efUQ~_0lz@jls zOGtfaYI|r3ioZ3a`$Ou#6@jhznNdXi{bOr=qpN&Sd!@jRAlkIJJdokdO-f0HB&Vci z<>p%oeghKDIgM4J-lhR?dl6=nS(ao(5xC7aK!%4!q~yg5sMrMILt5hO$@($NE9-eD1X!xE3grUm z*nye=rtu9G(I}qb>D>@;#M)7?<7Zf@wJ%%YAlvk+|%7SJ^$Dn_WlL64Ad zJRBRxnP?sN)*jidCFCUDp&VD!t-rUT;}ViOL3u%xoaS6a^7jH>1h zY0s$Rzb?Q*vo{zxh&EKVh;`8~EQ_})rP>28^QLgEok(nK1u8hp*QmGX0p?+L$? zakuftE?;~w61zS-kkKNRd2K`+zx>aCiOd`Li)#|X1?CC$rwSYd6Z{kj#YQpHPh2Nj zCzjUXxfCR}s?KG1FBLm%?H}6lupHp|YaM0|4LH=FQE4M8ug6Xv1QW~|gc>~N!U9h% zq}SL>^r-zLzSpA)x@LTF_K&T14=!EqnQFc=9BAw^X@iCQRpwwEnUXta&>)LPnZrS} zL91#t=Fn(E1rFp&e5%G!gu}`3^q!R6p{ZT^wpL`DMVc!VnIzd6nxtSm@^MXMBq9ul z7cww$GbH0%A(1~r5$aJXIhhPgIFgC2f$NY>$Td0GA%`$ldxnOi_h5_Arq`U3fwPG-tbG2S50{wvKA&aItM1OY3k|yTAv{9%bi*CTbWw!mV>$ zD%E4C1XDm8JJ5W+BdeX)7TUTd8rlYG>pNV4W6Ii(%e>3LK^uh;aL_e9LbE+$1dc0x zGg7fdEy7`h^df0H6#tr#O-r^I2&5t>*$7>T`5D9tTl57_-|LE&4JmILaG_xZil<*N zfy4qSaterumdGQ_F(RIwP$Us~2<1e^vo2E5jK7cQn|Waj#cXclC3@N&MdTwVKWx^PrYtwPg}u2t1Fre}H) z6^BVp^ZJUbtLvMbB1uY4$;ir1PEEzD`QCf)b#-+`CXrh14^lpn1eKju!?Hs@^NNaP z5~&_LmzA4eTv5gKj4IV;m{tbrvvUj2oxgy3$S*2E@wKS9dd&h}N=o)-=ZZ>eY(7xC zcyn?KODj-mJ_Sk$PrU9^Ug9-z$zb?)vEv5{uE^rKeL5<8}cKTjtP) zJT#=xK9Nc-tw!2U!gMutSNR(HjQ1kz z9a+osMQjL`lkdwbEV7NnbfKskTY5%Tx`&q29Cq>2wjeu@LlVep-{@NJ$f^st0F~V1 zA?6^%hNO*FYmG@0ph^vCTYRcsrvheX=g56Q4%{yO#x6A^A_0Z4j|AC>$;h_v35Son zayqoQf2g^4cIpY4gdKln9L?aw9NKUR1B8YSCR^AN2|LyD@q)LGDQ4>&LZ98fefvj0 z`jIU_Xsb?CAv=dE$I?28Rs{|fJ6_Dz`73MZP!hEXY)89P9AVT@Z5zj>PuX7wjzMXw zH-V#PWVPekLV0bVxU#ySBy?<>(|C$IaL^^;)u-0}d8PuIj2EYP*fT9 z+&IvTue8kRJ$VlFS=4?rYL};-%55@-1|@3GsLshyCuEpoD7G^^R3cG<aPRGfEZlg)`6p`wQK0cmA+ZAsd+_JzO{}iV{8gSsjXVE%NV=FII>%@*4+Rk9M^EQrApQ`?`00+KGTk)BDxp&5W0*6K$c;xTXC?cz)=yXQ}=EkW zkxD}hwkNcyF4@|@93(^&KM#5aeM(vyo$aokg%*)Ss+idzEGUCZxdo-M7f^Lsxp_s_ z9FA+_TYY02wM{LQ?FxSoMbLl)HA!|C-sYSSdvhtE*X|5@j*1I-{(NXxT#hQnbK^3z zbF}w_Q;EAOde;5sfv|&tL+ddaI2cFF?ou;pXtO~zA0iAh3;{=?bz;$NvFI~*fM93) z>8uJZ#2`$07OjJrK^RVBD=%Q{XsDsJj#oLG&7C$*0yyv`3W?CZ&26=fEgfQg%B1@Q z4s|evT~s3npZZ2?V#&Ge`X!EnQ;t(fPEAvRL(l&q{AH1QM%KCpm#uH{P%jn+j!dsM zJwnyT#g)|_2YpPtUw~j*J0~>YNJ>eiLse{n<7(er=fEQEmC0t3%0PW<*Mz2z0fnAO z;3%%B(o{PVqInN0a9rt~6+3b^Hi!1ZkTWfiXhm&{T2kcGrGSW}RFE;#~6QgU{l*vHluI9fWcs|T;Bz=4d>%V`H3=TS52sd!O`RLGHq zgWnVOce1i(-2X+AxLf0o%S3#juG6-cRB=S@F4bwLUS;8{YUD8Sf&!RJR8-oCdrh99 z);Xv$bJu4s^6Xm2b}|PIuOwQ>ofp}0>l{*V#^&$ozrN)nePf$a_1?JBH`m%ZUf()U zQx{qgtDc{t(#Ao7gPmsKAf&Ke7R%T{fssk~QXEM7q-yLQUg;cILaE!kr&>D3DIo@q zoV=2hG;c~;CL}3YENut_$GLOCrd}6)+}<+{+GxHycHyG1F)(nXWn^c_^(?l)k)D~8 zo|)?_uJJc?A!Aqj=P&op009w?rjHxihdhzMQP@QMi>Ds8CaDdeJBIJA|qQD=;5z|jk>=30sa31SnB zHN4z0uz0y|wyk>-1=oN>b(vXW#c7tv(i%0D|cpZ@My~0Y_?jR=QlM8Ffen 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 Sg`HFwfWXt$&t;ucLK6U+)k9DK literal 0 HcmV?d00001 diff --git a/public/images/events/september-update-zh_CN.png b/public/images/events/september-update-zh_CN.png new file mode 100644 index 0000000000000000000000000000000000000000..ee56d644d244c8ca71b1c6e196b638e552caecef GIT binary patch literal 38689 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 literal 0 HcmV?d00001 diff --git a/src/data/biomes.ts b/src/data/biomes.ts index d9ea22f50f2..721231f9cb0 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -7666,7 +7666,7 @@ export function initBiomes() { if (biome === Biome.END) { const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key))); biomeList.pop(); // Removes Biome.END from the list - const randIndex = Utils.randInt(biomeList.length, 2); // Will never be Biome.TOWN or Biome.PLAINS + const randIndex = Utils.randInt(biomeList.length, 1); // Will never be Biome.TOWN biome = Biome[biomeList[randIndex]]; } const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome]) diff --git a/src/loading-scene.ts b/src/loading-scene.ts index b086b0cb002..e4a73414cd1 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -41,8 +41,6 @@ export class LoadingScene extends SceneBase { this.loadImage("loading_bg", "arenas"); this.loadImage("logo", ""); - // this.loadImage("pride-update", "events"); - this.loadImage("august-variant-update", "events"); // Load menu images this.loadAtlas("bg", "ui"); @@ -246,7 +244,12 @@ export class LoadingScene extends SceneBase { } else { this.loadAtlas("types", ""); } - + const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt_BR", "zh_CN"]; + if (lang && availableLangs.includes(lang)) { + this.loadImage("september-update-"+lang, "events"); + } else { + this.loadImage("september-update-en", "events"); + } this.loadAtlas("statuses", ""); this.loadAtlas("categories", ""); diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index 18de67bfa86..7d9d71a8d68 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -1,35 +1,39 @@ -import BattleScene from "#app/battle-scene.js"; -import { TextStyle, addTextObject } from "#app/ui/text.js"; +import BattleScene from "#app/battle-scene"; +import { TextStyle, addTextObject } from "#app/ui/text"; +import i18next from "i18next"; export enum EventType { - SHINY + SHINY, + GENERIC } -interface TimedEvent { - name: string; - eventType: EventType; - shinyMultiplier?: number; - startDate: Date; - endDate: Date; - bannerFilename?: string +interface EventBanner { + bannerKey?: string; + xPosition?: number; + yPosition?: number; + scale?: number; + availableLangs?: string[]; +} + +interface TimedEvent extends EventBanner { + name: string; + eventType: EventType; + shinyMultiplier?: number; + startDate: Date; + endDate: Date; } const timedEvents: TimedEvent[] = [ { - name: "Pride Update", - eventType: EventType.SHINY, - shinyMultiplier: 2, - startDate: new Date(Date.UTC(2024, 5, 14, 0)), - endDate: new Date(Date.UTC(2024, 5, 23, 0)), - bannerFilename: "pride-update" - }, - { - name: "August Variant Update", - eventType: EventType.SHINY, - shinyMultiplier: 2, - startDate: new Date(Date.UTC(2024, 7, 16, 0)), - endDate: new Date(Date.UTC(2024, 7, 22, 0)), - bannerFilename: "august-variant-update" + name: "September Update", + eventType: EventType.GENERIC, + startDate: new Date(Date.UTC(2024, 7, 28, 0)), + endDate: new Date(Date.UTC(2024, 8, 15, 0)), + bannerKey: "september-update", + xPosition: 19, + yPosition: 115, + scale: 0.30, + availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es", "pt_BR", "zh_CN"] } ]; @@ -67,7 +71,7 @@ export class TimedEventManager { } getEventBannerFilename(): string { - return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerFilename!; // TODO: is this bang correct? + return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerKey!; // TODO: is this bang correct? } } @@ -85,38 +89,36 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { } setup() { - console.log(this.event?.bannerFilename); - this.banner = new Phaser.GameObjects.Image(this.scene, 29, 64, this.event!.bannerFilename!); // TODO: are the bangs correct here? - this.banner.setName("img-event-banner"); - this.banner.setOrigin(0.08, -0.35); - this.banner.setScale(0.18); - // this.bannerShadow = new Phaser.GameObjects.Rectangle( - // this.scene, - // this.banner.x - 2, - // this.banner.y + 2, - // this.banner.width, - // this.banner.height, - // 0x484848 - // ); - // this.bannerShadow.setName("rect-event-banner-shadow"); - // this.bannerShadow.setScale(0.07); - // this.bannerShadow.setAlpha(0.5); - // this.bannerShadow.setOrigin(0,0); - this.eventTimerText = addTextObject( - this.scene, - this.banner.x + 8, - this.banner.y + 100, - this.timeToGo(this.event!.endDate), // TODO: is the bang correct here? - TextStyle.WINDOW - ); - this.eventTimerText.setName("text-event-timer"); - this.eventTimerText.setScale(0.15); - this.eventTimerText.setOrigin(0, 0); + const lang = i18next.resolvedLanguage; + if (this.event && this.event.bannerKey) { + if (lang && this.event.availableLangs && this.event.availableLangs.length > 0) { + if (this.event.availableLangs.includes(lang)) { + this.event.bannerKey += "-"+lang; + } else { + this.event.bannerKey += "-en"; + } + } + console.log(this.event.bannerKey); + this.banner = new Phaser.GameObjects.Image(this.scene, this.event.xPosition ?? 29, this.event.yPosition ?? 64, this.event.bannerKey); + this.banner.setName("img-event-banner"); + this.banner.setOrigin(0.08, -0.35); + this.banner.setScale(this.event.scale ?? 0.18); + if (this.event.eventType !== EventType.GENERIC) { + this.eventTimerText = addTextObject( + this.scene, + this.banner.x + 8, + this.banner.y + 100, + this.timeToGo(this.event.endDate), + TextStyle.WINDOW + ); + this.eventTimerText.setName("text-event-timer"); + this.eventTimerText.setScale(0.15); + this.eventTimerText.setOrigin(0, 0); - this.add([ - this.eventTimerText, - // this.bannerShadow, - this.banner]); + this.add(this.eventTimerText); + } + this.add(this.banner); + } } show() { @@ -157,6 +159,8 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { } updateCountdown() { - this.eventTimerText.setText(this.timeToGo(this.event!.endDate)); // TODO: is the bang correct here? + if (this.event && this.event.eventType !== EventType.GENERIC) { + this.eventTimerText.setText(this.timeToGo(this.event.endDate)); + } } } From 95a02a96a710d89b0cbc228f650c263c1a92d7ff Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:11:23 -0700 Subject: [PATCH 05/40] Fixing banner error upon refresh (#3956) --- src/timed-event-manager.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index 7d9d71a8d68..13b4a85a2b8 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -91,15 +91,16 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { setup() { const lang = i18next.resolvedLanguage; if (this.event && this.event.bannerKey) { + const key = this.event.bannerKey; if (lang && this.event.availableLangs && this.event.availableLangs.length > 0) { if (this.event.availableLangs.includes(lang)) { - this.event.bannerKey += "-"+lang; + key += "-"+lang; } else { - this.event.bannerKey += "-en"; + key += "-en"; } } console.log(this.event.bannerKey); - this.banner = new Phaser.GameObjects.Image(this.scene, this.event.xPosition ?? 29, this.event.yPosition ?? 64, this.event.bannerKey); + this.banner = new Phaser.GameObjects.Image(this.scene, this.event.xPosition ?? 29, this.event.yPosition ?? 64, key); this.banner.setName("img-event-banner"); this.banner.setOrigin(0.08, -0.35); this.banner.setScale(this.event.scale ?? 0.18); From e80b4fe1223a57586c2c1ca3bd4e9ab767a89869 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Sun, 1 Sep 2024 21:16:20 +0100 Subject: [PATCH 06/40] feat: Update banner key assignment in TimedEventDisplay setup method --- src/timed-event-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index 13b4a85a2b8..abdb2db232a 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -91,7 +91,7 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { setup() { const lang = i18next.resolvedLanguage; if (this.event && this.event.bannerKey) { - const key = this.event.bannerKey; + let key = this.event.bannerKey; if (lang && this.event.availableLangs && this.event.availableLangs.length > 0) { if (this.event.availableLangs.includes(lang)) { key += "-"+lang; From 69a9e6a365745ea536c6c3c64a142d4c469254ae Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Sun, 1 Sep 2024 15:21:48 -0700 Subject: [PATCH 07/40] Localization: remove all `"_female": null` entries in /en (#3918) --- src/locales/en/achv.json | 36 +-- src/locales/en/dialogue-double-battle.json | 4 +- src/locales/en/dialogue-final-boss.json | 2 +- src/locales/en/dialogue.json | 252 ++++++++++----------- 4 files changed, 147 insertions(+), 147 deletions(-) diff --git a/src/locales/en/achv.json b/src/locales/en/achv.json index 0ed746c77b3..fae786e034a 100644 --- a/src/locales/en/achv.json +++ b/src/locales/en/achv.json @@ -10,19 +10,19 @@ }, "10K_MONEY": { "name": "Money Haver", - "name_female": null + "name_female": "Money Haver" }, "100K_MONEY": { "name": "Rich", - "name_female": null + "name_female": "Rich" }, "1M_MONEY": { "name": "Millionaire", - "name_female": null + "name_female": "Millionaire" }, "10M_MONEY": { "name": "One Percenter", - "name_female": null + "name_female": "One Percenter" }, "DamageAchv": { "description": "Inflict {{damageAmount}} damage in one hit" @@ -32,11 +32,11 @@ }, "1000_DMG": { "name": "Harder Hitter", - "name_female": null + "name_female": "Harder Hitter" }, "2500_DMG": { "name": "That's a Lotta Damage!", - "name_female": null + "name_female": "That's a Lotta Damage!" }, "10000_DMG": { "name": "One Punch Man", @@ -47,19 +47,19 @@ }, "250_HEAL": { "name": "Novice Healer", - "name_female": null + "name_female": "Novice Healer" }, "1000_HEAL": { "name": "Big Healer", - "name_female": null + "name_female": "Big Healer" }, "2500_HEAL": { "name": "Cleric", - "name_female": null + "name_female": "Cleric" }, "10000_HEAL": { "name": "Recovery Master", - "name_female": null + "name_female": "Recovery Master" }, "LevelAchv": { "description": "Level up a Pokémon to Lv{{level}}" @@ -69,7 +69,7 @@ }, "LV_250": { "name": "Elite", - "name_female": null + "name_female": "Elite" }, "LV_1000": { "name": "To Go Even Further Beyond" @@ -79,23 +79,23 @@ }, "10_RIBBONS": { "name": "Pokémon League Champion", - "name_female": null + "name_female": "Pokémon League Champion" }, "25_RIBBONS": { "name": "Great League Champion", - "name_female": null + "name_female": "Great League Champion" }, "50_RIBBONS": { "name": "Ultra League Champion", - "name_female": null + "name_female": "Ultra League Champion" }, "75_RIBBONS": { "name": "Rogue League Champion", - "name_female": null + "name_female": "Rogue League Champion" }, "100_RIBBONS": { "name": "Master League Champion", - "name_female": null + "name_female": "Master League Champion" }, "TRANSFER_MAX_BATTLE_STAT": { "name": "Teamwork", @@ -147,7 +147,7 @@ }, "SHINY_PARTY": { "name": "That's Dedication", - "name_female": null, + "name_female": "That's Dedication", "description": "Have a full party of shiny Pokémon" }, "HATCH_MYTHICAL": { @@ -176,7 +176,7 @@ }, "CLASSIC_VICTORY": { "name": "Undefeated", - "name_female": null, + "name_female": "Undefeated", "description": "Beat the game in classic mode" }, "UNEVOLVED_CLASSIC_VICTORY": { diff --git a/src/locales/en/dialogue-double-battle.json b/src/locales/en/dialogue-double-battle.json index 9484aa2edcc..4190af49d15 100644 --- a/src/locales/en/dialogue-double-battle.json +++ b/src/locales/en/dialogue-double-battle.json @@ -58,7 +58,7 @@ "iris_alder_double": { "encounter": { "1": "Iris: Welcome Challenger! I am THE Unova Champion!\n$Alder: Iris, aren't you a bit too excited?", - "1_female": null + "1_female": "Iris: Welcome Challenger! I am THE Unova Champion!\n$Alder: Iris, aren't you a bit too excited?" }, "victory": { "1": "Iris: A loss like this is not easy to take...\n$Alder: But we will only get stronger with every loss!" @@ -75,7 +75,7 @@ "marnie_piers_double": { "encounter": { "1": "Piers: Ready for a concert?\n$Marnie: Brother... They are here to fight, not to sing...", - "1_female": null + "1_female": "Piers: Ready for a concert?\n$Marnie: Brother... They are here to fight, not to sing..." }, "victory": { "1": "Piers: Now that was a great concert!\n$Marnie: Brother..." diff --git a/src/locales/en/dialogue-final-boss.json b/src/locales/en/dialogue-final-boss.json index 3abe4cd8831..6f99aae3e0c 100644 --- a/src/locales/en/dialogue-final-boss.json +++ b/src/locales/en/dialogue-final-boss.json @@ -1,6 +1,6 @@ { "encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.", - "encounter_female": null, + "encounter_female": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.", "firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.", "secondStageWin": "…Magnificent.", "key_ordinal_one": "st", diff --git a/src/locales/en/dialogue.json b/src/locales/en/dialogue.json index e96a42daf1d..1f8919f11b5 100644 --- a/src/locales/en/dialogue.json +++ b/src/locales/en/dialogue.json @@ -3,31 +3,31 @@ "encounter": { "1": "Hey, wanna battle?", "2": "Are you a new trainer too?", - "2_female": null, + "2_female": "Are you a new trainer too?", "3": "Hey, I haven't seen you before. Let's battle!", "4": "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", - "4_female": null, + "4_female": "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", "5": "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!", "6": "All right! Let's go!", "7": "All right! Here I come! I'll show you my power!", "8": "Haw haw haw... I'll show you how hawesome my Pokémon are!", "9": "No need to waste time saying hello. Bring it on whenever you're ready!", - "9_female": null, + "9_female": "No need to waste time saying hello. Bring it on whenever you're ready!", "10": "Don't let your guard down, or you may be crying when a kid beats you.", "11": "I've raised my Pokémon with great care. You're not allowed to hurt them!", "12": "Glad you made it! It won't be an easy job from here.", - "12_female": null, + "12_female": "Glad you made it! It won't be an easy job from here.", "13": "The battles continue forever! Welcome to the world with no end!", - "13_female": null + "13_female": "The battles continue forever! Welcome to the world with no end!" }, "victory": { "1": "Wow! You're strong!", - "1_female": null, + "1_female": "Wow! You're strong!", "2": "I didn't stand a chance, huh?", "3": "I'll find you again when I'm older and beat you!", "4": "Ugh. I don't have any more Pokémon.", "5": "No way… NO WAY! How could I lose again…", - "5_female": null, + "5_female": "No way… NO WAY! How could I lose again…", "6": "No! I lost!", "7": "Whoa! You are incredible! I'm amazed and surprised!", "8": "Could it be… How… My Pokémon and I are the strongest, though…", @@ -42,12 +42,12 @@ "encounter": { "1": "Let's have a battle, shall we?", "2": "You look like a new trainer. Let's have a battle!", - "2_female": null, + "2_female": "You look like a new trainer. Let's have a battle!", "3": "I don't recognize you. How about a battle?", "4": "Let's have a fun Pokémon battle!", "5": "I'll show you the ropes of how to really use Pokémon!", "6": "A serious battle starts from a serious beginning! Are you sure you're ready?", - "6_female": null, + "6_female": "A serious battle starts from a serious beginning! Are you sure you're ready?", "7": "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.", "8": "You'd better go easy on me, OK? Though I'll be seriously fighting!", "9": "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time." @@ -55,15 +55,15 @@ "victory": { "1": "That was impressive! I've got a lot to learn.", "2": "I didn't think you'd beat me that bad…", - "2_female": null, + "2_female": "I didn't think you'd beat me that bad…", "3": "I hope we get to have a rematch some day.", "4": "That was pretty amazingly fun! You've totally exhausted me…", "5": "You actually taught me a lesson! You're pretty amazing!", "6": "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", - "6_female": null, + "6_female": "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", "7": "I don't need memories like this. Deleting memory…", "8": "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", - "8_female": null, + "8_female": "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", "9": "I'm actually getting tired of battling… There's gotta be something new to do…" } }, @@ -154,7 +154,7 @@ "ace_trainer": { "encounter": { "1": "You seem quite confident.", - "1_female": null, + "1_female": "You seem quite confident.", "2": "Your Pokémon… Show them to me…", "3": "Because I'm an Ace Trainer, people think I'm strong.", "4": "Are you aware of what it takes to be an Ace Trainer?" @@ -163,9 +163,9 @@ "1": "Yes… You have good Pokémon…", "2": "What?! But I'm a battling genius!", "3": "Of course, you are the main character!", - "3_female": null, + "3_female": "Of course, you are the main character!", "4": "OK! OK! You could be an Ace Trainer!", - "4_female": null + "4_female": "OK! OK! You could be an Ace Trainer!" }, "defeat": { "1": "I am devoting my body and soul to Pokémon battles!", @@ -187,7 +187,7 @@ "1": "Get ready, because when we team up, it's double the trouble!", "2": "Two hearts, one strategy – let's see if you can keep up with our twin power!", "3": "Hope you're ready for double trouble, because we're about to bring the heat!", - "3_female": null + "3_female": "Hope you're ready for double trouble, because we're about to bring the heat!" }, "victory": { "1": "We may have lost this round, but our bond remains unbreakable!", @@ -216,7 +216,7 @@ "encounter": { "1": "I praise your courage in challenging me! For I am the one with the strongest kick!", "2": "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?", - "2_female": null + "2_female": "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?" }, "victory": { "1": "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.", @@ -328,7 +328,7 @@ "defeat": { "1": "New age simply refers to twentieth century classical composers, right?", "2": "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself.", - "2_female": null + "2_female": "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself." } }, "psychic": { @@ -360,7 +360,7 @@ "baker": { "encounter": { "1": "Hope you're ready to taste defeat!", - "1_female": null + "1_female": "Hope you're ready to taste defeat!" }, "victory": { "1": "I'll bake a comeback." @@ -391,7 +391,7 @@ "1": "Matey, you're walking the plank if you lose!", "2": "Come on then! My sailor's pride is at stake!", "3": "Ahoy there! Are you seasick?", - "3_female": null + "3_female": "Ahoy there! Are you seasick?" }, "victory": { "1": "Argh! Beaten by a kid!", @@ -419,7 +419,7 @@ }, "victory": { "1": "Tch, you really are strong. It's too bad.\n$If you were to join Team Rocket, you could become an Executive.", - "1_female": null, + "1_female": "Tch, you really are strong. It's too bad.\n$If you were to join Team Rocket, you could become an Executive.", "2": "I... I'm shattered...", "3": "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" } @@ -458,7 +458,7 @@ "1": "Hehehe! You might have beaten me, but you don't stand a chance against the boss!\n$If you get lost now, you won't have to face a sound whipping!", "2": "Hehehe... So, I lost, too...", "3": "Ahya! How could this be? For an Admin like me to lose to some random trainer...", - "3_female": null + "3_female": "Ahya! How could this be? For an Admin like me to lose to some random trainer..." } }, "courtney": { @@ -478,13 +478,13 @@ "1": "Ahahahaha! You're going to meddle in Team Aqua's affairs?\n$You're either absolutely fearless, simply ignorant, or both!\n$You're so cute, you're disgusting! I'll put you down", "2": "What's this? Who's this spoiled brat?", "3": "Cool your jets. Be patient. I'll crush you shortly.", - "3_female": null + "3_female": "Cool your jets. Be patient. I'll crush you shortly." }, "victory": { "1": "Ahahahaha! We got meddled with unexpectedly! We're out of options.\n$We'll have to pull out. But this isn't the last you'll see of Team Aqua!\n$We have other plans! Don't you forget it!", "2": "Ahhh?! Did I go too easy on you?!", "3": "Uh. Are you telling me you've upped your game even more during the fight?\n$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight…\n$Go on… Go and be destroyed by Archie.", - "3_female": null + "3_female": "Uh. Are you telling me you've upped your game even more during the fight?\n$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight…\n$Go on… Go and be destroyed by Archie." } }, "matt": { @@ -497,7 +497,7 @@ "1": "Muwuhahaha! That battle was fun even though I lost!", "2": "I can feel it! I can feel it, all right! The strength coming offa you!\n$More! I still want more! But looks like we're outta time...", "3": "Oho! That's a loss I can be proud of!", - "3_female": null + "3_female": "Oho! That's a loss I can be proud of!" } }, "mars": { @@ -505,7 +505,7 @@ "1": "I'm Mars, one of Team Galactic's top Commanders.", "2": "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", "3": "Feeling nervous? You should be!", - "3_female": null + "3_female": "Feeling nervous? You should be!" }, "victory": { "1": "This can't be happening! How did I lose?!", @@ -540,25 +540,25 @@ "zinzolin": { "encounter": { "1": "You could become a threat to Team Plasma, so we will eliminate you here and now!", - "1_female": null, + "1_female": "You could become a threat to Team Plasma, so we will eliminate you here and now!", "2": "You don't have the sense to know when to quit, it seems. It's an act of mercy on my part to bring an end to this now!", "3": "You're an impressive Trainer to have made it this far. But it ends here.", - "3_female": null + "3_female": "You're an impressive Trainer to have made it this far. But it ends here." }, "victory": { "1": "Ghetsis... I have failed you...", "2": "It's bitter cold. I'm shivering. I'm suffering. Yet, we will stand victorious.", "3": "Hmph. You're a smarter Trainer than I expected, but not smart enough.", - "3_female": null + "3_female": "Hmph. You're a smarter Trainer than I expected, but not smart enough." } }, "rood": { "encounter": { "1": "You are a threat to Team Plasma. We cannot let you walk away from here and now!", - "1_female": null, + "1_female": "You are a threat to Team Plasma. We cannot let you walk away from here and now!", "2": "It seems you don't know when to give up. I'll make sure no one interferes with our plans!", "3": "You are a remarkable Trainer to have made it this far. But this is where it ends.", - "3_female": null + "3_female": "You are a remarkable Trainer to have made it this far. But this is where it ends." }, "victory": { "1": "Ghetsis... I have failed my mission...", @@ -569,15 +569,15 @@ "xerosic": { "encounter": { "1": "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - "1_female": null, + "1_female": "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", "2": "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - "2_female": null, + "2_female": "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", "3": "I've been waiting for you! I need to do a little research on you! Come, let us begin!" }, "victory": { "1": "Ah, you're quite strong. Oh yes—very strong, indeed.", "2": "Ding-ding-ding! You did it! To the victor go the spoils!", - "2_female": null, + "2_female": "Ding-ding-ding! You did it! To the victor go the spoils!", "3": "Wonderful! Amazing! You have tremendous skill and bravery!" } }, @@ -585,7 +585,7 @@ "encounter": { "1": "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", "2": "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", - "2_female": null, + "2_female": "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", "3": "I've anticipated your arrival. It's time for a little test. Shall we begin?" }, "victory": { @@ -598,11 +598,11 @@ "encounter": { "1": "Prepare for trouble!", "2": "We're pulling a big job here! Get lost, kid!", - "2_female": null, + "2_female": "We're pulling a big job here! Get lost, kid!", "3": "Hand over your Pokémon, or face the wrath of Team Rocket!", "4": "You're about to experience the true terror of Team Rocket!", "5": "Hey, kid! Me am a Team Rocket member kind of guy!", - "5_female": null + "5_female": "Hey, kid! Me am a Team Rocket member kind of guy!" }, "victory": { "1": "Team Rocket blasting off again!", @@ -624,7 +624,7 @@ "1": "Huh? I lost?!", "2": "I can't believe I lost! I even skipped lunch for this", "3": "No way! You're just a kid!", - "3_female": null, + "3_female": "No way! You're just a kid!", "4": "Urrrgh... I should've ducked into our hideout right away...", "5": "You beat me... Do you think the boss will dock my pay for this?" } @@ -652,7 +652,7 @@ "3": "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", "4": "Get ready to lose!", "5": "Hope you're ready for a cosmic beatdown!", - "5_female": null + "5_female": "Hope you're ready for a cosmic beatdown!" }, "victory": { "1": "Shut down...", @@ -682,7 +682,7 @@ "encounter": { "1": "Your Pokémon are no match for the elegance of Team Flare.", "2": "Hope you brought your sunglasses, because things are about to get bright!", - "2_female": null, + "2_female": "Hope you brought your sunglasses, because things are about to get bright!", "3": "Team Flare will cleanse the world of imperfection!", "4": "Prepare to face the brilliance of Team Flare!", "5": "Fashion is most important to us!" @@ -784,7 +784,7 @@ }, "defeat": { "1": "Mark my words. Not being able to measure your own strength shows that you are still a child.", - "1_female": null + "1_female": "Mark my words. Not being able to measure your own strength shows that you are still a child." } }, "rocket_boss_giovanni_2": { @@ -845,7 +845,7 @@ "galactic_boss_cyrus_1": { "encounter": { "1": "You were compelled to come here by such vacuous sentimentality.\n$I will make you regret paying heed to your heart!", - "1_female": null + "1_female": "You were compelled to come here by such vacuous sentimentality.\n$I will make you regret paying heed to your heart!" }, "victory": { "1": "Interesting. And quite curious." @@ -995,7 +995,7 @@ "misty": { "encounter": { "1": "My policy is an all out offensive with Water-type Pokémon!", - "1_female": null, + "1_female": "My policy is an all out offensive with Water-type Pokémon!", "2": "Hiya, I'll show you the strength of my aquatic Pokémon!", "3": "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?" }, @@ -1013,14 +1013,14 @@ "lt_surge": { "encounter": { "1": "My Electric Pokémon saved me during the war! I'll show you how!", - "1_female": null, + "1_female": "My Electric Pokémon saved me during the war! I'll show you how!", "2": "Ten-hut! I'll shock you into surrender!", "3": "I'll zap you just like I do to all my enemies in battle!" }, "victory": { "1": "Whoa! Your team's the real deal, kid!", "2": "Aaargh, you're strong! Even my electric tricks lost against you.", - "2_female": null, + "2_female": "Aaargh, you're strong! Even my electric tricks lost against you.", "3": "That was an absolutely shocking loss!" }, "defeat": { @@ -1045,7 +1045,7 @@ "defeat": { "1": "I was afraid I would doze off…", "2": "Oh my, it seems my Grass Pokémon overwhelmed you.", - "2_female": null, + "2_female": "Oh my, it seems my Grass Pokémon overwhelmed you.", "3": "That battle was such a soothing experience.", "4": "Oh… Is that all?" } @@ -1106,7 +1106,7 @@ "1": "I, the leader of Team Rocket, will make you feel a world of pain!", "2": "My training here will be vital before I am to face my old associates again.", "3": "I do not think you are prepared for the level of failure you are about to experience!", - "3_female": null + "3_female": "I do not think you are prepared for the level of failure you are about to experience!" }, "victory": { "1": "WHAT! Me, lose?! There is nothing I wish to say to you!", @@ -1139,7 +1139,7 @@ "brawly": { "encounter": { "1": "Oh man, a challenger!\nLet's see what you can do!", - "1_female": null, + "1_female": "Oh man, a challenger!\nLet's see what you can do!", "2": "You seem like a big splash.\nLet's battle!", "3": "Time to create a storm!\nLet's go!" }, @@ -1167,7 +1167,7 @@ }, "defeat": { "1": "Recharge your batteries and challenge me again sometime!\nWahahahaha!", - "1_female": null, + "1_female": "Recharge your batteries and challenge me again sometime!\nWahahahaha!", "2": "I hope you found our battle electrifying!\nWahahahaha!", "3": "Aren't you shocked I won?\nWahahahaha!" } @@ -1214,7 +1214,7 @@ }, "victory": { "1": "You're the first Trainer I've seen with more grace than I.\nExcellently played.", - "1_female": null, + "1_female": "You're the first Trainer I've seen with more grace than I.\nExcellently played.", "2": "Oh, my Flying Pokémon have plummeted!\nVery well.", "3": "Though I may have fallen, my Pokémon will continue to fly!" }, @@ -1227,7 +1227,7 @@ "tate": { "encounter": { "1": "Hehehe…\nWere you surprised to see me without my sister?", - "1_female": null, + "1_female": "Hehehe…\nWere you surprised to see me without my sister?", "2": "I can see what you're thinking…\nYou want to battle!", "3": "How can you defeat someone…\nWho knows your every move?" }, @@ -1245,7 +1245,7 @@ "liza": { "encounter": { "1": "Fufufu…\nWere you surprised to see me without my brother?", - "1_female": null, + "1_female": "Fufufu…\nWere you surprised to see me without my brother?", "2": "I can determine what you desire…\nYou want to battle, don't you?", "3": "How can you defeat someone…\nWho's one with their Pokémon?" }, @@ -1317,10 +1317,10 @@ "nessa": { "encounter": { "1": "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", - "1_female": null, + "1_female": "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", "2": "I'm not here to chat. I'm here to win!", "3": "This is a little gift from my Pokémon… I hope you can take it!", - "3_female": null + "3_female": "This is a little gift from my Pokémon… I hope you can take it!" }, "victory": { "1": "You and your Pokémon are just too much…", @@ -1341,7 +1341,7 @@ }, "victory": { "1": "You… You're pretty good, huh?", - "1_female": null, + "1_female": "You… You're pretty good, huh?", "2": "If you find Gordie around, be sure to give him a right trashing, would you?", "3": "I think you took breaking the ice a little too literally…" }, @@ -1355,12 +1355,12 @@ "encounter": { "1": "You look strong! Shoots! Let's start!", "2": "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", - "2_female": null, + "2_female": "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", "3": "Oh ho, so I'm facing you! That's off the wall." }, "victory": { "1": "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", - "1_female": null, + "1_female": "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", "2": "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!", "3": "You're strong as a gnarly wave!" }, @@ -1373,7 +1373,7 @@ "shauntal": { "encounter": { "1": "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", - "1_female": null, + "1_female": "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", "2": "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?", "3": "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?" }, @@ -1391,7 +1391,7 @@ "marshal": { "encounter": { "1": "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", - "1_female": null, + "1_female": "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", "2": "Victory, decisive victory, is my intention! Challenger, here I come!", "3": "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!" }, @@ -1411,7 +1411,7 @@ "1": "You remind me of an old friend. That makes me excited about this Pokémon battle!", "2": "Pokémon battles have no meaning if you don't think why you battle.\n$Or better said, it makes battling together with Pokémon meaningless.", "3": "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you.", - "3_female": null + "3_female": "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you." }, "victory": { "1": "Thank you! I saw what was missing in me.", @@ -1427,65 +1427,65 @@ "chili": { "encounter": { "1": "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", - "1_female": null, + "1_female": "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", "2": "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", - "2_female": null, + "2_female": "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", "3": "I'm going to show you what me and my blazing Fire types can do!", - "3_female": null + "3_female": "I'm going to show you what me and my blazing Fire types can do!" }, "victory": { "1": "You got me. I am… burned… out…", - "1_female": null, + "1_female": "You got me. I am… burned… out…", "2": "Whoa ho! You're on fire!", - "2_female": null, + "2_female": "Whoa ho! You're on fire!", "3": "Augh! You got me!" }, "defeat": { "1": "I'm on fire! Play with me, and you'll get burned!", - "1_female": null, + "1_female": "I'm on fire! Play with me, and you'll get burned!", "2": "When you play with fire, you get burned!", "3": "I mean, c'mon, your opponent was me! You didn't have a chance!", - "3_female": null + "3_female": "I mean, c'mon, your opponent was me! You didn't have a chance!" } }, "cilan": { "encounter": { "1": "Nothing personal... No hard feelings... Me and my Grass-type Pokémon will...\n$Um... We're gonna battle come what may.", - "1_female": null, + "1_female": "Nothing personal... No hard feelings... Me and my Grass-type Pokémon will...\n$Um... We're gonna battle come what may.", "2": "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", - "2_female": null, + "2_female": "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", "3": "OK… So, um, I'm Cilan, I like Grass-type Pokémon.", - "3_female": null + "3_female": "OK… So, um, I'm Cilan, I like Grass-type Pokémon." }, "victory": { "1": "Er… Is it over now?", - "1_female": null, + "1_female": "Er… Is it over now?", "2": "…What a surprise. You are very strong, aren't you? \n$I guess my brothers wouldn't have been able to defeat you either…", - "2_female": null, + "2_female": "…What a surprise. You are very strong, aren't you? \n$I guess my brothers wouldn't have been able to defeat you either…", "3": "…Huh. Looks like my timing was, um, off?" }, "defeat": { "1": "Huh? Did I win?", - "1_female": null, + "1_female": "Huh? Did I win?", "2": "I guess… \n$I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.", - "2_female": null, + "2_female": "I guess… \n$I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.", "3": "It…it was quite a thrilling experience…", - "3_female": null + "3_female": "It…it was quite a thrilling experience…" } }, "roark": { "encounter": { "1": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", - "1_female": null, + "1_female": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", "2": "Here goes! These are my rocking Pokémon, my pride and joy!", "3": "Rock-type Pokémon are simply the best!", "4": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", - "4_female": null + "4_female": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!" }, "victory": { "1": "W-what? That can't be! My buffed-up Pokémon!", "2": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", - "2_female": null, + "2_female": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", "3": "With skill like yours, it's natural for you to win.", "4": "Wh-what?! It can't be! Even that wasn't enough?", "5": "I blew it." @@ -1508,7 +1508,7 @@ "victory": { "1": "I'm not good enough yet…", "2": "I see… Your journey has taken you to far-away places and you have witnessed much more than I.\n$I envy you for that…", - "2_female": null, + "2_female": "I see… Your journey has taken you to far-away places and you have witnessed much more than I.\n$I envy you for that…", "3": "How is this possible…", "4": "I don't think our potentials are so different.\n$But you seem to have something more than that… So be it.", "5": "Guess I need more training.", @@ -1568,13 +1568,13 @@ }, "defeat": { "1": "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?", - "1_female": null + "1_female": "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?" } }, "ramos": { "encounter": { "1": "Did yeh enjoy the garden playground I made with all these sturdy plants o' mine?\n$Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?", - "1_female": null + "1_female": "Did yeh enjoy the garden playground I made with all these sturdy plants o' mine?\n$Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?" }, "victory": { "1": "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout." @@ -1605,7 +1605,7 @@ "victory": { "1": "I must say, I'm warmed up to you! I might even admire you a little.", "2": "Wow! You're great! You've earned my respect! \n$I think your focus and will bowled us over totally. ", - "2_female": null + "2_female": "Wow! You're great! You've earned my respect! \n$I think your focus and will bowled us over totally. " }, "defeat": { "1": "I sensed your will to win, but I don't lose!", @@ -1618,7 +1618,7 @@ }, "victory": { "1": "Amazing! You're very good, aren't you?", - "1_female": null + "1_female": "Amazing! You're very good, aren't you?" }, "defeat": { "1": "Yes! My Pokémon and I are perfectly good!" @@ -1660,7 +1660,7 @@ "clay": { "encounter": { "1": "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!", - "1_female": null + "1_female": "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!" }, "victory": { "1": "Man oh man… It feels good to go all out and still be defeated!" @@ -1675,7 +1675,7 @@ }, "victory": { "1": "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!", - "1_female": null + "1_female": "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!" }, "defeat": { "1": "You come back to see me again now, ya hear?" @@ -1742,7 +1742,7 @@ }, "victory": { "1": "Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. \n$I find much joy in having met you and your Pokémon. You have proven yourself worthy.", - "1_female": null + "1_female": "Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. \n$I find much joy in having met you and your Pokémon. You have proven yourself worthy." }, "defeat": { "1": "A grand illusion!" @@ -1751,14 +1751,14 @@ "lorelei": { "encounter": { "1": "No one can best me when it comes to icy Pokémon! Freezing moves are powerful!\n$Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?", - "1_female": null + "1_female": "No one can best me when it comes to icy Pokémon! Freezing moves are powerful!\n$Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?" }, "victory": { "1": "How dare you!" }, "defeat": { "1": "There's nothing you can do once you're frozen.", - "1_female": null + "1_female": "There's nothing you can do once you're frozen." } }, "will": { @@ -1775,11 +1775,11 @@ "malva": { "encounter": { "1": "I feel like my heart might just burst into flames. \n$I'm burning up with my hatred for you, runt!", - "1_female": null + "1_female": "I feel like my heart might just burst into flames. \n$I'm burning up with my hatred for you, runt!" }, "victory": { "1": "What news… So a new challenger has defeated Malva!", - "1_female": null + "1_female": "What news… So a new challenger has defeated Malva!" }, "defeat": { "1": "I am delighted! Yes, delighted that I could squash you beneath my heel." @@ -1802,7 +1802,7 @@ }, "victory": { "1": "I certainly found an interesting Trainer to face!", - "1_female": null + "1_female": "I certainly found an interesting Trainer to face!" }, "defeat": { "1": "Ahaha. What an interesting battle." @@ -1814,11 +1814,11 @@ }, "victory": { "1": "Not bad, kiddo.", - "1_female": null + "1_female": "Not bad, kiddo." }, "defeat": { "1": "Nahahaha! You really are something else, kiddo!", - "1_female": null + "1_female": "Nahahaha! You really are something else, kiddo!" } }, "bruno": { @@ -1838,7 +1838,7 @@ }, "victory": { "1": "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win.", - "1_female": null + "1_female": "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win." }, "defeat": { "1": "Thanks! Thanks to our battle, I was also able to make progress in my research!" @@ -1869,11 +1869,11 @@ "lenora": { "encounter": { "1": "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!", - "1_female": null + "1_female": "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!" }, "victory": { "1": "My theory about you was correct. You're more than just talented… You're motivated! I salute you!", - "1_female": null + "1_female": "My theory about you was correct. You're more than just talented… You're motivated! I salute you!" }, "defeat": { "1": "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!" @@ -1899,7 +1899,7 @@ }, "defeat": { "1": "Hey, c'mon! Get serious! You gotta put more out there!", - "1_female": null + "1_female": "Hey, c'mon! Get serious! You gotta put more out there!" } }, "olivia": { @@ -1938,7 +1938,7 @@ "flint": { "encounter": { "1": "Hope you're warmed up, cause here comes the Big Bang!", - "1_female": null + "1_female": "Hope you're warmed up, cause here comes the Big Bang!" }, "victory": { "1": "Incredible! Your moves are so hot, they make mine look lukewarm!" @@ -1961,7 +1961,7 @@ "caitlin": { "encounter": { "1": "It's me who appeared when the flower opened up. You who have been waiting…\n$You look like a Pokémon Trainer with refined strength and deepened kindness. \n$What I look for in my opponent is superb strength… \n$Please unleash your power to the fullest!", - "1_female": null + "1_female": "It's me who appeared when the flower opened up. You who have been waiting…\n$You look like a Pokémon Trainer with refined strength and deepened kindness. \n$What I look for in my opponent is superb strength… \n$Please unleash your power to the fullest!" }, "victory": { "1": "My Pokémon and I learned so much! I offer you my thanks." @@ -1984,15 +1984,15 @@ "wikstrom": { "encounter": { "1": "Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! \n$Let the battle begin! En garde!", - "1_female": null + "1_female": "Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! \n$Let the battle begin! En garde!" }, "victory": { "1": "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!", - "1_female": null + "1_female": "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!" }, "defeat": { "1": "What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! \n$Winning against such a worthy opponent doth give my soul wings--thus do I soar!", - "1_female": null + "1_female": "What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! \n$Winning against such a worthy opponent doth give my soul wings--thus do I soar!" } }, "acerola": { @@ -2024,14 +2024,14 @@ }, "victory": { "1": "You got me. You are magnificent!", - "1_female": null, + "1_female": "You got me. You are magnificent!", "2": "I never expected another trainer to beat me… I'm surprised.", - "2_female": null + "2_female": "I never expected another trainer to beat me… I'm surprised." }, "defeat": { "1": "That was close. Want to try again?", "2": "It's not that you are weak. Don't let it bother you.", - "2_female": null + "2_female": "It's not that you are weak. Don't let it bother you." } }, "karen": { @@ -2057,7 +2057,7 @@ }, "victory": { "1": "The power of Grass has wilted… What an incredible Challenger!", - "1_female": null + "1_female": "The power of Grass has wilted… What an incredible Challenger!" }, "defeat": { "1": "This'll really leave you in shock and awe." @@ -2077,7 +2077,7 @@ "drasna": { "encounter": { "1": "You must be a strong Trainer. Yes, quite strong indeed…\n$That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!", - "1_female": null + "1_female": "You must be a strong Trainer. Yes, quite strong indeed…\n$That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!" }, "victory": { "1": "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!" @@ -2111,7 +2111,7 @@ "blue": { "encounter": { "1": "You must be pretty good to get this far.", - "1_female": null + "1_female": "You must be pretty good to get this far." }, "victory": { "1": "I've only lost to him and now to you… Him? Hee, hee…" @@ -2159,7 +2159,7 @@ }, "victory": { "1": "This is the emergence of a new Champion.", - "1_female": null + "1_female": "This is the emergence of a new Champion." }, "defeat": { "1": "I successfully defended my Championship." @@ -2248,7 +2248,7 @@ }, "victory": { "1": "Waaah! Waaah! You're so mean!", - "1_female": null + "1_female": "Waaah! Waaah! You're so mean!" }, "defeat": { "1": "And that's that!" @@ -2257,7 +2257,7 @@ "chuck": { "encounter": { "1": "Hah! You want to challenge me? Are you brave or just ignorant?", - "1_female": null + "1_female": "Hah! You want to challenge me? Are you brave or just ignorant?" }, "victory": { "1": "You're strong! Would you please make me your apprentice?" @@ -2269,7 +2269,7 @@ "katy": { "encounter": { "1": "Don't let your guard down unless you would like to find yourself knocked off your feet!", - "1_female": null + "1_female": "Don't let your guard down unless you would like to find yourself knocked off your feet!" }, "victory": { "1": "All of my sweet little Pokémon dropped like flies!" @@ -2303,7 +2303,7 @@ "maylene": { "encounter": { "1": "I've come to challenge you now, and I won't hold anything back. \n$Please prepare yourself for battle!", - "1_female": null + "1_female": "I've come to challenge you now, and I won't hold anything back. \n$Please prepare yourself for battle!" }, "victory": { "1": "I admit defeat…" @@ -2326,7 +2326,7 @@ "byron": { "encounter": { "1": "Trainer! You're young, just like my son, Roark. \n$With more young Trainers taking charge, the future of Pokémon is bright! \n$So, as a wall for young people, I'll take your challenge!", - "1_female": null + "1_female": "Trainer! You're young, just like my son, Roark. \n$With more young Trainers taking charge, the future of Pokémon is bright! \n$So, as a wall for young people, I'll take your challenge!" }, "victory": { "1": "Hmm! My sturdy Pokémon--defeated!" @@ -2349,7 +2349,7 @@ "volkner": { "encounter": { "1": "Since you've come this far, you must be quite strong…\n$I hope you're the Trainer who'll make me remember how fun it is to battle!", - "1_female": null + "1_female": "Since you've come this far, you must be quite strong…\n$I hope you're the Trainer who'll make me remember how fun it is to battle!" }, "victory": { "1": "You've got me beat…\n$Your desire and the noble way your Pokémon battled for you… \n$I even felt thrilled during our match. That was a very good battle." @@ -2452,7 +2452,7 @@ "valerie": { "encounter": { "1": "Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. \n$Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. \n$The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.", - "1_female": null + "1_female": "Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. \n$Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. \n$The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong." }, "victory": { "1": "I hope that you will find things worth smiling about tomorrow…" @@ -2500,7 +2500,7 @@ }, "victory": { "1": "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon.", - "1_female": null + "1_female": "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon." }, "defeat": { "1": "Too bad for you, I guess." @@ -2509,7 +2509,7 @@ "bede": { "encounter": { "1": "I suppose I should prove beyond doubt just how pathetic you are and how strong I am.", - "1_female": null + "1_female": "I suppose I should prove beyond doubt just how pathetic you are and how strong I am." }, "victory": { "1": "I see… Well, that's fine. I wasn't really trying all that hard anyway." @@ -2554,7 +2554,7 @@ "brassius": { "encounter": { "1": "I assume you are ready? Let our collaborative work of art begin!", - "1_female": null + "1_female": "I assume you are ready? Let our collaborative work of art begin!" }, "victory": { "1": "Ahhh…vant-garde!" @@ -2566,11 +2566,11 @@ "iono": { "encounter": { "1": "How're ya feelin' about this battle?\n$...\n$Let's get this show on the road! How strong is our challenger? \n$I 'unno! Let's find out together!", - "1_female": null + "1_female": "How're ya feelin' about this battle?\n$...\n$Let's get this show on the road! How strong is our challenger? \n$I 'unno! Let's find out together!" }, "victory": { "1": "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!", - "1_female": null + "1_female": "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!" }, "defeat": { "1": "Your eyeballs are MINE!" @@ -2593,7 +2593,7 @@ }, "victory": { "1": "You're cool, my friend—you move my SOUL!", - "1_female": null + "1_female": "You're cool, my friend—you move my SOUL!" }, "defeat": { "1": "Later, baby!" @@ -2627,9 +2627,9 @@ "nessa_elite": { "encounter": { "1": "The tides are turning in my favor. Ready to get swept away?", - "1_female": null, + "1_female": "The tides are turning in my favor. Ready to get swept away?", "2": "Let's make some waves with this battle! I hope you're prepared!", - "2_female": null + "2_female": "Let's make some waves with this battle! I hope you're prepared!" }, "victory": { "1": "You navigated those waters perfectly... Well done!", @@ -2657,7 +2657,7 @@ "allister_elite": { "encounter": { "1": "Shadows fall... Are you ready to face your fears?", - "1_female": null, + "1_female": "Shadows fall... Are you ready to face your fears?", "2": "Let's see if you can handle the darkness that I command." }, "victory": { @@ -2681,7 +2681,7 @@ "defeat": { "1": "Another storm weathered, another victory claimed! Well fought!", "2": "You got caught in my storm! Better luck next time!", - "2_female": null + "2_female": "You got caught in my storm! Better luck next time!" } }, "alder": { From 55e0d65ac8055b9b3fb6748289ae44796956b32c Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 15:23:25 -0700 Subject: [PATCH 08/40] [Refactor] Improvements on getOrder() (#3547) * Moved getOrder() into TurnStartPhase * Cleaned up bypass speed checks * Revert "Cleaned up bypass speed checks" This reverts commit 11150254f568b8575211693919c9c5deeb3d8dcd. * Added comments. * Fixed up some inconsistencies * changed isSameBracket check * changed isSameBracket check p2 * changed isSameBracket check p3 * changed isSameBracket check p3 * Fixed up conditionals + stall/M.m * Seems OK * Update battle-spec.ts * Updated tests to use new functions introduced. Less intuitive, but faster. * Update src/phases.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Moved getOrder() into TurnStartPhase * Cleaned up bypass speed checks * Revert "Cleaned up bypass speed checks" This reverts commit 11150254f568b8575211693919c9c5deeb3d8dcd. * Added comments. * Fixed up some inconsistencies * changed isSameBracket check * changed isSameBracket check p2 * changed isSameBracket check p3 * changed isSameBracket check p3 * Fixed up conditionals + stall/M.m * Seems OK * Update battle-spec.ts * Updated tests to use new functions introduced. Less intuitive, but faster. * Removed import * i hate git * Moved getOrder() into TurnStartPhase * Seems OK * missing import * Added Snooze's review * Added test fixes and removed unwanted edit. * fixed dynamax cannon test * typedocs fixes * Updating battle-order.test.ts * merge fixes * ughhh * Update src/test/abilities/mycelium_might.test.ts Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * tsdocs :) * Fixed tests * Update src/phases/turn-start-phase.ts Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * Update src/phases/turn-start-phase.ts Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * innerthunder's fixes * commas * Mocked stats instead of directly changing them --------- Co-authored-by: Frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> --- src/data/ability.ts | 4 +- src/phases/field-phase.ts | 35 +------ src/phases/turn-start-phase.ts | 110 ++++++++++++++++------ src/test/abilities/mycelium_might.test.ts | 51 +++++----- src/test/abilities/stall.test.ts | 48 +++++----- src/test/battle/battle-order.test.ts | 105 +++++++++++++-------- src/test/utils/gameManager.ts | 4 +- 7 files changed, 203 insertions(+), 154 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 8b7a7772efe..3d5b32f4ce8 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -5025,7 +5025,7 @@ export function initAbilities() { .attr(AlwaysHitAbAttr) .attr(DoubleBattleChanceAbAttr), new Ability(Abilities.STALL, 4) - .attr(ChangeMovePriorityAbAttr, (pokemon, move: Move) => true, -0.5), + .attr(ChangeMovePriorityAbAttr, (pokemon, move: Move) => true, -0.2), new Ability(Abilities.TECHNICIAN, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => { const power = new Utils.NumberHolder(move.power); @@ -5713,7 +5713,7 @@ export function initAbilities() { .partial() // Healing not blocked by Heal Block .ignorable(), new Ability(Abilities.MYCELIUM_MIGHT, 9) - .attr(ChangeMovePriorityAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS, -0.5) + .attr(ChangeMovePriorityAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS, -0.2) .attr(PreventBypassSpeedChanceAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS) .attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS), new Ability(Abilities.MINDS_EYE, 9) diff --git a/src/phases/field-phase.ts b/src/phases/field-phase.ts index a9622271f14..02d1f1395d3 100644 --- a/src/phases/field-phase.ts +++ b/src/phases/field-phase.ts @@ -1,42 +1,9 @@ -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"; +import Pokemon from "#app/field/pokemon"; 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/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index e4064fc784a..b2545e9ee30 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -1,12 +1,12 @@ -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 BattleScene from "#app/battle-scene"; +import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr, ChangeMovePriorityAbAttr } from "#app/data/ability"; +import { allMoves, applyMoveAttrs, IncrementMovePriorityAttr, MoveHeaderAttr } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { Stat } from "#app/enums/stat"; +import Pokemon, { PokemonMove } from "#app/field/pokemon"; +import { BypassSpeedChanceModifier } from "#app/modifier/modifier"; +import { Command } from "#app/ui/command-ui-handler"; +import * as Utils from "#app/utils"; import { AttemptCapturePhase } from "./attempt-capture-phase"; import { AttemptRunPhase } from "./attempt-run-phase"; import { BerryPhase } from "./berry-phase"; @@ -17,18 +17,59 @@ 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"; +import { BattlerIndex } from "#app/battle"; +import { TrickRoomTag } from "#app/data/arena-tag"; export class TurnStartPhase extends FieldPhase { constructor(scene: BattleScene) { super(scene); } - start() { - super.start(); + /** + * This orders the active Pokemon on the field by speed into an BattlerIndex array and returns that array. + * It also checks for Trick Room and reverses the array if it is present. + * @returns {@linkcode BattlerIndex[]} the battle indices of all pokemon on the field ordered by speed + */ + getSpeedOrder(): BattlerIndex[] { + const playerField = this.scene.getPlayerField().filter(p => p.isActive()) as Pokemon[]; + const enemyField = this.scene.getEnemyField().filter(p => p.isActive()) as Pokemon[]; - const field = this.scene.getField(); - const order = this.getOrder(); + // 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; + }); + + // Next, a check for Trick Room is applied. If Trick Room is present, the order is reversed. + 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 : BattlerIndex.PLAYER)); + } + + /** + * This takes the result of getSpeedOrder and applies priority / bypass speed attributes to it. + * This also considers the priority levels of various commands and changes the result of getSpeedOrder based on such. + * @returns {@linkcode BattlerIndex[]} the final sequence of commands for this turn + */ + getCommandOrder(): BattlerIndex[] { + let moveOrder = this.getSpeedOrder(); + // The creation of the battlerBypassSpeed object contains checks for the ability Quick Draw and the held item Quick Claw + // The ability Mycelium Might disables Quick Claw's activation when using a status move + // This occurs before the main loop because of battles with more than two Pokemon const battlerBypassSpeed = {}; this.scene.getField(true).filter(p => p.summonData).map(p => { @@ -42,8 +83,9 @@ export class TurnStartPhase extends FieldPhase { battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed; }); - const moveOrder = order.slice(0); - + // The function begins sorting orderedTargets based on command priority, move priority, and possible speed bypasses. + // Non-FIGHT commands (SWITCH, BALL, RUN) have a higher command priority and will always occur before any FIGHT commands. + moveOrder = moveOrder.slice(0); moveOrder.sort((a, b) => { const aCommand = this.scene.currentBattle.turnCommands[a]; const bCommand = this.scene.currentBattle.turnCommands[b]; @@ -55,37 +97,50 @@ export class TurnStartPhase extends FieldPhase { 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 aMove = allMoves[aCommand.move!.move]; + const bMove = allMoves[bCommand!.move!.move]; + // The game now considers priority and applies the relevant move and ability attributes 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? + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); - 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? + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, false, aMove, aPriority); + applyAbAttrs(ChangeMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, false, bMove, bPriority); + // The game now checks for differences in priority levels. + // If the moves share the same original priority bracket, it can check for differences in battlerBypassSpeed and return the result. + // This conditional is used to ensure that Quick Claw can still activate with abilities like Stall and Mycelium Might (attack moves only) + // Otherwise, the game returns the user of the move with the highest priority. + const isSameBracket = Math.ceil(aPriority.value) - Math.ceil(bPriority.value) === 0; 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) { + if (isSameBracket && battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) { return battlerBypassSpeed[a].value ? -1 : 1; } return aPriority.value < bPriority.value ? 1 : -1; } } + // If there is no difference between the move's calculated priorities, the game checks for differences in battlerBypassSpeed and returns the result. if (battlerBypassSpeed[a].value !== battlerBypassSpeed[b].value) { return battlerBypassSpeed[a].value ? -1 : 1; } - const aIndex = order.indexOf(a); - const bIndex = order.indexOf(b); + const aIndex = moveOrder.indexOf(a); + const bIndex = moveOrder.indexOf(b); return aIndex < bIndex ? -1 : aIndex > bIndex ? 1 : 0; }); + return moveOrder; + } + + start() { + super.start(); + + const field = this.scene.getField(); + const moveOrder = this.getCommandOrder(); let orderIndex = 0; @@ -150,10 +205,9 @@ export class TurnStartPhase extends FieldPhase { } } - this.scene.pushPhase(new WeatherEffectPhase(this.scene)); - for (const o of order) { + for (const o of moveOrder) { if (field[o].status && field[o].status.isPostTurn()) { this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, o)); } diff --git a/src/test/abilities/mycelium_might.test.ts b/src/test/abilities/mycelium_might.test.ts index 83396f7950f..d5bea185f59 100644 --- a/src/test/abilities/mycelium_might.test.ts +++ b/src/test/abilities/mycelium_might.test.ts @@ -1,6 +1,6 @@ import { BattleStat } from "#app/data/battle-stat"; -import { MovePhase } from "#app/phases/move-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; - describe("Abilities - Mycelium Might", () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -35,7 +34,7 @@ describe("Abilities - Mycelium Might", () => { }); /** - * Bulbapedia References: + * References: * https://bulbapedia.bulbagarden.net/wiki/Mycelium_Might_(Ability) * https://bulbapedia.bulbagarden.net/wiki/Priority * https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24 @@ -44,22 +43,22 @@ describe("Abilities - Mycelium Might", () => { 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 playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); const enemyIndex = enemyPokemon?.getBattlerIndex(); game.move.select(Moves.BABY_DOLL_EYES); - await game.phaseInterceptor.to(MovePhase, false); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); // The opponent Pokemon (without Mycelium Might) goes first despite having lower speed than the player Pokemon. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); - // The player Pokemon (with Mycelium Might) goes last despite having higher speed than the opponent. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); + expect(speedOrder).toEqual([playerIndex, enemyIndex]); + expect(commandOrder).toEqual([enemyIndex, playerIndex]); await game.phaseInterceptor.to(TurnEndPhase); + // Despite the opponent's ability (Clear Body), its attack stat is still reduced. expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); }, 20000); @@ -67,39 +66,41 @@ describe("Abilities - Mycelium Might", () => { game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); await game.startBattle([Species.REGIELEKI]); - const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyPokemon = game.scene.getEnemyPokemon(); + const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); const enemyIndex = enemyPokemon?.getBattlerIndex(); game.move.select(Moves.BABY_DOLL_EYES); - await game.phaseInterceptor.to(MovePhase, false); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); // The player Pokemon (with M.M.) goes first because its move is still within a higher priority bracket than its opponent. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); // The enemy Pokemon goes second because its move is in a lower priority bracket. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); + expect(speedOrder).toEqual([playerIndex, enemyIndex]); + expect(commandOrder).toEqual([playerIndex, enemyIndex]); await game.phaseInterceptor.to(TurnEndPhase); + // Despite the opponent's ability (Clear Body), its attack stat is still reduced. expect(enemyPokemon?.summonData.battleStats[BattleStat.ATK]).toBe(-1); }, 20000); it("will not affect non-status moves", async () => { await game.startBattle([Species.REGIELEKI]); - const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); + const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); game.move.select(Moves.QUICK_ATTACK); - await game.phaseInterceptor.to(MovePhase, false); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); // The player Pokemon (with M.M.) goes first because it has a higher speed and did not use a status move. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); // The enemy Pokemon (without M.M.) goes second because its speed is lower. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); + // This means that the commandOrder should be identical to the speedOrder + expect(speedOrder).toEqual([playerIndex, enemyIndex]); + expect(commandOrder).toEqual([playerIndex, enemyIndex]); }, 20000); }); diff --git a/src/test/abilities/stall.test.ts b/src/test/abilities/stall.test.ts index d8dbe9d0e06..7baf7c846f0 100644 --- a/src/test/abilities/stall.test.ts +++ b/src/test/abilities/stall.test.ts @@ -1,11 +1,10 @@ -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 { TurnStartPhase } from "#app/phases/turn-start-phase"; describe("Abilities - Stall", () => { let phaserGame: Phaser.Game; @@ -32,7 +31,7 @@ describe("Abilities - Stall", () => { }); /** - * Bulbapedia References: + * References: * https://bulbapedia.bulbagarden.net/wiki/Stall_(Ability) * https://bulbapedia.bulbagarden.net/wiki/Priority **/ @@ -40,55 +39,56 @@ describe("Abilities - Stall", () => { 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 playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); game.move.select(Moves.QUICK_ATTACK); - await game.phaseInterceptor.to(MovePhase, false); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); // The player Pokemon (without Stall) goes first despite having lower speed than the opponent. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); // The opponent Pokemon (with Stall) goes last despite having higher speed than the player Pokemon. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); + expect(speedOrder).toEqual([enemyIndex, playerIndex]); + expect(commandOrder).toEqual([playerIndex, 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]); - const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); + const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); game.move.select(Moves.TACKLE); - await game.phaseInterceptor.to(MovePhase, false); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); // The opponent Pokemon (with Stall) goes first because its move is still within a higher priority bracket than its opponent. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); - - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); // The player Pokemon goes second because its move is in a lower priority bracket. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); + expect(speedOrder).toEqual([enemyIndex, playerIndex]); + expect(commandOrder).toEqual([enemyIndex, playerIndex]); }, 20000); 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]); - const leadIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); + const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); game.move.select(Moves.TACKLE); - await game.phaseInterceptor.to(MovePhase, false); - // The opponent Pokemon (with Stall) goes first because it has a higher speed. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(enemyIndex); + await game.phaseInterceptor.to(TurnStartPhase, false); + const phase = game.scene.getCurrentPhase() as TurnStartPhase; + const speedOrder = phase.getSpeedOrder(); + const commandOrder = phase.getCommandOrder(); - await game.phaseInterceptor.run(MovePhase); - await game.phaseInterceptor.to(MovePhase, false); + // The opponent Pokemon (with Stall) goes first because it has a higher speed. // The player Pokemon (with Stall) goes second because its speed is lower. - expect((game.scene.getCurrentPhase() as MovePhase).pokemon.getBattlerIndex()).toBe(leadIndex); + expect(speedOrder).toEqual([enemyIndex, playerIndex]); + expect(commandOrder).toEqual([enemyIndex, playerIndex]); }, 20000); }); diff --git a/src/test/battle/battle-order.test.ts b/src/test/battle/battle-order.test.ts index 0129ecad254..e19168962dc 100644 --- a/src/test/battle/battle-order.test.ts +++ b/src/test/battle/battle-order.test.ts @@ -1,4 +1,3 @@ -import { Stat } from "#app/data/pokemon-stat"; import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import { SelectTargetPhase } from "#app/phases/select-target-phase"; import { TurnStartPhase } from "#app/phases/turn-start-phase"; @@ -7,8 +6,7 @@ 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 { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Battle order", () => { let phaserGame: Phaser.Game; @@ -37,30 +35,42 @@ describe("Battle order", () => { await game.startBattle([ Species.BULBASAUR, ]); - game.scene.getParty()[0].stats[Stat.SPD] = 50; - game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 150; + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set playerPokemon's speed to 50 + vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set enemyPokemon's speed to 150 game.move.select(Moves.TACKLE); await game.phaseInterceptor.run(EnemyCommandPhase); + + const playerPokemonIndex = playerPokemon.getBattlerIndex(); + const enemyPokemonIndex = enemyPokemon.getBattlerIndex(); const phase = game.scene.getCurrentPhase() as TurnStartPhase; - const order = phase.getOrder(); - expect(order[0]).toBe(2); - expect(order[1]).toBe(0); + const order = phase.getCommandOrder(); + expect(order[0]).toBe(enemyPokemonIndex); + expect(order[1]).toBe(playerPokemonIndex); }, 20000); 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; + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set playerPokemon's speed to 150 + vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set enemyPokemon's speed to 50 game.move.select(Moves.TACKLE); await game.phaseInterceptor.run(EnemyCommandPhase); + + const playerPokemonIndex = playerPokemon.getBattlerIndex(); + const enemyPokemonIndex = enemyPokemon.getBattlerIndex(); const phase = game.scene.getCurrentPhase() as TurnStartPhase; - const order = phase.getOrder(); - expect(order[0]).toBe(0); - expect(order[1]).toBe(2); + const order = phase.getCommandOrder(); + expect(order[0]).toBe(playerPokemonIndex); + expect(order[1]).toBe(enemyPokemonIndex); }, 20000); it("double - both opponents faster than player 50/50 vs 150/150", async () => { @@ -69,20 +79,25 @@ describe("Battle order", () => { Species.BULBASAUR, Species.BLASTOISE, ]); - game.scene.getParty()[0].stats[Stat.SPD] = 50; - game.scene.getParty()[1].stats[Stat.SPD] = 50; - game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 150; - game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; + + const playerPokemon = game.scene.getPlayerField(); + const enemyPokemon = game.scene.getEnemyField(); + + playerPokemon.forEach(p => vi.spyOn(p, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50])); // set both playerPokemons' speed to 50 + enemyPokemon.forEach(p => vi.spyOn(p, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150])); // set both enemyPokemons' speed to 150 + const playerIndices = playerPokemon.map(p => p?.getBattlerIndex()); + const enemyIndices = enemyPokemon.map(p => p?.getBattlerIndex()); 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(); - expect(order.indexOf(0)).toBeGreaterThan(order.indexOf(2)); - expect(order.indexOf(0)).toBeGreaterThan(order.indexOf(3)); - expect(order.indexOf(1)).toBeGreaterThan(order.indexOf(2)); - expect(order.indexOf(1)).toBeGreaterThan(order.indexOf(3)); + const order = phase.getCommandOrder(); + expect(order.slice(0, 2).includes(enemyIndices[0])).toBe(true); + expect(order.slice(0, 2).includes(enemyIndices[1])).toBe(true); + expect(order.slice(2, 4).includes(playerIndices[0])).toBe(true); + expect(order.slice(2, 4).includes(playerIndices[1])).toBe(true); }, 20000); it("double - speed tie except 1 - 100/100 vs 100/150", async () => { @@ -91,19 +106,25 @@ describe("Battle order", () => { Species.BULBASAUR, Species.BLASTOISE, ]); - game.scene.getParty()[0].stats[Stat.SPD] = 100; - game.scene.getParty()[1].stats[Stat.SPD] = 100; - game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 100; - game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; + + const playerPokemon = game.scene.getPlayerField(); + const enemyPokemon = game.scene.getEnemyField(); + playerPokemon.forEach(p => vi.spyOn(p, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 100])); //set both playerPokemons' speed to 100 + vi.spyOn(enemyPokemon[0], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 100]); // set enemyPokemon's speed to 100 + vi.spyOn(enemyPokemon[1], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set enemyPokemon's speed to 150 + const playerIndices = playerPokemon.map(p => p?.getBattlerIndex()); + const enemyIndices = enemyPokemon.map(p => p?.getBattlerIndex()); 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(); - expect(order.indexOf(3)).toBeLessThan(order.indexOf(0)); - expect(order.indexOf(3)).toBeLessThan(order.indexOf(1)); - expect(order.indexOf(3)).toBeLessThan(order.indexOf(2)); + const order = phase.getCommandOrder(); + expect(order[0]).toBe(enemyIndices[1]); + expect(order.slice(1, 4).includes(enemyIndices[0])).toBe(true); + expect(order.slice(1, 4).includes(playerIndices[0])).toBe(true); + expect(order.slice(1, 4).includes(playerIndices[1])).toBe(true); }, 20000); it("double - speed tie 100/150 vs 100/150", async () => { @@ -112,19 +133,25 @@ describe("Battle order", () => { Species.BULBASAUR, Species.BLASTOISE, ]); - game.scene.getParty()[0].stats[Stat.SPD] = 100; - game.scene.getParty()[1].stats[Stat.SPD] = 150; - game.scene.currentBattle.enemyParty[0].stats[Stat.SPD] = 100; - game.scene.currentBattle.enemyParty[1].stats[Stat.SPD] = 150; + + const playerPokemon = game.scene.getPlayerField(); + const enemyPokemon = game.scene.getEnemyField(); + vi.spyOn(playerPokemon[0], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 100]); // set one playerPokemon's speed to 100 + vi.spyOn(playerPokemon[1], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set other playerPokemon's speed to 150 + vi.spyOn(enemyPokemon[0], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 100]); // set one enemyPokemon's speed to 100 + vi.spyOn(enemyPokemon[1], "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set other enemyPokemon's speed to 150 + const playerIndices = playerPokemon.map(p => p?.getBattlerIndex()); + const enemyIndices = enemyPokemon.map(p => p?.getBattlerIndex()); 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(); - expect(order.indexOf(1)).toBeLessThan(order.indexOf(0)); - expect(order.indexOf(1)).toBeLessThan(order.indexOf(2)); - expect(order.indexOf(3)).toBeLessThan(order.indexOf(0)); - expect(order.indexOf(3)).toBeLessThan(order.indexOf(2)); + const order = phase.getCommandOrder(); + expect(order.slice(0, 2).includes(playerIndices[1])).toBe(true); + expect(order.slice(0, 2).includes(enemyIndices[1])).toBe(true); + expect(order.slice(2, 4).includes(playerIndices[0])).toBe(true); + expect(order.slice(2, 4).includes(enemyIndices[0])).toBe(true); }, 20000); }); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 60d07065090..5818244db8f 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -381,7 +381,7 @@ export default class GameManager { } /** - * Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder} + * Intercepts `TurnStartPhase` and mocks the getSpeedOrder's return value {@linkcode TurnStartPhase.getSpeedOrder} * Used to modify the turn order. * @param {BattlerIndex[]} order The turn order to set * @example @@ -392,7 +392,7 @@ export default class GameManager { async setTurnOrder(order: BattlerIndex[]): Promise { await this.phaseInterceptor.to(TurnStartPhase, false); - vi.spyOn(this.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); + vi.spyOn(this.scene.getCurrentPhase() as TurnStartPhase, "getSpeedOrder").mockReturnValue(order); } /** From 335d32e0d7afd9c4baab6eb3c837bf9b704647f1 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Sun, 1 Sep 2024 18:24:37 -0400 Subject: [PATCH 09/40] [UI] [QoL] [Enhancement] Exclude redundant species from certain filters in starter select (#3910) * Exclude species without HA from HA filters in starter select * Remove candyless starters from passive/cost reduction filters --- src/ui/dropdown.ts | 8 +++++++ src/ui/starter-select-ui-handler.ts | 33 ++++++++++++++++------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/ui/dropdown.ts b/src/ui/dropdown.ts index 1fef7259108..08d55b03cdb 100644 --- a/src/ui/dropdown.ts +++ b/src/ui/dropdown.ts @@ -23,6 +23,14 @@ export enum SortDirection { DESC = 1 } +export enum SortCriteria { + NUMBER = 0, + COST = 1, + CANDY = 2, + IV = 3, + NAME = 4 +} + export class DropDownLabel { public state: DropDownState; public text: string; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 267a62104e3..ff76a467d25 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -39,12 +39,13 @@ import { Species } from "#enums/species"; import {Button} from "#enums/buttons"; import { EggSourceType } from "#app/enums/egg-source-types.js"; import AwaitableUiHandler from "./awaitable-ui-handler"; -import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType } from "./dropdown"; +import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "./dropdown"; 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"; +import { Abilities } from "#app/enums/abilities"; export type StarterSelectCallback = (starters: Starter[]) => void; @@ -501,11 +502,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // sort filter const sortOptions = [ - new DropDownOption(this.scene, 0, new DropDownLabel(i18next.t("filterBar:sortByNumber"), undefined, DropDownState.ON)), - new DropDownOption(this.scene, 1, new DropDownLabel(i18next.t("filterBar:sortByCost"))), - new DropDownOption(this.scene, 2, new DropDownLabel(i18next.t("filterBar:sortByCandies"))), - new DropDownOption(this.scene, 3, new DropDownLabel(i18next.t("filterBar:sortByIVs"))), - new DropDownOption(this.scene, 4, new DropDownLabel(i18next.t("filterBar:sortByName"))) + new DropDownOption(this.scene, SortCriteria.NUMBER, new DropDownLabel(i18next.t("filterBar:sortByNumber"), undefined, DropDownState.ON)), + new DropDownOption(this.scene, SortCriteria.COST, new DropDownLabel(i18next.t("filterBar:sortByCost"))), + new DropDownOption(this.scene, SortCriteria.CANDY, new DropDownLabel(i18next.t("filterBar:sortByCandies"))), + new DropDownOption(this.scene, SortCriteria.IV, new DropDownLabel(i18next.t("filterBar:sortByIVs"))), + new DropDownOption(this.scene, SortCriteria.NAME, new DropDownLabel(i18next.t("filterBar:sortByName"))) ]; this.filterBar.addFilter(DropDownColumn.SORT, i18next.t("filterBar:sortFilter"), new DropDown(this.scene, 0, 0, sortOptions, this.updateStarters, DropDownType.SINGLE)); this.filterBarContainer.add(this.filterBar); @@ -2363,6 +2364,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // First, ensure you have the caught attributes for the species else default to bigint 0 const caughtAttr = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0); const starterData = this.scene.gameData.starterData[container.species.speciesId]; + const isStarterProgressable = speciesEggMoves.hasOwnProperty(container.species.speciesId); // Gen filter const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation); @@ -2398,7 +2400,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.ON) { return isPassiveUnlocked; } else if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.EXCLUDE) { - return !isPassiveUnlocked; + return isStarterProgressable && !isPassiveUnlocked; } else if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.UNLOCKABLE) { return isPassiveUnlockable; } else if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.OFF) { @@ -2413,7 +2415,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.ON) { return isCostReduced; } else if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.EXCLUDE) { - return !isCostReduced; + return isStarterProgressable && !isCostReduced; } else if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.UNLOCKABLE) { return isCostReductionUnlockable; } else if (unlocks.val === "COST_REDUCTION" && unlocks.state === DropDownState.OFF) { @@ -2450,12 +2452,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }); // HA Filter + const speciesHasHiddenAbility = container.species.abilityHidden !== container.species.ability1 && container.species.abilityHidden !== Abilities.NONE; const hasHA = starterData.abilityAttr & AbilityAttr.ABILITY_HIDDEN; const fitsHA = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.ON) { return hasHA; } else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.EXCLUDE) { - return !hasHA; + return speciesHasHiddenAbility && !hasHA; } else if (misc.val === "HIDDEN_ABILITY" && misc.state === DropDownState.OFF) { return true; } @@ -2467,7 +2470,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (misc.val === "EGG" && misc.state === DropDownState.ON) { return isEggPurchasable; } else if (misc.val === "EGG" && misc.state === DropDownState.EXCLUDE) { - return !isEggPurchasable; + return isStarterProgressable && !isEggPurchasable; } else if (misc.val === "EGG" && misc.state === DropDownState.OFF) { return true; } @@ -2498,19 +2501,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler { switch (sort.val) { default: break; - case 0: + case SortCriteria.NUMBER: return (a.species.speciesId - b.species.speciesId) * -sort.dir; - case 1: + case SortCriteria.COST: return (a.cost - b.cost) * -sort.dir; - case 2: + case SortCriteria.CANDY: const candyCountA = this.scene.gameData.starterData[a.species.speciesId].candyCount; const candyCountB = this.scene.gameData.starterData[b.species.speciesId].candyCount; return (candyCountA - candyCountB) * -sort.dir; - case 3: + case SortCriteria.IV: const avgIVsA = this.scene.gameData.dexData[a.species.speciesId].ivs.reduce((a, b) => a + b, 0) / this.scene.gameData.dexData[a.species.speciesId].ivs.length; const avgIVsB = this.scene.gameData.dexData[b.species.speciesId].ivs.reduce((a, b) => a + b, 0) / this.scene.gameData.dexData[b.species.speciesId].ivs.length; return (avgIVsA - avgIVsB) * -sort.dir; - case 4: + case SortCriteria.NAME: return a.species.name.localeCompare(b.species.name) * -sort.dir; } return 0; From a41133a55a60d84d73faca460d9b9ec8e57ce448 Mon Sep 17 00:00:00 2001 From: cadi Date: Mon, 2 Sep 2024 07:26:45 +0900 Subject: [PATCH 10/40] blocking inputs while showing texts to prevent moveing cursor (#2371) Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/ui/party-ui-handler.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index e7c4069c16e..a61037548e6 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -166,6 +166,8 @@ export default class PartyUiHandler extends MessageUiHandler { private iconAnimHandler: PokemonIconAnimHandler; + private blockInput: boolean; + private static FilterAll = (_pokemon: PlayerPokemon) => null; public static FilterNonFainted = (pokemon: PlayerPokemon) => { @@ -317,7 +319,7 @@ export default class PartyUiHandler extends MessageUiHandler { processInput(button: Button): boolean { const ui = this.getUi(); - if (this.pendingPrompt) { + if (this.pendingPrompt || this.blockInput) { return false; } @@ -485,7 +487,9 @@ export default class PartyUiHandler extends MessageUiHandler { this.clearOptions(); ui.playSelect(); if (this.cursor >= this.scene.currentBattle.getBattlerCount() || !pokemon.isAllowedInBattle()) { + this.blockInput = true; this.showText(i18next.t("partyUiHandler:releaseConfirmation", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + this.blockInput = false; ui.setModeWithoutClear(Mode.CONFIRM, () => { ui.setMode(Mode.PARTY); this.doRelease(this.cursor); From 7755f798fd0f88f5fffc2451e558882ecf27cd93 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sun, 1 Sep 2024 18:21:11 -0700 Subject: [PATCH 11/40] [Ability] Implement Tera Shell (#3856) * Implement Tera Shell * Apply suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> * Add comments and fixed damage condition to `applyPreDefend` * Fix speed tie breaking things in tera shell test * Change deprecated `startBattle` calls --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --- src/data/ability.ts | 47 ++++++++++- src/field/pokemon.ts | 7 +- src/locales/en/ability-trigger.json | 1 + src/test/abilities/tera_shell.test.ts | 111 ++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 src/test/abilities/tera_shell.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 3d5b32f4ce8..e40a88a04b2 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -8,7 +8,7 @@ import { Weather, WeatherType } from "./weather"; import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { Stat, getStatName } from "./pokemon-stat"; import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier"; @@ -475,6 +475,47 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { } } +/** + * Attribute implementing the effects of {@link https://bulbapedia.bulbagarden.net/wiki/Tera_Shell_(Ability) | Tera Shell} + * When the source is at full HP, incoming attacks will have a maximum 0.5x type effectiveness multiplier. + * @extends PreDefendAbAttr + */ +export class FullHpResistTypeAbAttr extends PreDefendAbAttr { + /** + * Reduces a type multiplier to 0.5 if the source is at full HP. + * @param pokemon {@linkcode Pokemon} the Pokemon with this ability + * @param passive n/a + * @param simulated n/a (this doesn't change game state) + * @param attacker n/a + * @param move {@linkcode Move} the move being used on the source + * @param cancelled n/a + * @param args `[0]` a container for the move's current type effectiveness multiplier + * @returns `true` if the move's effectiveness is reduced; `false` otherwise + */ + applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { + const typeMultiplier = args[0]; + if (!(typeMultiplier && typeMultiplier instanceof Utils.NumberHolder)) { + return false; + } + + if (move && move.hasAttr(FixedDamageAttr)) { + return false; + } + + if (pokemon.isFullHp() && typeMultiplier.value > 0.5) { + typeMultiplier.value = 0.5; + return true; + } + return false; + } + + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return i18next.t("abilityTriggers:fullHpResistType", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) + }); + } +} + export class PostDefendAbAttr extends AbAttr { applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { return false; @@ -5761,10 +5802,10 @@ export function initAbilities() { .attr(NoTransformAbilityAbAttr) .attr(NoFusionAbilityAbAttr), new Ability(Abilities.TERA_SHELL, 9) + .attr(FullHpResistTypeAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .ignorable() - .unimplemented(), + .ignorable(), new Ability(Abilities.TERAFORM_ZERO, 9) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9fcbdd8dc6c..457ff874095 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -22,7 +22,7 @@ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoo import { WeatherType } from "../data/weather"; import { TempBattleStat } from "../data/temp-battle-stat"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; -import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr } from "../data/ability"; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr } from "../data/ability"; import PokemonData from "../system/pokemon-data"; import { BattlerIndex } from "../battle"; import { Mode } from "../ui/ui"; @@ -1276,6 +1276,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } + // Apply Tera Shell's effect to attacks after all immunities are accounted for + if (!ignoreAbility && move.category !== MoveCategory.STATUS) { + applyPreDefendAbAttrs(FullHpResistTypeAbAttr, this, source, move, cancelledHolder, simulated, typeMultiplier); + } + return (!cancelledHolder.value ? typeMultiplier.value : 0) as TypeDamageMultiplier; } diff --git a/src/locales/en/ability-trigger.json b/src/locales/en/ability-trigger.json index 307ab70b85c..4f1d4dac766 100644 --- a/src/locales/en/ability-trigger.json +++ b/src/locales/en/ability-trigger.json @@ -12,6 +12,7 @@ "blockItemTheft": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents item theft!", "typeImmunityHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", "nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} avoided damage\nwith {{abilityName}}!", + "fullHpResistType": "{{pokemonNameWithAffix}} made its shell gleam!\nIt's distorting type matchups!", "moveImmunity": "It doesn't affect {{pokemonNameWithAffix}}!", "reverseDrain": "{{pokemonNameWithAffix}} sucked up the liquid ooze!", "postDefendTypeChange": "{{pokemonNameWithAffix}}'s {{abilityName}}\nmade it the {{typeName}} type!", diff --git a/src/test/abilities/tera_shell.test.ts b/src/test/abilities/tera_shell.test.ts new file mode 100644 index 00000000000..f9cb2935619 --- /dev/null +++ b/src/test/abilities/tera_shell.test.ts @@ -0,0 +1,111 @@ +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import { HitResult } from "#app/field/pokemon.js"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +const TIMEOUT = 10 * 1000; // 10 second timeout + +describe("Abilities - Tera Shell", () => { + 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") + .ability(Abilities.TERA_SHELL) + .moveset([Moves.SPLASH]) + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.INSOMNIA) + .enemyMoveset(Array(4).fill(Moves.MACH_PUNCH)) + .startingLevel(100) + .enemyLevel(100); + }); + + it( + "should change the effectiveness of non-resisted attacks when the source is at full HP", + async () => { + await game.classicMode.startBattle([Species.SNORLAX]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + vi.spyOn(playerPokemon, "getMoveEffectiveness"); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(playerPokemon.getMoveEffectiveness).toHaveLastReturnedWith(0.5); + + await game.toNextTurn(); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(playerPokemon.getMoveEffectiveness).toHaveLastReturnedWith(2); + }, TIMEOUT + ); + + it( + "should not override type immunities", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK)); + + await game.classicMode.startBattle([Species.SNORLAX]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + vi.spyOn(playerPokemon, "getMoveEffectiveness"); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(playerPokemon.getMoveEffectiveness).toHaveLastReturnedWith(0); + }, TIMEOUT + ); + + it( + "should not override type multipliers less than 0.5x", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.QUICK_ATTACK)); + + await game.classicMode.startBattle([Species.AGGRON]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + vi.spyOn(playerPokemon, "getMoveEffectiveness"); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(playerPokemon.getMoveEffectiveness).toHaveLastReturnedWith(0.25); + }, TIMEOUT + ); + + it( + "should not affect the effectiveness of fixed-damage moves", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.DRAGON_RAGE)); + + await game.classicMode.startBattle([Species.CHARIZARD]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + vi.spyOn(playerPokemon, "apply"); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(playerPokemon.apply).toHaveLastReturnedWith(HitResult.EFFECTIVE); + expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp() - 40); + }, TIMEOUT + ); +}); From 97e3250f62d956268a0076ade875e5bb9cd38af1 Mon Sep 17 00:00:00 2001 From: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:31:25 -0400 Subject: [PATCH 12/40] [Sprite] Chien-Pao sprite cleanup (#3961) * Delete public/images/pokemon/exp/shiny/1002b.png * Delete public/images/pokemon/exp/shiny/1002s.png * Delete public/images/pokemon/exp/shiny/1002sb.png --- public/images/pokemon/exp/shiny/1002b.png | Bin 3018 -> 0 bytes public/images/pokemon/exp/shiny/1002s.png | Bin 4517 -> 0 bytes public/images/pokemon/exp/shiny/1002sb.png | Bin 2924 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 public/images/pokemon/exp/shiny/1002b.png delete mode 100644 public/images/pokemon/exp/shiny/1002s.png delete mode 100644 public/images/pokemon/exp/shiny/1002sb.png diff --git a/public/images/pokemon/exp/shiny/1002b.png b/public/images/pokemon/exp/shiny/1002b.png deleted file mode 100644 index 85dfb1c4bd6b6b3fb8312e71372bf37f6758c24e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3018 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 diff --git a/public/images/pokemon/exp/shiny/1002s.png b/public/images/pokemon/exp/shiny/1002s.png deleted file mode 100644 index 835b3dcd73bde83d1eb1492aec1c6bd61a6a9608..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4517 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 diff --git a/public/images/pokemon/exp/shiny/1002sb.png b/public/images/pokemon/exp/shiny/1002sb.png deleted file mode 100644 index f87e2fc42397c82c99e00917b9c5dbd2e973ec67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2924 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 L+Y{<>-q-&N5*a0} From 3bcee779e296be330ba3c6168ff462d8f7f38d23 Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:39:12 +0800 Subject: [PATCH 13/40] [Move] Fully implement dragon cheer (#3959) --- src/data/battler-tags.ts | 21 +++++++++++++++++++++ src/data/move.ts | 5 ++--- src/enums/battler-tag-type.ts | 3 ++- src/field/pokemon.ts | 13 ++++++++++--- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 8c05d296e76..38db36e86f6 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1507,6 +1507,25 @@ export class CritBoostTag extends BattlerTag { } } +/** + * Tag for the effects of Dragon Cheer, which boosts the critical hit ratio of the user's allies. + * @extends {CritBoostTag} + */ +export class DragonCheerTag extends CritBoostTag { + /** The types of the user's ally when the tag is added */ + public typesOnAdd: Type[]; + + constructor() { + super(BattlerTagType.CRIT_BOOST, Moves.DRAGON_CHEER); + } + + onAdd(pokemon: Pokemon): void { + super.onAdd(pokemon); + + this.typesOnAdd = pokemon.getTypes(true); + } +} + export class SaltCuredTag extends BattlerTag { private sourceIndex: number; @@ -1923,6 +1942,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false); case BattlerTagType.CRIT_BOOST: return new CritBoostTag(tagType, sourceMove); + case BattlerTagType.DRAGON_CHEER: + return new DragonCheerTag(); case BattlerTagType.ALWAYS_CRIT: case BattlerTagType.IGNORE_ACCURACY: return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove); diff --git a/src/data/move.ts b/src/data/move.ts index d50dc7e2074..bbc33241454 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -9143,9 +9143,8 @@ export function initMoves() { new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 9) .attr(OpponentHighHpPowerAttr, 100), new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9) - .attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true) - .target(MoveTarget.NEAR_ALLY) - .partial(), + .attr(AddBattlerTagAttr, BattlerTagType.DRAGON_CHEER, false, true) + .target(MoveTarget.NEAR_ALLY), new AttackMove(Moves.ALLURING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9) .soundBased() .partial(), diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index b133b442801..73580a107b2 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -69,5 +69,6 @@ export enum BattlerTagType { GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA", GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU", BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING", - SHELL_TRAP = "SHELL_TRAP" + SHELL_TRAP = "SHELL_TRAP", + DRAGON_CHEER = "DRAGON_CHEER", } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 457ff874095..00d5f5d3dd2 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -18,7 +18,7 @@ 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 { BattleStat } from "../data/battle-stat"; -import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag } from "../data/battler-tags"; +import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag, DragonCheerTag, CritBoostTag } from "../data/battler-tags"; import { WeatherType } from "../data/weather"; import { TempBattleStat } from "../data/temp-battle-stat"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; @@ -2069,9 +2069,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { critLevel.value += 1; } } - if (source.getTag(BattlerTagType.CRIT_BOOST)) { - critLevel.value += 2; + + const critBoostTag = source.getTag(CritBoostTag); + if (critBoostTag) { + if (critBoostTag instanceof DragonCheerTag) { + critLevel.value += critBoostTag.typesOnAdd.includes(Type.DRAGON) ? 2 : 1; + } else { + critLevel.value += 2; + } } + console.log(`crit stage: +${critLevel.value}`); const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))]; isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance); From 64368b62bc983ad6a475a021cfd22b372ab274ee Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:39:42 +0800 Subject: [PATCH 14/40] [Ability] Add form change support for Flower Gift (#3941) * add form change support for flower gift * fix nits --- src/data/ability.ts | 34 ++++-- src/data/move.ts | 4 +- src/data/pokemon-forms.ts | 9 +- src/field/arena.ts | 10 +- src/test/abilities/flower_gift.test.ts | 154 +++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 18 deletions(-) create mode 100644 src/test/abilities/flower_gift.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index e40a88a04b2..4d3d32e22fa 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2428,7 +2428,7 @@ export class PostSummonWeatherSuppressedFormChangeAbAttr extends PostSummonAbAtt /** * Triggers weather-based form change when summoned into an active weather. - * Used by Forecast. + * Used by Forecast and Flower Gift. * @extends PostSummonAbAttr */ export class PostSummonFormChangeByWeatherAbAttr extends PostSummonAbAttr { @@ -2451,7 +2451,10 @@ export class PostSummonFormChangeByWeatherAbAttr extends PostSummonAbAttr { * @returns whether the form change was triggered */ applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - if (pokemon.species.speciesId === Species.CASTFORM && this.ability === Abilities.FORECAST) { + const isCastformWithForecast = (pokemon.species.speciesId === Species.CASTFORM && this.ability === Abilities.FORECAST); + const isCherrimWithFlowerGift = (pokemon.species.speciesId === Species.CHERRIM && this.ability === Abilities.FLOWER_GIFT); + + if (isCastformWithForecast || isCherrimWithFlowerGift) { if (simulated) { return simulated; } @@ -3124,37 +3127,41 @@ export class PostWeatherChangeAbAttr extends AbAttr { /** * Triggers weather-based form change when weather changes. - * Used by Forecast. + * Used by Forecast and Flower Gift. * @extends PostWeatherChangeAbAttr */ export class PostWeatherChangeFormChangeAbAttr extends PostWeatherChangeAbAttr { private ability: Abilities; + private formRevertingWeathers: WeatherType[]; - constructor(ability: Abilities) { + constructor(ability: Abilities, formRevertingWeathers: WeatherType[]) { super(false); this.ability = ability; + this.formRevertingWeathers = formRevertingWeathers; } /** * Calls {@linkcode Arena.triggerWeatherBasedFormChangesToNormal | triggerWeatherBasedFormChangesToNormal} when the * weather changed to form-reverting weather, otherwise calls {@linkcode Arena.triggerWeatherBasedFormChanges | triggerWeatherBasedFormChanges} - * @param {Pokemon} pokemon the Pokemon that changed the weather + * @param {Pokemon} pokemon the Pokemon with this ability * @param passive n/a * @param weather n/a * @param args n/a * @returns whether the form change was triggered */ applyPostWeatherChange(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: WeatherType, args: any[]): boolean { - if (pokemon.species.speciesId === Species.CASTFORM && this.ability === Abilities.FORECAST) { + const isCastformWithForecast = (pokemon.species.speciesId === Species.CASTFORM && this.ability === Abilities.FORECAST); + const isCherrimWithFlowerGift = (pokemon.species.speciesId === Species.CHERRIM && this.ability === Abilities.FLOWER_GIFT); + + if (isCastformWithForecast || isCherrimWithFlowerGift) { if (simulated) { return simulated; } - const formRevertingWeathers: WeatherType[] = [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]; const weatherType = pokemon.scene.arena.weather?.weatherType; - if (weatherType && formRevertingWeathers.includes(weatherType)) { + if (weatherType && this.formRevertingWeathers.includes(weatherType)) { pokemon.scene.arena.triggerWeatherBasedFormChangesToNormal(); } else { pokemon.scene.arena.triggerWeatherBasedFormChanges(); @@ -4744,7 +4751,8 @@ function setAbilityRevealed(pokemon: Pokemon): void { */ function getPokemonWithWeatherBasedForms(scene: BattleScene) { return scene.getField(true).filter(p => - p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM + (p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM) + || (p.hasAbility(Abilities.FLOWER_GIFT) && p.species.speciesId === Species.CHERRIM) ); } @@ -4943,7 +4951,7 @@ export function initAbilities() { .attr(UncopiableAbilityAbAttr) .attr(NoFusionAbilityAbAttr) .attr(PostSummonFormChangeByWeatherAbAttr, Abilities.FORECAST) - .attr(PostWeatherChangeFormChangeAbAttr, Abilities.FORECAST), + .attr(PostWeatherChangeFormChangeAbAttr, Abilities.FORECAST, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG ]), new Ability(Abilities.STICKY_HOLD, 3) .attr(BlockItemTheftAbAttr) .bypassFaint() @@ -5136,8 +5144,10 @@ export function initAbilities() { .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), BattleStatMultiplierAbAttr, BattleStat.SPDEF, 1.5) .attr(UncopiableAbilityAbAttr) .attr(NoFusionAbilityAbAttr) - .ignorable() - .partial(), + .attr(PostSummonFormChangeByWeatherAbAttr, Abilities.FLOWER_GIFT) + .attr(PostWeatherChangeFormChangeAbAttr, Abilities.FLOWER_GIFT, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG, WeatherType.HAIL, WeatherType.HEAVY_RAIN, WeatherType.SNOW, WeatherType.RAIN ]) + .partial() // Should also boosts stats of ally + .ignorable(), new Ability(Abilities.BAD_DREAMS, 4) .attr(PostTurnHurtIfSleepingAbAttr), new Ability(Abilities.PICKPOCKET, 5) diff --git a/src/data/move.ts b/src/data/move.ts index bbc33241454..2ffa8a36de9 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5888,9 +5888,9 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr { target.summonData.ability = tempAbilityId; user.scene.queueMessage(i18next.t("moveTriggers:swappedAbilitiesWithTarget", {pokemonName: getPokemonNameWithAffix(user)})); - // Swaps Forecast from Castform + // Swaps Forecast/Flower Gift from Castform/Cherrim user.scene.arena.triggerWeatherBasedFormChangesToNormal(); - // Swaps Forecast to Castform (edge case) + // Swaps Forecast/Flower Gift to Castform/Cherrim (edge case) user.scene.arena.triggerWeatherBasedFormChanges(); return true; diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index e4417f8e8bb..1420d8800aa 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -359,7 +359,7 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger { /** * Class used for triggering form changes based on weather. - * Used by Castform. + * Used by Castform and Cherrim. * @extends SpeciesFormChangeTrigger */ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger { @@ -392,7 +392,7 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger { /** * Class used for reverting to the original form when the weather runs out * or when the user loses the ability/is suppressed. - * Used by Castform. + * Used by Castform and Cherrim. * @extends SpeciesFormChangeTrigger */ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChangeTrigger { @@ -930,6 +930,11 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true), ], + [Species.CHERRIM]: [ + new SpeciesFormChange(Species.CHERRIM, "overcast", "sunshine", new SpeciesFormChangeWeatherTrigger(Abilities.FLOWER_GIFT, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true), + new SpeciesFormChange(Species.CHERRIM, "sunshine", "overcast", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FLOWER_GIFT, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG, WeatherType.HAIL, WeatherType.HEAVY_RAIN, WeatherType.SNOW, WeatherType.RAIN ]), true), + new SpeciesFormChange(Species.CHERRIM, "sunshine", "overcast", new SpeciesFormChangeActiveTrigger(), true), + ], }; export function initPokemonForms() { diff --git a/src/field/arena.ts b/src/field/arena.ts index 7622b9a014f..e8defbd1a8e 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -339,7 +339,10 @@ export class Arena { */ triggerWeatherBasedFormChanges(): void { this.scene.getField(true).forEach( p => { - if (p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM) { + const isCastformWithForecast = (p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM); + const isCherrimWithFlowerGift = (p.hasAbility(Abilities.FLOWER_GIFT) && p.species.speciesId === Species.CHERRIM); + + if (isCastformWithForecast || isCherrimWithFlowerGift) { new ShowAbilityPhase(this.scene, p.getBattlerIndex()); this.scene.triggerPokemonFormChange(p, SpeciesFormChangeWeatherTrigger); } @@ -351,7 +354,10 @@ export class Arena { */ triggerWeatherBasedFormChangesToNormal(): void { this.scene.getField(true).forEach( p => { - if (p.hasAbility(Abilities.FORECAST, false, true) && p.species.speciesId === Species.CASTFORM) { + const isCastformWithForecast = (p.hasAbility(Abilities.FORECAST, false, true) && p.species.speciesId === Species.CASTFORM); + const isCherrimWithFlowerGift = (p.hasAbility(Abilities.FLOWER_GIFT, false, true) && p.species.speciesId === Species.CHERRIM); + + if (isCastformWithForecast || isCherrimWithFlowerGift) { new ShowAbilityPhase(this.scene, p.getBattlerIndex()); return this.scene.triggerPokemonFormChange(p, SpeciesFormChangeRevertWeatherFormTrigger); } diff --git a/src/test/abilities/flower_gift.test.ts b/src/test/abilities/flower_gift.test.ts new file mode 100644 index 00000000000..f8c1141386d --- /dev/null +++ b/src/test/abilities/flower_gift.test.ts @@ -0,0 +1,154 @@ +import { BattlerIndex } from "#app/battle"; +import { Abilities } from "#app/enums/abilities"; +import { Stat } from "#app/enums/stat"; +import { WeatherType } from "#app/enums/weather-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"; + +describe("Abilities - Flower Gift", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + const OVERCAST_FORM = 0; + const SUNSHINE_FORM = 1; + + /** + * Tests reverting to normal form when Cloud Nine/Air Lock is active on the field + * @param {GameManager} game The game manager instance + * @param {Abilities} ability The ability that is active on the field + */ + const testRevertFormAgainstAbility = async (game: GameManager, ability: Abilities) => { + game.override.starterForms({ [Species.CASTFORM]: SUNSHINE_FORM }).enemyAbility(ability); + await game.classicMode.startBattle([Species.CASTFORM]); + + game.move.select(Moves.SPLASH); + + expect(game.scene.getPlayerPokemon()?.formIndex).toBe(OVERCAST_FORM); + }; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SKILL_SWAP]) + .enemySpecies(Species.MAGIKARP) + .enemyMoveset(SPLASH_ONLY) + .enemyAbility(Abilities.BALL_FETCH); + }); + + // TODO: Uncomment expect statements when the ability is implemented - currently does not increase stats of allies + it("increases the Attack and Special Defense stats of the Pokémon with this Ability and its allies by 1.5× during Harsh Sunlight", async () => { + game.override.battleType("double"); + await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]); + + const [ cherrim ] = game.scene.getPlayerField(); + const cherrimAtkStat = cherrim.getBattleStat(Stat.ATK); + const cherrimSpDefStat = cherrim.getBattleStat(Stat.SPDEF); + + // const magikarpAtkStat = magikarp.getBattleStat(Stat.ATK);; + // const magikarpSpDefStat = magikarp.getBattleStat(Stat.SPDEF); + + game.move.select(Moves.SUNNY_DAY, 0); + game.move.select(Moves.SPLASH, 1); + + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + expect(cherrim.getBattleStat(Stat.ATK)).toBe(Math.floor(cherrimAtkStat * 1.5)); + expect(cherrim.getBattleStat(Stat.SPDEF)).toBe(Math.floor(cherrimSpDefStat * 1.5)); + // expect(magikarp.getBattleStat(Stat.ATK)).toBe(Math.floor(magikarpAtkStat * 1.5)); + // expect(magikarp.getBattleStat(Stat.SPDEF)).toBe(Math.floor(magikarpSpDefStat * 1.5)); + }); + + it("changes the Pokemon's form during Harsh Sunlight", async () => { + game.override.weather(WeatherType.HARSH_SUN); + await game.classicMode.startBattle([Species.CHERRIM]); + + const cherrim = game.scene.getPlayerPokemon()!; + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + + game.move.select(Moves.SPLASH); + }); + + it("reverts to Overcast Form if a Pokémon on the field has Air Lock", async () => { + await testRevertFormAgainstAbility(game, Abilities.AIR_LOCK); + }); + + it("reverts to Overcast Form if a Pokémon on the field has Cloud Nine", async () => { + await testRevertFormAgainstAbility(game, Abilities.CLOUD_NINE); + }); + + it("reverts to Overcast Form when the Pokémon loses Flower Gift, changes form under Harsh Sunlight/Sunny when it regains it", async () => { + game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP)).weather(WeatherType.HARSH_SUN); + + await game.classicMode.startBattle([Species.CHERRIM]); + + const cherrim = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.SKILL_SWAP); + + await game.phaseInterceptor.to("TurnStartPhase"); + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(cherrim.formIndex).toBe(OVERCAST_FORM); + + await game.phaseInterceptor.to("MoveEndPhase"); + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + }); + + it("reverts to Overcast Form when the Flower Gift is suppressed, changes form under Harsh Sunlight/Sunny when it regains it", async () => { + game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)).weather(WeatherType.HARSH_SUN); + + await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]); + + const cherrim = game.scene.getPlayerPokemon()!; + + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + + game.move.select(Moves.SPLASH); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(cherrim.summonData.abilitySuppressed).toBe(true); + expect(cherrim.formIndex).toBe(OVERCAST_FORM); + + await game.toNextTurn(); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + + game.doSwitchPokemon(1); + await game.phaseInterceptor.to("MovePhase"); + + expect(cherrim.summonData.abilitySuppressed).toBe(false); + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + }); + + it("should be in Overcast Form after the user is switched out", async () => { + game.override.weather(WeatherType.SUNNY); + + await game.classicMode.startBattle([Species.CASTFORM, Species.MAGIKARP]); + const cherrim = game.scene.getPlayerPokemon()!; + + expect(cherrim.formIndex).toBe(SUNSHINE_FORM); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + + expect(cherrim.formIndex).toBe(OVERCAST_FORM); + }); +}); From 0c28da75b4a57236fae46e2ade4a95cbc8d09f02 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Sun, 1 Sep 2024 19:42:23 -0700 Subject: [PATCH 15/40] [Bug] Fix Opponent pokemon sprite disappears after using Roar and Dragon Tail #481 (#3927) --- src/data/battle-anims.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index a2f6e41f4ae..da4e7f6a33b 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -788,10 +788,10 @@ export abstract class BattleAnim { targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ]; targetSprite.setAngle(0); if (!this.isHideUser() && userSprite) { - userSprite.setVisible(true); + this.user?.getSprite().setVisible(true); // using this.user to fix context loss due to isOppAnim swap (#481) } if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) { - targetSprite.setVisible(true); + this.target?.getSprite().setVisible(true); // using this.target to fix context loss due to isOppAnim swap (#481) } for (const ms of Object.values(spriteCache).flat()) { if (ms) { From c070f110e5ebc2f53362ebe7dd3adb1a7d1d80bb Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:44:58 -0400 Subject: [PATCH 16/40] [Localization(fr)] Additional nature entries in pokemon-summary (#3869) Co-authored-by: Lugiad --- src/locales/fr/pokemon-summary.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/locales/fr/pokemon-summary.json b/src/locales/fr/pokemon-summary.json index f0b4f5a474f..01e712c8468 100644 --- a/src/locales/fr/pokemon-summary.json +++ b/src/locales/fr/pokemon-summary.json @@ -13,5 +13,32 @@ "metFragment": { "normal": "rencontré au N.{{level}},\n{{biome}}.", "apparently": "apparemment rencontré au N.{{level}},\n{{biome}}." + }, + "natureFragment": { + "Hardy": "{{nature}}", + "Lonely": "{{nature}}", + "Brave": "{{nature}}", + "Adamant": "{{nature}}", + "Naughty": "{{nature}}", + "Bold": "{{nature}}", + "Docile": "{{nature}}", + "Relaxed": "{{nature}}", + "Impish": "{{nature}}", + "Lax": "{{nature}}", + "Timid": "{{nature}}", + "Hasty": "{{nature}}", + "Serious": "{{nature}}", + "Jolly": "{{nature}}", + "Naive": "{{nature}}", + "Modest": "{{nature}}", + "Mild": "{{nature}}", + "Quiet": "{{nature}}", + "Bashful": "{{nature}}", + "Rash": "{{nature}}", + "Calm": "{{nature}}", + "Gentle": "{{nature}}", + "Sassy": "{{nature}}", + "Careful": "{{nature}}", + "Quirky": "{{nature}}" } -} \ No newline at end of file +} From 49c3158fd1e5d2ceb53312daf311d23e8a1396a1 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:45:42 -0400 Subject: [PATCH 17/40] [Localization(ko)] Change ghost type challenge acv for achv-female (#3866) Co-authored-by: sodam Co-authored-by: Enoch Co-authored-by: KimJeongSun --- src/locales/ko/achv.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/ko/achv.json b/src/locales/ko/achv.json index 8546dff949c..b9fd327ef3b 100644 --- a/src/locales/ko/achv.json +++ b/src/locales/ko/achv.json @@ -225,7 +225,7 @@ "name": "독침붕처럼 쏴라" }, "MONO_GHOST": { - "name": "누굴 부를 거야?" + "name": "무서운 게 딱 좋아!" }, "MONO_STEEL": { "name": "강철 심장" @@ -265,4 +265,4 @@ "name": "상성 전문가(였던 것)", "description": "거꾸로 배틀 챌린지 모드 클리어." } -} \ No newline at end of file +} From 14e0c66ed9d46f248f26ee7cc0e378e87792cfd1 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:46:53 -0400 Subject: [PATCH 18/40] [Localisation] [ES] Finished and reviewed terrain, modifier, trainer-names, splash messages (#3848) * Translate splash-messages.json via GitLocalize * Translate splash-messages.json via GitLocalize * Translate trainer-names.json via GitLocalize * Translate modifier.json via GitLocalize * Translate modifier.json via GitLocalize * Translate modifier.json via GitLocalize * Translate terrain.json via GitLocalize * Update src/locales/es/trainer-names.json Co-authored-by: Asdar --------- Co-authored-by: LilyAlternis Co-authored-by: Asdar Co-authored-by: Rafa Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/locales/es/modifier.json | 13 ++++++-- src/locales/es/splash-messages.json | 12 ++++---- src/locales/es/terrain.json | 17 +++++++++- src/locales/es/trainer-names.json | 48 ++++++++++++++--------------- 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/locales/es/modifier.json b/src/locales/es/modifier.json index 593b3df2f0f..a94e41a4574 100644 --- a/src/locales/es/modifier.json +++ b/src/locales/es/modifier.json @@ -1,3 +1,12 @@ { - "bypassSpeedChanceApply": "¡Gracias {{itemName}} {{pokemonName}} puede tener prioridad!" -} \ No newline at end of file + "surviveDamageApply": "{{pokemonNameWithAffix}} ha usado {{typeName}} y ha logrado resistir!", + "turnHealApply": "{{pokemonNameWithAffix}} ha recuperado unos pocos PS gracias a {{typeName}}!", + "hitHealApply": "{{pokemonNameWithAffix}} ha recuperado unos pocos PS gracias a {{typeName}}!", + "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} ha sido revivido gracias a su {{typeName}}!", + "pokemonResetNegativeStatStageApply": "Las estadísticas bajadas de {{pokemonNameWithAffix}} fueron restauradas gracias a {{typeName}}!", + "moneyInterestApply": "Recibiste intereses de ₽{{moneyAmount}}\ngracias a {{typeName}}!", + "turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} fue absorbido\npor {{pokemonName}}'s {{typeName}}!", + "contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} fue robado por {{pokemonName}}'s {{typeName}}!", + "enemyTurnHealApply": "¡{{pokemonNameWithAffix}}\nrecuperó algunos PS!", + "bypassSpeedChanceApply": "¡Gracias a su {{itemName}}, {{pokemonName}} puede tener prioridad!" +} diff --git a/src/locales/es/splash-messages.json b/src/locales/es/splash-messages.json index 90ce3593b89..b1d4820b06e 100644 --- a/src/locales/es/splash-messages.json +++ b/src/locales/es/splash-messages.json @@ -3,12 +3,12 @@ "joinTheDiscord": "¡Únete al Discord!", "infiniteLevels": "¡Niveles infinitos!", "everythingStacks": "¡Todo se acumula!", - "optionalSaveScumming": "¡Trampas guardando (¡opcionales!)!", + "optionalSaveScumming": "¡Trampas de guardado opcionales!", "biomes": "¡35 biomas!", "openSource": "¡Código abierto!", "playWithSpeed": "¡Juega a velocidad 5x!", - "liveBugTesting": "¡Arreglo de bugs sobre la marcha!", - "heavyInfluence": "¡Influencia Alta en RoR2!", + "liveBugTesting": "¡Testeo de bugs en directo!", + "heavyInfluence": "¡Mucha Influencia de RoR2!", "pokemonRiskAndPokemonRain": "¡Pokémon Risk y Pokémon Rain!", "nowWithMoreSalt": "¡Con un 33% más de polémica!", "infiniteFusionAtHome": "¡Infinite Fusion en casa!", @@ -17,16 +17,16 @@ "mubstitute": "¡Mubstituto!", "thatsCrazy": "¡De locos!", "oranceJuice": "¡Zumo de narancia!", - "questionableBalancing": "¡Balance cuestionable!", + "questionableBalancing": "¡Cambios en balance cuestionables!", "coolShaders": "¡Shaders impresionantes!", "aiFree": "¡Libre de IA!", "suddenDifficultySpikes": "¡Saltos de dificultad repentinos!", "basedOnAnUnfinishedFlashGame": "¡Basado en un juego Flash inacabado!", - "moreAddictiveThanIntended": "¡Más adictivo de la cuenta!", + "moreAddictiveThanIntended": "¡Más adictivo de lo previsto!", "mostlyConsistentSeeds": "¡Semillas CASI consistentes!", "achievementPointsDontDoAnything": "¡Los Puntos de Logro no hacen nada!", "youDoNotStartAtLevel": "¡No empiezas al nivel 2000!", - "dontTalkAboutTheManaphyEggIncident": "¡No hablen del incidente del Huevo Manaphy!", + "dontTalkAboutTheManaphyEggIncident": "¡No se habla del Incidente Manaphy!", "alsoTryPokengine": "¡Prueba también Pokéngine!", "alsoTryEmeraldRogue": "¡Prueba también Emerald Rogue!", "alsoTryRadicalRed": "¡Prueba también Radical Red!", diff --git a/src/locales/es/terrain.json b/src/locales/es/terrain.json index 9e26dfeeb6e..912f5186180 100644 --- a/src/locales/es/terrain.json +++ b/src/locales/es/terrain.json @@ -1 +1,16 @@ -{} \ No newline at end of file +{ + "misty": "Niebla", + "mistyStartMessage": "¡La niebla ha envuelto el terreno de combate!", + "mistyClearMessage": "La niebla se ha disipado.", + "mistyBlockMessage": "¡El campo de niebla ha protegido a {{pokemonNameWithAffix}} ", + "electric": "Eléctrico", + "electricStartMessage": "¡Se ha formado un campo de corriente eléctrica en el terreno\nde combate!", + "electricClearMessage": "El campo de corriente eléctrica ha desaparecido.\t", + "grassy": "Hierba", + "grassyStartMessage": "¡El terreno de combate se ha cubierto de hierba!", + "grassyClearMessage": "La hierba ha desaparecido.", + "psychic": "Psíquico", + "psychicStartMessage": "¡El terreno de combate se ha vuelto muy extraño!", + "psychicClearMessage": "Ha desaparecido la extraña sensación que se percibía en el terreno\nde combate.", + "defaultBlockMessage": "¡El campo {{terrainName}} ha protegido a {{pokemonNameWithAffix}} " +} diff --git a/src/locales/es/trainer-names.json b/src/locales/es/trainer-names.json index c6758366db7..ce09a0c9037 100644 --- a/src/locales/es/trainer-names.json +++ b/src/locales/es/trainer-names.json @@ -1,7 +1,7 @@ { "brock": "Brock", "misty": "Misty", - "lt_surge": "Tt. Surge", + "lt_surge": "Teniente Surge", "erika": "Erika", "janine": "Sachiko", "sabrina": "Sabrina", @@ -23,7 +23,7 @@ "winona": "Alana", "tate": "Vito", "liza": "Leti", - "juan": "Galán", + "juan": "Galano", "roark": "Roco", "gardenia": "Gardenia", "maylene": "Brega", @@ -34,7 +34,7 @@ "volkner": "Lectro", "cilan": "Millo", "chili": "Zeo", - "cress": "Maiz", + "cress": "Maíz", "cheren": "Cheren", "lenora": "Aloe", "roxie": "Hiedra", @@ -57,7 +57,7 @@ "nessa": "Cathy", "kabu": "Naboru", "bea": "Judith", - "allister": "Allistair", + "allister": "Alistair", "opal": "Sally", "bede": "Berto", "gordie": "Morris", @@ -123,30 +123,28 @@ "leon": "Lionel", "rival": "Finn", "rival_female": "Ivy", - "archer": "Archer", - "ariana": "Ariana", - "proton": "Proton", + "archer": "Atlas", + "ariana": "Atenea", + "proton": "Protón", "petrel": "Petrel", - "tabitha": "Tabitha", - "courtney": "Courtney", - "shelly": "Shelly", - "matt": "Matt", - "mars": "Mars", - "jupiter": "Jupiter", - "saturn": "Saturn", - "zinzolin": "Zinzolin", - "rood": "Rood", - "xerosic": "Xerosic", - "bryony": "Bryony", + "tabitha": "Tatiano", + "courtney": "Carola", + "shelly": "Silvina", + "matt": "Matías", + "mars": "Venus", + "jupiter": "Ceres", + "saturn": "Saturno", + "zinzolin": "Menek", + "rood": "Ruga", + "xerosic": "Xero", + "bryony": "Begonia", + "maxie": "Magno", + "archie": "Aquiles", + "cyrus": "Helio", + "ghetsis": "Ghechis", + "lysandre": "Lysson", "faba": "Fabio", - - "maxie": "Maxie", - "archie": "Archie", - "cyrus": "Cyrus", - "ghetsis": "Ghetsis", - "lysandre": "Lysandre", "lusamine": "Samina", - "blue_red_double": "Azul y Rojo", "red_blue_double": "Rojo y Azul", "tate_liza_double": "Vito y Leti", From dcb03f4ee99635a56d8b7e9316f2c0f4a29c0b92 Mon Sep 17 00:00:00 2001 From: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com> Date: Mon, 2 Sep 2024 04:47:22 +0200 Subject: [PATCH 19/40] [Test] Add test for final boss fight phase switch (#3847) * implement test for final boss encounter phase switch * Update Eternatus tests & helper function * fix endless_boss test following GameManager update --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/test/endless_boss.test.ts | 10 ++-- src/test/final_boss.test.ts | 98 +++++++++++++++++++++++++++++++---- src/test/utils/gameManager.ts | 29 +++++------ src/ui/ui.ts | 3 +- 4 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/test/endless_boss.test.ts b/src/test/endless_boss.test.ts index e983be245b6..8a564695e42 100644 --- a/src/test/endless_boss.test.ts +++ b/src/test/endless_boss.test.ts @@ -32,7 +32,7 @@ describe("Endless Boss", () => { it(`should spawn a minor boss every ${EndlessBossWave.Minor} waves in END biome in Endless`, async () => { game.override.startingWave(EndlessBossWave.Minor); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.ENDLESS); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.ENDLESS); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -44,7 +44,7 @@ describe("Endless Boss", () => { it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Endless`, async () => { game.override.startingWave(EndlessBossWave.Major); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.ENDLESS); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.ENDLESS); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -56,7 +56,7 @@ describe("Endless Boss", () => { it(`should spawn a minor boss every ${EndlessBossWave.Minor} waves in END biome in Spliced Endless`, async () => { game.override.startingWave(EndlessBossWave.Minor); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.SPLICED_ENDLESS); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.SPLICED_ENDLESS); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -68,7 +68,7 @@ describe("Endless Boss", () => { it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Spliced Endless`, async () => { game.override.startingWave(EndlessBossWave.Major); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.SPLICED_ENDLESS); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.SPLICED_ENDLESS); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -80,7 +80,7 @@ describe("Endless Boss", () => { it(`should NOT spawn major or minor boss outside wave ${EndlessBossWave.Minor}s in END biome`, async () => { game.override.startingWave(EndlessBossWave.Minor - 1); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.ENDLESS); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.ENDLESS); expect(game.scene.currentBattle.waveIndex).not.toBe(EndlessBossWave.Minor); expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(Species.ETERNATUS); diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index 0f59572619b..5d006998a0b 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -1,8 +1,13 @@ +import { StatusEffect } from "#app/data/status-effect"; +import { Abilities } from "#app/enums/abilities"; import { Biome } from "#app/enums/biome"; +import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import { GameModes } from "#app/game-mode"; +import { TurnHeldItemTransferModifier } from "#app/modifier/modifier"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; +import { SPLASH_ONLY } from "./utils/testUtils"; const FinalWave = { Classic: 200, @@ -20,7 +25,13 @@ describe("Final Boss", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.startingWave(FinalWave.Classic).startingBiome(Biome.END).disableCrits(); + game.override + .startingWave(FinalWave.Classic) + .startingBiome(Biome.END) + .disableCrits() + .enemyMoveset(SPLASH_ONLY) + .moveset([ Moves.SPLASH, Moves.WILL_O_WISP, Moves.DRAGON_PULSE ]) + .startingLevel(10000); }); afterEach(() => { @@ -28,7 +39,7 @@ describe("Final Boss", () => { }); it("should spawn Eternatus on wave 200 in END biome", async () => { - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.CLASSIC); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.CLASSIC); expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -37,7 +48,7 @@ describe("Final Boss", () => { it("should NOT spawn Eternatus before wave 200 in END biome", async () => { game.override.startingWave(FinalWave.Classic - 1); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.CLASSIC); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.CLASSIC); expect(game.scene.currentBattle.waveIndex).not.toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).toBe(Biome.END); @@ -46,7 +57,7 @@ describe("Final Boss", () => { it("should NOT spawn Eternatus outside of END biome", async () => { game.override.startingBiome(Biome.FOREST); - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.CLASSIC); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.CLASSIC); expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).not.toBe(Biome.END); @@ -54,12 +65,81 @@ describe("Final Boss", () => { }); it("should not have passive enabled on Eternatus", async () => { - await game.runToFinalBossEncounter(game, [Species.BIDOOF], GameModes.CLASSIC); + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.CLASSIC); - const eternatus = game.scene.getEnemyPokemon(); - expect(eternatus?.species.speciesId).toBe(Species.ETERNATUS); - expect(eternatus?.hasPassive()).toBe(false); + const eternatus = game.scene.getEnemyPokemon()!; + expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus.hasPassive()).toBe(false); + }); + + it("should change form on direct hit down to last boss fragment", async () => { + await game.runToFinalBossEncounter([Species.KYUREM], GameModes.CLASSIC); + await game.phaseInterceptor.to("CommandPhase"); + + // Eternatus phase 1 + const eternatus = game.scene.getEnemyPokemon()!; + const phase1Hp = eternatus.getMaxHp(); + expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus.formIndex).toBe(0); + expect(eternatus.bossSegments).toBe(4); + expect(eternatus.bossSegmentIndex).toBe(3); + + game.move.select(Moves.DRAGON_PULSE); + await game.toNextTurn(); + + // Eternatus phase 2: changed form, healed and restored its shields + expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus.hp).toBeGreaterThan(phase1Hp); + expect(eternatus.hp).toBe(eternatus.getMaxHp()); + expect(eternatus.formIndex).toBe(1); + expect(eternatus.bossSegments).toBe(5); + expect(eternatus.bossSegmentIndex).toBe(4); + const miniBlackHole = eternatus.getHeldItems().find(m => m instanceof TurnHeldItemTransferModifier); + expect(miniBlackHole).toBeDefined(); + expect(miniBlackHole?.stackCount).toBe(1); + }); + + it("should change form on status damage down to last boss fragment", async () => { + game.override.ability(Abilities.NO_GUARD); + + await game.runToFinalBossEncounter([Species.BIDOOF], GameModes.CLASSIC); + await game.phaseInterceptor.to("CommandPhase"); + + // Eternatus phase 1 + const eternatus = game.scene.getEnemyPokemon()!; + const phase1Hp = eternatus.getMaxHp(); + expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus.formIndex).toBe(0); + expect(eternatus.bossSegments).toBe(4); + expect(eternatus.bossSegmentIndex).toBe(3); + + game.move.select(Moves.WILL_O_WISP); + await game.toNextTurn(); + expect(eternatus.status?.effect).toBe(StatusEffect.BURN); + + const tickDamage = phase1Hp - eternatus.hp; + const lastShieldHp = Math.ceil(phase1Hp / eternatus.bossSegments); + // Stall until the burn is one hit away from breaking the last shield + while (eternatus.hp - tickDamage > lastShieldHp) { + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + } + + expect(eternatus.bossSegmentIndex).toBe(1); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // Eternatus phase 2: changed form, healed and restored its shields + expect(eternatus.hp).toBeGreaterThan(phase1Hp); + expect(eternatus.hp).toBe(eternatus.getMaxHp()); + expect(eternatus.status).toBeFalsy(); + expect(eternatus.formIndex).toBe(1); + expect(eternatus.bossSegments).toBe(5); + expect(eternatus.bossSegmentIndex).toBe(4); + const miniBlackHole = eternatus.getHeldItems().find(m => m instanceof TurnHeldItemTransferModifier); + expect(miniBlackHole).toBeDefined(); + expect(miniBlackHole?.stackCount).toBe(1); }); - it.todo("should change form on direct hit down to last boss fragment", () => {}); }); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 5818244db8f..a9a71d16bf7 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -6,6 +6,7 @@ import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import Trainer from "#app/field/trainer"; import { GameModes, getGameMode } from "#app/game-mode"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; +import overrides from "#app/overrides"; import { CommandPhase } from "#app/phases/command-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { FaintPhase } from "#app/phases/faint-phase"; @@ -148,28 +149,26 @@ export default class GameManager { * @param species * @param mode */ - async runToFinalBossEncounter(game: GameManager, species: Species[], mode: GameModes) { + async runToFinalBossEncounter(species: Species[], mode: GameModes) { console.log("===to final boss encounter==="); - await game.runToTitle(); + await this.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { - game.scene.gameMode = getGameMode(mode); - const starters = generateStarter(game.scene, species); - const selectStarterPhase = new SelectStarterPhase(game.scene); - game.scene.pushPhase(new EncounterPhase(game.scene, false)); + this.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.scene.gameMode = getGameMode(mode); + const starters = generateStarter(this.scene, species); + const selectStarterPhase = new SelectStarterPhase(this.scene); + this.scene.pushPhase(new EncounterPhase(this.scene, false)); selectStarterPhase.initBattle(starters); }); - game.onNextPrompt("EncounterPhase", Mode.MESSAGE, async () => { - // This will skip all entry dialogue (I can't figure out a way to sequentially handle the 8 chained messages via 1 prompt handler) - game.setMode(Mode.MESSAGE); - const encounterPhase = game.scene.getCurrentPhase() as EncounterPhase; + // This will consider all battle entry dialog as seens and skip them + vi.spyOn(this.scene.ui, "shouldSkipDialogue").mockReturnValue(true); - // No need to end phase, this will do it for you - encounterPhase.doEncounterCommon(false); - }); + if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { + this.removeEnemyHeldItems(); + } - await game.phaseInterceptor.to(EncounterPhase, true); + await this.phaseInterceptor.to(EncounterPhase); console.log("===finished run to final boss encounter==="); } diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 7108a8dd480..8ec91b59480 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -317,10 +317,11 @@ export default class UI extends Phaser.GameObjects.Container { if (i18next.exists(keyOrText) ) { const i18nKey = keyOrText; hasi18n = true; + text = i18next.t(i18nKey, { context: genderStr }); // override text with translation // Skip dialogue if the player has enabled the option and the dialogue has been already seen - if (battleScene.skipSeenDialogues && battleScene.gameData.getSeenDialogues()[i18nKey] === true) { + if (this.shouldSkipDialogue(i18nKey)) { console.log(`Dialogue ${i18nKey} skipped`); callback(); return; From 709066bd1ab9619059259348b84515c8e9b9f27e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 19:57:07 -0700 Subject: [PATCH 20/40] [Move] Finish Alluring Voice, Burning Jealousy and Lash Out (#3508) * Implement Alluring Voice and Burning Jealousy * Fix Alluring Voice and add tests * Replace `BattlerTag.STATS_BOOSTED` with `PokemonTurnData` field * Work around bug with turn data * Remove unused variable * Replace nearby instances of `integer` with `number` * Fix imports * Implement Lash Out * Rename `battleStats(In|De)crease` -> `battleStats(In|De)creased` * Fix copy/paste error Co-authored-by: schmidtc1 <62030095+schmidtc1@users.noreply.github.com> * Update tests --------- Co-authored-by: ElliottSimmonds Co-authored-by: schmidtc1 <62030095+schmidtc1@users.noreply.github.com> Co-authored-by: Mumble <171087428+frutescens@users.noreply.github.com> --- src/data/move.ts | 61 ++++++++++++-- src/field/pokemon.ts | 32 ++++---- src/phases/stat-change-phase.ts | 36 ++++++--- src/test/moves/alluring_voice.test.ts | 54 +++++++++++++ src/test/moves/burning_jealousy.test.ts | 103 ++++++++++++++++++++++++ src/test/moves/lash_out.test.ts | 52 ++++++++++++ 6 files changed, 307 insertions(+), 31 deletions(-) create mode 100644 src/test/moves/alluring_voice.test.ts create mode 100644 src/test/moves/burning_jealousy.test.ts create mode 100644 src/test/moves/lash_out.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 2ffa8a36de9..95d306a61ba 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6037,6 +6037,57 @@ export class DestinyBondAttr extends MoveEffectAttr { } } +/** + * Attribute to apply a battler tag to the target if they have had their stats boosted this turn. + * @extends AddBattlerTagAttr + */ +export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr { + constructor(tag: BattlerTagType) { + super(tag, false, false, 2, 5); + } + + /** + * @param user {@linkcode Pokemon} using this move + * @param target {@linkcode Pokemon} target of this move + * @param move {@linkcode Move} being used + * @param {any[]} args N/A + * @returns true + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (target.turnData.battleStatsIncreased) { + super.apply(user, target, move, args); + } + return true; + } +} + +/** + * Attribute to apply a status effect to the target if they have had their stats boosted this turn. + * @extends MoveEffectAttr + */ +export class StatusIfBoostedAttr extends MoveEffectAttr { + public effect: StatusEffect; + + constructor(effect: StatusEffect) { + super(true, MoveEffectTrigger.HIT); + this.effect = effect; + } + + /** + * @param user {@linkcode Pokemon} using this move + * @param target {@linkcode Pokemon} target of this move + * @param move {@linkcode Move} N/A + * @param {any[]} args N/A + * @returns true + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (target.turnData.battleStatsIncreased) { + target.trySetStatus(this.effect, true, user); + } + return true; + } +} + export class LastResortAttr extends MoveAttr { getCondition(): MoveConditionFunc { return (user: Pokemon, target: Pokemon, move: Move) => { @@ -8694,10 +8745,10 @@ export function initMoves() { new AttackMove(Moves.SKITTER_SMACK, Type.BUG, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8) .attr(StatChangeAttr, BattleStat.SPATK, -1), new AttackMove(Moves.BURNING_JEALOUSY, Type.FIRE, MoveCategory.SPECIAL, 70, 100, 5, 100, 0, 8) - .target(MoveTarget.ALL_NEAR_ENEMIES) - .partial(), + .attr(StatusIfBoostedAttr, StatusEffect.BURN) + .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.LASH_OUT, Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8) - .partial(), + .attr(MovePowerMultiplierAttr, (user, target, move) => user.turnData.battleStatsDecreased ? 2 : 1), new AttackMove(Moves.POLTERGEIST, Type.GHOST, MoveCategory.PHYSICAL, 110, 90, 5, -1, 0, 8) .attr(AttackedByItemAttr) .makesContact(false), @@ -9146,8 +9197,8 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.DRAGON_CHEER, false, true) .target(MoveTarget.NEAR_ALLY), new AttackMove(Moves.ALLURING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9) - .soundBased() - .partial(), + .attr(AddBattlerTagIfBoostedAttr, BattlerTagType.CONFUSED) + .soundBased(), new AttackMove(Moves.TEMPER_FLARE, Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9) .attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result === MoveResult.MISS || user.getLastXMoves(2)[1]?.result === MoveResult.FAIL ? 2 : 1), new AttackMove(Moves.SUPERCELL_SLAM, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 00d5f5d3dd2..b1fcd512e35 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4286,7 +4286,7 @@ export interface TurnMove { targets?: BattlerIndex[]; result: MoveResult; virtual?: boolean; - turn?: integer; + turn?: number; } export interface QueuedMove { @@ -4298,17 +4298,17 @@ export interface QueuedMove { export interface AttackMoveResult { move: Moves; result: DamageResult; - damage: integer; + damage: number; critical: boolean; - sourceId: integer; + sourceId: number; sourceBattlerIndex: BattlerIndex; } export class PokemonSummonData { - public battleStats: integer[] = [ 0, 0, 0, 0, 0, 0, 0 ]; + public battleStats: number[] = [ 0, 0, 0, 0, 0, 0, 0 ]; public moveQueue: QueuedMove[] = []; public disabledMove: Moves = Moves.NONE; - public disabledTurns: integer = 0; + public disabledTurns: number = 0; public tags: BattlerTag[] = []; public abilitySuppressed: boolean = false; public abilitiesApplied: Abilities[] = []; @@ -4318,14 +4318,14 @@ export class PokemonSummonData { public ability: Abilities = Abilities.NONE; public gender: Gender; public fusionGender: Gender; - public stats: integer[]; + public stats: number[]; public moveset: (PokemonMove | null)[]; // If not initialized this value will not be populated from save data. public types: Type[] = []; } export class PokemonBattleData { - public hitCount: integer = 0; + public hitCount: number = 0; public endured: boolean = false; public berriesEaten: BerryType[] = []; public abilitiesApplied: Abilities[] = []; @@ -4334,21 +4334,23 @@ export class PokemonBattleData { export class PokemonBattleSummonData { /** The number of turns the pokemon has passed since entering the battle */ - public turnCount: integer = 1; + public turnCount: number = 1; /** The list of moves the pokemon has used since entering the battle */ public moveHistory: TurnMove[] = []; } export class PokemonTurnData { - public flinched: boolean; - public acted: boolean; - public hitCount: integer; - public hitsLeft: integer; - public damageDealt: integer = 0; - public currDamageDealt: integer = 0; - public damageTaken: integer = 0; + public flinched: boolean = false; + public acted: boolean = false; + public hitCount: number; + public hitsLeft: number; + public damageDealt: number = 0; + public currDamageDealt: number = 0; + public damageTaken: number = 0; public attacksReceived: AttackMoveResult[] = []; public order: number; + public battleStatsIncreased: boolean = false; + public battleStatsDecreased: boolean = false; } export enum AiType { diff --git a/src/phases/stat-change-phase.ts b/src/phases/stat-change-phase.ts index 856d0a33eea..3116c49e8ef 100644 --- a/src/phases/stat-change-phase.ts +++ b/src/phases/stat-change-phase.ts @@ -1,14 +1,14 @@ -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 { BattlerIndex } from "#app/battle"; +import BattleScene from "#app/battle-scene"; +import { applyAbAttrs, applyPostStatChangeAbAttrs, applyPreStatChangeAbAttrs, PostStatChangeAbAttr, ProtectStatAbAttr, StatChangeCopyAbAttr, StatChangeMultiplierAbAttr } from "#app/data/ability"; +import { ArenaTagSide, MistTag } from "#app/data/arena-tag"; +import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "#app/data/battle-stat"; +import Pokemon from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { PokemonResetNegativeStatStageModifier } from "#app/modifier/modifier"; +import { handleTutorial, Tutorial } from "#app/tutorial"; +import * as Utils from "#app/utils"; 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; @@ -72,7 +72,7 @@ export class StatChangePhase extends PokemonPhase { } 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]); + 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); @@ -85,6 +85,20 @@ export class StatChangePhase extends PokemonPhase { } for (const stat of filteredStats) { + if (levels.value > 0 && pokemon.summonData.battleStats[stat] < 6) { + if (!pokemon.turnData) { + // Temporary fix for missing turn data struct on turn 1 + pokemon.resetTurnData(); + } + pokemon.turnData.battleStatsIncreased = true; + } else if (levels.value < 0 && pokemon.summonData.battleStats[stat] > -6) { + if (!pokemon.turnData) { + // Temporary fix for missing turn data struct on turn 1 + pokemon.resetTurnData(); + } + pokemon.turnData.battleStatsDecreased = true; + } + pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); } diff --git a/src/test/moves/alluring_voice.test.ts b/src/test/moves/alluring_voice.test.ts new file mode 100644 index 00000000000..e6ece39524a --- /dev/null +++ b/src/test/moves/alluring_voice.test.ts @@ -0,0 +1,54 @@ +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 { 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"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Alluring Voice", () => { + 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") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.ICE_SCALES) + .enemyMoveset(Array(4).fill(Moves.HOWL)) + .startingLevel(10) + .enemyLevel(10) + .starterSpecies(Species.FEEBAS) + .ability(Abilities.BALL_FETCH) + .moveset([Moves.ALLURING_VOICE]); + + }); + + it("should confuse the opponent if their stats were raised", async () => { + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.ALLURING_VOICE); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to(BerryPhase); + + expect(enemy.getTag(BattlerTagType.CONFUSED)?.tagType).toBe("CONFUSED"); + }, TIMEOUT); +}); diff --git a/src/test/moves/burning_jealousy.test.ts b/src/test/moves/burning_jealousy.test.ts new file mode 100644 index 00000000000..2281fe74acb --- /dev/null +++ b/src/test/moves/burning_jealousy.test.ts @@ -0,0 +1,103 @@ +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/enums/abilities"; +import { StatusEffect } from "#app/enums/status-effect"; +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 { SPLASH_ONLY } from "../utils/testUtils"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Burning Jealousy", () => { + 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") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.ICE_SCALES) + .enemyMoveset(Array(4).fill(Moves.HOWL)) + .startingLevel(10) + .enemyLevel(10) + .starterSpecies(Species.FEEBAS) + .ability(Abilities.BALL_FETCH) + .moveset([Moves.BURNING_JEALOUSY, Moves.GROWL]); + + }); + + it("should burn the opponent if their stats were raised", async () => { + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.BURNING_JEALOUSY); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.status?.effect).toBe(StatusEffect.BURN); + }, TIMEOUT); + + it("should still burn the opponent if their stats were both raised and lowered in the same turn", async () => { + game.override + .starterSpecies(0) + .battleType("double"); + await game.classicMode.startBattle([Species.FEEBAS, Species.ABRA]); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.BURNING_JEALOUSY); + game.move.select(Moves.GROWL, 1); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.status?.effect).toBe(StatusEffect.BURN); + }, TIMEOUT); + + it("should ignore stats raised by imposter", async () => { + game.override + .enemySpecies(Species.DITTO) + .enemyAbility(Abilities.IMPOSTER) + .enemyMoveset(SPLASH_ONLY); + await game.classicMode.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.BURNING_JEALOUSY); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy.status?.effect).toBeUndefined(); + }, TIMEOUT); + + it.skip("should ignore weakness policy", async () => { // TODO: Make this test if WP is implemented + await game.classicMode.startBattle(); + }, TIMEOUT); + + it("should be boosted by Sheer Force even if opponent didn't raise stats", async () => { + game.override + .ability(Abilities.SHEER_FORCE) + .enemyMoveset(SPLASH_ONLY); + vi.spyOn(allMoves[Moves.BURNING_JEALOUSY], "calculateBattlePower"); + await game.classicMode.startBattle(); + + game.move.select(Moves.BURNING_JEALOUSY); + await game.phaseInterceptor.to("BerryPhase"); + + expect(allMoves[Moves.BURNING_JEALOUSY].calculateBattlePower).toHaveReturnedWith(allMoves[Moves.BURNING_JEALOUSY].power * 5461 / 4096); + }, TIMEOUT); +}); diff --git a/src/test/moves/lash_out.test.ts b/src/test/moves/lash_out.test.ts new file mode 100644 index 00000000000..78f4b712cf0 --- /dev/null +++ b/src/test/moves/lash_out.test.ts @@ -0,0 +1,52 @@ +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/move"; +import { Abilities } from "#app/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, vi } from "vitest"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Lash Out", () => { + 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") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.FUR_COAT) + .enemyMoveset(Array(4).fill(Moves.GROWL)) + .startingLevel(10) + .enemyLevel(10) + .starterSpecies(Species.FEEBAS) + .ability(Abilities.BALL_FETCH) + .moveset([Moves.LASH_OUT]); + + }); + + it("should deal double damage if the user's stats were lowered this turn", async () => { + vi.spyOn(allMoves[Moves.LASH_OUT], "calculateBattlePower"); + await game.classicMode.startBattle(); + + game.move.select(Moves.LASH_OUT); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("BerryPhase"); + + expect(allMoves[Moves.LASH_OUT].calculateBattlePower).toHaveReturnedWith(150); + }, TIMEOUT); +}); From 80828359e2b135e7b6e2c7c2df990fa6b2d9be8a Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:28:10 -0400 Subject: [PATCH 21/40] [Localization(en)] Fix Roark Dialouge (#3873) * Translate dialogue-male.json via GitLocalize * Added female * ! * Update src/locales/en/dialogue-male.json * Remove empty files * Added missing comma --------- Co-authored-by: Jannik Tappert Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> --- src/locales/de/dialogue.json | 8 ++++---- src/locales/en/dialogue.json | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/locales/de/dialogue.json b/src/locales/de/dialogue.json index e5bcb81ce52..8a3dbb8880e 100644 --- a/src/locales/de/dialogue.json +++ b/src/locales/de/dialogue.json @@ -1403,19 +1403,19 @@ "1": "Ich muss dein Potenzial als Trainer und die Stärke der Pokémon sehen, die mit dir kämpfen!", "2": "Los geht's! Dies sind meine Gesteins-Pokémon, mein ganzer Stolz!", "3": "Gesteins-Pokémon sind einfach die besten!", - "4": "Ich muss dein Potenzial als Trainer und die Stärke der Pokémon sehen, die mit dir kämpfen!" + "4": "Tag für Tag grabe ich hier nach Fossilien.\n$Die viele Arbeit hat meine Pokémon felsenfest gemacht\nund das wirst du jetzt im Kampf zu spüren bekommen!" }, "victory": { "1": "W-was? Das kann nicht sein! Meine total tranierten Pokémon!", "2": "…Wir haben die Kontrolle verloren. Beim nächsten Mal fordere ich dich\n$zu einem Fossilien-Ausgrabungswettbewerb heraus.", "3": "Mit deinem Können ist es nur natürlich, dass du gewinnst.", - "4": "W-was?! Das kann nicht sein! Selbst das war nicht genug?", - "5": "Ich habe es vermasselt." + "4": "W-was?! Das kann nicht sein! Selbst das war nicht genug?" }, "defeat": { "1": "Siehst du? Ich bin stolz auf meinen steinigen Kampfstil!", "2": "Danke! Der Kampf hat mir Vertrauen gegeben, dass ich vielleicht meinen Vater besiegen kann!", - "3": "Ich fühle mich, als hätte ich gerade einen wirklich hartnäckigen Felsen durchbrochen!" + "3": "Na, was sagst du jetzt? Meine felsenfesten Pokémon waren hart genug für dich, was?", + "4": "Ich wusste, dass ich gewinnen würde!" } }, "morty": { diff --git a/src/locales/en/dialogue.json b/src/locales/en/dialogue.json index 1f8919f11b5..90b03a176d1 100644 --- a/src/locales/en/dialogue.json +++ b/src/locales/en/dialogue.json @@ -742,7 +742,7 @@ "plumeria": { "encounter": { "1": " ...Hmph. You don't look like anything special to me.", - "2": "It takes these dumb Grunts way too long to deal with you kids..", + "2": "It takes these dumb Grunts way too long to deal with you kids...", "3": "Mess with anyone in Team Skull, and I'll show you how serious I can get." }, "victory": { @@ -1479,21 +1479,21 @@ "1_female": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", "2": "Here goes! These are my rocking Pokémon, my pride and joy!", "3": "Rock-type Pokémon are simply the best!", - "4": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", - "4_female": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!" + "4": "Every day, I toughened up my Pokémon by digging up Fossils nonstop.\n$Could I show you how tough I made them in a battle?", + "4_female": "Every day, I toughened up my Pokémon by digging up Fossils nonstop.\n$Could I show you how tough I made them in a battle?" }, "victory": { "1": "W-what? That can't be! My buffed-up Pokémon!", "2": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", "2_female": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", "3": "With skill like yours, it's natural for you to win.", - "4": "Wh-what?! It can't be! Even that wasn't enough?", - "5": "I blew it." + "4": "Wh-what?! It can't be! Even that wasn't enough?" }, "defeat": { "1": "See? I'm proud of my rocking battle style!", "2": "Thanks! The battle gave me confidence that I may be able to beat my dad!", - "3": "I feel like I just smashed through a really stubborn boulder!" + "3": "See? These are my rocking Pokémon, my pride and joy!", + "4": "I knew I would win!" } }, "morty": { From 56b39032b9cf272e6b63c31eec2b43f834ef85be Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:30:27 +0800 Subject: [PATCH 22/40] [Dev] add script to create test boilerplate file (#3954) * add script to create test boilerplate file * add more docs * add timeout to template --- create-test-boilerplate.js | 101 +++++++++++++++++++++++++++++++++++++ package.json | 3 +- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 create-test-boilerplate.js diff --git a/create-test-boilerplate.js b/create-test-boilerplate.js new file mode 100644 index 00000000000..bf68258f321 --- /dev/null +++ b/create-test-boilerplate.js @@ -0,0 +1,101 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +/** + * This script creates a test boilerplate file for a move or ability. + * @param {string} type - The type of test to create. Either "move" or "ability". + * @param {string} fileName - The name of the file to create. + * @example npm run create-test move tackle + */ + +// Get the directory name of the current module file +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Get the arguments from the command line +const args = process.argv.slice(2); +const type = args[0]; // "move" or "ability" +let fileName = args[1]; // The file name + +if (!type || !fileName) { + console.error('Please provide both a type ("move" or "ability") and a file name.'); + process.exit(1); +} + +// Convert fileName from to snake_case if camelCase is given +fileName = fileName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); + +// Format the description for the test case +const formattedName = fileName + .replace(/_/g, ' ') + .replace(/\b\w/g, char => char.toUpperCase()); + +// Determine the directory based on the type +let dir; +let description; +if (type === 'move') { + dir = path.join(__dirname, 'src', 'test', 'moves'); + description = `Moves - ${formattedName}`; +} else if (type === 'ability') { + dir = path.join(__dirname, 'src', 'test', 'abilities'); + description = `Abilities - ${formattedName}`; +} else { + console.error('Invalid type. Please use "move" or "ability".'); + process.exit(1); +} + +// Ensure the directory exists +if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); +} + +// Create the file with the given name +const filePath = path.join(dir, `${fileName}.test.ts`); + +if (fs.existsSync(filePath)) { + console.error(`File "${fileName}.test.ts" already exists.`); + process.exit(1); +} + +// Define the content template +const content = `import { Abilities } from "#enums/abilities"; +import GameManager from "#test/utils/gameManager"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, it } from "vitest"; + +describe("${description}", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + const TIMEOUT = 20 * 1000; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(SPLASH_ONLY); + }); + + it("test case", async () => { + // await game.classicMode.startBattle(); + // game.move.select(); + }, TIMEOUT); +}); +`; + +// Write the template content to the file +fs.writeFileSync(filePath, content, 'utf8'); + +console.log(`File created at: ${filePath}`); \ No newline at end of file diff --git a/package.json b/package.json index b85ac639a1b..83e82585d1e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "eslint-ci": "eslint .", "docs": "typedoc", "depcruise": "depcruise src", - "depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg" + "depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg", + "create-test": "node ./create-test-boilerplate.js" }, "devDependencies": { "@eslint/js": "^9.3.0", From 1fd662111e0b668e9f98a7b2c333cd67b9f54c37 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 20:32:31 -0700 Subject: [PATCH 23/40] [Test] Tests now default to using "Set" battle style (#3728) * Tests now default to using "Set" battle style * Fix typo --- src/test/abilities/ability_timing.test.ts | 21 +-- src/test/abilities/disguise.test.ts | 42 ++--- src/test/abilities/intimidate.test.ts | 205 ++++++++-------------- src/test/evolution.test.ts | 27 ++- src/test/evolutions/evolutions.test.ts | 48 ----- src/test/{utils => }/misc.test.ts | 6 +- src/test/moves/spikes.test.ts | 96 ++++------ src/test/utils/gameManager.ts | 2 +- src/test/utils/helpers/settingsHelper.ts | 16 +- 9 files changed, 173 insertions(+), 290 deletions(-) delete mode 100644 src/test/evolutions/evolutions.test.ts rename src/test/{utils => }/misc.test.ts (90%) diff --git a/src/test/abilities/ability_timing.test.ts b/src/test/abilities/ability_timing.test.ts index 3238f880992..fb3d3af1a6b 100644 --- a/src/test/abilities/ability_timing.test.ts +++ b/src/test/abilities/ability_timing.test.ts @@ -1,13 +1,11 @@ +import { BattleStyle } from "#app/enums/battle-style"; 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 { 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"; @@ -28,19 +26,18 @@ describe("Ability Timing", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); - game.override.enemySpecies(Species.PIDGEY); - game.override.enemyAbility(Abilities.INTIMIDATE); - game.override.enemyMoveset(SPLASH_ONLY); - - game.override.ability(Abilities.BALL_FETCH); - game.override.moveset([Moves.SPLASH, Moves.ICE_BEAM]); + game.override + .battleType("single") + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.INTIMIDATE) + .ability(Abilities.BALL_FETCH); }); - it("should trigger after switch check", async() => { + it("should trigger after switch check", async () => { initI18n(); i18next.changeLanguage("en"); + game.settings.battleStyle = BattleStyle.SWITCH; await game.classicMode.runToSummon([Species.EEVEE, Species.FEEBAS]); game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { @@ -48,7 +45,7 @@ describe("Ability Timing", () => { game.endPhase(); }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase)); - await game.phaseInterceptor.to(MessagePhase); + await game.phaseInterceptor.to("MessagePhase"); const message = game.textInterceptor.getLatestMessage(); expect(message).toContain("Attack fell"); }, 5000); diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index 85141fdb491..bbb0a20dc1a 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -1,11 +1,5 @@ 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"; @@ -33,13 +27,12 @@ describe("Abilities - Disguise", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); - - game.override.enemySpecies(Species.MIMIKYU); - game.override.enemyMoveset(SPLASH_ONLY); - - game.override.starterSpecies(Species.REGIELEKI); - game.override.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]); + game.override + .battleType("single") + .enemySpecies(Species.MIMIKYU) + .enemyMoveset(SPLASH_ONLY) + .starterSpecies(Species.REGIELEKI) + .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, takes 1/8 max HP damage from the disguise breaking", async () => { @@ -53,7 +46,7 @@ describe("Abilities - Disguise", () => { game.move.select(Moves.SHADOW_SNEAK); - await game.phaseInterceptor.to(MoveEndPhase); + await game.phaseInterceptor.to("MoveEndPhase"); expect(mimikyu.hp).equals(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(bustedForm); @@ -68,7 +61,7 @@ describe("Abilities - Disguise", () => { game.move.select(Moves.VACUUM_WAVE); - await game.phaseInterceptor.to(MoveEndPhase); + await game.phaseInterceptor.to("MoveEndPhase"); expect(mimikyu.formIndex).toBe(disguisedForm); }, TIMEOUT); @@ -87,12 +80,12 @@ describe("Abilities - Disguise", () => { game.move.select(Moves.SURGING_STRIKES); // First hit - await game.phaseInterceptor.to(MoveEffectPhase); + await game.phaseInterceptor.to("MoveEffectPhase"); expect(mimikyu.hp).equals(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(disguisedForm); // Second hit - await game.phaseInterceptor.to(MoveEffectPhase); + await game.phaseInterceptor.to("MoveEffectPhase"); expect(mimikyu.hp).lessThan(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(bustedForm); }, TIMEOUT); @@ -105,7 +98,7 @@ describe("Abilities - Disguise", () => { game.move.select(Moves.TOXIC_THREAD); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); expect(mimikyu.formIndex).toBe(disguisedForm); expect(mimikyu.status?.effect).toBe(StatusEffect.POISON); @@ -125,7 +118,7 @@ describe("Abilities - Disguise", () => { game.move.select(Moves.SPLASH); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); expect(mimikyu.formIndex).toBe(bustedForm); expect(mimikyu.hp).equals(maxHp - disguiseDamage); @@ -133,7 +126,7 @@ describe("Abilities - Disguise", () => { await game.toNextTurn(); game.doSwitchPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); expect(mimikyu.formIndex).toBe(bustedForm); }, TIMEOUT); @@ -194,15 +187,6 @@ describe("Abilities - Disguise", () => { await game.toNextTurn(); 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); - 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); diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts index 93b663d06da..bc5b5ab1a7d 100644 --- a/src/test/abilities/intimidate.test.ts +++ b/src/test/abilities/intimidate.test.ts @@ -1,12 +1,8 @@ import { BattleStat } from "#app/data/battle-stat"; 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"; @@ -33,36 +29,26 @@ describe("Abilities - Intimidate", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(Abilities.INTIMIDATE); - game.override.enemyPassiveAbility(Abilities.HYDRATION); - game.override.ability(Abilities.INTIMIDATE); - game.override.startingWave(3); - game.override.enemyMoveset(SPLASH_ONLY); + game.override + .battleType("single") + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.INTIMIDATE) + .ability(Abilities.INTIMIDATE) + .moveset([Moves.SPLASH, Moves.AERIAL_ACE]) + .enemyMoveset(SPLASH_ONLY); }); it("single - wild with switch", async () => { - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); - expect(game.scene.getParty()[0].species.speciesId).toBe(Species.MIGHTYENA); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + game.doSwitchPokemon(1); - await game.phaseInterceptor.run(CommandPhase); - await game.phaseInterceptor.to(CommandPhase); - expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + await game.phaseInterceptor.to("CommandPhase"); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); @@ -73,25 +59,16 @@ describe("Abilities - Intimidate", () => { it("single - boss should only trigger once then switch", async () => { game.override.startingWave(10); - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + game.doSwitchPokemon(1); - await game.phaseInterceptor.run(CommandPhase); - await game.phaseInterceptor.to(CommandPhase); - expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + await game.phaseInterceptor.to("CommandPhase"); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); @@ -102,25 +79,16 @@ describe("Abilities - Intimidate", () => { it("single - trainer should only trigger once with switch", async () => { game.override.startingWave(5); - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + game.doSwitchPokemon(1); - await game.phaseInterceptor.run(CommandPhase); - await game.phaseInterceptor.to(CommandPhase); - expect(game.scene.getParty()[0].species.speciesId).toBe(Species.POOCHYENA); + await game.phaseInterceptor.to("CommandPhase"); battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(0); @@ -130,21 +98,14 @@ describe("Abilities - Intimidate", () => { }, 200000); it("double - trainer should only trigger once per pokemon", async () => { - game.override.battleType("double"); - game.override.startingWave(5); - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); + game.override + .battleType("double") + .startingWave(5); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); @@ -157,20 +118,11 @@ describe("Abilities - Intimidate", () => { it("double - wild: should only trigger once per pokemon", async () => { game.override.battleType("double"); - game.override.startingWave(3); - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); @@ -182,21 +134,14 @@ describe("Abilities - Intimidate", () => { }, 20000); it("double - boss: should only trigger once per pokemon", async () => { - game.override.battleType("double"); - game.override.startingWave(10); - await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); - game.onNextPrompt( - "CheckSwitchPhase", - Mode.CONFIRM, - () => { - game.setMode(Mode.MESSAGE); - game.endPhase(); - }, - () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase) - ); - await game.phaseInterceptor.to(CommandPhase, false); + game.override + .battleType("double") + .startingWave(10); + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-2); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-2); @@ -208,104 +153,101 @@ describe("Abilities - Intimidate", () => { }, 20000); it("single - wild next wave opp triger once, us: none", async () => { - game.override.startingWave(2); - game.override.moveset([Moves.AERIAL_ACE]); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + await game.startBattle([Species.MIGHTYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); 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); + await game.phaseInterceptor.to("DamagePhase"); + await game.doKillOpponents(); await game.toNextWave(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); }, 20000); it("single - wild next turn - no retrigger on next turn", async () => { - game.override.startingWave(2); - game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + await game.startBattle([Species.MIGHTYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.move.select(Moves.AERIAL_ACE); - console.log("===to new turn==="); + game.move.select(Moves.SPLASH); await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); }, 20000); it("single - trainer should only trigger once and each time he switch", async () => { - game.override.moveset([Moves.SPLASH]); - game.override.enemyMoveset([Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH, Moves.VOLT_SWITCH]); - game.override.startingWave(5); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + game.override + .enemyMoveset(Array(4).fill(Moves.VOLT_SWITCH)) + .startingWave(5); + await game.startBattle([Species.MIGHTYENA]); + let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.move.select(Moves.AERIAL_ACE); - console.log("===to new turn==="); + game.move.select(Moves.SPLASH); await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-2); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); - game.move.select(Moves.AERIAL_ACE); - console.log("===to new turn==="); + game.move.select(Moves.SPLASH); await game.toNextTurn(); + battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-3); + battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(0); }, 200000); it("single - trainer should only trigger once whatever turn we are", async () => { - game.override.moveset([Moves.SPLASH]); - game.override.enemyMoveset(SPLASH_ONLY); game.override.startingWave(5); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); - let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + await game.startBattle([Species.MIGHTYENA]); + + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; + const battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; + expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); - let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - game.move.select(Moves.AERIAL_ACE); - console.log("===to new turn==="); + game.move.select(Moves.SPLASH); await game.toNextTurn(); - battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; - expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; - expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); - game.move.select(Moves.AERIAL_ACE); - console.log("===to new turn==="); - await game.toNextTurn(); - battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats; expect(battleStatsPokemon[BattleStat.ATK]).toBe(-1); - battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); }, 20000); it("double - wild vs only 1 on player side", async () => { game.override.battleType("double"); - game.override.startingWave(3); await game.classicMode.runToSummon([Species.MIGHTYENA]); - await game.phaseInterceptor.to(CommandPhase, false); + await game.phaseInterceptor.to("CommandPhase", false); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-1); @@ -315,7 +257,6 @@ describe("Abilities - Intimidate", () => { it("double - wild vs only 1 alive on player side", async () => { game.override.battleType("double"); - game.override.startingWave(3); await game.runToTitle(); game.onNextPrompt("TitlePhase", Mode.TITLE, () => { @@ -330,9 +271,11 @@ describe("Abilities - Intimidate", () => { await game.phaseInterceptor.run(EncounterPhase); - await game.phaseInterceptor.to(CommandPhase, false); + await game.phaseInterceptor.to("CommandPhase", false); + const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); + const battleStatsOpponent2 = game.scene.currentBattle.enemyParty[1].summonData.battleStats; expect(battleStatsOpponent2[BattleStat.ATK]).toBe(-1); diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index f9123cf6d9a..5844e92ab8d 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -2,9 +2,10 @@ import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } fr import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; +import * as Utils from "#app/utils"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SPLASH_ONLY } from "./utils/testUtils"; describe("Evolution", () => { @@ -148,4 +149,28 @@ describe("Evolution", () => { expect(cyndaquil.hp).toBeGreaterThan(hpBefore); expect(cyndaquil.hp).toBeLessThan(cyndaquil.getMaxHp()); }, TIMEOUT); + + it("should handle rng-based split evolution", async () => { + /* this test checks to make sure that tandemaus will + * evolve into a 3 family maushold 25% of the time + * and a 4 family maushold the other 75% of the time + * This is done by using the getEvolution method in pokemon.ts + * getEvolution will give back the form that the pokemon can evolve into + * It does this by checking the pokemon conditions in pokemon-forms.ts + * For tandemaus, the conditions are random due to a randSeedInt(4) + * If the value is 0, it's a 3 family maushold, whereas if the value is + * 1, 2 or 3, it's a 4 family maushold + */ + await game.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus + const playerPokemon = game.scene.getPlayerPokemon()!; + playerPokemon.level = 25; // tandemaus evolves at level 25 + vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold + const threeForm = playerPokemon.getEvolution()!; + expect(threeForm.evoFormKey).toBe("three"); // as per pokemon-forms, the evoFormKey for 3 family mausholds is "three" + for (let f = 1; f < 4; f++) { + vi.spyOn(Utils, "randSeedInt").mockReturnValue(f); // setting the random generator to 1, 2 and 3 to force 4 family mausholds + const fourForm = playerPokemon.getEvolution()!; + expect(fourForm.evoFormKey).toBe(null); // meanwhile, according to the pokemon-forms, the evoFormKey for a 4 family maushold is null + } + }, TIMEOUT); }); diff --git a/src/test/evolutions/evolutions.test.ts b/src/test/evolutions/evolutions.test.ts deleted file mode 100644 index 2028764115c..00000000000 --- a/src/test/evolutions/evolutions.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -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; - let game: GameManager; - - beforeAll(() => { - phaserGame = new Phaser.Game({ - type: Phaser.HEADLESS, - }); - }); - - afterEach(() => { - game.phaseInterceptor.restoreOg(); - }); - - beforeEach(() => { - game = new GameManager(phaserGame); - }); - - it("tandemaus evolution form test", async () => { - /* this test checks to make sure that tandemaus will - * evolve into a 3 family maushold 25% of the time - * and a 4 family maushold the other 75% of the time - * This is done by using the getEvolution method in pokemon.ts - * getEvolution will give back the form that the pokemon can evolve into - * It does this by checking the pokemon conditions in pokemon-forms.ts - * For tandemaus, the conditions are random due to a randSeedInt(4) - * If the value is 0, it's a 3 family maushold, whereas if the value is - * 1, 2 or 3, it's a 4 family maushold - */ - await game.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus - const playerPokemon = game.scene.getPlayerPokemon()!; - playerPokemon.level = 25; // tandemaus evolves at level 25 - vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold - const threeForm = playerPokemon.getEvolution()!; - expect(threeForm.evoFormKey).toBe("three"); // as per pokemon-forms, the evoFormKey for 3 family mausholds is "three" - for (let f = 1; f < 4; f++) { - vi.spyOn(Utils, "randSeedInt").mockReturnValue(f); // setting the random generator to 1, 2 and 3 to force 4 family mausholds - const fourForm = playerPokemon.getEvolution()!; - expect(fourForm.evoFormKey).toBe(null); // meanwhile, according to the pokemon-forms, the evoFormKey for a 4 family maushold is null - } - }, 5000); -}); diff --git a/src/test/utils/misc.test.ts b/src/test/misc.test.ts similarity index 90% rename from src/test/utils/misc.test.ts rename to src/test/misc.test.ts index d7c10144ead..1052a282a64 100644 --- a/src/test/utils/misc.test.ts +++ b/src/test/misc.test.ts @@ -30,7 +30,7 @@ describe("Test misc", () => { return response.json(); }).then(data => { spy(); // Call the spy function - expect(data).toEqual({"username":"greenlamp", "lastSessionSlot":0}); + expect(data).toEqual({ "username": "greenlamp", "lastSessionSlot": 0 }); }); expect(spy).toHaveBeenCalled(); }); @@ -43,7 +43,7 @@ describe("Test misc", () => { return response.json(); }).then(data => { spy(); // Call the spy function - expect(data).toEqual({"username":"greenlamp", "lastSessionSlot":0}); + expect(data).toEqual({ "username": "greenlamp", "lastSessionSlot": 0 }); }); expect(spy).toHaveBeenCalled(); }); @@ -54,7 +54,7 @@ describe("Test misc", () => { expect(response.ok).toBe(true); expect(response.status).toBe(200); - expect(data).toEqual({"username":"greenlamp", "lastSessionSlot":0}); + expect(data).toEqual({ "username": "greenlamp", "lastSessionSlot": 0 }); }); it("test apifetch mock sync", async () => { diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts index c4096111c6f..05ea717ebbe 100644 --- a/src/test/moves/spikes.test.ts +++ b/src/test/moves/spikes.test.ts @@ -1,10 +1,10 @@ -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"; +import { SPLASH_ONLY } from "../utils/testUtils"; describe("Moves - Spikes", () => { @@ -23,93 +23,61 @@ describe("Moves - Spikes", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.scene.battleStyle = 1; - game.override.battleType("single"); - game.override.enemySpecies(Species.RATTATA); - game.override.enemyAbility(Abilities.HYDRATION); - game.override.enemyPassiveAbility(Abilities.HYDRATION); - 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 + .battleType("single") + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .ability(Abilities.BALL_FETCH) + .enemyMoveset(SPLASH_ONLY) + .moveset([Moves.SPIKES, Moves.SPLASH, Moves.ROAR]); }); - it("single - wild - stay on field - no damage", async () => { - await game.classicMode.runToSummon([ - Species.MIGHTYENA, - Species.POOCHYENA, - ]); - await game.phaseInterceptor.to(CommandPhase, true); - const initialHp = game.scene.getParty()[0].hp; - expect(game.scene.getParty()[0].hp).toBe(initialHp); + it("should not damage the team that set them", async () => { + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + game.move.select(Moves.SPIKES); await game.toNextTurn(); + game.move.select(Moves.SPLASH); await game.toNextTurn(); - expect(game.scene.getParty()[0].hp).toBe(initialHp); - }, 20000); - - 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 - await game.classicMode.runToSummon([ - Species.MIGHTYENA, - Species.POOCHYENA, - ]); - await game.phaseInterceptor.to(CommandPhase, false); - - const initialHp = game.scene.getParty()[0].hp; - game.doSwitchPokemon(1); - await game.phaseInterceptor.run(CommandPhase); - await game.phaseInterceptor.to(CommandPhase, false); game.doSwitchPokemon(1); - await game.phaseInterceptor.run(CommandPhase); - await game.phaseInterceptor.to(CommandPhase, false); + await game.toNextTurn(); - expect(game.scene.getParty()[0].hp).toBe(initialHp); + game.doSwitchPokemon(1); + await game.toNextTurn(); + + const player = game.scene.getParty()[0]; + expect(player.hp).toBe(player.getMaxHp()); }, 20000); - it("trainer - wild - force switch opponent - should take damage", async () => { + it("should damage opposing pokemon that are forced to switch in", async () => { game.override.startingWave(5); - // player set spikes on the field and do splash for 3 turns - // opponent do splash for 4 turns - // nobody should take damage - await game.classicMode.runToSummon([ - Species.MIGHTYENA, - Species.POOCHYENA, - ]); - await game.phaseInterceptor.to(CommandPhase, true); - const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + game.move.select(Moves.SPIKES); await game.toNextTurn(); + game.move.select(Moves.ROAR); await game.toNextTurn(); - expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); + + const enemy = game.scene.getEnemyParty()[0]; + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); }, 20000); - it("trainer - wild - force switch by himself opponent - should take damage", async () => { + it("should damage opposing pokemon that choose to switch in", async () => { game.override.startingWave(5); - game.override.startingLevel(5000); - game.override.enemySpecies(0); - // turn 1: player set spikes, opponent do splash - // turn 2: player do splash, opponent switch pokemon - // opponent pokemon should trigger spikes and lose HP - await game.classicMode.runToSummon([ - Species.MIGHTYENA, - Species.POOCHYENA, - ]); - await game.phaseInterceptor.to(CommandPhase, true); - const initialHpOpponent = game.scene.currentBattle.enemyParty[1].hp; + await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + game.move.select(Moves.SPIKES); await game.toNextTurn(); - game.forceOpponentToSwitch(); game.move.select(Moves.SPLASH); + game.forceOpponentToSwitch(); await game.toNextTurn(); - expect(game.scene.currentBattle.enemyParty[0].hp).toBeLessThan(initialHpOpponent); + + const enemy = game.scene.getEnemyParty()[0]; + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); }, 20000); }); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index a9a71d16bf7..6724e05521c 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -139,7 +139,7 @@ export default class GameManager { this.scene.hpBarSpeed = 3; this.scene.enableTutorials = false; this.scene.gameData.gender = PlayerGender.MALE; // set initial player gender - + this.scene.battleStyle = this.settings.battleStyle; } /** diff --git a/src/test/utils/helpers/settingsHelper.ts b/src/test/utils/helpers/settingsHelper.ts index 76ffafdbe10..8fca2a34d47 100644 --- a/src/test/utils/helpers/settingsHelper.ts +++ b/src/test/utils/helpers/settingsHelper.ts @@ -1,16 +1,30 @@ import { PlayerGender } from "#app/enums/player-gender"; +import { BattleStyle } from "#app/enums/battle-style"; import { GameManagerHelper } from "./gameManagerHelper"; /** * Helper to handle settings for tests */ export class SettingsHelper extends GameManagerHelper { + private _battleStyle: BattleStyle = BattleStyle.SET; + + get battleStyle(): BattleStyle { + return this._battleStyle; + } + + /** + * Change the battle style to Switch or Set mode (tests default to {@linkcode BattleStyle.SET}) + * @param mode {@linkcode BattleStyle.SWITCH} or {@linkcode BattleStyle.SET} + */ + set battleStyle(mode: BattleStyle.SWITCH | BattleStyle.SET) { + this._battleStyle = mode; + } /** * Disable/Enable type hints settings * @param enable true to enabled, false to disabled */ - typeHints(enable: boolean) { + typeHints(enable: boolean): void { this.game.scene.typeHints = enable; this.log(`Type Hints ${enable? "enabled" : "disabled"}` ); } From e29f1fe5fd5f8aceb0a69ae1b25305ad2267aeaa Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sun, 1 Sep 2024 20:39:26 -0700 Subject: [PATCH 24/40] [Bug] Fix some trapping moves' interactions with Ghost-type Pokemon (#3936) * Fix secondary effects to trapping moves not applying to Ghost types * Docs for `isTrapped` * more `isTrapped` cleanup * Remove .js from imports --- src/data/battler-tags.ts | 23 ++++++++++- src/data/move.ts | 2 +- src/enums/battler-tag-type.ts | 1 + src/field/pokemon.ts | 26 +++++++++++- src/phases/command-phase.ts | 68 ++++++++++++++----------------- src/phases/enemy-command-phase.ts | 14 ++----- 6 files changed, 82 insertions(+), 52 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 38db36e86f6..2e280634d5d 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -212,7 +212,7 @@ export class TrappedTag extends BattlerTag { canAdd(pokemon: Pokemon): boolean { const isGhost = pokemon.isOfType(Type.GHOST); - const isTrapped = pokemon.getTag(BattlerTagType.TRAPPED); + const isTrapped = pokemon.getTag(TrappedTag); return !isTrapped && !isGhost; } @@ -245,6 +245,23 @@ export class TrappedTag extends BattlerTag { } } +/** + * BattlerTag implementing No Retreat's trapping effect. + * This is treated separately from other trapping effects to prevent + * Ghost-type Pokemon from being able to reuse the move. + * @extends TrappedTag + */ +class NoRetreatTag extends TrappedTag { + constructor(sourceId: number) { + super(BattlerTagType.NO_RETREAT, BattlerTagLapseType.CUSTOM, 0, Moves.NO_RETREAT, sourceId); + } + + /** overrides {@linkcode TrappedTag.apply}, removing the Ghost-type condition */ + canAdd(pokemon: Pokemon): boolean { + return !pokemon.getTag(TrappedTag); + } +} + /** * BattlerTag that represents the {@link https://bulbapedia.bulbagarden.net/wiki/Flinch Flinch} status condition */ @@ -864,7 +881,7 @@ export abstract class DamagingTrapTag extends TrappedTag { } canAdd(pokemon: Pokemon): boolean { - return !pokemon.isOfType(Type.GHOST) && !pokemon.findTag(t => t instanceof DamagingTrapTag); + return !pokemon.getTag(TrappedTag); } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { @@ -1883,6 +1900,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new DrowsyTag(); case BattlerTagType.TRAPPED: return new TrappedTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); + case BattlerTagType.NO_RETREAT: + return new NoRetreatTag(sourceId); case BattlerTagType.BIND: return new BindTag(turnCount, sourceId); case BattlerTagType.WRAP: diff --git a/src/data/move.ts b/src/data/move.ts index 95d306a61ba..3f87fc68b89 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8553,7 +8553,7 @@ export function initMoves() { .partial(), new SelfStatusMove(Moves.NO_RETREAT, Type.FIGHTING, -1, 5, -1, 0, 8) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true) - .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, false, 1) + .attr(AddBattlerTagAttr, BattlerTagType.NO_RETREAT, true, false) .condition((user, target, move) => user.getTag(TrappedTag)?.sourceMove !== Moves.NO_RETREAT), // fails if the user is currently trapped by No Retreat new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, -1, 0, 8) .attr(StatChangeAttr, BattleStat.SPD, -1) diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 73580a107b2..20ceb1b331f 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -71,4 +71,5 @@ export enum BattlerTagType { BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING", SHELL_TRAP = "SHELL_TRAP", DRAGON_CHEER = "DRAGON_CHEER", + NO_RETREAT = "NO_RETREAT", } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b1fcd512e35..d8acddecedf 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -18,11 +18,11 @@ 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 { BattleStat } from "../data/battle-stat"; -import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag, DragonCheerTag, CritBoostTag } from "../data/battler-tags"; +import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag } from "../data/battler-tags"; import { WeatherType } from "../data/weather"; import { TempBattleStat } from "../data/temp-battle-stat"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; -import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr } from "../data/ability"; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr } from "../data/ability"; import PokemonData from "../system/pokemon-data"; import { BattlerIndex } from "../battle"; import { Mode } from "../ui/ui"; @@ -1210,6 +1210,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return !!this.getTag(GroundedTag) || (!this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE) && !this.getTag(BattlerTagType.MAGNET_RISEN) && !this.getTag(SemiInvulnerableTag)); } + /** + * Determines whether this Pokemon is prevented from running or switching due + * to effects from moves and/or abilities. + * @param trappedAbMessages `string[]` If defined, ability trigger messages + * (e.g. from Shadow Tag) are forwarded through this array. + * @param simulated `boolean` if `true`, applies abilities via simulated calls. + * @returns + */ + isTrapped(trappedAbMessages: string[] = [], simulated: boolean = true): boolean { + if (this.isOfType(Type.GHOST)) { + return false; + } + + const trappedByAbility = new Utils.BooleanHolder(false); + + this.scene.getEnemyField()!.forEach(enemyPokemon => + applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trappedByAbility, this, trappedAbMessages, simulated) + ); + + return (trappedByAbility.value || !!this.getTag(TrappedTag)); + } + /** * Calculates the type of a move when used by this Pokemon after * type-changing move and ability attributes have applied. diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 68ede826d95..9681a6eeee8 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -1,21 +1,18 @@ -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 BattleScene from "#app/battle-scene"; +import { TurnCommand, BattleType } from "#app/battle"; +import { TrappedTag, EncoreTag } from "#app/data/battler-tags"; +import { MoveTargetSet, getMoveTargets } from "#app/data/move"; +import { speciesStarters } from "#app/data/pokemon-species"; +import { Abilities } from "#app/enums/abilities"; +import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { Biome } from "#app/enums/biome"; +import { Moves } from "#app/enums/moves"; +import { PokeballType } from "#app/enums/pokeball"; +import { FieldPosition, PlayerPokemon } from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { Command } from "#app/ui/command-ui-handler"; +import { Mode } from "#app/ui/ui"; import i18next from "i18next"; -import * as Utils from "#app/utils.js"; import { FieldPhase } from "./field-phase"; import { SelectTargetPhase } from "./select-target-phase"; @@ -77,7 +74,6 @@ export class CommandPhase extends FieldPhase { 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) { @@ -184,14 +180,9 @@ export class CommandPhase extends FieldPhase { 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, trappedAbMessages, true)); - } - if (batonPass || (!trapTag && !trapped.value)) { + if (batonPass || !playerPokemon.isTrapped(trappedAbMessages)) { this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch ? { command: Command.POKEMON, cursor: cursor, args: args } : { command: Command.RUN }; @@ -199,14 +190,27 @@ export class CommandPhase extends FieldPhase { 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; + } else if (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); + } else { + const trapTag = playerPokemon.getTag(TrappedTag); + + // trapTag should be defined at this point, but just in case... + if (!trapTag) { 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); @@ -224,16 +228,6 @@ export class CommandPhase extends FieldPhase { 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; diff --git a/src/phases/enemy-command-phase.ts b/src/phases/enemy-command-phase.ts index 5277b2666c7..d9bb08d6fae 100644 --- a/src/phases/enemy-command-phase.ts +++ b/src/phases/enemy-command-phase.ts @@ -1,9 +1,6 @@ -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 BattleScene from "#app/battle-scene"; +import { BattlerIndex } from "#app/battle"; +import { Command } from "#app/ui/command-ui-handler"; import { FieldPhase } from "./field-phase"; /** @@ -45,10 +42,7 @@ export class EnemyCommandPhase extends FieldPhase { 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) { + if (!enemyPokemon.isTrapped()) { const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true); if (partyMemberScores.length) { From 781bfd831f1b137bf2d0834917cd3177c67ae689 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:55:07 -0400 Subject: [PATCH 25/40] [Localization] pokemon names, party-ui-handler, pokemon-info and pokemon-info-container localizations for italian (#3836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translate pokemon-info-container.json via GitLocalize * Translate pokemon-info.json via GitLocalize * Translate party-ui-handler.json via GitLocalize * Translate pokemon.json via GitLocalize --------- Co-authored-by: Niccolò --- src/locales/it/party-ui-handler.json | 87 ++++++++++++---------- src/locales/it/pokemon-info-container.json | 5 +- src/locales/it/pokemon.json | 24 +++++- 3 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/locales/it/party-ui-handler.json b/src/locales/it/party-ui-handler.json index f5582e5b630..95466779727 100644 --- a/src/locales/it/party-ui-handler.json +++ b/src/locales/it/party-ui-handler.json @@ -1,42 +1,47 @@ { - "SEND_OUT": "Manda in campo", - "SUMMARY": "Sommario", - "CANCEL": "Annulla", - "RELEASE": "Rilascia", - "APPLY": "Applica", - "TEACH": "Insegna", - "SPLICE": "Unisci", - "UNSPLICE": "Dividi", - "ACTIVATE": "Attiva", - "DEACTIVATE": "Disattiva", - "TRANSFER": "Trasferisci", - "ALL": "Tutto", - "PASS_BATON": "Staffetta", - "UNPAUSE_EVOLUTION": "Consenti evoluzione", - "REVIVE": "Revitalizza", - "RENAME": "Rinomina", - "choosePokemon": "Scegli un Pokémon.", - "doWhatWithThisPokemon": "Hai selezionato questo Pokémon.", - "noEnergy": "{{pokemonName}} non ha più energie\nper lottare!", - "hasEnergy": "{{pokemonName}} ha ancora energie\nper lottare!", - "cantBeUsed": "{{pokemonName}} non può essere usato\nin questa sfida!", - "tooManyItems": "{{pokemonName}} possiede già\nquest'oggetto in abbondanza!", - "anyEffect": "Non avrebbe alcun effetto.", - "unpausedEvolutions": "{{pokemonName}} può di nuovo evolversi.", - "unspliceConfirmation": "Vuoi davvero dividere {{fusionName}}\nda {{pokemonName}}? {{fusionName}} andrà perduto.", - "wasReverted": "{{fusionName}} è tornato ad essere {{pokemonName}}.", - "releaseConfirmation": "Vuoi davvero liberare {{pokemonName}}?", - "releaseInBattle": "Non puoi liberare un Pokémon che sta combattendo!", - "selectAMove": "Scegli una mossa.", - "changeQuantity": "Scegli un oggetto da trasferire.\nUsa < e > per cambiarne la quantità.", - "selectAnotherPokemonToSplice": "Scegli un altro Pokémon da unire.", - "cancel": "Annulla", - "goodbye": "Addio, {{pokemonName}}!", - "byebye": "Ciao ciao, {{pokemonName}}!", - "farewell": "Arrivederci, {{pokemonName}}!", - "soLong": "È stato bello, {{pokemonName}}!", - "thisIsWhereWePart": "Le nostre strade si dividono, {{pokemonName}}!", - "illMissYou": "Mi mancherai, {{pokemonName}}!", - "illNeverForgetYou": "Non ti dimenticherò, {{pokemonName}}!", - "untilWeMeetAgain": "Alla prossima, {{pokemonName}}!" - } \ No newline at end of file + "SEND_OUT": "Manda in campo", + "SUMMARY": "Sommario", + "CANCEL": "Annulla", + "RELEASE": "Rilascia", + "APPLY": "Applica", + "TEACH": "Insegna", + "SPLICE": "Unisci", + "UNSPLICE": "Dividi", + "ACTIVATE": "Attiva", + "DEACTIVATE": "Disattiva", + "TRANSFER": "Trasferisci", + "ALL": "Tutto", + "PASS_BATON": "Staffetta", + "UNPAUSE_EVOLUTION": "Consenti evoluzione", + "REVIVE": "Revitalizza", + "RENAME": "Rinomina", + "choosePokemon": "Scegli un Pokémon.", + "doWhatWithThisPokemon": "Hai selezionato questo Pokémon.", + "noEnergy": "{{pokemonName}} non ha più energie\nper lottare!", + "hasEnergy": "{{pokemonName}} ha ancora energie\nper lottare!", + "cantBeUsed": "{{pokemonName}} non può essere usato\nin questa sfida!", + "tooManyItems": "{{pokemonName}} possiede già\nquest'oggetto in abbondanza!", + "anyEffect": "Non avrebbe alcun effetto.", + "unpausedEvolutions": "{{pokemonName}} può di nuovo evolversi.", + "unspliceConfirmation": "Vuoi davvero dividere {{fusionName}}\nda {{pokemonName}}? {{fusionName}} andrà perduto.", + "wasReverted": "{{fusionName}} è tornato ad essere {{pokemonName}}.", + "releaseConfirmation": "Vuoi davvero liberare {{pokemonName}}?", + "releaseInBattle": "Non puoi liberare un Pokémon che sta combattendo!", + "selectAMove": "Scegli una mossa.", + "changeQuantity": "Scegli un oggetto da trasferire.\nUsa < e > per cambiarne la quantità.", + "selectAnotherPokemonToSplice": "Scegli un altro Pokémon da unire.", + "cancel": "Annulla", + "able": "Sì!", + "notAble": "No!", + "learned": "La conosce!", + "goodbye": "Addio, {{pokemonName}}!", + "byebye": "Ciao ciao, {{pokemonName}}!", + "farewell": "Arrivederci, {{pokemonName}}!", + "soLong": "È stato bello, {{pokemonName}}!", + "thisIsWhereWePart": "Le nostre strade si dividono, {{pokemonName}}!", + "illMissYou": "Mi mancherai, {{pokemonName}}!", + "illNeverForgetYou": "Non ti dimenticherò, {{pokemonName}}!", + "untilWeMeetAgain": "Alla prossima, {{pokemonName}}!", + "sayonara": "Sayonara, {{pokemonName}}!", + "smellYaLater": "Ci becchiamo, {{pokemonName}}!" +} diff --git a/src/locales/it/pokemon-info-container.json b/src/locales/it/pokemon-info-container.json index c3cc8d49ce1..f3de9081ebc 100644 --- a/src/locales/it/pokemon-info-container.json +++ b/src/locales/it/pokemon-info-container.json @@ -2,5 +2,6 @@ "moveset": "Set di mosse", "gender": "Genere:", "ability": "Abilità:", - "nature": "Natura:" -} \ No newline at end of file + "nature": "Natura:", + "form": "Forma:" +} diff --git a/src/locales/it/pokemon.json b/src/locales/it/pokemon.json index 9e26dfeeb6e..dcc4cc7f310 100644 --- a/src/locales/it/pokemon.json +++ b/src/locales/it/pokemon.json @@ -1 +1,23 @@ -{} \ No newline at end of file +{ + "type_null": "Tipo Zero", + "great_tusk": "Grandizanne", + "scream_tail": "Codaurlante", + "brute_bonnet": "Fungofurioso", + "flutter_mane": "Crinealato", + "slither_wing": "Alirasenti", + "sandy_shocks": "Peldisabbia", + "iron_treads": "Solcoferreo", + "iron_bundle": "Saccoferreo", + "iron_hands": "Manoferrea", + "iron_jugulis": "Colloferreo", + "iron_moth": "Falenaferrea", + "iron_thorns": "Spineferree", + "roaring_moon": "Lunaruggente", + "iron_valiant": "Eroeferreo", + "walking_wake": "Acquecrespe", + "iron_leaves": "Fogliaferrea", + "gouging_fire": "Vampeaguzze", + "raging_bolt": "Furiatonante", + "iron_boulder": "Massoferreo", + "iron_crown": "Capoferreo" +} From 08fe9e1e2134045b1f542875168b0062489410a5 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:57:28 -0400 Subject: [PATCH 26/40] [Localization(fr)] Translate trainer-classes.json (#3882) Co-authored-by: Lugiad --- src/locales/fr/trainer-classes.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/locales/fr/trainer-classes.json b/src/locales/fr/trainer-classes.json index cebdadf09e9..b7027cf544f 100644 --- a/src/locales/fr/trainer-classes.json +++ b/src/locales/fr/trainer-classes.json @@ -101,8 +101,8 @@ "workers": "Ouvriers", "youngster": "Gamin", "rocket_grunt": "Sbire de la Team Rocket", - "rocket_grunt_female": "Sbire de la Team Rocket", "rocket_grunts": "Sbires de la Team Rocket", + "rocket_grunt_female": "Sbire de la Team Rocket", "magma_grunt": "Sbire de la Team Magma", "magma_grunt_female": "Sbire de la Team Magma", "magma_grunts": "Sbires de la Team Magma", @@ -123,6 +123,7 @@ "aether_grunts": "Employés de la Fondation Æther", "skull_grunt": "Sbire de la Team Skull", "skull_grunt_female": "Sbire de la Team Skull", + "skull_grunts": "Sbires de la Team Skull", "macro_grunt": "Employé de Macro Cosmos", "macro_grunt_female": "Employée de Macro Cosmos", "macro_grunts": "Employés de Macro Cosmos" From 8edb9ca65b1b8a02c1a33421cf04605e22891a2a Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:57:48 -0400 Subject: [PATCH 27/40] [Localizaiton(pt_br)] Translate pokemon-summary.json via GitLocalize (#3868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Ricardo --- src/locales/pt_BR/pokemon-summary.json | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/locales/pt_BR/pokemon-summary.json b/src/locales/pt_BR/pokemon-summary.json index 62add589847..4c427dbac4f 100644 --- a/src/locales/pt_BR/pokemon-summary.json +++ b/src/locales/pt_BR/pokemon-summary.json @@ -13,5 +13,32 @@ "metFragment": { "normal": "encontrado no Nv.{{level}},\n{{biome}}.", "apparently": "aparentemente encontrado no Nv.{{level}},\n{{biome}}." + }, + "natureFragment": { + "Hardy": "{{nature}}", + "Lonely": "{{nature}}", + "Brave": "{{nature}}", + "Adamant": "{{nature}}", + "Naughty": "{{nature}}", + "Bold": "{{nature}}", + "Docile": "{{nature}}", + "Relaxed": "{{nature}}", + "Impish": "{{nature}}", + "Lax": "{{nature}}", + "Timid": "{{nature}}", + "Hasty": "{{nature}}", + "Serious": "{{nature}}", + "Jolly": "{{nature}}", + "Naive": "{{nature}}", + "Modest": "{{nature}}", + "Mild": "{{nature}}", + "Quiet": "{{nature}}", + "Bashful": "{{nature}}", + "Rash": "{{nature}}", + "Calm": "{{nature}}", + "Gentle": "{{nature}}", + "Sassy": "{{nature}}", + "Careful": "{{nature}}", + "Quirky": "{{nature}}" } -} \ No newline at end of file +} From c4c9cf939eaa9118bf0350bae495a6bdd6068401 Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:09:46 -0700 Subject: [PATCH 28/40] [Bug] Moved RNG call if the Pokemon's ability hasn't been determined (#3966) Co-authored-by: frutescens --- src/field/pokemon.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index d8acddecedf..16ad96f61cc 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -133,9 +133,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance); } - const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); - const randAbilityIndex = Utils.randSeedInt(2); - this.species = species; this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL; this.level = level; @@ -146,6 +143,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined } else { // If abilityIndex is not provided, determine it based on species and hidden ability + const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); + const randAbilityIndex = Utils.randSeedInt(2); if (species.abilityHidden && hasHiddenAbility) { // If the species has a hidden ability and the hidden ability is present this.abilityIndex = 2; From 0671a244a86c6f9711c64586d3932f3bc7db9b0b Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:16:54 -0400 Subject: [PATCH 29/40] [Localisation] [ES] Reviewed and finished ability.json and bgm-name.json (#3920) * Translate ability.json via GitLocalize * Translate ability.json via GitLocalize * Translate bgm-name.json via GitLocalize --------- Co-authored-by: Asdar Co-authored-by: LilyAlternis --- src/locales/es/ability.json | 752 +++++++++++++++++------------------ src/locales/es/bgm-name.json | 218 +++++----- 2 files changed, 487 insertions(+), 483 deletions(-) diff --git a/src/locales/es/ability.json b/src/locales/es/ability.json index 807cc755c94..598694f441e 100644 --- a/src/locales/es/ability.json +++ b/src/locales/es/ability.json @@ -1,1242 +1,1242 @@ { "stench": { - "name": "Hedor", + "name": "Hedor", "description": "Puede amedrentar a un Pokémon al atacarlo debido al mal olor que emana." }, "drizzle": { - "name": "Llovizna", + "name": "Llovizna", "description": "Hace que llueva al entrar en combate." }, "speedBoost": { - "name": "Impulso", + "name": "Impulso", "description": "Aumenta su Velocidad en cada turno." }, "battleArmor": { - "name": "Armadura Batalla", + "name": "Armadura Batalla", "description": "La robusta coraza que lo protege bloquea los golpes críticos." }, "sturdy": { - "name": "Robustez", + "name": "Robustez", "description": "El Pokémon no puede debilitarse de un solo golpe cuando tiene los PS al máximo. También evita los movimientos fulminantes." }, "damp": { - "name": "Humedad", + "name": "Humedad", "description": "Aumenta la humedad del entorno y evita que se puedan utilizar movimientos explosivos, tales como Autodestrucción." }, "limber": { - "name": "Flexibilidad", + "name": "Flexibilidad", "description": "Evita ser paralizado gracias a la flexibilidad de su cuerpo." }, "sandVeil": { - "name": "Velo Arena", + "name": "Velo Arena", "description": "Aumenta su Evasión durante las tormentas de arena." }, "static": { - "name": "Elec. Estática", + "name": "Elec. Estática", "description": "La electricidad estática que lo envuelve puede paralizar al Pokémon que lo ataque con un movimiento de contacto." }, "voltAbsorb": { - "name": "Absorbe Elec", + "name": "Absorbe Elec", "description": "Si lo alcanza un movimiento de tipo Eléctrico, recupera PS en vez de sufrir daño." }, "waterAbsorb": { - "name": "Absorbe Agua", + "name": "Absorbe Agua", "description": "Si lo alcanza un movimiento de tipo Agua, recupera PS en vez de sufrir daño." }, "oblivious": { - "name": "Despiste", + "name": "Despiste", "description": "Su indiferencia evita que sea provocado, caiga presa del enamoramiento o sufra los efectos de Intimidación." }, "cloudNine": { - "name": "Aclimatación", + "name": "Aclimatación", "description": "Anula todos los efectos del tiempo atmosférico." }, "compoundEyes": { - "name": "Ojo Compuesto", + "name": "Ojo Compuesto", "description": "Aumenta la precisión de sus movimientos." }, "insomnia": { - "name": "Insomnio", + "name": "Insomnio", "description": "Su resistencia al sueño le impide quedarse dormido." }, "colorChange": { - "name": "Cambio Color", + "name": "Cambio Color", "description": "Adopta el tipo del último movimiento del que es blanco." }, "immunity": { - "name": "Inmunidad", + "name": "Inmunidad", "description": "Su sistema inmunitario evita el envenenamiento." }, "flashFire": { - "name": "Absorbe Fuego", + "name": "Absorbe Fuego", "description": "Si lo alcanza algún movimiento de tipo Fuego, potencia sus propios movimientos de dicho tipo." }, "shieldDust": { - "name": "Polvo Escudo", + "name": "Polvo Escudo", "description": "El polvo de escamas que lo envuelve lo protege de los efectos secundarios de los ataques recibidos." }, "ownTempo": { - "name": "Ritmo Propio", + "name": "Ritmo Propio", "description": "Como le gusta hacer las cosas a su manera, no le afecta la confusión ni sufre los efectos de Intimidación." }, "suctionCups": { - "name": "Ventosas", + "name": "Ventosas", "description": "Sus ventosas se aferran al suelo, con lo cual anula movimientos y objetos que fuercen el cambio de Pokémon." }, "intimidate": { - "name": "Intimidación", + "name": "Intimidación", "description": "Al entrar en combate, amilana al rival de tal manera que reduce su Ataque." }, "shadowTag": { - "name": "Sombra Trampa", + "name": "Sombra Trampa", "description": "Pisa la sombra del rival para impedir que huya o lo cambien por otro." }, "roughSkin": { - "name": "Piel Tosca", + "name": "Piel Tosca", "description": "Hiere con su piel áspera al Pokémon que lo ataque con un movimiento de contacto." }, "wonderGuard": { - "name": "Superguarda", + "name": "Superguarda", "description": "Gracias a un poder misterioso, solo le hacen daño los movimientos supereficaces." }, "levitate": { - "name": "Levitación", + "name": "Levitación", "description": "Su capacidad de flotar sobre el suelo le proporciona inmunidad frente a los movimientos de tipo Tierra." }, "effectSpore": { - "name": "Efecto Espora", + "name": "Efecto Espora", "description": "Puede dormir, envenenar o paralizar al Pokémon que lo ataque con un movimiento de contacto." }, "synchronize": { - "name": "Sincronía", + "name": "Sincronía", "description": "Contagia el envenenamiento, las quemaduras o la parálisis al Pokémon que le cause ese estado." }, "clearBody": { - "name": "Cuerpo Puro", + "name": "Cuerpo Puro", "description": "Evita que se reduzcan sus características a causa de movimientos o habilidades de otros Pokémon." }, "naturalCure": { - "name": "Cura Natural", + "name": "Cura Natural", "description": "Sus problemas de estado desaparecen cuando se retira del combate." }, "lightningRod": { - "name": "Pararrayos", + "name": "Pararrayos", "description": "Atrae y neutraliza los movimientos de tipo Eléctrico, que además le aumentan el Ataque Especial." }, "sereneGrace": { - "name": "Dicha", + "name": "Dicha", "description": "Aumenta la probabilidad de que los movimientos causen efectos secundarios." }, "swiftSwim": { - "name": "Nado Rápido", + "name": "Nado Rápido", "description": "Aumenta su Velocidad cuando llueve." }, "chlorophyll": { - "name": "Clorofila", + "name": "Clorofila", "description": "Aumenta su Velocidad cuando hace sol." }, "illuminate": { - "name": "Iluminación", + "name": "Iluminación", "description": "Al iluminar el entorno, evita que su Precisión se reduzca." }, "trace": { - "name": "Calco", + "name": "Calco", "description": "Copia la habilidad del rival al entrar en combate." }, "hugePower": { - "name": "Potencia", + "name": "Potencia", "description": "Duplica la potencia de sus ataques físicos." }, "poisonPoint": { - "name": "Punto Tóxico", + "name": "Punto Tóxico", "description": "Puede envenenar al Pokémon que lo ataque con un movimiento de contacto." }, "innerFocus": { - "name": "Fuerza Mental", + "name": "Fuerza Mental", "description": "Gracias a su profunda concentración, no se amedrenta ante los ataques de otros Pokémon ni sufre los efectos de Intimidación." }, "magmaArmor": { - "name": "Escudo Magma", + "name": "Escudo Magma", "description": "Gracias al magma candente que lo envuelve, no puede ser congelado." }, "waterVeil": { - "name": "Velo Agua", + "name": "Velo Agua", "description": "Evita las quemaduras gracias a la capa de agua que lo envuelve." }, "magnetPull": { - "name": "Imán", + "name": "Imán", "description": "Su magnetismo atrae a los Pokémon de tipo Acero y les impide huir o ser cambiados por otros." }, "soundproof": { - "name": "Insonorizar", + "name": "Insonorizar", "description": "Su aislamiento acústico lo protege de movimientos que usan sonido." }, "rainDish": { - "name": "Cura Lluvia", + "name": "Cura Lluvia", "description": "Recupera PS de forma gradual cuando llueve." }, "sandStream": { - "name": "Chorro Arena", + "name": "Chorro Arena", "description": "Crea una tormenta de arena al entrar en combate." }, "pressure": { - "name": "Presión", + "name": "Presión", "description": "Presiona al rival de tal manera que este consume más PP al usar sus movimientos." }, "thickFat": { - "name": "Sebo", + "name": "Sebo", "description": "Gracias a la gruesa capa de grasa que lo protege, reduce a la mitad el daño que recibe de ataques de tipo Fuego o Hielo." }, "earlyBird": { - "name": "Madrugar", + "name": "Madrugar", "description": "Si se duerme, tardará la mitad de tiempo en despertarse." }, "flameBody": { - "name": "Cuerpo Llama", + "name": "Cuerpo Llama", "description": "Puede quemar al Pokémon que lo ataque con un movimiento de contacto." }, "runAway": { - "name": "Fuga", + "name": "Fuga", "description": "Puede escapar de cualquier Pokémon salvaje." }, "keenEye": { - "name": "Vista Lince", + "name": "Vista Lince", "description": "Su aguda vista evita que su Precisión se reduzca." }, "hyperCutter": { - "name": "Corte Fuerte", + "name": "Corte Fuerte", "description": "Evita que otros Pokémon le reduzcan el Ataque." }, "pickup": { - "name": "Recogida", - "description": "Puede recoger objetos que otros Pokémon hayan usado, o bien aquellos que encuentre en plena aventura." + "name": "Recogida", + "description": "Puede que recoja un objeto del enemigo tras cada batalla, al azar." }, "truant": { - "name": "Pereza", + "name": "Pereza", "description": "Al ejecutar un movimiento, descansará en el turno siguiente." }, "hustle": { - "name": "Entusiasmo", - "description": "Aumenta su Ataque, pero reduce su Precisión." + "name": "Entusiasmo", + "description": "Aumenta su ataque, pero reduce su precisión." }, "cuteCharm": { - "name": "Gran Encanto", + "name": "Gran Encanto", "description": "Puede causar enamoramiento al Pokémon que lo ataque con un movimiento de contacto." }, "plus": { - "name": "Más", - "description": "Aumenta su Ataque Especial si un Pokémon aliado tiene la habilidad Más o la habilidad Menos." + "name": "Más", + "description": "Aumenta su ataque especial si un Pokémon aliado tiene la habilidad Más o la habilidad Menos." }, "minus": { - "name": "Menos", - "description": "Aumenta su Ataque Especial si un Pokémon aliado tiene la habilidad Más o la habilidad Menos." + "name": "Menos", + "description": "Aumenta su ataque especial si un Pokémon aliado tiene la habilidad Más o la habilidad Menos." }, "forecast": { - "name": "Predicción", + "name": "Predicción", "description": "Cambia a tipo Agua, Fuego o Hielo en función del tiempo atmosférico." }, "stickyHold": { - "name": "Viscosidad", + "name": "Viscosidad", "description": "Los objetos se quedan pegados a su cuerpo, por lo que no pueden robárselos." }, "shedSkin": { - "name": "Mudar", + "name": "Mudar", "description": "Puede curar sus problemas de estado al mudar la piel." }, "guts": { - "name": "Agallas", - "description": "Si sufre un problema de estado, se arma de valor y aumenta su Ataque." + "name": "Agallas", + "description": "Si sufre un problema de estado, se arma de valor y aumenta su ataque." }, "marvelScale": { - "name": "Escama Especial", - "description": "Si sufre un problema de estado, sus escamas especiales reaccionan y aumenta su Defensa." + "name": "Escama Especial", + "description": "Si sufre un problema de estado, sus escamas especiales reaccionan y aumenta su defensa." }, "liquidOoze": { - "name": "Viscosecreción", + "name": "Viscosecreción", "description": "Exuda una secreción viscosa y tóxica de intenso hedor que hiere a quienes intentan drenarle PS." }, "overgrow": { - "name": "Espesura", + "name": "Espesura", "description": "Potencia sus movimientos de tipo Planta cuando le quedan pocos PS." }, "blaze": { - "name": "Mar Llamas", + "name": "Mar Llamas", "description": "Potencia sus movimientos de tipo Fuego cuando le quedan pocos PS." }, "torrent": { - "name": "Torrente", + "name": "Torrente", "description": "Potencia sus movimientos de tipo Agua cuando le quedan pocos PS." }, "swarm": { - "name": "Enjambre", + "name": "Enjambre", "description": "Potencia sus movimientos de tipo Bicho cuando le quedan pocos PS." }, "rockHead": { - "name": "Cabeza Roca", + "name": "Cabeza Roca", "description": "No pierde PS al usar movimientos que también hieren al usuario." }, "drought": { - "name": "Sequía", + "name": "Sequía", "description": "El tiempo pasa a ser soleado al entrar en combate." }, "arenaTrap": { - "name": "Trampa Arena", + "name": "Trampa Arena", "description": "Evita que el rival huya o sea cambiado por otro." }, "vitalSpirit": { - "name": "Espíritu Vital", + "name": "Espíritu Vital", "description": "Su determinación le impide quedarse dormido." }, "whiteSmoke": { - "name": "Humo Blanco", + "name": "Humo Blanco", "description": "El humo blanco que lo protege evita que otros Pokémon le reduzcan las características." }, "purePower": { - "name": "Energía Pura", + "name": "Energía Pura", "description": "Duplica la potencia de sus ataques físicos gracias al yoga." }, "shellArmor": { - "name": "Caparazón", + "name": "Caparazón", "description": "La robusta coraza que lo protege bloquea los golpes críticos." }, "airLock": { - "name": "Esclusa de Aire", + "name": "Esclusa de Aire", "description": "Neutraliza todos los efectos del tiempo atmosférico." }, "tangledFeet": { - "name": "Tumbos", - "description": "Aumenta su Evasión si está confuso." + "name": "Tumbos", + "description": "Aumenta su evasión si está confuso." }, "motorDrive": { - "name": "Electromotor", - "description": "Si lo alcanza un movimiento de tipo Eléctrico, aumenta su Velocidad en vez de sufrir daño." + "name": "Electromotor", + "description": "Si lo alcanza un movimiento de tipo Eléctrico, aumenta su velocidad en vez de sufrir daño." }, "rivalry": { - "name": "Rivalidad", + "name": "Rivalidad", "description": "Si el objetivo es del mismo sexo, su competitividad le lleva a infligir más daño. Si es del sexo contrario, en cambio, el daño será menor." }, "steadfast": { - "name": "Impasible", - "description": "Cada vez que se amedrenta, aumenta su Velocidad debido a su voluntad inquebrantable." + "name": "Impasible", + "description": "Cada vez que se amedrenta, aumenta su velocidad debido a su voluntad inquebrantable." }, "snowCloak": { - "name": "Manto Níveo", - "description": "Aumenta su Evasión cuando nieva." + "name": "Manto Níveo", + "description": "Aumenta su evasión cuando nieva." }, "gluttony": { - "name": "Gula", + "name": "Gula", "description": "Cuando sus PS se ven reducidos a la mitad, engulle la baya que normalmente solo se comería cuando le quedasen pocos PS." }, "angerPoint": { - "name": "Irascible", - "description": "Si recibe un golpe crítico, monta en cólera y su Ataque aumenta al máximo." + "name": "Irascible", + "description": "Si recibe un golpe crítico, monta en cólera y su ataque aumenta al máximo." }, "unburden": { - "name": "Liviano", - "description": "Aumenta su Velocidad si usa o pierde el objeto que lleva." + "name": "Liviano", + "description": "Aumenta su velocidad si usa o pierde el objeto que lleva." }, "heatproof": { - "name": "Ignífugo", + "name": "Ignífugo", "description": "Su cuerpo, resistente al calor, reduce a la mitad el daño recibido por movimientos de tipo Fuego." }, "simple": { - "name": "Simple", + "name": "Simple", "description": "Duplica los cambios en las características." }, "drySkin": { - "name": "Piel Seca", + "name": "Piel Seca", "description": "Pierde PS si hace sol y los recupera si llueve o recibe un movimiento de tipo Agua. Los movimientos de tipo Fuego, por su parte, le hacen más daño de lo normal." }, "download": { - "name": "Descarga", - "description": "Compara la Defensa y la Defensa Especial del rival para ver cuál es inferior y aumenta su propio Ataque o Ataque Especial según sea lo más eficaz." + "name": "Descarga", + "description": "Compara la defensa y la defensa especial del rival para ver cuál es inferior y aumenta su propio ataque o ataque especial según sea lo más eficaz." }, "ironFist": { - "name": "Puño Férreo", + "name": "Puño Férreo", "description": "Aumenta la potencia de los movimientos con los puños." }, "poisonHeal": { - "name": "Antídoto", + "name": "Antídoto", "description": "Si resulta envenenado, recupera PS en vez de perderlos." }, "adaptability": { - "name": "Adaptable", + "name": "Adaptable", "description": "Potencia aún más los movimientos cuyo tipo coincida con el suyo." }, "skillLink": { - "name": "Encadenado", + "name": "Encadenado", "description": "Ejecuta siempre los movimientos de ataque múltiple con el número máximo de golpes." }, "hydration": { - "name": "Hidratación", + "name": "Hidratación", "description": "Cura los problemas de estado si está lloviendo." }, "solarPower": { - "name": "Poder Solar", - "description": "Si hace sol, aumenta su Ataque Especial, pero pierde PS en cada turno." + "name": "Poder Solar", + "description": "Si hace sol, aumenta su ataque especial, pero pierde PS en cada turno." }, "quickFeet": { - "name": "Pies Rápidos", - "description": "Aumenta su Velocidad si sufre problemas de estado." + "name": "Pies Rápidos", + "description": "Aumenta su velocidad si sufre problemas de estado." }, "normalize": { - "name": "Normalidad", + "name": "Normalidad", "description": "Hace que todos sus movimientos se vuelvan de tipo Normal y aumenta ligeramente su potencia." }, "sniper": { - "name": "Francotirador", + "name": "Francotirador", "description": "Potencia los golpes críticos que asesta aún más de lo normal." }, "magicGuard": { - "name": "Muro Mágico", + "name": "Muro Mágico", "description": "Solo recibe daño de ataques." }, "noGuard": { - "name": "Indefenso", + "name": "Indefenso", "description": "Al quedar ambos expuestos, tanto sus movimientos como los del Pokémon que lo ataque acertarán siempre." }, "stall": { - "name": "Rezagado", + "name": "Rezagado", "description": "Ejecuta su movimiento tras todos los demás." }, "technician": { - "name": "Experto", + "name": "Experto", "description": "Aumenta la potencia de sus movimientos débiles." }, "leafGuard": { - "name": "Defensa Hoja", + "name": "Defensa Hoja", "description": "Evita los problemas de estado si hace sol." }, "klutz": { - "name": "Zoquete", + "name": "Zoquete", "description": "No puede usar objetos equipados." }, "moldBreaker": { - "name": "Rompemoldes", + "name": "Rompemoldes", "description": "Sus movimientos no se ven afectados por la habilidad del objetivo." }, "superLuck": { - "name": "Afortunado", + "name": "Afortunado", "description": "Su buena suerte aumenta la probabilidad de asestar golpes críticos." }, "aftermath": { - "name": "Detonación", + "name": "Detonación", "description": "Daña al Pokémon que le ha dado el golpe de gracia con un movimiento de contacto." }, "anticipation": { - "name": "Anticipación", + "name": "Anticipación", "description": "Prevé los movimientos peligrosos del rival." }, "forewarn": { - "name": "Alerta", + "name": "Alerta", "description": "Revela uno de los movimientos del rival al entrar en combate." }, "unaware": { - "name": "Ignorante", + "name": "Ignorante", "description": "Pasa por alto los cambios en las características de un Pokémon al atacarlo o recibir daño." }, "tintedLens": { - "name": "Cromolente", + "name": "Cromolente", "description": "Potencia los movimientos que no son muy eficaces, que infligen ahora un daño normal." }, "filter": { - "name": "Filtro", + "name": "Filtro", "description": "Mitiga el daño que le infligen los movimientos supereficaces." }, "slowStart": { - "name": "Inicio Lento", - "description": "Reduce a la mitad su Ataque y su Velocidad durante cinco turnos." + "name": "Inicio Lento", + "description": "Reduce a la mitad su ataque y su velocidad durante cinco turnos." }, "scrappy": { - "name": "Intrépido", + "name": "Intrépido", "description": "Alcanza a Pokémon de tipo Fantasma con movimientos de tipo Normal o Lucha. Además, no sufre los efectos de Intimidación." }, "stormDrain": { - "name": "Colector", - "description": "Atrae y neutraliza los movimientos de tipo Agua, que además le aumentan el Ataque Especial." + "name": "Colector", + "description": "Atrae y neutraliza los movimientos de tipo Agua, que además le aumentan el ataque especial." }, "iceBody": { - "name": "Gélido", + "name": "Gélido", "description": "Recupera PS de forma gradual cuando nieva." }, "solidRock": { - "name": "Roca Sólida", + "name": "Roca Sólida", "description": "Mitiga el daño que le infligen los movimientos supereficaces." }, "snowWarning": { - "name": "Nevada", + "name": "Nevada", "description": "Invoca una nevada al entrar en combate." }, "honeyGather": { - "name": "Recogemiel", - "description": "The Pokémon gathers Honey after a battle. The Honey is then sold for money." + "name": "Recogemiel", + "description": "El Pokémon recoge miel tras cada batalla. La miel se vende inmediatamente por ₽." }, "frisk": { - "name": "Cacheo", + "name": "Cacheo", "description": "Cuando entra en combate, el Pokémon puede comprobar la habilidad de un Pokémon rival." }, "reckless": { - "name": "Audaz", + "name": "Audaz", "description": "Potencia los movimientos que también dañan al usuario." }, "multitype": { - "name": "Multitipo", + "name": "Multitipo", "description": "Cambia su tipo al de la tabla que lleve." }, "flowerGift": { - "name": "Don Floral", - "description": "Si hace sol, aumenta su Ataque y su Defensa Especial, así como los de sus aliados." + "name": "Don Floral", + "description": "Si hace sol, aumenta su ataque y su defensa Especial, así como los de sus aliados." }, "badDreams": { - "name": "Mal Sueño", + "name": "Mal Sueño", "description": "Inflige daño a cualquier rival que esté dormido." }, "pickpocket": { - "name": "Hurto", + "name": "Hurto", "description": "Roba el objeto del Pokémon que lo ataque con un movimiento de contacto." }, "sheerForce": { - "name": "Potencia Bruta", + "name": "Potencia Bruta", "description": "Aumenta la potencia de sus movimientos en detrimento de los efectos secundarios, que se ven anulados." }, "contrary": { - "name": "Respondón", + "name": "Respondón", "description": "Invierte los cambios en las características: bajan cuando les toca subir y suben cuando les toca bajar." }, "unnerve": { - "name": "Nerviosismo", + "name": "Nerviosismo", "description": "Pone nervioso al rival y le impide comer bayas." }, "defiant": { - "name": "Competitivo", - "description": "Aumenta mucho su Ataque cuando el rival le reduce cualquiera de sus características." + "name": "Competitivo", + "description": "Aumenta mucho su ataque cuando el rival le reduce cualquiera de sus características." }, "defeatist": { - "name": "Flaqueza", - "description": "Cuando sus PS se ven reducidos a la mitad, se cansa tanto que su Ataque y su Ataque Especial también se ven reducidos a la mitad." + "name": "Flaqueza", + "description": "Cuando sus PS se ven reducidos a la mitad, se cansa tanto que su ataque y su ataque Especial también se ven reducidos a la mitad." }, "cursedBody": { - "name": "Cuerpo Maldito", + "name": "Cuerpo Maldito", "description": "Puede anular el movimiento usado en su contra." }, "healer": { - "name": "Alma Cura", + "name": "Alma Cura", "description": "A veces cura los problemas de estado de un aliado." }, "friendGuard": { - "name": "Compiescolta", + "name": "Compiescolta", "description": "Reduce el daño que sufren los aliados." }, "weakArmor": { - "name": "Armadura Frágil", - "description": "Al recibir daño de un ataque físico, se reduce su Defensa, pero aumenta mucho su Velocidad." + "name": "Armadura Frágil", + "description": "Al recibir daño de un ataque físico, se reduce su defensa, pero aumenta mucho su velocidad." }, "heavyMetal": { - "name": "Metal Pesado", + "name": "Metal Pesado", "description": "Duplica su peso." }, "lightMetal": { - "name": "Metal Liviano", + "name": "Metal Liviano", "description": "Reduce a la mitad su peso." }, "multiscale": { - "name": "Multiescamas", + "name": "Multiescamas", "description": "Reduce el daño que sufre si sus PS están al máximo." }, "toxicBoost": { - "name": "Ímpetu Tóxico", + "name": "Ímpetu Tóxico", "description": "Aumenta la potencia de sus ataques físicos cuando está envenenado." }, "flareBoost": { - "name": "Ímpetu Ardiente", + "name": "Ímpetu Ardiente", "description": "Aumenta la potencia de sus ataques especiales cuando sufre quemaduras." }, "harvest": { - "name": "Cosecha", + "name": "Cosecha", "description": "Puede reutilizar varias veces una misma baya." }, "telepathy": { - "name": "Telepatía", + "name": "Telepatía", "description": "Elude los ataques de los aliados durante el combate." }, "moody": { - "name": "Veleta", + "name": "Veleta", "description": "Aumenta mucho una característica en cada turno, pero reduce otra." }, "overcoat": { - "name": "Funda", + "name": "Funda", "description": "No recibe daño de las tormentas de arena ni sufre los efectos causados por polvos o esporas." }, "poisonTouch": { - "name": "Toque Tóxico", + "name": "Toque Tóxico", "description": "Puede envenenar al Pokémon al que ataque con un movimiento de contacto." }, "regenerator": { - "name": "Regeneración", + "name": "Regeneración", "description": "Recupera unos pocos PS cuando se retira del combate." }, "bigPecks": { - "name": "Sacapecho", - "description": "Impide que otros Pokémon le reduzcan la Defensa." + "name": "Sacapecho", + "description": "Impide que otros Pokémon le reduzcan la defensa." }, "sandRush": { - "name": "Ímpetu Arena", - "description": "Aumenta su Velocidad durante las tormentas de arena." + "name": "Ímpetu Arena", + "description": "Aumenta su velocidad durante las tormentas de arena." }, "wonderSkin": { - "name": "Piel Milagro", + "name": "Piel Milagro", "description": "Presenta una mayor resistencia ante los movimientos de estado." }, "analytic": { - "name": "Cálculo Final", + "name": "Cálculo Final", "description": "Aumenta la potencia de su movimiento si es el último en atacar." }, "illusion": { - "name": "Ilusión", + "name": "Ilusión", "description": "Adopta el aspecto del último Pokémon del equipo al entrar en combate para desconcertar al rival." }, "imposter": { - "name": "Impostor", + "name": "Impostor", "description": "Se transforma en el Pokémon que tiene enfrente." }, "infiltrator": { - "name": "Allanamiento", + "name": "Allanamiento", "description": "Ataca sorteando las barreras o el sustituto del objetivo." }, "mummy": { - "name": "Momia", + "name": "Momia", "description": "Contagia la habilidad Momia al Pokémon que lo ataque con un movimiento de contacto." }, "moxie": { - "name": "Autoestima", - "description": "Al debilitar a un objetivo, su confianza se refuerza de tal manera que aumenta su Ataque." + "name": "Autoestima", + "description": "Al debilitar a un objetivo, su confianza se refuerza de tal manera que aumenta su ataque." }, "justified": { - "name": "Justiciero", - "description": "Si lo alcanza un movimiento de tipo Siniestro, aumenta el Ataque debido a su integridad." + "name": "Justiciero", + "description": "Si lo alcanza un movimiento de tipo Siniestro, aumenta el ataque debido a su integridad." }, "rattled": { - "name": "Cobardía", - "description": "Si lo alcanza un ataque de tipo Siniestro, Bicho o Fantasma, o si sufre los efectos de Intimidación, el miedo hace que aumente su Velocidad." + "name": "Cobardía", + "description": "Si lo alcanza un ataque de tipo Siniestro, Bicho o Fantasma, o si sufre los efectos de Intimidación, el miedo hace que aumente su velocidad." }, "magicBounce": { - "name": "Espejo Mágico", + "name": "Espejo Mágico", "description": "Puede devolver los movimientos de estado sin verse afectado por ellos." }, "sapSipper": { - "name": "Herbívoro", - "description": "Si lo alcanza un movimiento de tipo Planta, aumenta su Ataque en vez de sufrir daño." + "name": "Herbívoro", + "description": "Si lo alcanza un movimiento de tipo Planta, aumenta su ataque en vez de sufrir daño." }, "prankster": { - "name": "Bromista", + "name": "Bromista", "description": "Sus movimientos de estado tienen prioridad alta." }, "sandForce": { - "name": "Poder Arena", + "name": "Poder Arena", "description": "Potencia los movimientos de tipo Tierra, Acero y Roca durante las tormentas de arena." }, "ironBarbs": { - "name": "Punta Acero", + "name": "Punta Acero", "description": "Inflige daño con sus púas de acero al Pokémon que lo ataque con un movimiento de contacto." }, "zenMode": { - "name": "Modo Daruma", + "name": "Modo Daruma", "description": "Cambia de forma si sus PS se ven reducidos a la mitad o menos." }, "victoryStar": { - "name": "Tinovictoria", - "description": "Aumenta su Precisión y la de sus aliados." + "name": "Tinovictoria", + "description": "Aumenta su precisión y la de sus aliados." }, "turboblaze": { - "name": "Turbollama", + "name": "Turbollama", "description": "Sus movimientos no se ven afectados por la habilidad del objetivo." }, "teravolt": { - "name": "Terravoltaje", + "name": "Terravoltaje", "description": "Sus movimientos no se ven afectados por la habilidad del objetivo." }, "aromaVeil": { - "name": "Velo Aroma", + "name": "Velo Aroma", "description": "Se protege a sí mismo y a sus aliados de efectos que impiden usar movimientos." }, "flowerVeil": { - "name": "Velo Flor", + "name": "Velo Flor", "description": "Evita que los Pokémon de tipo Planta aliados sufran problemas de estado o que les reduzcan sus características." }, "cheekPouch": { - "name": "Carrillo", + "name": "Carrillo", "description": "Recupera PS al comer cualquier baya." }, "protean": { - "name": "Mutatipo", + "name": "Mutatipo", "description": "Al entrar en combate, cambia su tipo al del primer movimiento que va a usar." }, "furCoat": { - "name": "Pelaje Recio", + "name": "Pelaje Recio", "description": "Reduce a la mitad el daño que recibe de ataques físicos." }, "magician": { - "name": "Prestidigitador", + "name": "Prestidigitador", "description": "Roba el objeto del Pokémon al que alcance con un movimiento." }, "bulletproof": { - "name": "Antibalas", + "name": "Antibalas", "description": "No le afectan las bombas ni algunos proyectiles." }, "competitive": { - "name": "Tenacidad", - "description": "Aumenta mucho su Ataque Especial cuando el rival le reduce cualquiera de sus características." + "name": "Tenacidad", + "description": "Aumenta mucho su ataque especial cuando el rival le reduce cualquiera de sus características." }, "strongJaw": { - "name": "Mandíbula Fuerte", + "name": "Mandíbula Fuerte", "description": "Su robusta mandíbula le confiere una mordedura mucho más potente." }, "refrigerate": { - "name": "Piel Helada", + "name": "Piel Helada", "description": "Convierte los movimientos de tipo Normal en tipo Hielo y aumenta ligeramente su potencia." }, "sweetVeil": { - "name": "Velo Dulce", + "name": "Velo Dulce", "description": "No cae dormido y evita también que sus aliados se duerman." }, "stanceChange": { - "name": "Cambio Táctico", + "name": "Cambio Táctico", "description": "Adopta la Forma Filo al lanzar un ataque, o bien la Forma Escudo si usa el movimiento Escudo Real." }, "galeWings": { - "name": "Alas Vendaval", + "name": "Alas Vendaval", "description": "Da prioridad a los movimientos de tipo Volador si sus PS están al máximo." }, "megaLauncher": { - "name": "Megadisparador", + "name": "Megadisparador", "description": "Aumenta la potencia de algunos movimientos de pulsos y auras." }, "grassPelt": { - "name": "Manto Frondoso", - "description": "Aumenta su Defensa si hay un campo de hierba en el terreno de combate." + "name": "Manto Frondoso", + "description": "Aumenta su defensa si hay un campo de hierba en el terreno de combate." }, "symbiosis": { - "name": "Simbiosis", + "name": "Simbiosis", "description": "Pasa su objeto a un aliado cuando este use el suyo." }, "toughClaws": { - "name": "Garra Dura", + "name": "Garra Dura", "description": "Aumenta la potencia de los movimientos de contacto." }, "pixilate": { - "name": "Piel Feérica", + "name": "Piel Feérica", "description": "Convierte los movimientos de tipo Normal en tipo Hada y aumenta ligeramente su potencia." }, "gooey": { - "name": "Baba", - "description": "Reduce la Velocidad del Pokémon que lo ataque con un movimiento de contacto." + "name": "Baba", + "description": "Reduce la velocidad del Pokémon que lo ataque con un movimiento de contacto." }, "aerilate": { - "name": "Piel Celeste", + "name": "Piel Celeste", "description": "Convierte los movimientos de tipo Normal en tipo Volador y aumenta ligeramente su potencia." }, "parentalBond": { - "name": "Amor Filial", + "name": "Amor Filial", "description": "Une fuerzas con su cría y ataca dos veces." }, "darkAura": { - "name": "Aura Oscura", + "name": "Aura Oscura", "description": "Aumenta la potencia de los movimientos de tipo Siniestro de todos los Pokémon." }, "fairyAura": { - "name": "Aura Feérica", + "name": "Aura Feérica", "description": "Aumenta la potencia de los movimientos de tipo Hada de todos los Pokémon." }, "auraBreak": { - "name": "Rompeaura", + "name": "Rompeaura", "description": "Invierte los efectos de las habilidades de auras, por lo que reduce la potencia de ciertos movimientos en vez de aumentarla." }, "primordialSea": { - "name": "Mar del Albor", + "name": "Mar del Albor", "description": "Altera el clima para anular los ataques de tipo Fuego." }, "desolateLand": { - "name": "Tierra del Ocaso", + "name": "Tierra del Ocaso", "description": "Altera el clima para anular los ataques de tipo Agua." }, "deltaStream": { - "name": "Ráfaga Delta", + "name": "Ráfaga Delta", "description": "Altera el clima para anular las vulnerabilidades del tipo Volador." }, "stamina": { - "name": "Firmeza", - "description": "Aumenta su Defensa al recibir un ataque." + "name": "Firmeza", + "description": "Aumenta su defensa al recibir un ataque." }, "wimpOut": { - "name": "Huida", + "name": "Huida", "description": "Se asusta y abandona el terreno de combate cuando sus PS se ven reducidos a la mitad." }, "emergencyExit": { - "name": "Retirada", + "name": "Retirada", "description": "Abandona el terreno de combate cuando sus PS se ven reducidos a la mitad para evitar males mayores." }, "waterCompaction": { - "name": "Hidrorrefuerzo", - "description": "Aumenta mucho su Defensa si lo alcanza un movimiento de tipo Agua." + "name": "Hidrorrefuerzo", + "description": "Aumenta mucho su defensa si lo alcanza un movimiento de tipo Agua." }, "merciless": { - "name": "Ensañamiento", + "name": "Ensañamiento", "description": "Hace que sus movimientos asesten siempre un golpe crítico si el objetivo está envenenado." }, "shieldsDown": { - "name": "Escudo Limitado", + "name": "Escudo Limitado", "description": "Rompe su coraza cuando sus PS se ven reducidos a la mitad y adopta una forma ofensiva." }, "stakeout": { - "name": "Vigilante", + "name": "Vigilante", "description": "Si el objetivo de su ataque es sustituido por otro, duplica el daño que infligirá." }, "waterBubble": { - "name": "Pompa", + "name": "Pompa", "description": "Reduce el daño que le provocan los movimientos de tipo Fuego y es inmune a las quemaduras." }, "steelworker": { - "name": "Acero Templado", + "name": "Acero Templado", "description": "Potencia los movimientos de tipo Acero." }, "berserk": { - "name": "Cólera", - "description": "Aumenta su Ataque Especial si sus PS se ven reducidos a la mitad debido a algún ataque." + "name": "Cólera", + "description": "Aumenta su ataque especial si sus PS se ven reducidos a la mitad debido a algún ataque." }, "slushRush": { - "name": "Quitanieves", - "description": "Aumenta su Velocidad cuando nieva." + "name": "Quitanieves", + "description": "Aumenta su velocidad cuando nieva." }, "longReach": { - "name": "Remoto", + "name": "Remoto", "description": "Puede usar cualquier movimiento sin entrar en contacto con su objetivo." }, "liquidVoice": { - "name": "Voz Fluida", + "name": "Voz Fluida", "description": "Hace que todos sus movimientos que usan sonido pasen a ser de tipo Agua." }, "triage": { - "name": "Primer Auxilio", + "name": "Primer Auxilio", "description": "Da prioridad a los movimientos que restauran PS." }, "galvanize": { - "name": "Piel Eléctrica", + "name": "Piel Eléctrica", "description": "Convierte los movimientos de tipo Normal en tipo Eléctrico y aumenta ligeramente su potencia." }, "surgeSurfer": { - "name": "Cola Surf", - "description": "Duplica su Velocidad si hay un campo eléctrico en el terreno de combate." + "name": "Cola Surf", + "description": "Duplica su velocidad si hay un campo eléctrico en el terreno de combate." }, "schooling": { - "name": "Banco", + "name": "Banco", "description": "Forma bancos con sus congéneres cuando tiene muchos PS, lo cual le otorga más fuerza. Cuando le quedan pocos PS, el banco se dispersa." }, "disguise": { - "name": "Disfraz", + "name": "Disfraz", "description": "Puede eludir un ataque valiéndose de la tela que le cubre el cuerpo una vez por combate." }, "battleBond": { - "name": "Fuerte Afecto", - "description": "Al derrotar a un Pokémon, los vínculos con su Entrenador se refuerzan y aumentan su Ataque, su Ataque Especial y su Velocidad." + "name": "Fuerte Afecto", + "description": "Al derrotar a un Pokémon, los vínculos con su Entrenador se refuerzan y aumentan su ataque, su ataque especial y su velocidad." }, "powerConstruct": { - "name": "Agrupamiento", + "name": "Agrupamiento", "description": "Cuando sus PS se ven reducidos a la mitad, las células se reagrupan y adopta su Forma Completa." }, "corrosion": { - "name": "Corrosión", + "name": "Corrosión", "description": "Puede envenenar incluso a Pokémon de tipo Acero o Veneno." }, "comatose": { - "name": "Letargo Perenne", + "name": "Letargo Perenne", "description": "No despierta jamás de su profundo letargo e incluso ataca dormido." }, "queenlyMajesty": { - "name": "Regia Presencia", + "name": "Regia Presencia", "description": "Intimida al rival y le impide usar movimientos con prioridad contra él y sus aliados." }, "innardsOut": { - "name": "Revés", + "name": "Revés", "description": "Al caer debilitado, inflige al atacante un daño equivalente a los PS que le quedaran antes de recibir el golpe de gracia." }, "dancer": { - "name": "Pareja de Baile", + "name": "Pareja de Baile", "description": "Puede copiar inmediatamente cualquier movimiento de baile que haya usado otro Pokémon presente en el combate." }, "battery": { - "name": "Batería", + "name": "Batería", "description": "Potencia los ataques especiales de los aliados." }, "fluffy": { - "name": "Peluche", + "name": "Peluche", "description": "Reduce a la mitad el daño recibido por los movimientos de contacto, pero duplica el que le infligen los de tipo Fuego." }, "dazzling": { - "name": "Cuerpo Vívido", + "name": "Cuerpo Vívido", "description": "Desconcierta al rival y le impide usar movimientos con prioridad contra él y sus aliados." }, "soulHeart": { - "name": "Coránima", - "description": "Aumenta su Ataque Especial cada vez que un Pokémon cae debilitado." + "name": "Coránima", + "description": "Aumenta su ataque especial cada vez que un Pokémon cae debilitado." }, "tanglingHair": { - "name": "Rizos Rebeldes", - "description": "Reduce la Velocidad del Pokémon que lo ataque con un movimiento de contacto." + "name": "Rizos Rebeldes", + "description": "Reduce la velocidad del Pokémon que lo ataque con un movimiento de contacto." }, "receiver": { - "name": "Receptor", + "name": "Receptor", "description": "Adquiere la habilidad de un aliado debilitado." }, "powerOfAlchemy": { - "name": "Reacción Química", + "name": "Reacción Química", "description": "Reacciona copiando la habilidad de un aliado debilitado." }, "beastBoost": { - "name": "Ultraimpulso", + "name": "Ultraimpulso", "description": "Al derrotar a un Pokémon, aumenta su característica más fuerte." }, "rksSystem": { - "name": "Sistema Alfa", + "name": "Sistema Alfa", "description": "Cambia su tipo según el disco que lleve instalado." }, "electricSurge": { - "name": "Electrogénesis", + "name": "Electrogénesis", "description": "Crea un campo eléctrico al entrar en combate." }, "psychicSurge": { - "name": "Psicogénesis", + "name": "Psicogénesis", "description": "Crea un campo psíquico al entrar en combate." }, "mistySurge": { - "name": "Nebulogénesis", + "name": "Nebulogénesis", "description": "Crea un campo de niebla al entrar en combate." }, "grassySurge": { - "name": "Herbogénesis", + "name": "Herbogénesis", "description": "Crea un campo de hierba al entrar en combate." }, "fullMetalBody": { - "name": "Guardia Metálica", + "name": "Guardia Metálica", "description": "Evita que se reduzcan sus características a causa de movimientos o habilidades de otros Pokémon." }, "shadowShield": { - "name": "Guardia Espectro", + "name": "Guardia Espectro", "description": "Reduce el daño que sufre si sus PS están al máximo." }, "prismArmor": { - "name": "Armadura Prisma", + "name": "Armadura Prisma", "description": "Mitiga el daño que le infligen los movimientos supereficaces." }, "neuroforce": { - "name": "Fuerza Cerebral", + "name": "Fuerza Cerebral", "description": "Potencia los ataques supereficaces." }, "intrepidSword": { - "name": "Espada Indómita", - "description": "Aumenta su Ataque al entrar en combate por primera vez." + "name": "Espada Indómita", + "description": "Aumenta su ataque al entrar en combate por primera vez." }, "dauntlessShield": { - "name": "Escudo Recio", - "description": "Aumenta su Defensa al entrar en combate por primera vez." + "name": "Escudo Recio", + "description": "Aumenta su defensa al entrar en combate por primera vez." }, "libero": { - "name": "Líbero", + "name": "Líbero", "description": "Al entrar en combate, cambia su tipo al del primer movimiento que va a usar." }, "ballFetch": { - "name": "Recogebolas", - "description": "Si no lleva equipado ningún objeto, recupera la Poké Ball del primer intento de captura fallido." + "name": "Recogebolas", + "description": "Recupera la Poké Ball del primer intento de captura fallido." }, "cottonDown": { - "name": "Pelusa", - "description": "Al ser alcanzado por un ataque, suelta una pelusa de algodón que reduce la Velocidad de todos los demás Pokémon." + "name": "Pelusa", + "description": "Al ser alcanzado por un ataque, suelta una pelusa de algodón que reduce la velocidad de todos los demás Pokémon." }, "propellerTail": { - "name": "Hélice Caudal", + "name": "Hélice Caudal", "description": "Ignora los efectos de las habilidades o los movimientos que permiten a un Pokémon centrar la atención sobre sí." }, "mirrorArmor": { - "name": "Coraza Reflejo", + "name": "Coraza Reflejo", "description": "Refleja los efectos que reducen las características." }, "gulpMissile": { - "name": "Tragamisil", + "name": "Tragamisil", "description": "Tras usar Surf o Buceo, emerge con una presa en la boca. Al recibir daño, ataca escupiéndola." }, "stalwart": { - "name": "Acérrimo", + "name": "Acérrimo", "description": "Ignora los efectos de las habilidades o los movimientos que permiten a un Pokémon centrar la atención sobre sí." }, "steamEngine": { - "name": "Combustible", - "description": "Si lo alcanza un movimiento de tipo Fuego o Agua, aumenta muchísimo su Velocidad." + "name": "Combustible", + "description": "Si lo alcanza un movimiento de tipo Fuego o Agua, aumenta muchísimo su velocidad." }, "punkRock": { - "name": "Punk Rock", + "name": "Punk Rock", "description": "Potencia los movimientos que usan sonido y reduce a la mitad el daño que le infligen dichos movimientos." }, "sandSpit": { - "name": "Expulsarena", + "name": "Expulsarena", "description": "Provoca una tormenta de arena al recibir un ataque." }, "iceScales": { - "name": "Escama de Hielo", + "name": "Escama de Hielo", "description": "Las gélidas escamas que protegen su cuerpo reducen a la mitad el daño que le infligen los ataques especiales." }, "ripen": { - "name": "Maduración", + "name": "Maduración", "description": "Hace madurar las bayas, por lo que duplica sus efectos." }, "iceFace": { - "name": "Cara de Hielo", + "name": "Cara de Hielo", "description": "Absorbe el daño de un ataque físico con el hielo de la cabeza, tras lo cual cambia de forma. El hielo se regenerará la próxima vez que nieve." }, "powerSpot": { - "name": "Fuente Energía", + "name": "Fuente Energía", "description": "Potencia los movimientos de los Pokémon adyacentes." }, "mimicry": { - "name": "Mimetismo", + "name": "Mimetismo", "description": "Cambia su tipo según el campo que haya en el terreno de combate." }, "screenCleaner": { - "name": "Antibarrera", + "name": "Antibarrera", "description": "Anula los efectos de Pantalla de Luz, Reflejo y Velo Aurora tanto de rivales como de aliados al entrar en combate." }, "steelySpirit": { - "name": "Alma Acerada", + "name": "Alma Acerada", "description": "Potencia los movimientos de tipo Acero del Pokémon y sus aliados." }, "perishBody": { - "name": "Cuerpo Mortal", + "name": "Cuerpo Mortal", "description": "Si lo alcanza un movimiento de contacto, se debilitará al cabo de 3 turnos, así como el atacante, a menos que abandonen el terreno de combate." }, "wanderingSpirit": { - "name": "Alma Errante", + "name": "Alma Errante", "description": "Si lo alcanza un movimiento de contacto, intercambia su habilidad con la del atacante." }, "gorillaTactics": { - "name": "Monotema", - "description": "Aumenta su Ataque, pero solo puede usar el primer movimiento escogido." + "name": "Monotema", + "description": "Aumenta su ataque, pero solo puede usar el primer movimiento escogido." }, "neutralizingGas": { - "name": "Gas Reactivo", + "name": "Gas Reactivo", "description": "Anula los efectos de las habilidades de los demás Pokémon presentes mientras esté en el terreno de combate." }, "pastelVeil": { - "name": "Velo Pastel", + "name": "Velo Pastel", "description": "Se protege a sí mismo y a sus aliados del envenenamiento." }, "hungerSwitch": { - "name": "Mutapetito", + "name": "Mutapetito", "description": "Alterna entre su Forma Saciada y Forma Voraz al final de cada turno." }, "quickDraw": { - "name": "Mano Rápida", + "name": "Mano Rápida", "description": "A veces, puede atacar el primero." }, "unseenFist": { - "name": "Puño Invisible", + "name": "Puño Invisible", "description": "Si usa un movimiento de contacto, puede infligir daño al objetivo aunque este se proteja." }, "curiousMedicine": { - "name": "Medicina Extraña", + "name": "Medicina Extraña", "description": "Al entrar en combate, rezuma una substancia medicinal por la caracola que revierte los cambios en las características de los aliados." }, "transistor": { - "name": "Transistor", + "name": "Transistor", "description": "Potencia los movimientos de tipo Eléctrico." }, "dragonsMaw": { - "name": "Mandíbula Dragón", + "name": "Mandíbula Dragón", "description": "Potencia los movimientos de tipo Dragón." }, "chillingNeigh": { - "name": "Relincho Blanco", - "description": "Al derrotar a un objetivo, emite un relincho gélido y aumenta su Ataque." + "name": "Relincho Blanco", + "description": "Al derrotar a un objetivo, emite un relincho gélido y aumenta su ataque." }, "grimNeigh": { - "name": "Relincho Negro", - "description": "Al derrotar a un objetivo, emite un relincho aterrador y aumenta su Ataque Especial." + "name": "Relincho Negro", + "description": "Al derrotar a un objetivo, emite un relincho aterrador y aumenta su ataque especial." }, "asOneGlastrier": { - "name": "Unidad Ecuestre", + "name": "Unidad Ecuestre", "description": "El Pokémon tiene dos habilidades: Relincho Negro de Spectrier y Nerviosismo de Calyrex." }, "asOneSpectrier": { - "name": "Unidad Ecuestre", + "name": "Unidad Ecuestre", "description": "El Pokémon tiene dos habilidades: Relincho Negro de Spectrier y Nerviosismo de Calyrex." }, "lingeringAroma": { - "name": "Olor Persistente", + "name": "Olor Persistente", "description": "Contagia la habilidad Olor Persistente al Pokémon que lo ataque con un movimiento de contacto." }, "seedSower": { - "name": "Disemillar", + "name": "Disemillar", "description": "Crea un campo de hierba al recibir un ataque." }, "thermalExchange": { - "name": "Termoconversión", - "description": "Evita las quemaduras y, si lo alcanza un movimiento de tipo Fuego, aumenta su Ataque." + "name": "Termoconversión", + "description": "Evita las quemaduras y, si lo alcanza un movimiento de tipo Fuego, aumenta su ataque." }, "angerShell": { - "name": "Coraza Ira", - "description": "Cuando un ataque reduce sus PS a la mitad, un arrebato de cólera reduce su Defensa y su Defensa Especial, pero aumenta su Ataque, su Ataque Especial y su Velocidad." + "name": "Coraza Ira", + "description": "Cuando un ataque reduce sus PS a la mitad, un arrebato de cólera reduce su defensa y su defensa especial, pero aumenta su ataque, su ataque especial y su velocidad." }, "purifyingSalt": { - "name": "Sal Purificadora", + "name": "Sal Purificadora", "description": "Su sal pura lo protege de los problemas de estado y reduce a la mitad el daño que recibe de ataques de tipo Fantasma." }, "wellBakedBody": { - "name": "Cuerpo Horneado", - "description": "Si lo alcanza un movimiento de tipo Fuego, aumenta mucho su Defensa en vez de sufrir daño." + "name": "Cuerpo Horneado", + "description": "Si lo alcanza un movimiento de tipo Fuego, aumenta mucho su defensa en vez de sufrir daño." }, "windRider": { - "name": "Surcavientos", - "description": "Si sopla un Viento Afín o lo alcanza un movimiento que usa viento, aumenta su Ataque. Tampoco recibe daño de este último." + "name": "Surcavientos", + "description": "Si sopla un Viento Afín o lo alcanza un movimiento que usa viento, aumenta su ataque. Tampoco recibe daño de este último." }, "guardDog": { - "name": "Perro Guardián", - "description": "Aumenta su Ataque si sufre los efectos de Intimidación. También anula movimientos y objetos que fuercen el cambio de Pokémon." + "name": "Perro Guardián", + "description": "Aumenta su ataque si sufre los efectos de Intimidación. También anula movimientos y objetos que fuercen el cambio de Pokémon." }, "rockyPayload": { - "name": "Transportarrocas", + "name": "Transportarrocas", "description": "Potencia los movimientos de tipo Roca." }, "windPower": { - "name": "Energía Eólica", + "name": "Energía Eólica", "description": "Su cuerpo se carga de electricidad si lo alcanza un movimiento que usa viento, lo que potencia su siguiente movimiento de tipo Eléctrico." }, "zeroToHero": { - "name": "Cambio Heroico", + "name": "Cambio Heroico", "description": "Adopta la Forma Heroica cuando se retira del combate." }, "commander": { - "name": "Comandar", + "name": "Comandar", "description": "Si al entrar en combate coincide con un Dondozo aliado, se cuela en el interior de su boca para tomar el control." }, "electromorphosis": { - "name": "Dinamo", + "name": "Dinamo", "description": "Su cuerpo se carga de electricidad al recibir daño, lo que potencia su siguiente movimiento de tipo Eléctrico." }, "protosynthesis": { - "name": "Paleosíntesis", + "name": "Paleosíntesis", "description": "Si hace sol o lleva un tanque de Energía Potenciadora, aumenta su característica más alta." }, "quarkDrive": { - "name": "Carga Cuark", + "name": "Carga Cuark", "description": "Si hay un campo eléctrico en el terreno de combate o lleva un tanque de Energía Potenciadora, aumenta su característica más alta." }, "goodAsGold": { - "name": "Cuerpo Áureo", + "name": "Cuerpo Áureo", "description": "Su robusto cuerpo de oro inoxidable lo hace inmune frente a movimientos de estado de otros Pokémon." }, "vesselOfRuin": { - "name": "Caldero Debacle", - "description": "Reduce el Ataque Especial de todos los demás Pokémon con el poder de su caldero maldito." + "name": "Caldero Debacle", + "description": "Reduce el ataque especial de todos los demás Pokémon con el poder de su caldero maldito." }, "swordOfRuin": { - "name": "Espada Debacle", - "description": "Reduce la Defensa de todos los demás Pokémon con el poder de su espada maldita." + "name": "Espada Debacle", + "description": "Reduce la defensa de todos los demás Pokémon con el poder de su espada maldita." }, "tabletsOfRuin": { - "name": "Tablilla Debacle", - "description": "Reduce el Ataque de todos los demás Pokémon con el poder de sus tablillas malditas." + "name": "Tablilla Debacle", + "description": "Reduce el ataque de todos los demás Pokémon con el poder de sus tablillas malditas." }, "beadsOfRuin": { - "name": "Abalorio Debacle", - "description": "Reduce la Defensa Especial de todos los demás Pokémon con el poder de sus abalorios malditos." + "name": "Abalorio Debacle", + "description": "Reduce la defensa especial de todos los demás Pokémon con el poder de sus abalorios malditos." }, "orichalcumPulse": { - "name": "Latido Oricalco", - "description": "El tiempo pasa a ser soleado cuando entra en combate. Si hace mucho sol, su Ataque aumenta gracias a su pulso primigenio." + "name": "Latido Oricalco", + "description": "El tiempo pasa a ser soleado cuando entra en combate. Si hace mucho sol, su ataque aumenta gracias a su pulso primigenio." }, "hadronEngine": { - "name": "Motor Hadrónico", - "description": "Crea un campo eléctrico al entrar en combate. Si hay un campo eléctrico, su Ataque Especial aumenta gracias a su motor futurista." + "name": "Motor Hadrónico", + "description": "Crea un campo eléctrico al entrar en combate. Si hay un campo eléctrico, su ataque especial aumenta gracias a su motor futurista." }, "opportunist": { - "name": "Oportunista", + "name": "Oportunista", "description": "Copia las mejoras en las características del rival, aprovechándose de la situación." }, "cudChew": { - "name": "Rumia", + "name": "Rumia", "description": "Cuando ingiere una baya, la regurgita al final del siguiente turno y se la come por segunda vez." }, "sharpness": { - "name": "Cortante", + "name": "Cortante", "description": "Aumenta la potencia de los movimientos cortantes." }, "supremeOverlord": { - "name": "General Supremo", - "description": "Al entrar en combate, su Ataque y su Ataque Especial aumentan un poco por cada miembro del equipo que haya sido derrotado hasta el momento." + "name": "General Supremo", + "description": "Al entrar en combate, su ataque y su ataque especial aumentan un poco por cada miembro del equipo que haya sido derrotado hasta el momento." }, "costar": { - "name": "Unísono", + "name": "Unísono", "description": "Al entrar en combate, copia los cambios en las características de su aliado." }, "toxicDebris": { - "name": "Capa Tóxica", + "name": "Capa Tóxica", "description": "Al recibir daño de un ataque físico, lanza una trampa de púas tóxicas a los pies del rival." }, "armorTail": { - "name": "Cola Armadura", + "name": "Cola Armadura", "description": "La extraña cola que le envuelve la cabeza impide al rival usar movimientos con prioridad contra él y sus aliados." }, "earthEater": { - "name": "Geofagia", + "name": "Geofagia", "description": "Si lo alcanza un movimiento de tipo Tierra, recupera PS en vez de sufrir daño." }, "myceliumMight": { - "name": "Poder Fúngico", + "name": "Poder Fúngico", "description": "El Pokémon siempre actúa con lentitud cuando usa movimientos de estado, pero estos no se ven afectados por la habilidad del objetivo." }, "mindsEye": { - "name": "Ojo Mental", - "description": "Alcanza a Pokémon de tipo Fantasma con movimientos de tipo Normal o Lucha. Su Precisión no se puede reducir e ignora los cambios en la Evasión del objetivo." + "name": "Ojo Mental", + "description": "Alcanza a Pokémon de tipo Fantasma con movimientos de tipo Normal o Lucha. Su precisión no se puede reducir e ignora los cambios en la evasión del objetivo." }, "supersweetSyrup": { - "name": "Néctar Dulce", - "description": "Al entrar en combate por primera vez, esparce un aroma dulzón a néctar que reduce la Evasión del rival." + "name": "Néctar Dulce", + "description": "Al entrar en combate por primera vez, esparce un aroma dulzón a néctar que reduce la evasión del rival." }, "hospitality": { - "name": "Hospitalidad", + "name": "Hospitalidad", "description": "Al entrar en combate, restaura algunos PS de su aliado como muestra de hospitalidad." }, "toxicChain": { - "name": "Cadena Tóxica", + "name": "Cadena Tóxica", "description": "Gracias al poder de su cadena impregnada de toxinas, puede envenenar gravemente al Pokémon al que ataque." }, "embodyAspectTeal": { - "name": "Evocarrecuerdos", - "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la Máscara Cimiento y aumenta su Defensa." + "name": "Evocarrecuerdos", + "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la máscara turquesa y aumenta su velocidad." }, "embodyAspectWellspring": { - "name": "Evocarrecuerdos", - "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la Máscara Cimiento y aumenta su Defensa." + "name": "Evocarrecuerdos", + "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la máscara fuente y aumenta su defensa especial." }, "embodyAspectHearthflame": { - "name": "Evocarrecuerdos", - "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la Máscara Cimiento y aumenta su Defensa." + "name": "Evocarrecuerdos", + "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la máscara horno y aumenta su ataque." }, "embodyAspectCornerstone": { - "name": "Evocarrecuerdos", - "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la Máscara Cimiento y aumenta su Defensa." + "name": "Evocarrecuerdos", + "description": "Al evocar viejos recuerdos, el Pokémon hace brillar la máscara cimiento y aumenta su defensa." }, "teraShift": { - "name": "Teracambio", + "name": "Teracambio", "description": "Al entrar en combate, adopta la Forma Teracristal tras absorber la energía de su alrededor." }, "teraShell": { - "name": "Teracaparazón", + "name": "Teracaparazón", "description": "Su caparazón encierra energía de todos los tipos. Gracias a ello, si sus PS están al máximo, el movimiento que lo alcance no será muy eficaz." }, "teraformZero": { - "name": "Teraformación 0", + "name": "Teraformación 0", "description": "Cuando Terapagos adopta la Forma Astral, anula todos los efectos del tiempo atmosférico y de los campos que haya en el terreno gracias a su poder oculto." }, "poisonPuppeteer": { - "name": "Títere Tóxico", + "name": "Títere Tóxico", "description": "Los rivales que Pecharunt envenene con sus movimientos también sufrirán confusión." } } diff --git a/src/locales/es/bgm-name.json b/src/locales/es/bgm-name.json index be617b79567..f0e0ab7e852 100644 --- a/src/locales/es/bgm-name.json +++ b/src/locales/es/bgm-name.json @@ -1,95 +1,99 @@ { "music": "Música: ", "missing_entries": "{{name}}", - "battle_kanto_champion": "B2W2 - ¡Vs Campeón de Kanto!", - "battle_johto_champion": "B2W2 - ¡Vs Campeón de Johto!", - "battle_hoenn_champion_g5": "B2W2 - ¡Vs Campeón de Hoenn!", - "battle_hoenn_champion_g6": "ORAS - ¡Vs Campeón de Hoenn!", - "battle_sinnoh_champion": "B2W2 - ¡Vs Campeón de Sinnoh!", - "battle_champion_alder": "BW - ¡Vs Campeón de Teselia!", - "battle_champion_iris": "B2W2 - ¡Vs Campeón de Teselia!", - "battle_kalos_champion": "XY - ¡Vs Campeón de Kalos!", - "battle_alola_champion": "USUM - ¡Vs Campeón de Alola!", - "battle_galar_champion": "SWSH - ¡Vs Campeón de Galar!", - "battle_champion_geeta": "SV - ¡Vs Campeona Ságita!", - "battle_champion_nemona": "SV - ¡Vs Campeona Mencía!", - "battle_champion_kieran": "SV - ¡Vs Campeón Cass!", - "battle_hoenn_elite": "ORAS - ¡Vs Alto Mando!", - "battle_unova_elite": "BW - ¡Vs Alto Mando!", - "battle_kalos_elite": "XY - ¡Vs Alto Mando!", - "battle_alola_elite": "SM - ¡Vs Alto Mando!", - "battle_galar_elite": "SWSH - Torneo de Finalistas", - "battle_paldea_elite": "SV - ¡Vs Alto Mando!", - "battle_bb_elite": "SV - ¡Vs Alto Mando de la Academia Arándano!", + "battle_kanto_champion": "B2W2 - ¡Vs. Campeón de Kanto!", + "battle_johto_champion": "B2W2 - ¡Vs. Campeón de Johto!", + "battle_hoenn_champion_g5": "B2W2 - ¡Vs. Campeón de Hoenn!", + "battle_hoenn_champion_g6": "ORAS - ¡Vs. Campeón de Hoenn!", + "battle_sinnoh_champion": "B2W2 - ¡Vs. Campeón de Sinnoh!", + "battle_champion_alder": "BW - ¡Vs. Campeón de Teselia!", + "battle_champion_iris": "B2W2 - ¡Vs. Campeón de Teselia!", + "battle_kalos_champion": "XY - ¡Vs. Campeón de Kalos!", + "battle_alola_champion": "USUM - ¡Vs. Campeón de Alola!", + "battle_galar_champion": "SWSH - ¡Vs. Campeón de Galar!", + "battle_champion_geeta": "SV - ¡Vs. Campeona Ságita!", + "battle_champion_nemona": "SV - ¡Vs. Campeona Mencía!", + "battle_champion_kieran": "SV - ¡Vs. Campeón Cass!", + "battle_hoenn_elite": "ORAS - ¡Vs. Alto Mando!", + "battle_unova_elite": "BW - ¡Vs. Alto Mando!", + "battle_kalos_elite": "XY - ¡Vs. Alto Mando!", + "battle_alola_elite": "SM - ¡Vs. Alto Mando!", + "battle_galar_elite": "SWSH - Torneo de finalistas", + "battle_paldea_elite": "SV - ¡Vs. Alto Mando!", + "battle_bb_elite": "SV - ¡Vs. Alto Mando de la Academia Arándano!", "battle_final_encounter": "PMD RTDX - Dominio de Rayquaza", - "battle_final": "BW - ¡Vs Ghechis!", - "battle_kanto_gym": "B2W2 - ¡Vs Líder de Kanto!", - "battle_johto_gym": "B2W2 - ¡Vs Líder de Johto!", - "battle_hoenn_gym": "B2W2 - ¡Vs Líder de Hoenn!", - "battle_sinnoh_gym": "B2W2 - ¡Vs Líder de Sinnoh!", - "battle_unova_gym": "BW - ¡Vs Líder de Teselia!", - "battle_kalos_gym": "XY - ¡Vs Líder de Kalos!", - "battle_galar_gym": "SWSH - ¡Vs Líder de Galar!", - "battle_paldea_gym": "SV - ¡Vs Líder de Paldea!", - "battle_legendary_kanto": "XY - ¡Vs Legendarios de Kanto!", - "battle_legendary_raikou": "HGSS - ¡Vs Raikou!", - "battle_legendary_entei": "HGSS - ¡Vs Entei!", - "battle_legendary_suicune": "HGSS - ¡Vs Suicune!", - "battle_legendary_lugia": "HGSS - ¡Vs Lugia!", - "battle_legendary_ho_oh": "HGSS - ¡Vs Ho-oh!", - "battle_legendary_regis_g5": "B2W2 - ¡Vs Regis!", - "battle_legendary_regis_g6": "ORAS - ¡Vs Regis!", - "battle_legendary_gro_kyo": "ORAS - ¡Vs Groudon/Kyogre!", - "battle_legendary_rayquaza": "ORAS - ¡Vs Rayquaza!", - "battle_legendary_deoxys": "ORAS - ¡Vs Deoxys!", - "battle_legendary_lake_trio": "ORAS - ¡Vs Trío del Lago!", - "battle_legendary_sinnoh": "ORAS - ¡Vs Legendarios de Sinnoh!", - "battle_legendary_dia_pal": "ORAS - ¡Vs Dialga/Palkia!", - "battle_legendary_giratina": "ORAS - ¡Vs Giratina!", - "battle_legendary_arceus": "HGSS - ¡Vs Arceus!", - "battle_legendary_unova": "BW - ¡Vs Legendarios de Teselia!", - "battle_legendary_kyurem": "BW - ¡Vs Kyurem!", - "battle_legendary_res_zek": "BW - ¡Vs Reshiram/Zekrom!", - "battle_legendary_xern_yvel": "XY - ¡Vs Xerneas/Yveltal!", - "battle_legendary_tapu": "SM - ¡Vs Tapus!", - "battle_legendary_sol_lun": "SM - ¡Vs Solgaleo/Lunala!", - "battle_legendary_ub": "SM - ¡Vs Ultraentes!", - "battle_legendary_dusk_dawn": "USUM - ¡Vs Necrozma Melena Crepuscular/Alas del Alba!", - "battle_legendary_ultra_nec": "USUM - ¡Vs Ultra-Necrozma!", - "battle_legendary_zac_zam": "SWSH - ¡Vs Zacian/Zamazenta!", - "battle_legendary_glas_spec": "SWSH - ¡Vs Glastrier/Spectrier!", - "battle_legendary_calyrex": "SWSH - ¡Vs Calyrex!", - "battle_legendary_birds_galar": "SWSH - ¡Vs Aves Legendarias de Galar!", - "battle_legendary_ruinous": "SV - ¡Vs Tesoros Funestos!", - "battle_legendary_kor_mir": "SV Depths of Area Zero Battle", - "battle_legendary_loyal_three": "SV - ¡Vs Compatrones!", - "battle_legendary_ogerpon": "SV - ¡Vs Ogerpon!", - "battle_legendary_terapagos": "SV - ¡Vs Terapagos!", - "battle_legendary_pecharunt": "SV - ¡Vs Pecharunt!", - "battle_rival": "BW - ¡Vs Rival!", + "battle_final": "BW - ¡Vs. Ghechis!", + "battle_kanto_gym": "B2W2 - ¡Vs. Líder de Kanto!", + "battle_johto_gym": "B2W2 - ¡Vs. Líder de Johto!", + "battle_hoenn_gym": "B2W2 - ¡Vs. Líder de Hoenn!", + "battle_sinnoh_gym": "B2W2 - ¡Vs. Líder de Sinnoh!", + "battle_unova_gym": "BW - ¡Vs. Líder de Teselia!", + "battle_kalos_gym": "XY - ¡Vs. Líder de Kalos!", + "battle_galar_gym": "SWSH - ¡Vs. Líder de Galar!", + "battle_paldea_gym": "SV - ¡Vs. Líder de Paldea!", + "battle_legendary_kanto": "XY - ¡Vs. Legendarios de Kanto!", + "battle_legendary_raikou": "HGSS - ¡Vs. Raikou!", + "battle_legendary_entei": "HGSS - ¡Vs. Entei!", + "battle_legendary_suicune": "HGSS - ¡Vs. Suicune!", + "battle_legendary_lugia": "HGSS - ¡Vs. Lugia!", + "battle_legendary_ho_oh": "HGSS - ¡Vs. Ho-oh!", + "battle_legendary_regis_g5": "B2W2 - ¡Vs. Regis!", + "battle_legendary_regis_g6": "ORAS - ¡Vs. Regis!", + "battle_legendary_gro_kyo": "ORAS - ¡Vs. Groudon/Kyogre!", + "battle_legendary_rayquaza": "ORAS - ¡Vs. Rayquaza!", + "battle_legendary_deoxys": "ORAS - ¡Vs. Deoxys!", + "battle_legendary_lake_trio": "ORAS - ¡Vs. trío del Lago!", + "battle_legendary_sinnoh": "ORAS - ¡Vs. legendarios de Sinnoh!", + "battle_legendary_dia_pal": "ORAS - ¡Vs. Dialga/Palkia!", + "battle_legendary_origin_forme": "LA - ¡Vs. Dialga & Palkia, Forma Origen!", + "battle_legendary_giratina": "ORAS - ¡Vs. Giratina!", + "battle_legendary_arceus": "HGSS - ¡Vs. Arceus!", + "battle_legendary_unova": "BW - ¡Vs. legendarios de Teselia!", + "battle_legendary_kyurem": "BW - ¡Vs. Kyurem!", + "battle_legendary_res_zek": "BW - ¡Vs. Reshiram/Zekrom!", + "battle_legendary_xern_yvel": "XY - ¡Vs. Xerneas/Yveltal!", + "battle_legendary_tapu": "SM - ¡Vs. Tapus!", + "battle_legendary_sol_lun": "SM - ¡Vs. Solgaleo/Lunala!", + "battle_legendary_ub": "SM - ¡Vs. Ultraentes!", + "battle_legendary_dusk_dawn": "USUM - ¡Vs. Necrozma Melena Crepuscular/Alas del Alba!", + "battle_legendary_ultra_nec": "USUM - ¡Vs. Ultra-Necrozma!", + "battle_legendary_zac_zam": "SWSH - ¡Vs. Zacian/Zamazenta!", + "battle_legendary_glas_spec": "SWSH - ¡Vs. Glastrier/Spectrier!", + "battle_legendary_calyrex": "SWSH - ¡Vs. Calyrex!", + "battle_legendary_riders": "SWSH - ¡Vs. Calyrex Jinete!", + "battle_legendary_birds_galar": "SWSH - ¡Vs. Aves Legendarias de Galar!", + "battle_legendary_ruinous": "SV - ¡Vs. Tesoros Funestos!", + "battle_legendary_kor_mir": "SV - ¡Batalla en el área Zero!", + "battle_legendary_loyal_three": "SV - ¡Vs. Compatrones!", + "battle_legendary_ogerpon": "SV - ¡Vs. Ogerpon!", + "battle_legendary_terapagos": "SV - ¡Vs. Terapagos!", + "battle_legendary_pecharunt": "SV - ¡Vs. Pecharunt!", + "battle_rival": "BW - ¡Vs. Rival!", "battle_rival_2": "BW - ¡Vs N!", - "battle_rival_3": "BW - ¡Vs N (Liga Pokémon)!", - "battle_trainer": "BW - ¡Vs Entrenador!", - "battle_wild": "BW - ¡Vs Pokémon Salvaje!", - "battle_wild_strong": "BW - ¡Vs Pokémon Salvaje Raro!", - "end_summit": "PMD RTDX - Techo del Cielo", - "battle_rocket_grunt": "HGSS Team Rocket Battle", - "battle_aqua_magma_grunt": "ORAS Team Aqua & Magma Battle", - "battle_galactic_grunt": "BDSP Team Galactic Battle", + "battle_rival_3": "BW - ¡Vs. N (Liga Pokémon)!", + "battle_trainer": "BW - ¡Vs. entrenador!", + "battle_wild": "BW - ¡Vs. Pokémon salvaje!", + "battle_wild_strong": "BW - ¡Vs. Pokémon salvaje raro!", + "end_summit": "PMD RTDX - Techo del cielo", + "battle_rocket_grunt": "HGSS - ¡Vs. Team Rocket!", + "battle_aqua_magma_grunt": "ORAS - ¡Vs. Equipo Aqua & Magma!", + "battle_galactic_grunt": "BDSP - ¡Vs. Equipo Galaxia!", "battle_plasma_grunt": "BW - ¡Vs Equipo Plasma!", - "battle_flare_grunt": "XY Team Flare Battle", - "battle_aether_grunt": "SM Aether Foundation Battle", - "battle_skull_grunt": "SM Team Skull Battle", - "battle_macro_grunt": "SWSH Trainer Battle", - "battle_galactic_admin": "BDSP Team Galactic Admin Battle", - "battle_skull_admin": "SM Team Skull Admin Battle", - "battle_oleana": "SWSH Oleana Battle", - "battle_rocket_boss": "USUM Giovanni Battle", - "battle_aqua_magma_boss": "ORAS Archie & Maxie Battle", - "battle_galactic_boss": "BDSP Cyrus Battle", - "battle_plasma_boss": "B2W2 Ghetsis Battle", - "battle_flare_boss": "XY Lysandre Battle", - + "battle_flare_grunt": "XY - ¡Vs. Team Flare!", + "battle_aether_grunt": "SM - ¡Vs. Fundación Æther!", + "battle_skull_grunt": "SM - ¡Vs. Team Skull!", + "battle_macro_grunt": "SWSH - ¡Vs. entrenador!", + "battle_galactic_admin": "BDSP - ¡Vs. Comandante del Equipo Galaxia!", + "battle_skull_admin": "SM - ¡Vs. Comandante del Team Skull!", + "battle_oleana": "SWSH - ¡Vs. Olivia!", + "battle_rocket_boss": "USUM - ¡Vs. Giovanni!", + "battle_aqua_magma_boss": "ORAS - ¡Vs. Aquiles & Magno!", + "battle_galactic_boss": "BDSP - ¡Vs. Helio!", + "battle_plasma_boss": "B2W2 - ¡Vs. Ghechis Armonia!", + "battle_flare_boss": "XY - ¡Vs. Lysson!", + "battle_aether_boss": "SM - ¡Vs. Samina!", + "battle_skull_boss": "SM - ¡Vs. Guzmán!", + "battle_macro_boss": "SWSH - ¡Vs. Rose!", "abyss": "PMD EoS - Cráter Oscuro", "badlands": "PMD EoS - Valle Desolado", "beach": "PMD EoS - Risco Calado", @@ -105,40 +109,40 @@ "graveyard": "PMD EoS - Bosque Misterio", "ice_cave": "PMD EoS - Gran Iceberg", "island": "PMD EoS - Costa Escarpada", - "jungle": "Lmz - Jungle", - "laboratory": "Firel - Laboratory", + "jungle": "Lmz - Jungla", + "laboratory": "Firel - Laboratorio", "lake": "PMD EoS - Cueva Cristal", "meadow": "PMD EoS - Bosque de la Cumbre del Cielo", - "metropolis": "Firel - Metropolis", + "metropolis": "Firel - Metrópolis", "mountain": "PMD EoS - Monte Cuerno", "plains": "PMD EoS - Pradera de la Cumbre del Cielo", "power_plant": "PMD EoS - Pradera Destello", "ruins": "PMD EoS - Sima Hermética", - "sea": "Andr06 - Marine Mystique", - "seabed": "Firel - Seabed", - "slum": "Andr06 - Sneaky Snom", + "sea": "Andr06 - Misticismo marino", + "seabed": "Firel - Lecho del mar", + "slum": "Andr06 - Snom sigiloso", "snowy_forest": "PMD EoS - Campo nevado de la Cumbre del Cielo", - "space": "Firel - Aether", + "space": "Firel - Æther ", "swamp": "PMD EoS - Mar Circundante", "tall_grass": "PMD EoS - Bosque Niebla", "temple": "PMD EoS - Cueva Regia", "town": "PMD EoS - Tema del territorio aleatorio 3", "volcano": "PMD EoS - Cueva Vapor", "wasteland": "PMD EoS - Corazón Tierra Oculta", - "encounter_ace_trainer": "BW - Desafío Combate (Entrenador Guay)", - "encounter_backpacker": "BW - Desafío Combate (Mochilero)", - "encounter_clerk": "BW - Desafío Combate (Empresario)", - "encounter_cyclist": "BW - Desafío Combate (Ciclista)", - "encounter_lass": "BW - Desafío Combate (Chica)", - "encounter_parasol_lady": "BW - Desafío Combate (Dama parasol)", - "encounter_pokefan": "BW - Desafío Combate (Pokéfan)", - "encounter_psychic": "BW - Desafío Combate (Médium)", - "encounter_rich": "BW - Desafío Combate (Aristócrata)", - "encounter_rival": "BW - Desafío Combate (Cheren)", - "encounter_roughneck": "BW - Desafío Combate (Calvo)", - "encounter_scientist": "BW - Desafío Combate (Científico)", - "encounter_twins": "BW - Desafío Combate (Gemelas)", - "encounter_youngster": "BW - Desafío Combate (Joven)", + "encounter_ace_trainer": "BW - ¡Vs. entrenador guay!", + "encounter_backpacker": "BW - ¡Vs. mochilero!", + "encounter_clerk": "BW - ¡Vs. empresario!", + "encounter_cyclist": "BW - ¡Vs. ciclista!", + "encounter_lass": "BW - ¡Vs. chica joven!", + "encounter_parasol_lady": "BW - ¡Vs. dama parasol!", + "encounter_pokefan": "BW - ¡Vs. poké-fan!", + "encounter_psychic": "BW -¡Vs. médium!", + "encounter_rich": "BW - ¡Vs. aristócrata!", + "encounter_rival": "BW - ¡Vs. Cheren!", + "encounter_roughneck": "BW - ¡Vs. tío chungo!", + "encounter_scientist": "BW - ¡Vs. científico!", + "encounter_twins": "BW - ¡Vs. gemelas!", + "encounter_youngster": "BW - ¡Vs. chico joven!", "heal": "BW - Cura Pokémon", "menu": "PMD EoS - ¡Bienvenidos al mundo de los Pokémon!", "title": "PMD EoS - Tema del menú principal" From dd033f4ec1636adff8488545bd35bdcc85715aa7 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:17:05 -0400 Subject: [PATCH 30/40] [Localization] [pt_BR] Updated many translations (#3917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translate tutorial.json via GitLocalize * Translate challenges.json via GitLocalize * Translate menu-ui-handler.json via GitLocalize --------- Co-authored-by: José Ricardo --- src/locales/pt_BR/challenges.json | 2 +- src/locales/pt_BR/menu-ui-handler.json | 8 ++++---- src/locales/pt_BR/tutorial.json | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/locales/pt_BR/challenges.json b/src/locales/pt_BR/challenges.json index 6b20a92f4f6..8402ad106b6 100644 --- a/src/locales/pt_BR/challenges.json +++ b/src/locales/pt_BR/challenges.json @@ -33,4 +33,4 @@ "value.0": "Desligado", "value.1": "Ligado" } -} \ No newline at end of file +} diff --git a/src/locales/pt_BR/menu-ui-handler.json b/src/locales/pt_BR/menu-ui-handler.json index cc087c8335e..df654976d68 100644 --- a/src/locales/pt_BR/menu-ui-handler.json +++ b/src/locales/pt_BR/menu-ui-handler.json @@ -14,8 +14,8 @@ "importSlotSelect": "Selecione um slot para importar.", "exportSession": "Exportar sessão", "exportSlotSelect": "Selecione um slot para exportar.", - "importRunHistory":"Importar Histórico de Jogos", - "exportRunHistory":"Exportar Histórico de Jogos", + "importRunHistory": "Importar Histórico de Jogos", + "exportRunHistory": "Exportar Histórico de Jogos", "importData": "Importar dados", "exportData": "Exportar dados", "consentPreferences": "Opções de Privacidade", @@ -25,5 +25,5 @@ "unlinkGoogle": "Desconectar Google", "cancel": "Cancelar", "losingProgressionWarning": "Você vai perder todo o progresso desde o início da batalha. Confirmar?", - "noEggs": "Você não está chocando\nnenhum ovo no momento!" -} \ No newline at end of file + "noEggs": "Você não está chocando nenhum ovo\nno momento!" +} diff --git a/src/locales/pt_BR/tutorial.json b/src/locales/pt_BR/tutorial.json index e347ca6fbee..92ea0dd080f 100644 --- a/src/locales/pt_BR/tutorial.json +++ b/src/locales/pt_BR/tutorial.json @@ -1,10 +1,10 @@ { - "intro": "Bem-vindo ao PokéRogue! Este é um jogo Pokémon feito por fãs focado em batalhas com elementos roguelite.\n$Este jogo não é monetizado e não reivindicamos propriedade de Pokémon nem dos ativos protegidos\n$por direitos autorais usados.\n$O jogo é um trabalho em andamento, mas é totalmente jogável.\n$Para relatórios de bugs, use a comunidade no Discord.\n$Se o jogo estiver rodando lentamente, certifique-se de que a 'Aceleração de hardware' esteja ativada \n$nas configurações do seu navegador.", + "intro": "Bem-vindo ao PokéRogue!\n$Este é um fangame Pokémon focado em batalhas com elementos roguelite.\n$Este jogo não é monetizado e não reivindicamos propriedade do Pokémon nem dos ativos protegidos$por direitos autorais usados.\n$O jogo é um trabalho em andamento,\nmas totalmente jogável.\n$Para relatórios de bugs, use a comunidade do Discord.\n$Se o jogo rodar lentamente, certifique-se de que\na 'Aceleração de Hardware' esteja ativada$nas configurações do seu navegador.", "accessMenu": "Para acessar o menu, pressione M ou Esc.\n$O menu contém configurações e diversas funções.", - "menu": "A partir deste menu, você pode acessar as configurações. \n$Nas configurações, você pode alterar a velocidade do jogo,\n$o estilo da janela, entre outras opções. \n$Existem também vários outros recursos disponíveis aqui.\n$Não deixe de conferir todos eles!", - "starterSelect": "Aqui você pode escolher seus iniciais apertando a tecla Z ou\na Barra de Espaço.\n$Esses serão os primeiro Pokémon da sua equipe.\n$Cada inicial tem seu custo. Sua equipe pode ter até 6\nmembros, desde que a soma dos custos não ultrapasse 10. \n$Você pode escolher o gênero, a habilidade\ne até a forma do seu inicial.\n$Essas opções dependem das variantes dessa\nespécie que você já capturou ou chocou. \n$Os IVs de cada inicial são os melhores de todos os Pokémon\ndaquela espécie que você já capturou ou chocou.\n$Sempre capture vários Pokémon de várias espécies!", + "menu": "A partir deste menu, você pode\\nacessar as configurações.\n$A partir das configurações, você\npode alterar a velocidade do jogo,\n$o estilo da janela e outras opções.\n$Há também vários outros recursos aqui.\nCertifique-se de verificar todos eles!", + "starterSelect": "Nesta tela, você pode selecionar seus iniciais\npressionando Z ou a barra de espaço.\n$Esses serão os primeiros membros da sua equipe.\n$Cada inicial tem um custo. Sua equipe pode ter até 6 membros,\ndesde que desde que o custo total não exceda 10.\n$Você pode escolher o gênero, a habilidade\ne até a forma do seu inicial.\n$Essas opções dependem das variantes dessa\nespécie que você já capturou ou chocou.\n$Os IVs de cada inicial são os melhores de todos os Pokémon\ndaquela espécie que você já capturou ou chocou.\n$Sempre capture vários Pokémon de todas as espécies!", "pokerus": "Todo dia, 3 Pokémon iniciais ficam com uma borda roxa.\n$Caso veja um inicial que você possui com uma dessa, tente\nadicioná-lo a sua equipe. Lembre-se de olhar seu sumário!", "statChange": "As mudanças de atributos se mantém após a batalha desde que o Pokémon não seja trocado.\n$Seus Pokémon voltam a suas Poké Bolas antes de batalhas contra treinadores e de entrar em um novo bioma.\n$Para ver as mudanças de atributos dos Pokémon em campo, mantena C ou Shift pressionado durante a batalha.", "selectItem": "Após cada batalha, você pode escolher entre 3 itens aleatórios.\n$Você pode escolher apenas um deles.\n$Esses itens variam entre consumíveis, itens de segurar e itens passivos permanentes.\n$A maioria dos efeitos de itens não consumíveis podem ser acumulados.\n$Alguns itens só aparecerão se puderem ser usados, como os itens de evolução.\n$Você também pode transferir itens de segurar entre os Pokémon utilizando a opção \"Alterar\".\n$A opção de transferir irá aparecer no canto inferior direito assim que você obter um item de segurar.\n$Você pode comprar itens consumíveis com dinheiro, e sua variedade aumentará conforme você for mais longe.\n$Certifique-se de comprá-los antes de escolher seu item aleatório. Ao escolhê-lo, a próxima batalha começará.", - "eggGacha": "Aqui você pode trocar seus vouchers\npor ovos de Pokémon.\n$Ovos ficam mais próximos de chocar após cada batalha.\nOvos mais raros demoram mais para chocar.\n$Pokémon chocados não serão adicionados a sua equipe,\nmas sim aos seus iniciais.\n$Pokémon chocados geralmente possuem IVs melhores\nque Pokémon selvagens.\n$Alguns Pokémon só podem ser obtidos através de seus ovos.\n$Temos 3 máquinas, cada uma com seu bônus específico,\nentão escolha a que mais lhe convém!" + "eggGacha": "Nesta tela, você pode trocar seus vouchers por ovos\nde Pokémon.\n$Ovos ficam mais próximos de chocar após cada batalha.\nOvos mais raros demoram mais tempo para chocar.\n$Pokémon chocados não serão adicionados a sua equipe,\nmas sim aos seus iniciais.\n$Pokémon chocados de ovos geralmente têm IVs melhores\ndo que Pokémon selvagens.\n$Alguns Pokémon só podem ser obtidos através de ovos.\n$Existem 3 máquinas para usar com diferentes bônus, então\nescolha a que mais lhe convém!" } From a894438e24166f51ef7258c70f03194d5833eeea Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:18:49 -0400 Subject: [PATCH 31/40] [Localisation] [JA] Several files translated (#3916) * Translate ability-trigger.json via GitLocalize * Translate game-stats-ui-handler.json via GitLocalize * Translate modifier-select-ui-handler.json via GitLocalize * Translate pokemon-form-battle.json via GitLocalize * Translate battle-info.json via GitLocalize * Translate menu.json via GitLocalize * Translate battler-tags.json via GitLocalize * Translate pokemon-info.json via GitLocalize * Translate achv.json via GitLocalize * Translate berry.json via GitLocalize * Translate achv-female.json via GitLocalize * Translate challenges.json via GitLocalize * Translate menu-ui-handler.json via GitLocalize * Translate egg.json via GitLocalize * Translate pokemon.json via GitLocalize * Translate pokemon.json via GitLocalize * Translate starter-select-ui-handler.json via GitLocalize * Translate command-ui-handler.json via GitLocalize * Translate settings.json via GitLocalize * Update achv-female.json * Update menu-ui-handler.json * Update settings.json * Update achv.json * Update achv.json * Update achv.json * Delete src/locales/ja/achv-female.json * Update achv.json Compared in-game, with these changes it should all look good. * Update challenges.json * Update game-mode.json * Update menu.json * Update settings.json * Translate game-stats-ui-handler.json via GitLocalize * Update game-stats-ui-handler.json * Update settings.json --------- Co-authored-by: gitlocalize-app[bot] <55277160+gitlocalize-app[bot]@users.noreply.github.com> Co-authored-by: Enoch Co-authored-by: Chapybara-jp --- src/locales/ja/ability-trigger.json | 3 +- src/locales/ja/achv.json | 23 ++++--- src/locales/ja/battler-tags.json | 14 +++- src/locales/ja/berry.json | 24 +++---- src/locales/ja/challenges.json | 22 +++--- src/locales/ja/command-ui-handler.json | 4 +- src/locales/ja/egg.json | 22 +++--- src/locales/ja/game-mode.json | 6 +- src/locales/ja/game-stats-ui-handler.json | 30 ++++---- src/locales/ja/menu-ui-handler.json | 17 +++-- src/locales/ja/menu.json | 67 +++++++++++------- .../ja/modifier-select-ui-handler.json | 10 +-- src/locales/ja/pokemon-info.json | 29 ++++---- src/locales/ja/pokemon.json | 8 +-- src/locales/ja/settings.json | 68 +++++++++++++++---- src/locales/ja/starter-select-ui-handler.json | 9 +-- 16 files changed, 218 insertions(+), 138 deletions(-) diff --git a/src/locales/ja/ability-trigger.json b/src/locales/ja/ability-trigger.json index f9d1cc60e4c..ec77d4d97d3 100644 --- a/src/locales/ja/ability-trigger.json +++ b/src/locales/ja/ability-trigger.json @@ -12,7 +12,6 @@ "blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!", "typeImmunityHeal": "{{pokemonNameWithAffix}}は {{abilityName}}で\n体力を 回復した!", "nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}}は {{abilityName}}で\nダメージを 受けない。", - "postDefendDisguise": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!", "moveImmunity": "{{pokemonNameWithAffix}}には\n効果が ないようだ…", "reverseDrain": "{{pokemonNameWithAffix}}は\nヘドロえきを 吸い取った!", "postDefendTypeChange": "{{pokemonNameWithAffix}}は {{abilityName}}で\n{{typeName}}タイプに なった!", @@ -60,4 +59,4 @@ "postSummonTabletsOfRuin": "{{pokemonNameWithAffix}}の わざわいのおふだ\nまわりの {{statName}}が 弱まった!", "postSummonBeadsOfRuin": "{{pokemonNameWithAffix}}の わざわいのたまで\nまわりの {{statName}}が 弱まった!", "preventBerryUse": "{{pokemonNameWithAffix}}は 緊張して\nきのみが 食べられなくなった!" -} \ No newline at end of file +} diff --git a/src/locales/ja/achv.json b/src/locales/ja/achv.json index 0dc5dc8185a..809375e5c7e 100644 --- a/src/locales/ja/achv.json +++ b/src/locales/ja/achv.json @@ -6,7 +6,7 @@ "name": "なし" }, "MoneyAchv": { - "description": "一回の ランで ₽{{moneyAmount}}を 稼ぐ" + "description": "一回の ランで {{moneyAmount}}円を 稼ぐ" }, "10K_MONEY": { "name": "お金を持つ人" @@ -21,7 +21,7 @@ "name": "超富裕層" }, "DamageAchv": { - "description": "一撃で {{damageAmount}}ダメージを 与える" + "description": "一撃で HP{{damageAmount}}の ダメージを 与える" }, "250_DMG": { "name": "力持ち" @@ -33,10 +33,11 @@ "name": "カカロット" }, "10000_DMG": { - "name": "ワンパンマン" + "name": "ワンパンマン", + "name_female": "ワンパンウーマン" }, "HealAchv": { - "description": "一つの 技や 特性や 持っているアイテムで {{healAmount}}{{HP}}を 一気に 回復する" + "description": "一つの 技や 特性や 持っているアイテムで\n{{healAmount}}{{HP}}を 一気に 回復する" }, "250_HEAL": { "name": "回復発見者" @@ -82,7 +83,7 @@ }, "TRANSFER_MAX_BATTLE_STAT": { "name": "同力", - "description": "少なくとも 一つの 能力を 最大まで あげて 他の 手持ちポケモンに バトンタッチする" + "description": "少なくとも 一つの 能力を 最大まで あげて\n他の 手持ちポケモンに バトンタッチする" }, "MAX_FRIENDSHIP": { "name": "マブ達", @@ -106,7 +107,7 @@ }, "SPLICE": { "name": "インフィニット・フュジョン", - "description": "いでんしのくさびで 二つの ポケモンを 吸収合体させる" + "description": "遺伝子のくさびで 二つの ポケモンを 吸収合体させる" }, "MINI_BLACK_HOLE": { "name": "アイテムホーリック", @@ -161,8 +162,8 @@ "description": "クラシックモードを クリアする" }, "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": "はじめてのおつかい", + "description": "少なくとも 一つの 進化していない 手持ちポケモンで\nクラシックモードを クリアする" }, "MONO_GEN_ONE": { "name": "原始", @@ -260,5 +261,9 @@ "FRESH_START": { "name": "一発で!", "description": "出直しチャレンジを クリアする" + }, + "INVERSE_BATTLE": { + "name": "カガミよミガカ", + "description": "反転バトルチャレンジを クリアする\nるすアリク をジンレャチルトバ転反" } -} \ No newline at end of file +} diff --git a/src/locales/ja/battler-tags.json b/src/locales/ja/battler-tags.json index beef485ffd2..25412c971e9 100644 --- a/src/locales/ja/battler-tags.json +++ b/src/locales/ja/battler-tags.json @@ -1,4 +1,12 @@ { + "trappedDesc": "捕らわれること", + "flinchedDesc": "ひるむこと", + "confusedDesc": "混乱", + "infatuatedDesc": "メロメロ", + "seedDesc": "種を植えつくこと", + "nightmareDesc": "あくむ", + "ingrainDesc": "根", + "drowsyDesc": "ねむけ", "rechargingLapse": "{{pokemonNameWithAffix}}は 攻撃の 反動で 動けない!", "trappedOnAdd": "{{pokemonNameWithAffix}}は もう 逃げられない!", "trappedOnRemove": "{{pokemonNameWithAffix}}は\n{{moveName}}の 効果が 解けた!", @@ -13,9 +21,9 @@ "infatuatedOnAdd": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロに なった!", "infatuatedOnOverlap": "{{pokemonNameWithAffix}}は すでに メロメロだ!", "infatuatedLapse": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロだ!", - "infatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は\nメロメロで わざが 出せなかった!", + "infatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は メロメロで 技が出せなかった!", "infatuatedOnRemove": "{{pokemonNameWithAffix}}は メロメロ状態が 治った!", - "seededOnAdd": "{{pokemonNameWithAffix}}に 種を 植(う)えつけた!", + "seededOnAdd": "{{pokemonNameWithAffix}}に 種を 植えつけた!", "seededLapse": "やどりぎが {{pokemonNameWithAffix}}の 体力を うばう!", "seededLapseShed": "{{pokemonNameWithAffix}}は ヘドロえきを 吸い取った!", "nightmareOnAdd": "{{pokemonNameWithAffix}}は あくむを 見始めた!", @@ -60,4 +68,4 @@ "cursedOnAdd": "{{pokemonNameWithAffix}}は 自分の 体力を 削って\n{{pokemonName}}に のろいを かけた!", "cursedLapse": "{{pokemonNameWithAffix}}は のろわれている!", "stockpilingOnAdd": "{{pokemonNameWithAffix}}は {{stockpiledCount}}つ たくわえた!" -} \ No newline at end of file +} diff --git a/src/locales/ja/berry.json b/src/locales/ja/berry.json index 641901583b2..73d13d5e8f0 100644 --- a/src/locales/ja/berry.json +++ b/src/locales/ja/berry.json @@ -1,46 +1,46 @@ { "SITRUS": { "name": "オボンのみ", - "effect": "HP 50%いかのとき HPを 25パーセント かいふくする" + "effect": "持たせると HPが 50%以下になるとき HPを 25% 回復する" }, "LUM": { "name": "ラムのみ", - "effect": "すべての じょうたい いじょうと こんらんを かいふくする" + "effect": "持たせると 状態異常や 混乱になるとき 回復する\n" }, "ENIGMA": { "name": "ナゾのみ", - "effect": "こうかばつぐんの わざを うけたとき HPを 25パーセント かいふくする" + "effect": "持たせると 効果バツグンの 技を 受けたとき HPを 25%回復する" }, "LIECHI": { "name": "チイラのみ", - "effect": "HP 25%いかのとき こうげきが あがる" + "effect": "持たせると HPが 25%以下に なるとき 攻撃が あがる" }, "GANLON": { "name": "リュガのみ", - "effect": "HP 25%いかのとき ぼうぎょが あがる" + "effect": "持たせると HPが 25%以下に なるとき 防御が あがる\n" }, "PETAYA": { "name": "ヤタピのみ", - "effect": "HP 25%いかのとき とくこうが あがる" + "effect": "持たせると HPが 25%以下に なるとき 特攻が あがる\n" }, "APICOT": { "name": "ズアのみ", - "effect": "HP 25%いかのとき とくぼうが あがる" + "effect": "持たせると HPが 25%以下に なるとき 特防が あがる\n" }, "SALAC": { "name": "カムラのみ", - "effect": "HP 25%いかのとき すばやさが あがる" + "effect": "持たせると HPが 25%以下に なるとき 素早さが あがる" }, "LANSAT": { "name": "サンのみ", - "effect": "HP 25%いかのとき こうげきが きゅうしょに あたりやすくなる" + "effect": "持たせると HPが 25%以下に なるとき 攻撃が 急所に 当たりやすくなる" }, "STARF": { "name": "スターのみ", - "effect": "HP 25%いかのとき のうりょくの どれか 1つが ぐーんと あがる" + "effect": "持たせると HPが 25%以下に なるとき どれか 1つの 能力が ぐーんと あがる" }, "LEPPA": { "name": "ヒメリのみ", - "effect": "PPが 0に なった わざの PPを 10だけ かいふくする" + "effect": "持たせると PPが 0になる 技のPPを 10回復する" } -} \ No newline at end of file +} diff --git a/src/locales/ja/challenges.json b/src/locales/ja/challenges.json index 54225ebf766..99c6e978d49 100644 --- a/src/locales/ja/challenges.json +++ b/src/locales/ja/challenges.json @@ -1,10 +1,10 @@ { - "title": "チャレンジを 設定", + "title": "チャレンジを 設定", "illegalEvolution": "{{pokemon}}は このチャレンジで\n対象外の ポケモンに なってしまった!", "singleGeneration": { "name": "単一世代", - "desc": "{{gen}}世代からの ポケモンしか 使えません", - "desc_default": "選んだ 世代からの ポケモンしか 使えません", + "desc": "{{gen}}世代からの ポケモンしか 使えません", + "desc_default": "選んだ 世代からの ポケモンしか 使えません", "gen_1": "1", "gen_2": "2", "gen_3": "3", @@ -17,14 +17,20 @@ }, "singleType": { "name": "単一タイプ", - "desc": "{{type}}タイプの ポケモンしか 使えません", - "desc_default": "選んだ タイプの ポケモンしか 使えません" + "desc": "{{type}}タイプの ポケモンしか 使えません", + "desc_default": "選んだ タイプの ポケモンしか 使えません" }, "freshStart": { "name": "出直し", - "shortName": "出直し", - "desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の 最初のパートナーしか 使えません", + "desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の スターターしか 使えません", + "value.0": "オフ", + "value.1": "オン" + }, + "inverseBattle": { + "name": "反転バトル", + "shortName": "反バ", + "desc": "タイプ相性が 反転で、なんの タイプも 「効果はなし」が ありません\n他の チャレンジの 実績が 無効に されます", "value.0": "オフ", "value.1": "オン" } -} \ No newline at end of file +} diff --git a/src/locales/ja/command-ui-handler.json b/src/locales/ja/command-ui-handler.json index 0b2020a9517..6248a19785f 100644 --- a/src/locales/ja/command-ui-handler.json +++ b/src/locales/ja/command-ui-handler.json @@ -3,5 +3,5 @@ "ball": "ボール", "pokemon": "ポケモン", "run": "にげる", - "actionMessage": "{{pokemonName}}は どうする?" -} \ No newline at end of file + "actionMessage": "{{pokemonName}}は どうする?" +} diff --git a/src/locales/ja/egg.json b/src/locales/ja/egg.json index b0cb7b7de61..91b1442c56c 100644 --- a/src/locales/ja/egg.json +++ b/src/locales/ja/egg.json @@ -4,23 +4,23 @@ "ultraTier": "超レア", "masterTier": "伝説", "defaultTier": "ふつう", - "hatchWavesMessageSoon": "なかから おとが きこえてくる! もうすぐ うまれそう!", - "hatchWavesMessageClose": "ときどき うごいている みたい。 うまれるまで もう ちょっとかな?", - "hatchWavesMessageNotClose": "なにが うまれてくるのかな? うまれるまで まだまだ じかんが かかりそう。", - "hatchWavesMessageLongTime": "この タマゴは うまれるまで かなり じかんが かかりそう。", + "hatchWavesMessageSoon": "中から 音が 聞こえてくる! もうすぐ 生まれそう!", + "hatchWavesMessageClose": "時々 動いている みたい。生まれるまで もう ちょっとかな?", + "hatchWavesMessageNotClose": "なにが 生まれてくるのかな? 生まれるまで まだまだ 時間が かかりそう。", + "hatchWavesMessageLongTime": "この タマゴは 生まれるまで かなり 時間が かかりそう。", "gachaTypeLegendary": "伝説確率アップ", - "gachaTypeMove": "レアなタマゴわざ確率アップ", + "gachaTypeMove": "レアなタマゴ技確率アップ", "gachaTypeShiny": "色違い確率アップ", "selectMachine": "ガチャマシンを選択", "notEnoughVouchers": "タマゴクーポンが足りません!", "tooManyEggs": "タマゴが一杯です!", "pull": "回引く", "pulls": "回引く", - "sameSpeciesEgg": "{{species}}は このタマゴから うまれる!", - "hatchFromTheEgg": "{{pokemonName}}は タマゴから うまれた!", - "eggMoveUnlock": "タマゴわざ {{moveName}}を おぼえた!", - "rareEggMoveUnlock": "レアなタマゴわざ {{moveName}}を おぼえた!!", - "moveUPGacha": "わざ UP!", + "sameSpeciesEgg": "{{species}}は このタマゴから 生まれる!", + "hatchFromTheEgg": "{{pokemonName}}は タマゴから 生まれた!", + "eggMoveUnlock": "タマゴ技: {{moveName}}を 覚えた!", + "rareEggMoveUnlock": "レアなタマゴ技: {{moveName}}を 覚えた!!", + "moveUPGacha": "技 UP!", "shinyUPGacha": "色違い UP!", "legendaryUPGacha": "UP!" -} \ No newline at end of file +} diff --git a/src/locales/ja/game-mode.json b/src/locales/ja/game-mode.json index 36559e5cce3..dc04b36932f 100644 --- a/src/locales/ja/game-mode.json +++ b/src/locales/ja/game-mode.json @@ -1,8 +1,8 @@ { "classic": "クラシック", "endless": "エンドレス", - "endlessSpliced": "エンドレス (Spliced)", + "endlessSpliced": "エンドレス(吸収合体)", "dailyRun": "デイリーラン", - "unknown": "Unknown", + "unknown": "???", "challenge": "チャレンジ" -} \ No newline at end of file +} diff --git a/src/locales/ja/game-stats-ui-handler.json b/src/locales/ja/game-stats-ui-handler.json index 25bb21f701a..2fff802734a 100644 --- a/src/locales/ja/game-stats-ui-handler.json +++ b/src/locales/ja/game-stats-ui-handler.json @@ -1,6 +1,6 @@ { "stats": "統計", - "playTime": "プレー時間", + "playTime": "プレイ時間", "totalBattles": "合計バトル数", "starters": "スターター数", "shinyStarters": "色違いスターター数", @@ -12,31 +12,31 @@ "dailyRunAttempts": "デイリーラン", "dailyRunWins": "デイリーラン勝利", "endlessRuns": "エンドレスラン", - "highestWaveEndless": "エンドレス最高ウェーブ", + "highestWaveEndless": "エンドレス最高波", "highestMoney": "最大貯金", "highestDamage": "最大ダメージ", "highestHPHealed": "最大HP回復", "pokemonEncountered": "遭遇したポケモン", "pokemonDefeated": "倒したポケモン", "pokemonCaught": "捕まえたポケモン", - "eggsHatched": "ふかしたタマゴ", - "subLegendsSeen": "見つけた順伝説", - "subLegendsCaught": "捕まえた順伝説", - "subLegendsHatched": "ふかした順伝説", - "legendsSeen": "見つけた伝説", - "legendsCaught": "捕まえた伝説", - "legendsHatched": "ふかした伝説", + "eggsHatched": "孵化したタマゴ", + "subLegendsSeen": "見つけた順伝説ポケモン", + "subLegendsCaught": "捕まえた準伝説ポケモン", + "subLegendsHatched": "孵化した準伝説ポケモン", + "legendsSeen": "見つけた伝説ポケモン", + "legendsCaught": "捕まえた伝説ポケモン", + "legendsHatched": "孵化した伝説ポケモン", "mythicalsSeen": "見つけた幻ポケモン", "mythicalsCaught": "捕まえた幻ポケモン", - "mythicalsHatched": "ふかした幻ポケモン", - "shiniesSeen": "見つけた色違い", - "shiniesCaught": "捕まえた色違い", - "shiniesHatched": "ふかした色違い", - "pokemonFused": "合体したポケモン", + "mythicalsHatched": "孵化した幻ポケモン", + "shiniesSeen": "見つけた色違いポケモン", + "shiniesCaught": "捕まえた色違いポケモン", + "shiniesHatched": "孵化した色違いポケモン", + "pokemonFused": "吸収合体したポケモン", "trainersDefeated": "倒したトレーナー", "eggsPulled": "引いたタマゴ", "rareEggsPulled": "引いたレアタマゴ", "epicEggsPulled": "引いた超レアタマゴ", "legendaryEggsPulled": "引いた伝説タマゴ", "manaphyEggsPulled": "引いたマナフィタマゴ" -} \ No newline at end of file +} diff --git a/src/locales/ja/menu-ui-handler.json b/src/locales/ja/menu-ui-handler.json index beb014b84a9..1930c3999c6 100644 --- a/src/locales/ja/menu-ui-handler.json +++ b/src/locales/ja/menu-ui-handler.json @@ -2,19 +2,22 @@ "GAME_SETTINGS": "設定", "ACHIEVEMENTS": "実績", "STATS": "統計", + "RUN_HISTORY": "ラン歴", "EGG_LIST": "タマゴリスト", "EGG_GACHA": "タマゴガチャ", "MANAGE_DATA": "データ管理", "COMMUNITY": "コミュニティ", - "SAVE_AND_QUIT": "保存して終了", + "SAVE_AND_QUIT": "セーブして終了", "LOG_OUT": "ログアウト", "slot": "スロット {{slotNumber}}", - "importSession": "セッションのインポート", + "importSession": "セッションをインポート", "importSlotSelect": "インポート先の スロットを 選んでください", - "exportSession": "セッションのエクスポート", + "exportSession": "セッションをエクスポート", "exportSlotSelect": "エクスポート元の スロットを 選んでください", - "importData": "データのインポート", - "exportData": "データのエクスポート", + "importRunHistory": "ラン歴をインポート", + "exportRunHistory": "ラン歴をエクスポート", + "importData": "データをインポート", + "exportData": "データをエクスポート", "consentPreferences": "同意設定", "linkDiscord": "Discord連携", "unlinkDiscord": "Discord連携解除", @@ -22,5 +25,5 @@ "unlinkGoogle": "Google連携解除", "cancel": "キャンセル", "losingProgressionWarning": "戦闘開始からの データが 保存されません。\nよろしいですか?", - "noEggs": "現在 タマゴを ふかしていません!" -} \ No newline at end of file + "noEggs": "現在は タマゴを 孵化していません!" +} diff --git a/src/locales/ja/menu.json b/src/locales/ja/menu.json index ce6f9ae0672..0e7701578bf 100644 --- a/src/locales/ja/menu.json +++ b/src/locales/ja/menu.json @@ -1,38 +1,55 @@ { "cancel": "キャンセル", "continue": "つづきから", - "loadGame": "ロードセーブ", + "dailyRun": "日替わりラン(ベータ版)", + "loadGame": "セーブを読み込む", "newGame": "はじめから", - "username": "ユーザーめい", + "settings": "設定", + "selectGameMode": "ゲームモードを 選んでください。", + "logInOrCreateAccount": "始めるには、ログイン、または 登録して ください。\nメールアドレスは 必要が ありません!", + "username": "ユーザー名", "password": "パスワード", "login": "ログイン", - "orUse": "Or use", - "register": "かいいん とうろく", - "emptyUsername": "ユーザー名は空にできません", - "invalidLoginUsername": "入力したユーザー名は無効です", - "invalidRegisterUsername": "ユーザー名には英文字、数字、アンダースコアのみを含める必要があります", + "orUse": "他の\nログイン方法", + "register": "登録", + "emptyUsername": "ユーザー名を 空にする ことは できません", + "invalidLoginUsername": "入力されたユーザー名は無効です", + "invalidRegisterUsername": "ユーザー名には 英文字、 数字、 アンダースコアのみを 含くむ必要が あります", "invalidLoginPassword": "入力したパスワードは無効です", - "invalidRegisterPassword": "パスワードは6文字以上でなければなりません", - "usernameAlreadyUsed": "ユーザー名は既に使用されています", - "accountNonExistent": "ユーザーは存在しません", - "unmatchingPassword": "パスワードが一致しません", - "passwordNotMatchingConfirmPassword": "パスワードは確認パスワードと一致する必要があります", + "invalidRegisterPassword": "パスワードは 6文字以上 でなければなりません", + "usernameAlreadyUsed": "入力したユーザー名は すでに 使用されています", + "accountNonExistent": "入力したユーザーは 存在しません", + "unmatchingPassword": "入力したパスワードが 一致しません", + "passwordNotMatchingConfirmPassword": "パスワードは パスワード確認と 一致する 必要があります", "confirmPassword": "パスワード確認", - "registrationAgeWarning": "登録することで、あなたが13歳以上であることを確認します。", + "registrationAgeWarning": "登録では 13歳以上 であることを 確認します。", "backToLogin": "ログインへ", - "failedToLoadSaveData": "保存データの読み込みに失敗しました。ページを再読み込みしてください。\nこれが続く場合は、管理者に連絡してください。", - "sessionSuccess": "セッションが正常に読み込まれました。", - "failedToLoadSession": "セッションデータを読み込むことができませんでした。\nデータが破損している可能性があります。", - "boyOrGirl": "おとこのこ?\nそれとも おんなのこ?", - "evolving": "…おや!?\n{{pokemonName}}のようすが…!", - "stoppedEvolving": "{{pokemonName}}のへんかがとまった", - "evolutionDone": "おめでとう!\n{{pokemonName}}は{{evolvedPokemonName}}にしんかした!", - "dailyRankings": "ほんじつのランキング", - "weeklyRankings": "しゅうのランキング", + "failedToLoadSaveData": "セーブデータの 読み込みは 不可能でした。ページを 再読み込み してください。\n長い間に続く 場合は 管理者に 連絡してください。", + "sessionSuccess": "セッションが 正常に 読み込まれました。", + "failedToLoadSession": "セッションデータを 読み込むことが できませんでした。\nデータが 破損している 可能性が あります。", + "boyOrGirl": "男の子?\nそれとも 女の子?", + "evolving": "…おや!?\n{{pokemonName}}の 様子が…!", + "stoppedEvolving": "あれ…? {{pokemonName}}の 変化が 止まった!", + "pauseEvolutionsQuestion": "{{pokemonName}}の 進化を 休止しますか?\n後で 手持ち画面から 進化を また 可能にできます。", + "evolutionsPaused": "{{pokemonName}}の 進化を 休止しました。", + "evolutionDone": "おめでとう!\n{{pokemonName}}は {{evolvedPokemonName}}に 進化した!", + "dailyRankings": "今日のランキング", + "weeklyRankings": "今週のランキング", "noRankings": "ランキングなし", "positionIcon": "#", - "loading": "よみこみちゅう…", + "usernameScoreboard": "ユーザー名", + "score": "スコア", + "wave": "波", + "loading": "読み込み中…", + "loadingAsset": "読み込み中:{{assetName}}", "playersOnline": "オンラインのプレイヤー", "yes": "はい", - "no": "いいえ" -} \ No newline at end of file + "no": "いいえ", + "disclaimer": "免責", + "disclaimerDescription": "このゲームは 未完成作品です。\nセーブデータの 損失を含める ゲーム性に関する 問題が 起きる可能性が あります。\nなお、ゲームは 予告なく変更される 可能性もあり、さらに更新され、完成されるとも 限りません。", + "choosePokemon": "ポケモンを選ぶ", + "renamePokemon": "ニックネームを変える", + "rename": "変える", + "nickname": "ニックネーム", + "errorServerDown": "おや!\nサーバーとの 接続中に 問題が 発生しました。\nゲームは 自動的に 再接続されます から\nウィンドウは 開いたままに しておいても よろしいです。" +} diff --git a/src/locales/ja/modifier-select-ui-handler.json b/src/locales/ja/modifier-select-ui-handler.json index 9370f01491e..d7428c8e373 100644 --- a/src/locales/ja/modifier-select-ui-handler.json +++ b/src/locales/ja/modifier-select-ui-handler.json @@ -1,12 +1,12 @@ { "transfer": "アイテム移行", "reroll": "選択肢変更", - "lockRarities": "レア度の固定", - "checkTeam": "チームを確認", - "transferDesc": "ポケモンの 手持ちアイテムを 移行する", + "lockRarities": "レア度を固定", + "checkTeam": "手持ちを確認", + "transferDesc": "手持ちポケモンの 持たせるアイテムを 移行する", "rerollDesc": "お金を 使って アイテムの 選択肢を 変更する", - "lockRaritiesDesc": "選択肢を 変更するときの レア度を 固定する\n(選択肢変更金額を影響する)", - "checkTeamDesc": "チームの 状態を 確認する\nフォルムチェンジアイテムを 有効・無効にする", + "lockRaritiesDesc": "選択肢を 変更するときの レア度を 固定する\n(選択肢変更の価格は変わる)", + "checkTeamDesc": "手持ちポケモンの 状態を 確認する\nフォルムチェンジアイテムを 有効・無効にする", "rerollCost": "{{formattedMoney}}円", "itemCost": "{{formattedMoney}}円" } diff --git a/src/locales/ja/pokemon-info.json b/src/locales/ja/pokemon-info.json index 9b7a7506953..456b4949839 100644 --- a/src/locales/ja/pokemon-info.json +++ b/src/locales/ja/pokemon-info.json @@ -2,21 +2,22 @@ "Stat": { "HP": "HP", "HPshortened": "HP", - "ATK": "こうげき", - "ATKshortened": "こうげき", - "DEF": "ぼうぎょ", - "DEFshortened": "ぼうぎょ", - "SPATK": "とくこう", - "SPATKshortened": "とくこう", - "SPDEF": "とくぼう", - "SPDEFshortened": "とくぼう", - "SPD": "すばやさ", - "SPDshortened": "すばやさ", - "ACC": "めいちゅう", - "EVA": "かいひ" + "ATK": "攻撃", + "ATKshortened": "攻撃", + "DEF": "防御", + "DEFshortened": "防御", + "SPATK": "特攻", + "SPATKshortened": "特攻", + "SPDEF": "特防", + "SPDEFshortened": "特防", + "SPD": "素早さ", + "SPDshortened": "素早さ", + "ACC": "命中", + "EVA": "回避", + "HPStat": "HP" }, "Type": { - "UNKNOWN": "Unknown", + "UNKNOWN": "???", "NORMAL": "ノーマル", "FIGHTING": "かくとう", "FLYING": "ひこう", @@ -37,4 +38,4 @@ "FAIRY": "フェアリー", "STELLAR": "ステラ" } -} \ No newline at end of file +} diff --git a/src/locales/ja/pokemon.json b/src/locales/ja/pokemon.json index 6c182c09f86..e6fcd02a750 100644 --- a/src/locales/ja/pokemon.json +++ b/src/locales/ja/pokemon.json @@ -437,7 +437,7 @@ "bronzor": "ドーミラー", "bronzong": "ドータクン", "bonsly": "ウソハチ", - "mime_jr.": "マネネ", + "mime_jr": "マネネ", "happiny": "ピンプク", "chatot": "ペラップ", "spiritomb": "ミカルゲ", @@ -770,7 +770,7 @@ "sandygast": "スナバァ", "palossand": "シロデスナ", "pyukumuku": "ナマコブシ", - "type:_null": "タイプ:ヌル", + "type_null": "タイプ:ヌル", "silvally": "シルヴァディ", "minior": "メテノ", "komala": "ネッコアラ", @@ -863,7 +863,7 @@ "obstagoon": "タチフサグマ", "perrserker": "ニャイキング", "cursola": "サニゴーン", - "sirfetch_d": "ネギガナイト", + "sirfetchd": "ネギガナイト", "mr_rime": "バリコオル", "runerigus": "デスバーン", "milcery": "マホミル", @@ -1081,4 +1081,4 @@ "paldea_tauros": "ケンタロス", "paldea_wooper": "ウパー", "bloodmoon_ursaluna": "ガチグマ" -} \ No newline at end of file +} diff --git a/src/locales/ja/settings.json b/src/locales/ja/settings.json index c88792979f6..4cb10c670de 100644 --- a/src/locales/ja/settings.json +++ b/src/locales/ja/settings.json @@ -6,12 +6,14 @@ "audio": "音声", "gamepad": "コントローラー", "keyboard": "キーボード", - "gameSpeed": "ゲームスピード", - "hpBarSpeed": "HPバーの増減スピード", - "expGainsSpeed": "EXPバーの増加スピード", - "expPartyDisplay": "パーティの経験値取得表示", + "gameSpeed": "ゲームの速さ", + "hpBarSpeed": "HPバー増減の速さ", + "expGainsSpeed": "経験値バー増加の速さ", + "expPartyDisplay": "手持ちの経験値取得表示", + "skipSeenDialogues": "もう見た話をスキップ", "battleStyle": "試合のルール", - "enableRetries": "リトライを有効にする", + "enableRetries": "再挑戦を有効にする", + "hideIvs": "個体値スキャナーを隠す", "tutorials": "チュートリアル", "touchControls": "タッチ操作", "vibrations": "振動", @@ -35,33 +37,71 @@ "moneyFormat": "お金の表示形式", "damageNumbers": "ダメージ表示", "simple": "シンプル", - "fancy": "Fancy", + "fancy": "オシャレ", "abbreviated": "省略", - "moveAnimations": "戦闘アニメ", + "moveAnimations": "戦闘アニメーション", "showStatsOnLevelUp": "レベルアップ時のステータス表示", + "candyUpgradeNotification": "飴アプグレ通知", "passivesOnly": "パッシブのみ", + "candyUpgradeDisplay": "飴アプグレ表示", "icon": "アイコン", "animation": "アニメーション", - "moveInfo": "技の情報表示", + "moveInfo": "技情報", + "showMovesetFlyout": "技情報表示", + "showArenaFlyout": "戦場情報表示", + "showTimeOfDayWidget": "時刻指標", + "timeOfDayAnimation": "時刻指標アニメーション", + "bounce": "跳ねる", + "timeOfDay_back": "跳ね返る", + "spriteSet": "スプライト設定", + "consistent": "一貫", + "mixedAnimated": "アニメーションミックス", + "fusionPaletteSwaps": "吸収合体ポケモンの色違い", "playerGender": "プレイヤーの性別", - "typeHints": "相性のヒント", + "typeHints": "タイプ相性ヒント", "masterVolume": "マスターボリューム", - "bgmVolume": "BGMのボリューム", - "seVolume": "SEのボリューム", + "bgmVolume": "BGMボリューム", + "fieldVolume": "フィールドボリューム", + "seVolume": "SEボリューム", + "uiVolume": "UIボリューム", + "musicPreference": "BGM設定", + "mixed": "ミックス", + "gamepadPleasePlug": "コントローラーを 接続してください\nまたは、ボタンを 押してください", + "delete": "削除", + "keyboardPleasePress": "キーを押してください", "reset": "リセット", "requireReload": "再読み込みが必要", "action": "決定", "back": "戻る", + "pressToBind": "押下でキーバインド", + "pressButton": "ボタンを押してください", "buttonUp": "上", "buttonDown": "下", "buttonLeft": "左", "buttonRight": "右", "buttonAction": "決定", "buttonMenu": "メニュー", - "buttonSubmit": "Submit", + "buttonSubmit": "提出", "buttonCancel": "キャンセル", - "alt": " (代替)", + "buttonStats": "能力変化表示", + "buttonCycleForm": "フォルム変更", + "buttonCycleShiny": "色違い変更", + "buttonCycleGender": "性別変更", + "buttonCycleAbility": "特性変更", + "buttonCycleNature": "性格変更", + "buttonCycleVariant": "色変更", + "buttonSpeedUp": "速さを上げる", + "buttonSlowDown": "速さを下げる", + "alt": "(代替)", "mute": "ミュート", "controller": "コントローラー", - "gamepadSupport": "コントローラーサポート" + "gamepadSupport": "コントローラーサポート", + "showBgmBar": "BGMの名前を表示", + "moveTouchControls": "タッチ移動操作", + "shopOverlayOpacity": "ショップオーバレイ不透明度", + "shopCursorTarget": "ショップカーソル初位置", + "items": "アイテム", + "reroll": "選択肢変更", + "shop": "ショップ", + "checkTeam": "手持ちを確認" } diff --git a/src/locales/ja/starter-select-ui-handler.json b/src/locales/ja/starter-select-ui-handler.json index 84eaa8598e9..cab5c500df6 100644 --- a/src/locales/ja/starter-select-ui-handler.json +++ b/src/locales/ja/starter-select-ui-handler.json @@ -1,5 +1,5 @@ { - "confirmStartTeam": "この条件で チャレンジを 始めますか?", + "confirmStartTeam": "この手持ちで 始めますか?", "confirmExit": "終了しますか?", "invalidParty": "手持ちは チャレンジの 条件で 認められない!", "gen1": "1世代", @@ -16,8 +16,8 @@ "passive": "パッシブ:", "nature": "性格:", "eggMoves": "タマゴ技", - "start": "始める", "addToParty": "手持ちに入れる", + "removeFromParty": "手持ちから除く", "toggleIVs": "個体値を表示", "manageMoves": "技を並び替える", "manageNature": "性格を変える", @@ -36,9 +36,10 @@ "cycleAbility": ": 特性変更", "cycleNature": ": 性格変更", "cycleVariant": ": 色変更", + "goFilter": ": フィルタ へ ", "enablePassive": "パッシブ - オン", "disablePassive": "パッシブ - オフ", - "locked": "開放されていない", + "locked": "非開放", "disabled": "無効", "uncaught": "捕まっていない" -} \ No newline at end of file +} From 22d31bc704572c746dddfab82d8f7d0842862138 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:19:02 -0400 Subject: [PATCH 32/40] [Localisation] [ES] Review and finished pokemon-form and pokemon-form-battle (#3903) * Translate pokemon-form.json via GitLocalize * Translate pokemon-form.json via GitLocalize * Translate pokemon-form-battle.json via GitLocalize * Translate pokemon-form-battle.json via GitLocalize * Update src/locales/es/pokemon-form.json Co-authored-by: Asdar --------- Co-authored-by: Rafa Co-authored-by: LilyAlternis Co-authored-by: Asdar Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> --- src/locales/es/pokemon-form-battle.json | 10 +++++-- src/locales/es/pokemon-form.json | 39 +++++++++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/locales/es/pokemon-form-battle.json b/src/locales/es/pokemon-form-battle.json index 7af01f8f093..5266baa7049 100644 --- a/src/locales/es/pokemon-form-battle.json +++ b/src/locales/es/pokemon-form-battle.json @@ -4,5 +4,11 @@ "mega-y": "Mega {{pokemonName}} Y", "primal": "{{pokemonName}} Primigenio", "gigantamax": "G-Max {{pokemonName}}", - "eternamax": "E-Max {{pokemonName}}" -} \ No newline at end of file + "eternamax": "E-Max {{pokemonName}}", + "megaChange": "¡{{preName}} ha mega-evolucionado a {{pokemonName}}!", + "gigantamaxChange": "¡{{preName}} ha gigamaxizado a {{pokemonName}}!", + "eternamaxChange": "¡{{preName}} ha eternamaxizado a {{pokemonName}}!", + "revertChange": "¡{{pokemonName}} ha revertido a su forma original!", + "formChange": "¡{{preName}} ha cambiado de forma!", + "disguiseChange": "¡El disfraz ha actuado como señuelo!\t" +} diff --git a/src/locales/es/pokemon-form.json b/src/locales/es/pokemon-form.json index c46521d78da..2f70038ad2d 100644 --- a/src/locales/es/pokemon-form.json +++ b/src/locales/es/pokemon-form.json @@ -7,6 +7,7 @@ "pikachuToughCosplay": "Enmascarada", "pikachuPartner": "Compañero", "eeveePartner": "Compañero", + "pichuSpiky": "Picoreja", "unownA": "A", "unownB": "B", "unownC": "C", @@ -49,6 +50,8 @@ "rotomFrost": "Frío", "rotomFan": "Ventilador", "rotomMow": "Corte", + "giratinaAltered": "Modificada", + "shayminLand": "Tierra", "basculinRedStriped": "Raya Roja", "basculinBlueStriped": "Raya Azul", "basculinWhiteStriped": "Raya Blanca", @@ -56,6 +59,10 @@ "deerlingSummer": "Verano", "deerlingAutumn": "Otoño", "deerlingWinter": "Invierno", + "tornadusIncarnate": "Avatar", + "thundurusIncarnate": "Avatar", + "landorusIncarnate": "Avatar", + "keldeoOrdinary": "Habitual", "meloettaAria": "Lírica", "meloettaPirouette": "Danza", "froakieBattleBond": "Fuerte Afecto", @@ -87,12 +94,12 @@ "furfrouHeart": "Corazón", "furfrouStar": "Estrella", "furfrouDiamond": "Diamante", - "furfrouDebutante": "Debutante", - "furfrouMatron": "Matrón", - "furfrouDandy": "Dandi", - "furfrouLaReine": "La Reine", + "furfrouDebutante": "Señorita", + "furfrouMatron": "Dama", + "furfrouDandy": "Caballero", + "furfrouLaReine": "Aristócrata", "furfrouKabuki": "Kabuki", - "furfrouPharaoh": "Faraón", + "furfrouPharaoh": "Faraónico", "pumpkabooSmall": "Pequeño", "pumpkabooLarge": "Grande", "pumpkabooSuper": "Enorme", @@ -127,11 +134,15 @@ "magearnaOriginal": "Vetusto", "marshadowZenith": "Cénit", "sinisteaPhony": "Falsificada", - "sinisteaAntique": "Auténtica", + "sinisteaAntique": "Genuina", "eiscueNoIce": "Cara Deshielo", "indeedeeMale": "Macho", "indeedeeFemale": "Hembra", + "morpekoFullBelly": "Saciada", + "zacianHeroOfManyBattles": "Guerrero avezado", + "zamazentaHeroOfManyBattles": "Guerrero avezado", "zarudeDada": "Papá", + "enamorusIncarnate": "Avatar", "squawkabillyGreenPlumage": "Plumaje Verde", "squawkabillyBluePlumage": "Plumaje Azul", "squawkabillyYellowPlumage": "Plumaje Amarillo", @@ -141,9 +152,19 @@ "tatsugiriStretchy": "Estirada", "gimmighoulChest": "Cofre", "gimmighoulRoaming": "Andante", - "poltchageistCounterfeit": "Imitación", - "poltchageistArtisan": "Original", + "koraidonApexBuild": "Forma Plena", + "koraidonLimitedBuild": "Forma Limitada", + "koraidonSprintingBuild": "Forma Carrera", + "koraidonSwimmingBuild": "Forma Nado", + "koraidonGlidingBuild": "Forma Planeo", + "miraidonUltimateMode": "Modo Pleno", + "miraidonLowPowerMode": "Modo Limitado", + "miraidonDriveMode": "Modo Conducción", + "miraidonAquaticMode": "Modo Flote", + "miraidonGlideMode": "Modo Planeo", + "poltchageistCounterfeit": "Fraudulenta", + "poltchageistArtisan": "Opulenta", "paldeaTaurosCombat": "Combatiente", "paldeaTaurosBlaze": "Ardiente", "paldeaTaurosAqua": "Acuático" -} \ No newline at end of file +} From 4553c1c34ffdbbdda2696bbd69315b3b5a294950 Mon Sep 17 00:00:00 2001 From: PrabbyDD <147005742+PrabbyDD@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:20:16 -0700 Subject: [PATCH 33/40] [Bug] Fix Octolock Ignores Clear Body, White Smoke, Big Pecks #3876 Pecks, Clear Body, and White Smoke Adding tests for octolock --- src/data/battler-tags.ts | 2 +- src/test/moves/octolock.test.ts | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 2e280634d5d..92df6fc294f 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -767,7 +767,7 @@ export class OctolockTag extends TrappedTag { const shouldLapse = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType); if (shouldLapse) { - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.DEF, BattleStat.SPDEF], -1)); + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [BattleStat.DEF, BattleStat.SPDEF], -1)); return true; } diff --git a/src/test/moves/octolock.test.ts b/src/test/moves/octolock.test.ts index 389e4a4c4cf..34dad13b0d9 100644 --- a/src/test/moves/octolock.test.ts +++ b/src/test/moves/octolock.test.ts @@ -61,6 +61,48 @@ describe("Moves - Octolock", () => { expect(enemyPokemon[0].summonData.battleStats[BattleStat.SPDEF]).toBe(-2); }); + it("If target pokemon has Big Pecks, Octolock should only reduce spdef by 1", { timeout: 10000 }, async () => { + game.override.enemyAbility(Abilities.BIG_PECKS); + await game.startBattle([Species.GRAPPLOCT]); + + const enemyPokemon = game.scene.getEnemyField(); + + // use Octolock and advance to init phase of next turn to check for stat changes + game.move.select(Moves.OCTOLOCK); + await game.phaseInterceptor.to(TurnInitPhase); + + expect(enemyPokemon[0].summonData.battleStats[BattleStat.DEF]).toBe(0); + expect(enemyPokemon[0].summonData.battleStats[BattleStat.SPDEF]).toBe(-1); + }); + + it("If target pokemon has White Smoke, Octolock should not reduce any stats", { timeout: 10000 }, async () => { + game.override.enemyAbility(Abilities.WHITE_SMOKE); + await game.startBattle([Species.GRAPPLOCT]); + + const enemyPokemon = game.scene.getEnemyField(); + + // use Octolock and advance to init phase of next turn to check for stat changes + game.move.select(Moves.OCTOLOCK); + await game.phaseInterceptor.to(TurnInitPhase); + + expect(enemyPokemon[0].summonData.battleStats[BattleStat.DEF]).toBe(0); + expect(enemyPokemon[0].summonData.battleStats[BattleStat.SPDEF]).toBe(0); + }); + + it("If target pokemon has Clear Body, Octolock should not reduce any stats", { timeout: 10000 }, async () => { + game.override.enemyAbility(Abilities.CLEAR_BODY); + await game.startBattle([Species.GRAPPLOCT]); + + const enemyPokemon = game.scene.getEnemyField(); + + // use Octolock and advance to init phase of next turn to check for stat changes + game.move.select(Moves.OCTOLOCK); + await game.phaseInterceptor.to(TurnInitPhase); + + expect(enemyPokemon[0].summonData.battleStats[BattleStat.DEF]).toBe(0); + expect(enemyPokemon[0].summonData.battleStats[BattleStat.SPDEF]).toBe(0); + }); + it("Traps the target pokemon", { timeout: 10000 }, async () => { await game.startBattle([Species.GRAPPLOCT]); From 69a9916b4c2780fd478dd861f1b0e554613ae2e0 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:21:56 -0700 Subject: [PATCH 34/40] [Bug] Moves copied by Dancer should not consume PP (#3623) * Moves copied by Dancer should not consume PP * Add test for Dancer (unfinished) * Delete src/test/abilities/dancer.test.ts This test is not finished lol * Add test --- src/data/ability.ts | 4 +- src/phases/move-phase.ts | 16 ++++---- src/test/abilities/dancer.test.ts | 64 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/test/abilities/dancer.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 4d3d32e22fa..818ab07637f 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3695,10 +3695,10 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { // 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)); + dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, 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)); + dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true, true)); } } return true; diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index c446660b16f..e2893d587a7 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -1,9 +1,9 @@ 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 { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr } 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 { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags.js"; +import { allMoves, applyMoveAttrs, BypassRedirectAttr, BypassSleepAttr, ChargeAttr, CopyMoveAttr, HealStatusEffectAttr, MoveFlags, 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"; @@ -13,10 +13,10 @@ 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 Pokemon, { MoveResult, PokemonMove, TurnMove } from "#app/field/pokemon.js"; import { getPokemonNameWithAffix } from "#app/messages.js"; -import i18next from "i18next"; import * as Utils from "#app/utils.js"; +import i18next from "i18next"; import { BattlePhase } from "./battle-phase"; import { CommonAnimPhase } from "./common-anim-phase"; import { MoveEffectPhase } from "./move-effect-phase"; @@ -38,8 +38,8 @@ export class MovePhase extends BattlePhase { this.pokemon = pokemon; this.targets = targets; this.move = move; - this.followUp = !!followUp; - this.ignorePp = !!ignorePp; + this.followUp = followUp ?? false; + this.ignorePp = ignorePp ?? false; this.failed = false; this.cancelled = false; } @@ -194,7 +194,7 @@ export class MovePhase extends BattlePhase { return this.end(); } - if (!moveQueue.length || !moveQueue.shift()?.ignorePP) { // using .shift here clears out two turn moves once they've been used + if ((!moveQueue.length || !moveQueue.shift()?.ignorePP) && !this.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)); } diff --git a/src/test/abilities/dancer.test.ts b/src/test/abilities/dancer.test.ts new file mode 100644 index 00000000000..d80f497f8b2 --- /dev/null +++ b/src/test/abilities/dancer.test.ts @@ -0,0 +1,64 @@ +import { BattlerIndex } from "#app/battle"; +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"; + +const TIMEOUT = 20 * 1000; + +describe("Abilities - Dancer", () => { + 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("double") + .moveset([Moves.SWORDS_DANCE, Moves.SPLASH]) + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.DANCER) + .enemyMoveset(Array(4).fill(Moves.VICTORY_DANCE)); + }); + + // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability) + + it("triggers when dance moves are used, doesn't consume extra PP", async () => { + await game.classicMode.startBattle([Species.ORICORIO, Species.FEEBAS]); + + const [oricorio] = game.scene.getPlayerField(); + + game.move.select(Moves.SPLASH); + game.move.select(Moves.SWORDS_DANCE, 1); + await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); + await game.phaseInterceptor.to("MovePhase"); + // immediately copies ally move + await game.phaseInterceptor.to("MovePhase", false); + let currentPhase = game.scene.getCurrentPhase() as MovePhase; + expect(currentPhase.pokemon).toBe(oricorio); + expect(currentPhase.move.moveId).toBe(Moves.SWORDS_DANCE); + await game.phaseInterceptor.to("MoveEndPhase"); + await game.phaseInterceptor.to("MovePhase"); + // immediately copies enemy move + await game.phaseInterceptor.to("MovePhase", false); + currentPhase = game.scene.getCurrentPhase() as MovePhase; + expect(currentPhase.pokemon).toBe(oricorio); + expect(currentPhase.move.moveId).toBe(Moves.VICTORY_DANCE); + await game.phaseInterceptor.to("BerryPhase"); + + // doesn't use PP if copied move is also in moveset + expect(oricorio.moveset[0]?.ppUsed).toBe(0); + }, TIMEOUT); +}); From f3c41edf5e35266fb2ca752eac988c04ab1d881d Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:24:12 -0700 Subject: [PATCH 35/40] [Bug] Don't reset turn count or used moves array at the start of a new wave (fakeout and gigaton hammer) (#3606) * Don't reset turn count or used moves array at the start of a new wave * Add tests --- src/phases/battle-end-phase.ts | 6 -- src/test/moves/fake_out.test.ts | 83 +++++++++++++++++++++++++++ src/test/moves/gigaton_hammer.test.ts | 81 ++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 src/test/moves/fake_out.test.ts create mode 100644 src/test/moves/gigaton_hammer.test.ts diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts index a9999370cdd..06315668a8b 100644 --- a/src/phases/battle-end-phase.ts +++ b/src/phases/battle-end-phase.ts @@ -23,12 +23,6 @@ export class BattleEndPhase extends BattlePhase { 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); } diff --git a/src/test/moves/fake_out.test.ts b/src/test/moves/fake_out.test.ts new file mode 100644 index 00000000000..92331ebb758 --- /dev/null +++ b/src/test/moves/fake_out.test.ts @@ -0,0 +1,83 @@ +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"; + +describe("Moves - Fake Out", () => { + 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.CORVIKNIGHT) + .starterSpecies(Species.FEEBAS) + .moveset([Moves.FAKE_OUT, Moves.SPLASH]) + .enemyMoveset(SPLASH_ONLY) + .disableCrits(); + }); + + it("can only be used on the first turn a pokemon is sent out", async() => { + await game.startBattle(); + + const enemy = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FAKE_OUT)); + await game.toNextTurn(); + + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); + const postTurnOneHp = enemy.hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FAKE_OUT)); + await game.toNextTurn(); + + expect(enemy.hp).toBe(postTurnOneHp); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.doKillOpponents(); + await game.toNextWave(); + + const newEnemy = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FAKE_OUT)); + await game.toNextTurn(); + + expect(newEnemy.hp).toBe(newEnemy.getMaxHp()); + }, 20000); + + it("can be used again if recalled and sent back out", async() => { + game.override.startingWave(4); + await game.startBattle(); + + const enemy1 = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FAKE_OUT)); + await game.phaseInterceptor.to("MoveEndPhase"); + + expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp()); + + await game.doKillOpponents(); + await game.toNextWave(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.FAKE_OUT)); + await game.toNextTurn(); + + const enemy2 = game.scene.getEnemyPokemon()!; + + expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp()); + }, 20000); +}); diff --git a/src/test/moves/gigaton_hammer.test.ts b/src/test/moves/gigaton_hammer.test.ts new file mode 100644 index 00000000000..aca95a76332 --- /dev/null +++ b/src/test/moves/gigaton_hammer.test.ts @@ -0,0 +1,81 @@ +import { BattlerIndex } from "#app/battle.js"; +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"; + +describe("Moves - Gigaton Hammer", () => { + 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.MAGIKARP) + .starterSpecies(Species.FEEBAS) + .moveset([Moves.GIGATON_HAMMER]) + .startingLevel(10) + .enemyLevel(100) + .enemyMoveset(SPLASH_ONLY) + .disableCrits(); + }); + + it("can't be used two turns in a row", async() => { + await game.startBattle(); + + const enemy1 = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.GIGATON_HAMMER)); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEndPhase"); + + expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp()); + + await game.doKillOpponents(); + await game.toNextWave(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.GIGATON_HAMMER)); + await game.toNextTurn(); + + const enemy2 = game.scene.getEnemyPokemon()!; + + expect(enemy2.hp).toBe(enemy2.getMaxHp()); + }, 20000); + + it("can be used again if recalled and sent back out", async() => { + game.override.startingWave(4); + await game.startBattle(); + + const enemy1 = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.GIGATON_HAMMER)); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEndPhase"); + + expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp()); + + await game.doKillOpponents(); + await game.toNextWave(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.GIGATON_HAMMER)); + await game.toNextTurn(); + + const enemy2 = game.scene.getEnemyPokemon()!; + + expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp()); + }, 20000); +}); From 2d5bd57c44292dae075bfaddbb8543b6573f2752 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:25:07 -0400 Subject: [PATCH 36/40] [Localization] [FR] pokemon-info.json and dialogue-misc.json completion (#3761) * Translate pokemon-info.json via GitLocalize * Update dialogue-misc.json --------- Co-authored-by: Lugiad --- src/locales/fr/dialogue-misc.json | 6 ++++-- src/locales/fr/pokemon-info.json | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/locales/fr/dialogue-misc.json b/src/locales/fr/dialogue-misc.json index d932d283d37..359c2dfb46b 100644 --- a/src/locales/fr/dialogue-misc.json +++ b/src/locales/fr/dialogue-misc.json @@ -1,4 +1,6 @@ { "ending": "@c{smile}Oh ? T’as gagné ?@d{96} @c{smile_eclosed}J’aurais dû le savoir.\nMais de voilà de retour.\n$@c{smile}C’est terminé.@d{64} T’as brisé ce cycle infernal.\n$@c{serious_smile_fists}T’as aussi accompli ton rêve non ?\nTu n’as pas connu la moindre défaite.\n$@c{neutral}Je suis le seul à me souvenir de ce que t’as fait.@d{96}\nJe pense que ça ira, non ?\n$@c{serious_smile_fists}Ta légende vivra à jamais dans nos cœurs.\n$@c{smile_eclosed}Bref, j’en ai un peu marre de ce endroit, pas toi ? Rentrons à la maison.\n$@c{serious_smile_fists}On se fera un p’tit combat une fois rentrés ?\nSi t’es d’accord.", - "ending_female": "@c{shock}T’es revenu ?@d{32} Ça veut dire…@d{96} que t’as gagné ?!\n@c{smile_ehalf}J’aurais dû le savoir.\n$@c{smile_eclosed}Bien sûr… J’ai toujours eu ce sentiment.\n@c{smile}C’est fini maitenant hein ? T’as brisé ce cycle.\n$@c{smile_ehalf}T’as aussi accompli ton rêve non ?\nTu n’as pas connu la moindre défaite.\n$Je serai la seule à me souvenir de ce que t’as fait.\n@c{angry_mopen}Je tâcherai de ne pas oublier !\n$@c{smile_wave_wink}J’déconne !@d{64} @c{smile}Jamais j’oublierai.@d{32}\nTa légende vivra à jamais dans nos cœurs.\n$@c{smile_wave}Bon,@d{64} il se fait tard…@d{96} je crois ?\nDifficile à dire ici.\n$Rentrons, @c{smile_wave_wink}et demain on se fera un p’tit combat, comme au bon vieux temps ?" -} \ No newline at end of file + "ending_female": "@c{shock}T’es revenu ?@d{32} Ça veut dire…@d{96} que t’as gagné ?!\n@c{smile_ehalf}J’aurais dû le savoir.\n$@c{smile_eclosed}Bien sûr… J’ai toujours eu ce sentiment.\n@c{smile}C’est fini maitenant hein ? T’as brisé ce cycle.\n$@c{smile_ehalf}T’as aussi accompli ton rêve non ?\nTu n’as pas connu la moindre défaite.\n$Je serai la seule à me souvenir de ce que t’as fait.\n@c{angry_mopen}Je tâcherai de ne pas oublier !\n$@c{smile_wave_wink}J’déconne !@d{64} @c{smile}Jamais j’oublierai.@d{32}\nTa légende vivra à jamais dans nos cœurs.\n$@c{smile_wave}Bon,@d{64} il se fait tard…@d{96} je crois ?\nDifficile à dire ici.\n$Rentrons, @c{smile_wave_wink}et demain on se fera un p’tit combat, comme au bon vieux temps ?", + "ending_endless": "Félicitations ! Vous avez atteint la fin actuelle.\nPlus de contenu à venir bientôt !", + "ending_name": "Les devs" +} diff --git a/src/locales/fr/pokemon-info.json b/src/locales/fr/pokemon-info.json index 1e55f332432..1160ec95b75 100644 --- a/src/locales/fr/pokemon-info.json +++ b/src/locales/fr/pokemon-info.json @@ -13,7 +13,8 @@ "SPD": "Vitesse", "SPDshortened": "Vit", "ACC": "Précison", - "EVA": "Esquive" + "EVA": "Esquive", + "HPStat": "PV" }, "Type": { "UNKNOWN": "Inconnu", @@ -37,4 +38,4 @@ "FAIRY": "Fée", "STELLAR": "Stellaire" } -} \ No newline at end of file +} From f54846f735e2c22f195348cb3ae9f347d7c5cfe3 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:26:20 -0700 Subject: [PATCH 37/40] [Move] Implement Safeguard (#3447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implemented safeguard and tests * Update tests * Add i18n placeholders * Implement Safeguard for non-volatile statuses * Implement protection from confusion and Yawn * Replace `target instanceof EnemyPokemon` with `target.isPlayer()` * Minor capitalization change * First batch of i18n Adds fr, pt_BR, zh_CN, zh_TW Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Add more translations + de, es, ko Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Asdar Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> * Fix broken character in es translation * Update test with new function definition * Add Italian translation Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> * Add move category check for message display Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> * Update phase imports in Safeguard test * Fix test imports * Update tests --------- Co-authored-by: Joshua Keegan Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Asdar Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> Co-authored-by: Niccolò <123510358+NicusPulcis@users.noreply.github.com> Co-authored-by: innerthunder <168692175+innerthunder@users.noreply.github.com> --- src/data/ability.ts | 2 +- src/data/arena-tag.ts | 17 ++++ src/data/move.ts | 22 +++- src/enums/arena-tag-type.ts | 1 + src/field/pokemon.ts | 5 + src/locales/de/arena-tag.json | 8 +- src/locales/de/move-trigger.json | 3 +- src/locales/es/arena-tag.json | 9 +- src/locales/es/move-trigger.json | 3 +- src/locales/fr/arena-tag.json | 8 +- src/locales/fr/move-trigger.json | 3 +- src/locales/it/arena-tag.json | 9 +- src/locales/it/move-trigger.json | 3 +- src/locales/ko/arena-tag.json | 8 +- src/locales/ko/move-trigger.json | 3 +- src/locales/pt_BR/arena-tag.json | 8 +- src/locales/pt_BR/move-trigger.json | 3 +- src/locales/zh_CN/arena-tag.json | 8 +- src/locales/zh_CN/move-trigger.json | 3 +- src/locales/zh_TW/arena-tag.json | 8 +- src/locales/zh_TW/move-trigger.json | 3 +- src/test/moves/safeguard.test.ts | 150 ++++++++++++++++++++++++++++ 22 files changed, 268 insertions(+), 19 deletions(-) create mode 100644 src/test/moves/safeguard.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 818ab07637f..40312eaa8be 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -850,7 +850,7 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr { } export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr { - private chance: integer; + public chance: integer; private effects: StatusEffect[]; constructor(chance: integer, ...effects: StatusEffect[]) { diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index a60ea5c2981..09cc7a5b97c 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -905,6 +905,21 @@ class HappyHourTag extends ArenaTag { } } +class SafeguardTag extends ArenaTag { + constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { + super(ArenaTagType.SAFEGUARD, turnCount, Moves.SAFEGUARD, sourceId, side); + } + + onAdd(arena: Arena): void { + arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`)); + } + + onRemove(arena: Arena): void { + arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`)); + } +} + + export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null { switch (tagType) { case ArenaTagType.MIST: @@ -950,6 +965,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov return new TailwindTag(turnCount, sourceId, side); case ArenaTagType.HAPPY_HOUR: return new HappyHourTag(turnCount, sourceId, side); + case ArenaTagType.SAFEGUARD: + return new SafeguardTag(turnCount, sourceId, side); default: return null; } diff --git a/src/data/move.ts b/src/data/move.ts index 3f87fc68b89..1dc715f264a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1953,6 +1953,13 @@ export class StatusEffectAttr extends MoveEffectAttr { return false; } } + + if (user !== target && target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)) { + if (move.category === MoveCategory.STATUS) { + user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)})); + } + return false; + } if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0)) && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) { applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect); @@ -4659,6 +4666,17 @@ export class ConfuseAttr extends AddBattlerTagAttr { constructor(selfTarget?: boolean) { super(BattlerTagType.CONFUSED, selfTarget, false, 2, 5); } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!this.selfTarget && target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)) { + if (move.category === MoveCategory.STATUS) { + user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)})); + } + return false; + } + + return super.apply(user, target, move, args); + } } export class RechargeAttr extends AddBattlerTagAttr { @@ -7014,7 +7032,7 @@ export function initMoves() { .attr(FriendshipPowerAttr, true), new StatusMove(Moves.SAFEGUARD, Type.NORMAL, -1, 25, -1, 0, 2) .target(MoveTarget.USER_SIDE) - .unimplemented(), + .attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true), new StatusMove(Moves.PAIN_SPLIT, Type.NORMAL, -1, 20, -1, 0, 2) .attr(HpSplitAttr) .condition(failOnBossCondition), @@ -7203,7 +7221,7 @@ export function initMoves() { .attr(RemoveScreensAttr), new StatusMove(Moves.YAWN, Type.NORMAL, -1, 10, -1, 0, 3) .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true) - .condition((user, target, move) => !target.status), + .condition((user, target, move) => !target.status && !target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)), new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) .attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.isTransferrable).length > 0 ? 1.5 : 1) .attr(RemoveHeldItemAttr, false), diff --git a/src/enums/arena-tag-type.ts b/src/enums/arena-tag-type.ts index 1265b815bf4..1c79750c91a 100644 --- a/src/enums/arena-tag-type.ts +++ b/src/enums/arena-tag-type.ts @@ -22,5 +22,6 @@ export enum ArenaTagType { CRAFTY_SHIELD = "CRAFTY_SHIELD", TAILWIND = "TAILWIND", HAPPY_HOUR = "HAPPY_HOUR", + SAFEGUARD = "SAFEGUARD", NO_CRIT = "NO_CRIT" } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 16ad96f61cc..c970c99e7d3 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2787,6 +2787,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const types = this.getTypes(true, true); + const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + if (sourcePokemon && sourcePokemon !== this && this.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) { + return false; + } + switch (effect) { case StatusEffect.POISON: case StatusEffect.TOXIC: diff --git a/src/locales/de/arena-tag.json b/src/locales/de/arena-tag.json index 454effae60c..3bed4fefbd0 100644 --- a/src/locales/de/arena-tag.json +++ b/src/locales/de/arena-tag.json @@ -47,5 +47,11 @@ "tailwindOnRemovePlayer": "Der Rückenwind auf deiner Seite hat sich gelegt!", "tailwindOnRemoveEnemy": "Der Rückenwind auf gegnerischer Seite hat sich gelegt!", "happyHourOnAdd": "Goldene Zeiten sind angebrochen!", - "happyHourOnRemove": "Die goldenen Zeiten sind vorbei!" + "happyHourOnRemove": "Die goldenen Zeiten sind vorbei!", + "safeguardOnAdd": "Das ganze Feld wird von einem Schleier umhüllt!", + "safeguardOnAddPlayer": "Das Team des Anwenders wird von einem Schleier umhüllt!", + "safeguardOnAddEnemy": "Das gegnerische Team wird von einem Schleier umhüllt!", + "safeguardOnRemove": "Der mystische Schleier, der das ganze Feld umgab, hat sich gelüftet!", + "safeguardOnRemovePlayer": "Der mystische Schleier, der dein Team umgab, hat sich gelüftet!", + "safeguardOnRemoveEnemy": "Der mystische Schleier, der das gegnerische Team umgab, hat sich gelüftet!" } \ No newline at end of file diff --git a/src/locales/de/move-trigger.json b/src/locales/de/move-trigger.json index 5b2b2471df9..163e8014d8b 100644 --- a/src/locales/de/move-trigger.json +++ b/src/locales/de/move-trigger.json @@ -61,5 +61,6 @@ "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}}!" + "exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!", + "safeguard": "{{targetName}} wird durch Bodyguard geschützt!" } \ No newline at end of file diff --git a/src/locales/es/arena-tag.json b/src/locales/es/arena-tag.json index 9e26dfeeb6e..913876ddf87 100644 --- a/src/locales/es/arena-tag.json +++ b/src/locales/es/arena-tag.json @@ -1 +1,8 @@ -{} \ No newline at end of file +{ + "safeguardOnAdd": "¡Todos los Pokémon están protegidos por Velo Sagrado!", + "safeguardOnAddPlayer": "¡Tu equipo se ha protegido con Velo Sagrado!", + "safeguardOnAddEnemy": "¡El equipo enemigo se ha protegido con Velo Sagrado!", + "safeguardOnRemove": "¡Velo Sagrado dejó de hacer efecto!", + "safeguardOnRemovePlayer": "El efecto de Velo Sagrado en tu equipo se ha disipado.", + "safeguardOnRemoveEnemy": "El efecto de Velo Sagrado en el equipo enemigo se ha disipado." +} \ No newline at end of file diff --git a/src/locales/es/move-trigger.json b/src/locales/es/move-trigger.json index b570f029377..52a6f86d930 100644 --- a/src/locales/es/move-trigger.json +++ b/src/locales/es/move-trigger.json @@ -7,5 +7,6 @@ "usedUpAllElectricity": "¡{{pokemonName}} ha descargado toda su electricidad!", "stoleItem": "¡{{pokemonName}} robó el objeto\n{{itemName}} de {{targetName}}!", "statEliminated": "¡Los cambios en estadísticas fueron eliminados!", - "revivalBlessing": "¡{{pokemonName}} ha revivido!" + "revivalBlessing": "¡{{pokemonName}} ha revivido!", + "safeguard": "¡{{targetName}} está protegido por Velo Sagrado!" } \ No newline at end of file diff --git a/src/locales/fr/arena-tag.json b/src/locales/fr/arena-tag.json index 16355816ae4..c3c705290fa 100644 --- a/src/locales/fr/arena-tag.json +++ b/src/locales/fr/arena-tag.json @@ -47,5 +47,11 @@ "tailwindOnRemovePlayer": "Le vent arrière soufflant\nsur votre équipe s’arrête !", "tailwindOnRemoveEnemy": "Le vent arrière soufflant\nsur l’équipe ennemie s’arrête !", "happyHourOnAdd": "L’ambiance est euphorique !", - "happyHourOnRemove": "L’ambiance se calme !" + "happyHourOnRemove": "L’ambiance se calme !", + "safeguardOnAdd": "Un voile mystérieux recouvre\ntout le terrain !", + "safeguardOnAddPlayer": "Un voile mystérieux recouvre\nvotre équipe !", + "safeguardOnAddEnemy": "Un voile mystérieux recouvre\nl’équipe ennemie !", + "safeguardOnRemove": "Le terrain n’est plus protégé\npar le voile mystérieux !", + "safeguardOnRemovePlayer": "Votre équipe n’est plus protégée\npar le voile mystérieux !", + "safeguardOnRemoveEnemy": "L’équipe ennemie n’est plus protégée\npar le voile mystérieux !" } \ No newline at end of file diff --git a/src/locales/fr/move-trigger.json b/src/locales/fr/move-trigger.json index 43cf09d5bf6..5c814745a8e 100644 --- a/src/locales/fr/move-trigger.json +++ b/src/locales/fr/move-trigger.json @@ -61,5 +61,6 @@ "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}} !" + "exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !", + "safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !" } \ No newline at end of file diff --git a/src/locales/it/arena-tag.json b/src/locales/it/arena-tag.json index 9e26dfeeb6e..a1c5ee5b3c9 100644 --- a/src/locales/it/arena-tag.json +++ b/src/locales/it/arena-tag.json @@ -1 +1,8 @@ -{} \ No newline at end of file +{ + "safeguardOnAdd": "Un velo mistico ricopre il campo!", + "safeguardOnAddPlayer": "Un velo mistico ricopre la tua squadra!", + "safeguardOnAddEnemy": "Un velo mistico ricopre la squadra avversaria!", + "safeguardOnRemove": "Il campo non è più protetto da Salvaguardia!", + "safeguardOnRemovePlayer": "La tua squadra non è più protetta da Salvaguardia!", + "safeguardOnRemoveEnemy": "La squadra avversaria non è più protetta da Salvaguardia!" +} \ No newline at end of file diff --git a/src/locales/it/move-trigger.json b/src/locales/it/move-trigger.json index e852c2fb52a..58b7b1a4c5b 100644 --- a/src/locales/it/move-trigger.json +++ b/src/locales/it/move-trigger.json @@ -61,5 +61,6 @@ "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}}!" + "exposedMove": "{{pokemonName}} ha identificato\n{{targetPokemonName}}!", + "safeguard": "Salvaguardia protegge {{targetName}}!" } \ No newline at end of file diff --git a/src/locales/ko/arena-tag.json b/src/locales/ko/arena-tag.json index 61586508a94..ce9922ab3bf 100644 --- a/src/locales/ko/arena-tag.json +++ b/src/locales/ko/arena-tag.json @@ -47,5 +47,11 @@ "tailwindOnRemovePlayer": "우리 편의\n순풍이 멈췄다!", "tailwindOnRemoveEnemy": "상대의\n순풍이 멈췄다!", "happyHourOnAdd": "모두 행복한 기분에\n휩싸였다!", - "happyHourOnRemove": "기분이 원래대로 돌아왔다." + "happyHourOnRemove": "기분이 원래대로 돌아왔다.", + "safeguardOnAdd": "필드 전체가 신비의 베일에 둘러싸였다!", + "safeguardOnAddPlayer": "우리 편은 신비의 베일에 둘러싸였다!", + "safeguardOnAddEnemy": "상대 편은 신비의 베일에 둘러싸였다!", + "safeguardOnRemove": "필드를 감싸던 신비의 베일이 없어졌다!", + "safeguardOnRemovePlayer": "우리 편을 감싸던 신비의 베일이 없어졌다!", + "safeguardOnRemoveEnemy": "상대 편을 감싸던 신비의 베일이 없어졌다!" } \ No newline at end of file diff --git a/src/locales/ko/move-trigger.json b/src/locales/ko/move-trigger.json index 61dffa122a3..f0e0fbd6a56 100644 --- a/src/locales/ko/move-trigger.json +++ b/src/locales/ko/move-trigger.json @@ -61,5 +61,6 @@ "suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!", "revivalBlessing": "{{pokemonName}}[[는]]\n정신을 차려 싸울 수 있게 되었다!", "swapArenaTags": "{{pokemonName}}[[는]]\n서로의 필드 효과를 교체했다!", - "exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!" + "exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!", + "safeguard": "{{targetName}}[[는]] 신비의 베일이 지켜 주고 있다!" } \ No newline at end of file diff --git a/src/locales/pt_BR/arena-tag.json b/src/locales/pt_BR/arena-tag.json index 20ef208c8fc..7ab1ecea721 100644 --- a/src/locales/pt_BR/arena-tag.json +++ b/src/locales/pt_BR/arena-tag.json @@ -47,5 +47,11 @@ "tailwindOnRemovePlayer": "O Tailwind de sua equipe acabou!", "tailwindOnRemoveEnemy": "O Tailwind da equipe adversária acabou!", "happyHourOnAdd": "Todos foram envolvidos por uma atmosfera alegre!", - "happyHourOnRemove": "A atmosfera retornou ao normal." + "happyHourOnRemove": "A atmosfera retornou ao normal.", + "safeguardOnAdd": "O campo de batalha está envolto num véu místico!", + "safeguardOnAddPlayer": "Sua equipe se envolveu num véu místico!", + "safeguardOnAddEnemy": "A equipe adversária se envolveu num véu místico!", + "safeguardOnRemove": "O campo não está mais protegido por Safeguard!", + "safeguardOnRemovePlayer": "Sua equipe não está mais protegido por Safeguard!", + "safeguardOnRemoveEnemy": "A equipe adversária não está mais protegido por Safeguard!" } \ No newline at end of file diff --git a/src/locales/pt_BR/move-trigger.json b/src/locales/pt_BR/move-trigger.json index 416740dba0d..ea320412a24 100644 --- a/src/locales/pt_BR/move-trigger.json +++ b/src/locales/pt_BR/move-trigger.json @@ -61,5 +61,6 @@ "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}}!" + "exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!", + "safeguard": "{{targetName}} está protegido por Safeguard!" } \ No newline at end of file diff --git a/src/locales/zh_CN/arena-tag.json b/src/locales/zh_CN/arena-tag.json index 5a36b3ae1f7..74ad38ba9bf 100644 --- a/src/locales/zh_CN/arena-tag.json +++ b/src/locales/zh_CN/arena-tag.json @@ -47,5 +47,11 @@ "tailwindOnRemovePlayer": "我方的顺风停止了!", "tailwindOnRemoveEnemy": "敌方的顺风停止了!", "happyHourOnAdd": "大家被欢乐的\n气氛包围了!", - "happyHourOnRemove": "气氛回复到平常了。" + "happyHourOnRemove": "气氛回复到平常了。", + "safeguardOnAdd": "整个场地被\n神秘之幕包围了!", + "safeguardOnAddPlayer": "我方被\n神秘之幕包围了!", + "safeguardOnAddEnemy": "对手被\n神秘之幕包围了!", + "safeguardOnRemove": "包围整个场地的\n神秘之幕消失了!", + "safeguardOnRemovePlayer": "包围我方的\n神秘之幕消失了!", + "safeguardOnRemoveEnemy": "包围对手的\n神秘之幕消失了!" } \ No newline at end of file diff --git a/src/locales/zh_CN/move-trigger.json b/src/locales/zh_CN/move-trigger.json index 5a76f402783..44705d54e76 100644 --- a/src/locales/zh_CN/move-trigger.json +++ b/src/locales/zh_CN/move-trigger.json @@ -61,5 +61,6 @@ "suppressAbilities": "{{pokemonName}}的特性\n变得无效了!", "revivalBlessing": "{{pokemonName}}复活了!", "swapArenaTags": "{{pokemonName}}\n交换了双方的场地效果!", - "exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!" + "exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!", + "safeguard": "{{targetName}}\n正受到神秘之幕的保护!" } \ No newline at end of file diff --git a/src/locales/zh_TW/arena-tag.json b/src/locales/zh_TW/arena-tag.json index b60946a3b77..78246d9c44f 100644 --- a/src/locales/zh_TW/arena-tag.json +++ b/src/locales/zh_TW/arena-tag.json @@ -1,5 +1,11 @@ { "noCritOnAddPlayer": "{{moveName}}保護了你的\n隊伍不被擊中要害!", "noCritOnAddEnemy": "{{moveName}}保護了對方的\n隊伍不被擊中要害!", - "noCritOnRemove": "{{pokemonNameWithAffix}}的{{moveName}}\n效果消失了!" + "noCritOnRemove": "{{pokemonNameWithAffix}}的{{moveName}}\n效果消失了!", + "safeguardOnAdd": "整個場地被\n神秘之幕包圍了!", + "safeguardOnAddPlayer": "我方被\n神秘之幕包圍了!", + "safeguardOnAddEnemy": "對手被\n神秘之幕包圍了!", + "safeguardOnRemove": "包圍整個場地的\n神秘之幕消失了!", + "safeguardOnRemovePlayer": "包圍我方的\n神秘之幕消失了!", + "safeguardOnRemoveEnemy": "包圍對手的\n神秘之幕消失了!" } \ No newline at end of file diff --git a/src/locales/zh_TW/move-trigger.json b/src/locales/zh_TW/move-trigger.json index 03ca6841a7f..60dcc1eab7a 100644 --- a/src/locales/zh_TW/move-trigger.json +++ b/src/locales/zh_TW/move-trigger.json @@ -61,5 +61,6 @@ "suppressAbilities": "{{pokemonName}}的特性\n變得無效了!", "revivalBlessing": "{{pokemonName}}復活了!", "swapArenaTags": "{{pokemonName}}\n交換了雙方的場地效果!", - "exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!" + "exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!", + "safeguard": "{{targetName}}\n正受到神秘之幕的保護!" } \ No newline at end of file diff --git a/src/test/moves/safeguard.test.ts b/src/test/moves/safeguard.test.ts new file mode 100644 index 00000000000..94a7aa6031e --- /dev/null +++ b/src/test/moves/safeguard.test.ts @@ -0,0 +1,150 @@ +import { BattlerIndex } from "#app/battle"; +import { allAbilities, PostDefendContactApplyStatusEffectAbAttr } from "#app/data/ability"; +import { Abilities } from "#app/enums/abilities"; +import { StatusEffect } from "#app/enums/status-effect"; +import GameManager from "#app/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"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Safeguard", () => { + 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.DRATINI) + .enemyMoveset(Array(4).fill(Moves.SAFEGUARD)) + .enemyAbility(Abilities.BALL_FETCH) + .enemyLevel(5) + .starterSpecies(Species.DRATINI) + .moveset([Moves.NUZZLE, Moves.SPORE, Moves.YAWN, Moves.SPLASH]) + .ability(Abilities.BALL_FETCH); + }); + + it("protects from damaging moves with additional effects", async () => { + await game.startBattle(); + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.NUZZLE); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemy.status).toBeUndefined(); + }, TIMEOUT); + + it("protects from status moves", async () => { + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SPORE); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemyPokemon.status).toBeUndefined(); + }, TIMEOUT); + + it("protects from confusion", async () => { + game.override.moveset([Moves.CONFUSE_RAY]); + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.CONFUSE_RAY); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemyPokemon.summonData.tags).toEqual([]); + }, TIMEOUT); + + it("protects ally from status", async () => { + game.override.battleType("double"); + + await game.startBattle(); + + game.move.select(Moves.SPORE, 0, BattlerIndex.ENEMY_2); + game.move.select(Moves.NUZZLE, 1, BattlerIndex.ENEMY_2); + + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2]); + + await game.phaseInterceptor.to("BerryPhase"); + + const enemyPokemon = game.scene.getEnemyField(); + + expect(enemyPokemon[0].status).toBeUndefined(); + expect(enemyPokemon[1].status).toBeUndefined(); + }, TIMEOUT); + + it("protects from Yawn", async () => { + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.YAWN); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemyPokemon.summonData.tags).toEqual([]); + }, TIMEOUT); + + it("doesn't protect from already existing Yawn", async () => { + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.YAWN); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.toNextTurn(); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(enemyPokemon.status?.effect).toEqual(StatusEffect.SLEEP); + }, TIMEOUT); + + it("doesn't protect from self-inflicted via Rest or Flame Orb", async () => { + game.override.enemyHeldItems([{name: "FLAME_ORB"}]); + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SPLASH); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemyPokemon.status?.effect).toEqual(StatusEffect.BURN); + + game.override.enemyMoveset(Array(4).fill(Moves.REST)); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(enemyPokemon.status?.effect).toEqual(StatusEffect.SLEEP); + }, TIMEOUT); + + it("protects from ability-inflicted status", async () => { + game.override.ability(Abilities.STATIC); + vi.spyOn(allAbilities[Abilities.STATIC].getAttrs(PostDefendContactApplyStatusEffectAbAttr)[0], "chance", "get").mockReturnValue(100); + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SPLASH); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(enemyPokemon.status).toBeUndefined(); + }, TIMEOUT); +}); From 1e432fc74b958e4629c4b33de85ee103444069ed Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:26:35 -0700 Subject: [PATCH 38/40] [Bug] Fixed pre-set volume oversight (#3963) Co-authored-by: frutescens --- src/battle-scene.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 2a920864850..e761d8fca39 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1791,6 +1791,7 @@ export default class BattleScene extends SceneBase { config = config ?? {}; try { const keyDetails = key.split("/"); + config["volume"] = config["volume"] ?? 1; switch (keyDetails[0]) { case "level_up_fanfare": case "item_fanfare": @@ -1800,11 +1801,11 @@ export default class BattleScene extends SceneBase { case "evolution_fanfare": // These sounds are loaded in as BGM, but played as sound effects // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() - config["volume"] = this.masterVolume * this.bgmVolume; + config["volume"] *= (this.masterVolume * this.bgmVolume); break; case "battle_anims": case "cry": - config["volume"] = this.masterVolume * this.fieldVolume; + config["volume"] *= (this.masterVolume * this.fieldVolume); //PRSFX sound files are unusually loud if (keyDetails[1].startsWith("PRSFX- ")) { config["volume"] *= 0.5; @@ -1812,10 +1813,10 @@ export default class BattleScene extends SceneBase { break; case "ui": //As of, right now this applies to the "select", "menu_open", "error" sound effects - config["volume"] = this.masterVolume * this.uiVolume; + config["volume"] *= (this.masterVolume * this.uiVolume); break; case "se": - config["volume"] = this.masterVolume * this.seVolume; + config["volume"] *= (this.masterVolume * this.seVolume); break; } this.sound.play(key, config); From 84ef7f0683737eb8f35505420acb3071c4593ca5 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:26:47 -0700 Subject: [PATCH 39/40] [Balance] Double base shiny odds, adjusted Shiny Charm to match (#3964) * Double shiny odds "anyone wanna double the base shiny odds for me" - damo, 2024 * Adjust Shiny Charm to compensate for increased base odds * Remove magic number * Update tsdoc and remove unneeded `console.log()` * Clarify tsdoc --- src/field/pokemon.ts | 18 +++++++++--------- src/modifier/modifier.ts | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c970c99e7d3..8594d5b769b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1527,13 +1527,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** - * Function that tries to set a Pokemon shiny based on the trainer's trainer ID and secret ID + * Function that tries to set a Pokemon shiny based on the trainer's trainer ID and secret ID. * Endless Pokemon in the end biome are unable to be set to shiny * - * The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID - * F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits - * The XOR of E and F are then compared to the thresholdOverride (default case 32) to see whether or not to generate a shiny - * @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance + * The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID. + * F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits. + * The XOR of E and F are then compared to the {@linkcode shinyThreshold} (or {@linkcode thresholdOverride} if set) to see whether or not to generate a shiny. + * The base shiny odds are {@linkcode baseShinyChance} / 65536 + * @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm) * @returns true if the Pokemon has been set as a shiny, false otherwise */ trySetShiny(thresholdOverride?: integer): boolean { @@ -1548,7 +1549,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const E = this.scene.gameData.trainerId ^ this.scene.gameData.secretId; const F = rand1 ^ rand2; - const shinyThreshold = new Utils.IntegerHolder(32); + /** `64/65536 -> 1/1024` */ + const baseShinyChance = 64; + const shinyThreshold = new Utils.IntegerHolder(baseShinyChance); if (thresholdOverride === undefined) { if (this.scene.eventManager.isEventActive()) { shinyThreshold.value *= this.scene.eventManager.getShinyMultiplier(); @@ -1561,9 +1564,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } this.shiny = (E ^ F) < shinyThreshold.value; - if ((E ^ F) < 32) { - console.log("REAL SHINY!!"); - } if (this.shiny) { this.initShinySparkle(); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 99f4540f493..ca0b18ce18b 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -12,7 +12,7 @@ import { getPokemonNameWithAffix } from "../messages"; import * as Utils from "../utils"; import { TempBattleStat } from "../data/temp-battle-stat"; import { getBerryEffectFunc, getBerryPredicate } from "../data/berry"; -import { BattlerTagType} from "#enums/battler-tag-type"; +import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { StatusEffect, getStatusEffectHealText } from "../data/status-effect"; import { achvs } from "../system/achv"; @@ -2193,7 +2193,7 @@ export class ShinyRateBoosterModifier extends PersistentModifier { } apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value *= Math.pow(2, 2 + this.getStackCount()); + (args[0] as Utils.IntegerHolder).value *= Math.pow(2, 1 + this.getStackCount()); return true; } From 0cbdaab28e6902e91bbc5019e87c1f930d87291b Mon Sep 17 00:00:00 2001 From: Mumble <171087428+frutescens@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:32:22 -0700 Subject: [PATCH 40/40] [UI][Misc] Force users to have an active challenge (#3953) * I hope this is good enough * renamed variable to better name * Remove random newline * When player is ready cool box * Fixed cancel behavior * standardized action/cancel behavior * Added comments --------- Co-authored-by: frutescens Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/locales/en/challenges.json | 1 + src/ui/challenges-select-ui-handler.ts | 181 ++++++++++++++----------- 2 files changed, 101 insertions(+), 81 deletions(-) diff --git a/src/locales/en/challenges.json b/src/locales/en/challenges.json index f189266cea2..7d330401407 100644 --- a/src/locales/en/challenges.json +++ b/src/locales/en/challenges.json @@ -1,6 +1,7 @@ { "title": "Challenge Modifiers", "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!", + "noneSelected": "None Selected", "singleGeneration": { "name": "Mono Gen", "desc": "You can only use Pokémon from Generation {{gen}}.", diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts index f1ba0da6c51..e08736d2b70 100644 --- a/src/ui/challenges-select-ui-handler.ts +++ b/src/ui/challenges-select-ui-handler.ts @@ -5,13 +5,13 @@ import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import {Button} from "#enums/buttons"; import i18next from "i18next"; -import { Challenge } from "#app/data/challenge.js"; +import { Challenge } from "#app/data/challenge"; import * as Utils from "../utils"; -import { Challenges } from "#app/enums/challenges.js"; +import { Challenges } from "#app/enums/challenges"; 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"; +import { Color, ShadowColor } from "#app/enums/color"; +import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { TitlePhase } from "#app/phases/title-phase"; /** * Handles all the UI for choosing optional challenges. @@ -33,7 +33,10 @@ export default class GameChallengesUiHandler extends UiHandler { private cursorObj: Phaser.GameObjects.NineSlice | null; + private startBg: Phaser.GameObjects.NineSlice; private startCursor: Phaser.GameObjects.NineSlice; + private startText: Phaser.GameObjects.Text; + private hasSelectedChallenge: boolean; private optionsWidth: number; @@ -104,20 +107,20 @@ export default class GameChallengesUiHandler extends UiHandler { this.descriptionText.setShadow(4, 5, ShadowColor.ORANGE); this.descriptionText.setOrigin(0, 0); - const startBg = addWindow(this.scene, 0, 0, descriptionBg.width, 24); - startBg.setName("window-start-bg"); - startBg.setOrigin(0, 0); - startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height); + this.startBg = addWindow(this.scene, 0, 0, descriptionBg.width, 24); + this.startBg.setName("window-start-bg"); + this.startBg.setOrigin(0, 0); + this.startBg.setPositionRelative(descriptionBg, 0, descriptionBg.height); - const startText = addTextObject(this.scene, 0, 0, i18next.t("common:start"), TextStyle.SETTINGS_LABEL); - startText.setName("text-start"); - startText.setOrigin(0, 0); - startText.setPositionRelative(startBg, (startBg.width - startText.displayWidth) / 2, 4); + this.startText = addTextObject(this.scene, 0, 0, i18next.t("challenges:noneSelected"), TextStyle.SETTINGS_LABEL); + this.startText.setName("text-start"); + this.startText.setOrigin(0, 0); + this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4); this.startCursor = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, descriptionBg.width - 8, 16, 1, 1, 1, 1); this.startCursor.setName("9s-start-cursor"); this.startCursor.setOrigin(0, 0); - this.startCursor.setPositionRelative(startBg, 4, 3); + this.startCursor.setPositionRelative(this.startBg, 4, 3); this.startCursor.setVisible(false); this.valuesContainer = this.scene.add.container(0, 0); @@ -157,8 +160,8 @@ export default class GameChallengesUiHandler extends UiHandler { this.challengesContainer.add(this.optionsBg); this.challengesContainer.add(descriptionBg); this.challengesContainer.add(this.descriptionText); - this.challengesContainer.add(startBg); - this.challengesContainer.add(startText); + this.challengesContainer.add(this.startBg); + this.challengesContainer.add(this.startText); this.challengesContainer.add(this.startCursor); this.challengesContainer.add(this.valuesContainer); @@ -216,6 +219,21 @@ export default class GameChallengesUiHandler extends UiHandler { this.monoTypeValue.setVisible(false); } + // This checks if a challenge has been selected by the user and updates the text/its opacity accordingly. + this.hasSelectedChallenge = this.scene.gameMode.challenges.some(c => c.value !== 0); + if (this.hasSelectedChallenge) { + + this.startText.setText(i18next.t("common:start")); + this.startText.setAlpha(1); + this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4); + } else { + + this.startText.setText(i18next.t("challenges:noneSelected")); + this.startText.setAlpha(0.5); + this.startText.setPositionRelative(this.startBg, (this.startBg.width - this.startText.displayWidth) / 2, 4); + } + this.challengesContainer.update(); + // const totalDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getDifficulty(), 0); // const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0); // this.difficultyText.text = `${totalDifficulty}` + (totalMinDifficulty ? `/${totalMinDifficulty}` : ""); @@ -227,6 +245,8 @@ export default class GameChallengesUiHandler extends UiHandler { this.startCursor.setVisible(false); this.challengesContainer.setVisible(true); + // Should always be false at the start + this.hasSelectedChallenge = this.scene.gameMode.challenges.some(c => c.value !== 0); this.setCursor(0); this.initLabels(); @@ -257,6 +277,7 @@ export default class GameChallengesUiHandler extends UiHandler { if (button === Button.CANCEL) { if (this.startCursor.visible) { + // If the user presses cancel when the start cursor has been activated, the game deactivates the start cursor and allows typical challenge selection behavior this.startCursor.setVisible(false); this.cursorObj?.setVisible(true); } else { @@ -266,83 +287,82 @@ export default class GameChallengesUiHandler extends UiHandler { } success = true; } else if (button === Button.SUBMIT || button === Button.ACTION) { - if (this.startCursor.visible) { - const totalDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getDifficulty(), 0); - const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0); - if (totalDifficulty >= totalMinDifficulty) { + if (this.hasSelectedChallenge) { + if (this.startCursor.visible) { this.scene.unshiftPhase(new SelectStarterPhase(this.scene)); this.scene.getCurrentPhase()?.end(); - success = true; } else { - success = false; + this.startCursor.setVisible(true); + this.cursorObj?.setVisible(false); } - } else { - this.startCursor.setVisible(true); - this.cursorObj?.setVisible(false); success = true; + } else { + success = false; } } else { - switch (button) { - case Button.UP: - if (this.cursor === 0) { - if (this.scrollCursor === 0) { - // When at the top of the menu and pressing UP, move to the bottommost item. - if (this.scene.gameMode.challenges.length > rowsToDisplay) { // If there are more than 9 challenges, scroll to the bottom - // First, set the cursor to the last visible element, preparing for the scroll to the end. - const successA = this.setCursor(rowsToDisplay - 1); - // Then, adjust the scroll to display the bottommost elements of the menu. - const successB = this.setScrollCursor(this.scene.gameMode.challenges.length - rowsToDisplay); - success = successA && successB; // success is just there to play the little validation sound effect - } else { // If there are 9 or less challenges, just move to the bottom one - success = this.setCursor(this.scene.gameMode.challenges.length - 1); + if (this.cursorObj?.visible && !this.startCursor.visible) { + switch (button) { + case Button.UP: + if (this.cursor === 0) { + if (this.scrollCursor === 0) { + // When at the top of the menu and pressing UP, move to the bottommost item. + if (this.scene.gameMode.challenges.length > rowsToDisplay) { // If there are more than 9 challenges, scroll to the bottom + // First, set the cursor to the last visible element, preparing for the scroll to the end. + const successA = this.setCursor(rowsToDisplay - 1); + // Then, adjust the scroll to display the bottommost elements of the menu. + const successB = this.setScrollCursor(this.scene.gameMode.challenges.length - rowsToDisplay); + success = successA && successB; // success is just there to play the little validation sound effect + } else { // If there are 9 or less challenges, just move to the bottom one + success = this.setCursor(this.scene.gameMode.challenges.length - 1); + } + } else { + success = this.setScrollCursor(this.scrollCursor - 1); } } else { - success = this.setScrollCursor(this.scrollCursor - 1); + success = this.setCursor(this.cursor - 1); } - } else { - success = this.setCursor(this.cursor - 1); - } - if (success) { - this.updateText(); - } - break; - case Button.DOWN: - if (this.cursor === rowsToDisplay - 1) { - if (this.scrollCursor < this.scene.gameMode.challenges.length - rowsToDisplay) { - // When at the bottom and pressing DOWN, scroll if possible. - success = this.setScrollCursor(this.scrollCursor + 1); + if (success) { + this.updateText(); + } + break; + case Button.DOWN: + if (this.cursor === rowsToDisplay - 1) { + if (this.scrollCursor < this.scene.gameMode.challenges.length - rowsToDisplay) { + // When at the bottom and pressing DOWN, scroll if possible. + success = this.setScrollCursor(this.scrollCursor + 1); + } else { + // When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item. + // First, set the cursor to the first visible element, preparing for the scroll to the top. + const successA = this.setCursor(0); + // Then, adjust the scroll to display the topmost elements of the menu. + const successB = this.setScrollCursor(0); + success = successA && successB; // success is just there to play the little validation sound effect + } + } else if (this.scene.gameMode.challenges.length < rowsToDisplay && this.cursor === this.scene.gameMode.challenges.length - 1) { + // When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item. + success = this.setCursor(0); } else { - // When at the bottom of a scrolling menu and pressing DOWN, move to the topmost item. - // First, set the cursor to the first visible element, preparing for the scroll to the top. - const successA = this.setCursor(0); - // Then, adjust the scroll to display the topmost elements of the menu. - const successB = this.setScrollCursor(0); - success = successA && successB; // success is just there to play the little validation sound effect + success = this.setCursor(this.cursor + 1); } - } else if (this.scene.gameMode.challenges.length < rowsToDisplay && this.cursor === this.scene.gameMode.challenges.length - 1) { - // When at the bottom of a non-scrolling menu and pressing DOWN, move to the topmost item. - success = this.setCursor(0); - } else { - success = this.setCursor(this.cursor + 1); + if (success) { + this.updateText(); + } + break; + case Button.LEFT: + // Moves the option cursor left, if possible. + success = this.getActiveChallenge().decreaseValue(); + if (success) { + this.updateText(); + } + break; + case Button.RIGHT: + // Moves the option cursor right, if possible. + success = this.getActiveChallenge().increaseValue(); + if (success) { + this.updateText(); + } + break; } - if (success) { - this.updateText(); - } - break; - case Button.LEFT: - // Moves the option cursor left, if possible. - success = this.getActiveChallenge().decreaseValue(); - if (success) { - this.updateText(); - } - break; - case Button.RIGHT: - // Moves the option cursor right, if possible. - success = this.getActiveChallenge().increaseValue(); - if (success) { - this.updateText(); - } - break; } } @@ -350,7 +370,6 @@ export default class GameChallengesUiHandler extends UiHandler { if (success) { ui.playSelect(); } - return success; }